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,7 +90,15 @@ func (l *Launcher) LaunchAgent(p *preset.Preset, displayName, initialPrompt, par
|
||||
|
||||
// Spawn with the chosen identity.
|
||||
cols, rows := l.size()
|
||||
c, err := l.sess.spawnWithIdentity(displayName, KindAgent, argv, env, cols, rows, parentID, identity)
|
||||
c, err := l.sess.Spawn(SpawnSpec{
|
||||
Kind: KindAgent,
|
||||
Argv: argv,
|
||||
Env: env,
|
||||
Name: displayName,
|
||||
ParentID: parentID,
|
||||
PresetRef: p.Name,
|
||||
Identity: identity,
|
||||
}, cols, rows)
|
||||
if err != nil {
|
||||
_ = os.Remove(mcpConfigPath)
|
||||
return nil, err
|
||||
@@ -111,17 +119,72 @@ func (l *Launcher) LaunchAgent(p *preset.Preset, displayName, initialPrompt, par
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// LaunchProcess spawns a process preset. No MCP injection; just argv.
|
||||
func (l *Launcher) LaunchProcess(p *preset.Preset, displayName string) (*Child, error) {
|
||||
if p.Kind != preset.KindProcess {
|
||||
return nil, fmt.Errorf("launch: %q is not a process preset", p.Name)
|
||||
// LaunchCommandPreset spawns a process preset as a SPEC §7 command
|
||||
// entry. No MCP injection; just argv. The entry is session-persistent
|
||||
// (survives PTY exit so it can be Restart'd).
|
||||
func (l *Launcher) LaunchCommandPreset(p *preset.Preset, displayName, parentID string) (*Child, error) {
|
||||
if p.Kind != preset.KindCommand {
|
||||
return nil, fmt.Errorf("launch: %q is not a command preset", p.Name)
|
||||
}
|
||||
env := l.sess.ChildEnv()
|
||||
for k, v := range p.Env {
|
||||
env = append(env, k+"="+v)
|
||||
}
|
||||
cols, rows := l.size()
|
||||
return l.sess.Spawn(displayName, KindProcess, p.ResolvedArgv(), env, cols, rows, "")
|
||||
return l.sess.Spawn(SpawnSpec{
|
||||
Kind: KindCommand,
|
||||
Argv: p.ResolvedArgv(),
|
||||
Env: env,
|
||||
Name: displayName,
|
||||
ParentID: parentID,
|
||||
WorkDir: p.WorkingDir,
|
||||
PresetRef: p.Name,
|
||||
}, cols, rows)
|
||||
}
|
||||
|
||||
// LaunchCommandArgv spawns a freeform-argv command entry. Trust gating
|
||||
// (SPEC §7) lives one level up in toolHost — by the time we get here
|
||||
// trust is settled (freeform argv is implicitly trusted).
|
||||
func (l *Launcher) LaunchCommandArgv(argv []string, displayName, parentID, workDir string, env []string, shell bool) (*Child, error) {
|
||||
if shell && len(argv) > 0 {
|
||||
argv = []string{"sh", "-lc", strings.Join(argv, " ")}
|
||||
}
|
||||
if env == nil {
|
||||
env = l.sess.ChildEnv()
|
||||
}
|
||||
cols, rows := l.size()
|
||||
return l.sess.Spawn(SpawnSpec{
|
||||
Kind: KindCommand,
|
||||
Argv: argv,
|
||||
Env: env,
|
||||
Name: displayName,
|
||||
ParentID: parentID,
|
||||
WorkDir: workDir,
|
||||
}, cols, rows)
|
||||
}
|
||||
|
||||
// LaunchTerminal spawns a bare interactive shell. SPEC §7 kind=terminal.
|
||||
// argv defaults to $SHELL -i when empty.
|
||||
func (l *Launcher) LaunchTerminal(argv []string, displayName, parentID, workDir string, env []string) (*Child, error) {
|
||||
if len(argv) == 0 {
|
||||
sh := os.Getenv("SHELL")
|
||||
if sh == "" {
|
||||
sh = "/bin/sh"
|
||||
}
|
||||
argv = []string{sh, "-i"}
|
||||
}
|
||||
if env == nil {
|
||||
env = l.sess.ChildEnv()
|
||||
}
|
||||
cols, rows := l.size()
|
||||
return l.sess.Spawn(SpawnSpec{
|
||||
Kind: KindTerminal,
|
||||
Argv: argv,
|
||||
Env: env,
|
||||
Name: displayName,
|
||||
ParentID: parentID,
|
||||
WorkDir: workDir,
|
||||
}, cols, rows)
|
||||
}
|
||||
|
||||
func (l *Launcher) writeMCPConfig() (identity, path string, err error) {
|
||||
|
||||
Reference in New Issue
Block a user