Sync MCP surface to SPEC §7 process model
Rename list_children/read_output/kill/send_message_to to their SPEC §7 process_id-shaped names; drop report_to_parent (direction inferred by send_message) and policy_check (replaced by per-project trust gating). Add the SPEC's missing tools: start_process, restart_process, close_process, rename_process, select_process, get_process_status, get_project_status, get_process_raw_output, search_output, get_process_ports, whoami, help. Process model now distinguishes agent/terminal/command kinds with opaque p_<6hex> IDs. Command entries are session-persistent so they survive PTY exit and can be Restart'd. Status enum gains starting and stopped. screen_version, port detection, and bracketed-paste send_input land alongside. Trust gating (internal/trust) replaces the regex policy: command-preset spawns return needs_trust on first use; the user confirms in a status-line modal and the grant persists to \$XDG_DATA_HOME/patterm/projects/<key>/trust.json. Tests cover send_message direction inference (parent↔child, sibling rejection, nil caller paths) and trust grant persistence across reopen.
This commit is contained in:
@@ -90,9 +90,21 @@ func (s *Store) Read(name string) (content string, revision string, err error) {
|
||||
return string(b), revisionOf(b), nil
|
||||
}
|
||||
|
||||
// RevisionMismatchError is returned by Write when expectedRevision
|
||||
// doesn't match the on-disk revision. The MCP scratchpad_write tool
|
||||
// surfaces CurrentRevision as `current_revision` in the response so
|
||||
// the caller can re-read and merge (SPEC §7 / §14).
|
||||
type RevisionMismatchError struct {
|
||||
CurrentRevision string
|
||||
}
|
||||
|
||||
func (e *RevisionMismatchError) Error() string {
|
||||
return "scratchpad: revision mismatch (current=" + e.CurrentRevision + ")"
|
||||
}
|
||||
|
||||
// Write replaces the file's contents. expectedRevision, if non-empty,
|
||||
// must match the current revision or the write is rejected (SPEC §14
|
||||
// last-write-wins-with-token).
|
||||
// must match the current revision or the write is rejected with a
|
||||
// *RevisionMismatchError (SPEC §14 last-write-wins-with-token).
|
||||
func (s *Store) Write(name, content, expectedRevision string) (string, error) {
|
||||
p, err := s.safePath(name)
|
||||
if err != nil {
|
||||
@@ -100,8 +112,9 @@ func (s *Store) Write(name, content, expectedRevision string) (string, error) {
|
||||
}
|
||||
if expectedRevision != "" {
|
||||
if cur, err := os.ReadFile(p); err == nil {
|
||||
if revisionOf(cur) != expectedRevision {
|
||||
return "", fmt.Errorf("scratchpad: revision mismatch")
|
||||
curRev := revisionOf(cur)
|
||||
if curRev != expectedRevision {
|
||||
return "", &RevisionMismatchError{CurrentRevision: curRev}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user