@selesai/code 0.5.19 → 0.5.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/extensions/handoff-new.test.ts +8 -9
- package/dist/extensions/handoff-new.ts +6 -8
- package/dist/extensions/pi-intercom/broker/spawn.test.ts +31 -0
- package/dist/extensions/pi-intercom/broker/spawn.ts +5 -3
- package/dist/extensions/pi-subagents/CHANGELOG.md +1367 -0
- package/dist/extensions/pi-subagents/README.md +602 -220
- package/dist/extensions/pi-subagents/banner.png +0 -0
- package/dist/extensions/pi-subagents/index.ts +1 -0
- package/dist/extensions/pi-subagents/install.mjs +3 -3
- package/dist/extensions/pi-subagents/package-lock.json +3405 -0
- package/dist/extensions/pi-subagents/package.json +26 -14
- package/dist/extensions/pi-subagents/prompts/gather-context-and-clarify.md +1 -1
- package/dist/extensions/pi-subagents/prompts/parallel-cleanup.md +9 -9
- package/dist/extensions/pi-subagents/prompts/parallel-context-build.md +3 -3
- package/dist/extensions/pi-subagents/prompts/parallel-handoff-plan.md +7 -7
- package/dist/extensions/pi-subagents/prompts/parallel-research.md +6 -6
- package/dist/extensions/pi-subagents/prompts/parallel-review.md +8 -8
- package/dist/extensions/pi-subagents/prompts/review-loop.md +13 -11
- package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +267 -176
- package/dist/extensions/pi-subagents/src/agents/agent-management.ts +89 -16
- package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +19 -0
- package/dist/extensions/pi-subagents/src/agents/agents.ts +218 -120
- package/dist/extensions/pi-subagents/src/agents/frontmatter.ts +67 -13
- package/dist/extensions/pi-subagents/src/agents/proactive-skills.ts +2 -2
- package/dist/extensions/pi-subagents/src/agents/skills.ts +25 -12
- package/dist/extensions/pi-subagents/src/api/background-work.ts +197 -0
- package/dist/extensions/pi-subagents/src/api/capability-ceiling.ts +17 -0
- package/dist/extensions/pi-subagents/src/api/delegation.ts +285 -0
- package/dist/extensions/pi-subagents/src/api/preflight.ts +399 -0
- package/dist/extensions/pi-subagents/src/extension/chain-validation.ts +165 -0
- package/dist/extensions/pi-subagents/src/extension/config.ts +7 -1
- package/dist/extensions/pi-subagents/src/extension/doctor.ts +15 -0
- package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +3 -1
- package/dist/extensions/pi-subagents/src/extension/index.ts +113 -157
- package/dist/extensions/pi-subagents/src/extension/rpc.ts +41 -4
- package/dist/extensions/pi-subagents/src/extension/schemas.ts +45 -15
- package/dist/extensions/pi-subagents/src/extension/steering-notices.ts +35 -0
- package/dist/extensions/pi-subagents/src/extension/tool-description.ts +28 -15
- package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +4 -3
- package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +225 -29
- package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +11 -0
- package/dist/extensions/pi-subagents/src/profiles/profiles.ts +8 -10
- package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +452 -62
- package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +60 -9
- package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +198 -52
- package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +119 -21
- package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +67 -0
- package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +2 -0
- package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +16 -8
- package/dist/extensions/pi-subagents/src/runs/background/completion-batcher.ts +6 -4
- package/dist/extensions/pi-subagents/src/runs/background/completion-dedupe.ts +2 -11
- package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +260 -13
- package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +32 -6
- package/dist/extensions/pi-subagents/src/runs/background/notify.ts +171 -90
- package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +280 -0
- package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +149 -88
- package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +14 -2
- package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +33 -17
- package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +9 -1
- package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +38 -10
- package/dist/extensions/pi-subagents/src/runs/background/steering.ts +237 -0
- package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +1297 -307
- package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +610 -0
- package/dist/extensions/pi-subagents/src/runs/background/top-level-async.ts +2 -1
- package/dist/extensions/pi-subagents/src/runs/background/wait-config.ts +36 -0
- package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +26 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +230 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +22 -6
- package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +228 -140
- package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +452 -138
- package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +90 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +1001 -416
- package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +443 -132
- package/dist/extensions/pi-subagents/src/runs/shared/agent-contract.ts +38 -0
- package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +178 -0
- package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +121 -0
- package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +41 -93
- package/dist/extensions/pi-subagents/src/runs/shared/context-mode.ts +44 -0
- package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +11 -9
- package/dist/extensions/pi-subagents/src/runs/shared/long-running-guard.ts +4 -0
- package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +12 -6
- package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +36 -0
- package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +44 -7
- package/dist/extensions/pi-subagents/src/runs/shared/nested-render.ts +4 -1
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +154 -0
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +18 -0
- package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +174 -54
- package/dist/extensions/pi-subagents/src/runs/shared/pi-spawn.ts +38 -31
- package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +90 -5
- package/dist/extensions/pi-subagents/src/runs/shared/session-lease.ts +299 -0
- package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +61 -6
- package/dist/extensions/pi-subagents/src/runs/shared/spawn-budget.ts +128 -0
- package/dist/extensions/pi-subagents/src/runs/shared/structured-output.ts +112 -7
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +14 -6
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +149 -36
- package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +181 -0
- package/dist/extensions/pi-subagents/src/runs/shared/tool-availability.ts +83 -0
- package/dist/extensions/pi-subagents/src/runs/shared/tool-budget.ts +11 -5
- package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +50 -4
- package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +63 -14
- package/dist/extensions/pi-subagents/src/shared/accessible-dir.ts +25 -0
- package/dist/extensions/pi-subagents/src/shared/artifacts.ts +37 -7
- package/dist/extensions/pi-subagents/src/shared/atomic-json.ts +18 -43
- package/dist/extensions/pi-subagents/src/shared/child-transcript.ts +52 -0
- package/dist/extensions/pi-subagents/src/shared/env.ts +16 -0
- package/dist/extensions/pi-subagents/src/shared/file-system-retry.ts +47 -0
- package/dist/extensions/pi-subagents/src/shared/fork-context.ts +28 -3
- package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +123 -0
- package/dist/extensions/pi-subagents/src/shared/model-info.ts +8 -5
- package/dist/extensions/pi-subagents/src/shared/settings.ts +9 -1
- package/dist/extensions/pi-subagents/src/shared/status-format.ts +7 -1
- package/dist/extensions/pi-subagents/src/shared/types.ts +522 -51
- package/dist/extensions/pi-subagents/src/shared/utils.ts +59 -53
- package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +604 -0
- package/dist/extensions/pi-subagents/src/slash/delegation-json.ts +108 -0
- package/dist/extensions/pi-subagents/src/slash/delegation-request.ts +249 -0
- package/dist/extensions/pi-subagents/src/slash/prompt-template-bridge.ts +353 -345
- package/dist/extensions/pi-subagents/src/slash/prompt-workflows.ts +2 -2
- package/dist/extensions/pi-subagents/src/slash/selector.ts +147 -0
- package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +265 -23
- package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +2 -2
- package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +428 -0
- package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +362 -0
- package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +472 -0
- package/dist/extensions/pi-subagents/src/tui/fleet.ts +664 -0
- package/dist/extensions/pi-subagents/src/tui/render.ts +115 -31
- package/dist/extensions/pi-subagents/src/watchdog/change-signature.ts +220 -0
- package/dist/extensions/pi-subagents/src/watchdog/child-status.ts +205 -0
- package/dist/extensions/pi-subagents/src/watchdog/emission-guard.ts +123 -0
- package/dist/extensions/pi-subagents/src/watchdog/lsp-diagnostics.ts +532 -0
- package/dist/extensions/pi-subagents/src/watchdog/model-selection.ts +167 -0
- package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +117 -0
- package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +433 -0
- package/dist/extensions/pi-subagents/src/watchdog/render.ts +54 -0
- package/dist/extensions/pi-subagents/src/watchdog/review.ts +298 -0
- package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +714 -0
- package/dist/extensions/pi-subagents/src/watchdog/settings.ts +528 -0
- package/dist/extensions/pi-subagents/src/watchdog/tool-actions.ts +155 -0
- package/dist/extensions/pi-subagents/src/watchdog/turn-delta.ts +161 -0
- package/dist/extensions/pi-subagents/src/watchdog/types.ts +188 -0
- package/dist/extensions/pi-subagents/src/watchdog/warning-format.ts +73 -0
- package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +130 -2
- package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +439 -0
- package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +1632 -61
- package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +54 -1
- package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +112 -0
- package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +98 -1
- package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +179 -9
- package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +16 -9
- package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +6 -5
- package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +589 -9
- package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +528 -21
- package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +227 -3
- package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +235 -7
- package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +27 -0
- package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +172 -2
- package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +1502 -18
- package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +993 -4
- package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +27 -0
- package/dist/extensions/pi-subagents/test/integration/top-level-async.test.ts +7 -1
- package/dist/extensions/pi-subagents/test/support/helpers.ts +32 -0
- package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +59 -2
- package/dist/extensions/pi-subagents/test/support/mock-pi.ts +32 -6
- package/dist/extensions/pi-subagents/test/support/real-session-child-cli.mjs +25 -24
- package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +59 -35
- package/dist/extensions/pi-subagents/test/support/session-lease-child.mjs +42 -0
- package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +703 -69
- package/dist/extensions/pi-subagents/test/unit/accessible-dir.test.ts +82 -0
- package/dist/extensions/pi-subagents/test/unit/agent-disabled.test.ts +15 -15
- package/dist/extensions/pi-subagents/test/unit/agent-eject-disable.test.ts +66 -66
- package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +478 -19
- package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +228 -7
- package/dist/extensions/pi-subagents/test/unit/agent-memory.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +198 -78
- package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +15 -1
- package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +102 -7
- package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +439 -6
- package/dist/extensions/pi-subagents/test/unit/atomic-json.test.ts +41 -1
- package/dist/extensions/pi-subagents/test/unit/auto-drain.test.ts +79 -0
- package/dist/extensions/pi-subagents/test/unit/background-work.test.ts +285 -0
- package/dist/extensions/pi-subagents/test/unit/capability-ceiling-pi-args.test.ts +84 -0
- package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +68 -0
- package/dist/extensions/pi-subagents/test/unit/chain-validation.test.ts +326 -0
- package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +82 -0
- package/dist/extensions/pi-subagents/test/unit/child-transcript.test.ts +46 -4
- package/dist/extensions/pi-subagents/test/unit/completion-batcher.test.ts +3 -1
- package/dist/extensions/pi-subagents/test/unit/completion-dedupe.test.ts +9 -17
- package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +175 -3
- package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +10 -5
- package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +126 -6
- package/dist/extensions/pi-subagents/test/unit/default-extensions.test.ts +219 -0
- package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +913 -0
- package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +13 -2
- package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +3 -3
- package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +351 -0
- package/dist/extensions/pi-subagents/test/unit/fleet-transcript.test.ts +280 -0
- package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +575 -0
- package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +65 -0
- package/dist/extensions/pi-subagents/test/unit/fork-context.test.ts +94 -1
- package/dist/extensions/pi-subagents/test/unit/get-final-output.test.ts +23 -0
- package/dist/extensions/pi-subagents/test/unit/host-peer-runtime-imports.test.ts +157 -0
- package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +367 -5
- package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +11 -0
- package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +36 -0
- package/dist/extensions/pi-subagents/test/unit/model-info.test.ts +25 -3
- package/dist/extensions/pi-subagents/test/unit/model-scope.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +341 -10
- package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +16 -0
- package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +52 -0
- package/dist/extensions/pi-subagents/test/unit/notify.test.ts +168 -7
- package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +85 -7
- package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +175 -0
- package/dist/extensions/pi-subagents/test/unit/path-resolution.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +243 -16
- package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +79 -36
- package/dist/extensions/pi-subagents/test/unit/pi-spawn.test.ts +174 -56
- package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +322 -0
- package/dist/extensions/pi-subagents/test/unit/process-terminal.test.ts +204 -0
- package/dist/extensions/pi-subagents/test/unit/recursion-guard.test.ts +20 -12
- package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +117 -4
- package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +40 -7
- package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +48 -1
- package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +21 -3
- package/dist/extensions/pi-subagents/test/unit/selector.test.ts +57 -0
- package/dist/extensions/pi-subagents/test/unit/session-lease.test.ts +326 -0
- package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +101 -2
- package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +111 -1
- package/dist/extensions/pi-subagents/test/unit/spawn-budget.test.ts +124 -0
- package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +6 -4
- package/dist/extensions/pi-subagents/test/unit/status-format.test.ts +7 -0
- package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +397 -0
- package/dist/extensions/pi-subagents/test/unit/steering-notices.test.ts +58 -0
- package/dist/extensions/pi-subagents/test/unit/steering.test.ts +173 -0
- package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +25 -4
- package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +390 -25
- package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +837 -0
- package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +86 -0
- package/dist/extensions/pi-subagents/test/unit/tool-budget.test.ts +15 -0
- package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +47 -1
- package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +56 -10
- package/dist/extensions/pi-subagents/test/unit/watchdog-change-signature.test.ts +387 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-child-status.test.ts +110 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-emission-guard.test.ts +62 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-lsp-diagnostics.test.ts +144 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-model-selection.test.ts +121 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-render.test.ts +76 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-review.test.ts +327 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +863 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +290 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-tool-actions.test.ts +91 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-turn-delta.test.ts +130 -0
- package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +32 -4
- package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +5 -1
- package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +30 -0
- package/dist/extensions/question/batch.ts +39 -0
- package/dist/extensions/question/dialog-adapter.ts +23 -1
- package/dist/extensions/question/index.ts +237 -7
- package/dist/extensions/question/schemas.ts +28 -15
- package/dist/extensions/question/tests/batch.test.ts +26 -0
- package/dist/extensions/question/tests/ui-protocol.test.ts +23 -3
- package/dist/extensions/question/tui-adapter.ts +2 -3
- package/dist/extensions/question/types.ts +37 -0
- package/dist/extensions/question/ui-protocol.ts +3 -3
- package/dist/skills/batch-grill-me/SKILL.md +3 -1
- package/package.json +2 -1
|
@@ -16,29 +16,39 @@ import { randomUUID } from "node:crypto";
|
|
|
16
16
|
import * as fs from "node:fs";
|
|
17
17
|
import * as os from "node:os";
|
|
18
18
|
import * as path from "node:path";
|
|
19
|
+
import "../shared/env.ts";
|
|
19
20
|
import type { AgentToolResult } from "@earendil-works/pi-agent-core";
|
|
20
21
|
import { keyText, type ExtensionAPI, type ExtensionContext, type ToolDefinition } from "@selesai/code";
|
|
21
22
|
import { Box, Container, Spacer, Text, truncateToWidth, visibleWidth, wrapTextWithAnsi, type Component } from "@earendil-works/pi-tui";
|
|
22
|
-
import { discoverAgents
|
|
23
|
+
import { discoverAgents } from "../agents/agents.ts";
|
|
24
|
+
import { ensureAccessibleDir } from "../shared/accessible-dir.ts";
|
|
23
25
|
import { cleanupAllArtifactDirs, cleanupOldArtifacts, getArtifactsDir } from "../shared/artifacts.ts";
|
|
24
26
|
import { resolveCurrentSessionId } from "../shared/session-identity.ts";
|
|
25
27
|
import { cleanupOldChainDirs } from "../shared/settings.ts";
|
|
26
|
-
import { clearLegacyResultAnimationTimer,
|
|
27
|
-
import {
|
|
28
|
+
import { clearLegacyResultAnimationTimer, renderSubagentResult } from "../tui/render.ts";
|
|
29
|
+
import { openSubagentFleet } from "../tui/fleet.ts";
|
|
30
|
+
import { SubagentFleetStatus } from "../tui/fleet-status.ts";
|
|
31
|
+
import { SubagentParams } from "./schemas.ts";
|
|
32
|
+
import { validateChainInput } from "./chain-validation.ts";
|
|
28
33
|
import { createSubagentExecutor, type SubagentParamsLike } from "../runs/foreground/subagent-executor.ts";
|
|
29
34
|
import { createAsyncJobTracker } from "../runs/background/async-job-tracker.ts";
|
|
30
35
|
import { createResultWatcher } from "../runs/background/result-watcher.ts";
|
|
31
36
|
import { createScheduledRunManager } from "../runs/background/scheduled-runs.ts";
|
|
32
37
|
import { registerSlashCommands } from "../slash/slash-commands.ts";
|
|
33
38
|
import { registerPromptTemplateDelegationBridge } from "../slash/prompt-template-bridge.ts";
|
|
39
|
+
import { registerMainWatchdog } from "../watchdog/register-main.ts";
|
|
34
40
|
import { registerSlashSubagentBridge } from "../slash/slash-bridge.ts";
|
|
35
41
|
import { createNativeSupervisorChannel } from "../intercom/native-supervisor-channel.ts";
|
|
36
42
|
import { registerSubagentRpcBridge } from "./rpc.ts";
|
|
37
43
|
import { clearSlashSnapshots, getSlashRenderableSnapshot, resolveSlashMessageDetails, restoreSlashFinalSnapshots, type SlashMessageDetails } from "../slash/slash-live-state.ts";
|
|
38
44
|
import { inspectSubagentStatus } from "../runs/background/run-status.ts";
|
|
39
|
-
import {
|
|
40
|
-
import
|
|
45
|
+
import { resolveWaitToolConfig } from "../runs/background/subagent-wait.ts";
|
|
46
|
+
import { registerWaitTool } from "../runs/background/wait-tool.ts";
|
|
47
|
+
import { drainOutstandingWork } from "../runs/background/auto-drain.ts";
|
|
48
|
+
import registerSubagentNotify, { parseSubagentNotifyContent, type SubagentNotifyDetails } from "../runs/background/notify.ts";
|
|
49
|
+
import { formatSteeringNotice, handleSubagentSteeringNotice, SUBAGENT_STEERING_MESSAGE_TYPE, type SubagentSteeringMessageDetails } from "./steering-notices.ts";
|
|
41
50
|
import { SUBAGENT_CHILD_ENV, SUBAGENT_PARENT_SESSION_ENV } from "../runs/shared/pi-args.ts";
|
|
51
|
+
import { resolveCurrentSubagentCapabilityCeiling } from "../runs/shared/capability-ceiling.ts";
|
|
42
52
|
import { formatDuration, shortenPath } from "../shared/formatters.ts";
|
|
43
53
|
import { loadConfig } from "./config.ts";
|
|
44
54
|
import { buildSubagentToolDescription } from "./tool-description.ts";
|
|
@@ -53,7 +63,9 @@ import {
|
|
|
53
63
|
SUBAGENT_ASYNC_COMPLETE_EVENT,
|
|
54
64
|
SUBAGENT_ASYNC_STARTED_EVENT,
|
|
55
65
|
SUBAGENT_CONTROL_EVENT,
|
|
66
|
+
SUBAGENT_STEERING_NOTICE_EVENT,
|
|
56
67
|
WIDGET_KEY,
|
|
68
|
+
resolveMaxSubagentSpawnsPerSession,
|
|
57
69
|
} from "../shared/types.ts";
|
|
58
70
|
import {
|
|
59
71
|
clearPendingForegroundControlNotices,
|
|
@@ -85,58 +97,12 @@ function expandTilde(p: string): string {
|
|
|
85
97
|
return p.startsWith("~/") ? path.join(os.homedir(), p.slice(2)) : p;
|
|
86
98
|
}
|
|
87
99
|
|
|
88
|
-
/**
|
|
89
|
-
* Create a directory and verify it is actually accessible.
|
|
90
|
-
* On Windows with Azure AD/Entra ID, directories created shortly after
|
|
91
|
-
* wake-from-sleep can end up with broken NTFS ACLs (null DACL) when the
|
|
92
|
-
* cloud SID cannot be resolved without network connectivity. This leaves
|
|
93
|
-
* the directory completely inaccessible to the creating user.
|
|
94
|
-
*/
|
|
95
|
-
function ensureAccessibleDir(dirPath: string): void {
|
|
96
|
-
fs.mkdirSync(dirPath, { recursive: true });
|
|
97
|
-
try {
|
|
98
|
-
fs.accessSync(dirPath, fs.constants.R_OK | fs.constants.W_OK);
|
|
99
|
-
} catch {
|
|
100
|
-
try {
|
|
101
|
-
fs.rmSync(dirPath, { recursive: true, force: true });
|
|
102
|
-
} catch {
|
|
103
|
-
// Best effort: retry mkdir/access even if cleanup fails.
|
|
104
|
-
}
|
|
105
|
-
fs.mkdirSync(dirPath, { recursive: true });
|
|
106
|
-
fs.accessSync(dirPath, fs.constants.R_OK | fs.constants.W_OK);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
100
|
function isSlashResultRunning(result: { details?: Details }): boolean {
|
|
111
101
|
return result.details?.progress?.some((entry) => entry.status === "running")
|
|
112
102
|
|| result.details?.results.some((entry) => entry.progress?.status === "running")
|
|
113
103
|
|| false;
|
|
114
104
|
}
|
|
115
105
|
|
|
116
|
-
// Drives the inline running-indicator braille animation for foreground subagent
|
|
117
|
-
// results. Foreground runs receive progress only on child events, so the glyph
|
|
118
|
-
// (derived from progress fields) would freeze between events. While a result is
|
|
119
|
-
// running we tick a frame counter + invalidate() every 80ms so renderSubagentResult
|
|
120
|
-
// can blend the frame into runningGlyph and produce a smooth spinner.
|
|
121
|
-
function subagentResultIsRunning(result: { details?: Details }): boolean {
|
|
122
|
-
return result.details?.progress?.some((entry) => entry.status === "running")
|
|
123
|
-
|| result.details?.results.some((entry) => entry.progress?.status === "running")
|
|
124
|
-
|| false;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function ensureSubagentResultAnimation(context: { state: Record<string, unknown>; invalidate?: () => void }): void {
|
|
128
|
-
const state = context.state as { subagentResultAnimationTimer?: ReturnType<typeof setInterval>; frame?: number };
|
|
129
|
-
if (state.subagentResultAnimationTimer) return;
|
|
130
|
-
if (typeof context.invalidate !== "function") return;
|
|
131
|
-
if (state.frame === undefined) state.frame = 0;
|
|
132
|
-
state.subagentResultAnimationTimer = setInterval(() => {
|
|
133
|
-
state.frame = ((state.frame ?? 0) + 1) % 10;
|
|
134
|
-
try {
|
|
135
|
-
context.invalidate();
|
|
136
|
-
} catch {}
|
|
137
|
-
}, 80);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
106
|
function isSlashResultError(result: { details?: Details }): boolean {
|
|
141
107
|
return result.details?.results.some((entry) => entry.exitCode !== 0 && entry.progress?.status !== "running") || false;
|
|
142
108
|
}
|
|
@@ -177,38 +143,6 @@ function createSlashResultComponent(
|
|
|
177
143
|
return container;
|
|
178
144
|
}
|
|
179
145
|
|
|
180
|
-
function parseSubagentNotifyContent(content: string): SubagentNotifyDetails | undefined {
|
|
181
|
-
const lines = content.split("\n");
|
|
182
|
-
const header = lines[0] ?? "";
|
|
183
|
-
const match = header.match(/^Background task (completed|failed|paused): \*\*(.+?)\*\*(?:\s+(\([^)]*\)))?$/);
|
|
184
|
-
if (!match) return undefined;
|
|
185
|
-
const body = lines.slice(2);
|
|
186
|
-
let sessionIndex = -1;
|
|
187
|
-
for (let i = body.length - 1; i >= 1; i--) {
|
|
188
|
-
if (body[i - 1]?.trim() === "" && /^(Session|Session file|Session share error):\s+/.test(body[i]!)) {
|
|
189
|
-
sessionIndex = i;
|
|
190
|
-
break;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
const sessionLine = sessionIndex >= 0 ? body[sessionIndex] : undefined;
|
|
194
|
-
const resultLines = sessionIndex >= 0 ? body.slice(0, sessionIndex) : body;
|
|
195
|
-
const resultPreview = resultLines.join("\n").trim() || "(no output)";
|
|
196
|
-
let sessionLabel: string | undefined;
|
|
197
|
-
let sessionValue: string | undefined;
|
|
198
|
-
if (sessionLine) {
|
|
199
|
-
const separator = sessionLine.indexOf(":");
|
|
200
|
-
sessionLabel = sessionLine.slice(0, separator).toLowerCase();
|
|
201
|
-
sessionValue = sessionLine.slice(separator + 1).trim();
|
|
202
|
-
}
|
|
203
|
-
return {
|
|
204
|
-
agent: match[2]!,
|
|
205
|
-
status: match[1] as SubagentNotifyDetails["status"],
|
|
206
|
-
...(match[3] ? { taskInfo: match[3] } : {}),
|
|
207
|
-
resultPreview,
|
|
208
|
-
...(sessionLabel && sessionValue ? { sessionLabel, sessionValue } : {}),
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
|
|
212
146
|
class SubagentControlNoticeComponent implements Component {
|
|
213
147
|
constructor(
|
|
214
148
|
private readonly details: SubagentControlMessageDetails,
|
|
@@ -257,16 +191,28 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
|
|
|
257
191
|
cleanupOldChainDirs();
|
|
258
192
|
|
|
259
193
|
const config = loadConfig();
|
|
194
|
+
const waitToolConfig = resolveWaitToolConfig(config.waitTool);
|
|
260
195
|
const asyncByDefault = config.asyncByDefault === true;
|
|
196
|
+
const fleetViewEnabled = config.fleetView !== false;
|
|
197
|
+
const asyncWidgetEnabled = config.asyncWidget === true || (!fleetViewEnabled && config.asyncWidget !== false);
|
|
261
198
|
const tempArtifactsDir = getArtifactsDir(null);
|
|
262
199
|
cleanupAllArtifactDirs(DEFAULT_ARTIFACT_CONFIG.cleanupDays);
|
|
263
200
|
|
|
264
201
|
const state: SubagentState = {
|
|
265
202
|
baseCwd: "",
|
|
266
203
|
currentSessionId: null,
|
|
204
|
+
artifactDirPreference: config.artifactDir ?? DEFAULT_ARTIFACT_CONFIG.dir,
|
|
205
|
+
parentSessionFile: null,
|
|
267
206
|
subagentInProgress: false,
|
|
268
|
-
subagentSpawns: {
|
|
207
|
+
subagentSpawns: {
|
|
208
|
+
sessionId: null,
|
|
209
|
+
count: 0,
|
|
210
|
+
configuredLimit: resolveMaxSubagentSpawnsPerSession(config.maxSubagentSpawnsPerSession) ?? null,
|
|
211
|
+
granted: 0,
|
|
212
|
+
grantHistory: [],
|
|
213
|
+
},
|
|
269
214
|
asyncJobs: new Map(),
|
|
215
|
+
fleetJobs: new Map(),
|
|
270
216
|
foregroundRuns: new Map(),
|
|
271
217
|
foregroundControls: new Map(),
|
|
272
218
|
lastForegroundControlId: null,
|
|
@@ -284,19 +230,31 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
|
|
|
284
230
|
};
|
|
285
231
|
|
|
286
232
|
const supervisorChannel = createNativeSupervisorChannel(pi, state);
|
|
233
|
+
const mainWatchdog = registerMainWatchdog(pi);
|
|
234
|
+
const completionNotifier = registerSubagentNotify(pi, state, { batchConfig: config.completionBatch });
|
|
235
|
+
const fleetStatus = fleetViewEnabled
|
|
236
|
+
? new SubagentFleetStatus(state, async (itemKey) => {
|
|
237
|
+
const ctx = state.lastUiContext;
|
|
238
|
+
if (!ctx?.hasUI) return;
|
|
239
|
+
await openSubagentFleet(ctx, state, { initialKey: itemKey });
|
|
240
|
+
})
|
|
241
|
+
: undefined;
|
|
287
242
|
const { startResultWatcher, primeExistingResults, stopResultWatcher } = createResultWatcher(
|
|
288
243
|
pi,
|
|
289
244
|
state,
|
|
290
245
|
RESULTS_DIR,
|
|
291
246
|
10 * 60 * 1000,
|
|
247
|
+
{ notifier: completionNotifier },
|
|
292
248
|
);
|
|
293
|
-
startResultWatcher();
|
|
294
|
-
primeExistingResults();
|
|
295
249
|
|
|
296
250
|
const runtimeCleanup = () => {
|
|
297
251
|
stopResultWatcher();
|
|
252
|
+
state.currentSessionId = null;
|
|
253
|
+
completionNotifier.dispose();
|
|
254
|
+
mainWatchdog.dispose();
|
|
298
255
|
scheduledRunManager.stop();
|
|
299
256
|
supervisorChannel.dispose();
|
|
257
|
+
fleetStatus?.dispose();
|
|
300
258
|
clearPendingForegroundControlNotices(state);
|
|
301
259
|
if (state.poller) {
|
|
302
260
|
clearInterval(state.poller);
|
|
@@ -305,7 +263,9 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
|
|
|
305
263
|
};
|
|
306
264
|
globalStore[runtimeCleanupStoreKey] = runtimeCleanup;
|
|
307
265
|
|
|
308
|
-
const { ensurePoller, handleStarted, handleComplete, resetJobs, restoreActiveJobs } = createAsyncJobTracker(pi, state, ASYNC_DIR
|
|
266
|
+
const { ensurePoller, refreshWidget, handleStarted, handleComplete, resetJobs, restoreActiveJobs } = createAsyncJobTracker(pi, state, ASYNC_DIR, {
|
|
267
|
+
widgetEnabled: asyncWidgetEnabled,
|
|
268
|
+
});
|
|
309
269
|
let executorExecute: ((id: string, params: SubagentParamsLike, signal: AbortSignal, onUpdate: ((r: AgentToolResult<Details>) => void) | undefined, ctx: ExtensionContext) => Promise<AgentToolResult<Details>>) | undefined;
|
|
310
270
|
const scheduledRunManager = createScheduledRunManager({
|
|
311
271
|
config,
|
|
@@ -319,13 +279,16 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
|
|
|
319
279
|
}
|
|
320
280
|
return executorExecute(randomUUID(), params, signal, undefined, ctx);
|
|
321
281
|
},
|
|
282
|
+
resolveCapabilityCeiling: (sessionId) => resolveCurrentSubagentCapabilityCeiling(sessionId),
|
|
322
283
|
});
|
|
323
284
|
const executor = createSubagentExecutor({
|
|
324
285
|
pi,
|
|
325
286
|
state,
|
|
326
287
|
config,
|
|
327
288
|
asyncByDefault,
|
|
289
|
+
waitToolEnabled: waitToolConfig.enabled,
|
|
328
290
|
handleScheduledRunAction: (params, ctx) => scheduledRunManager.handleToolCall(params, ctx),
|
|
291
|
+
watchdog: mainWatchdog,
|
|
329
292
|
tempArtifactsDir,
|
|
330
293
|
getSubagentSessionRoot,
|
|
331
294
|
expandTilde,
|
|
@@ -380,6 +343,12 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
|
|
|
380
343
|
return new Text(text, 0, 0);
|
|
381
344
|
});
|
|
382
345
|
|
|
346
|
+
pi.registerMessageRenderer<SubagentSteeringMessageDetails>(SUBAGENT_STEERING_MESSAGE_TYPE, (message, _options, theme) => {
|
|
347
|
+
const details = message.details as SubagentSteeringMessageDetails | undefined;
|
|
348
|
+
if (!details) return undefined;
|
|
349
|
+
return new Text(theme.fg(details.state === "recovered" ? "warning" : "error", formatSteeringNotice(details)), 0, 0);
|
|
350
|
+
});
|
|
351
|
+
|
|
383
352
|
pi.registerMessageRenderer<SubagentControlMessageDetails>(SUBAGENT_CONTROL_MESSAGE_TYPE, (message, _options, theme) => {
|
|
384
353
|
const details = message.details as SubagentControlMessageDetails | undefined;
|
|
385
354
|
if (!details?.event) return undefined;
|
|
@@ -402,38 +371,11 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
|
|
|
402
371
|
const promptTemplateBridge = registerPromptTemplateDelegationBridge({
|
|
403
372
|
events: pi.events,
|
|
404
373
|
getContext: () => state.lastUiContext,
|
|
405
|
-
execute:
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
tasks: request.tasks,
|
|
411
|
-
context: request.context,
|
|
412
|
-
cwd: request.cwd,
|
|
413
|
-
worktree: request.worktree,
|
|
414
|
-
async: false,
|
|
415
|
-
clarify: false,
|
|
416
|
-
},
|
|
417
|
-
signal,
|
|
418
|
-
onUpdate,
|
|
419
|
-
ctx,
|
|
420
|
-
);
|
|
421
|
-
}
|
|
422
|
-
return executeSubagentCollapsed(
|
|
423
|
-
requestId,
|
|
424
|
-
{
|
|
425
|
-
agent: request.agent,
|
|
426
|
-
task: request.task,
|
|
427
|
-
context: request.context,
|
|
428
|
-
cwd: request.cwd,
|
|
429
|
-
model: request.model,
|
|
430
|
-
async: false,
|
|
431
|
-
clarify: false,
|
|
432
|
-
},
|
|
433
|
-
signal,
|
|
434
|
-
onUpdate,
|
|
435
|
-
ctx,
|
|
436
|
-
);
|
|
374
|
+
execute: (requestId, params, signal, ctx, onUpdate) =>
|
|
375
|
+
executeSubagentCollapsed(requestId, params, signal, onUpdate, ctx),
|
|
376
|
+
executeVersioned: (requestId, params, signal, ctx, onUpdate) => {
|
|
377
|
+
if (ctx.hasUI) ctx.ui.setToolsExpanded(false);
|
|
378
|
+
return executor.executeDelegated(requestId, params, signal, onUpdate, ctx);
|
|
437
379
|
},
|
|
438
380
|
});
|
|
439
381
|
|
|
@@ -457,6 +399,14 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
|
|
|
457
399
|
description: buildSubagentToolDescription(config),
|
|
458
400
|
parameters: SubagentParams,
|
|
459
401
|
|
|
402
|
+
prepareArguments(args) {
|
|
403
|
+
// Run friendly chain validation before pi-ai's raw TypeBox schema check
|
|
404
|
+
// so the model sees which property is disallowed, what is allowed, and a
|
|
405
|
+
// valid example instead of `chain.N: must not have additional properties`.
|
|
406
|
+
validateChainInput(args);
|
|
407
|
+
return args as never;
|
|
408
|
+
},
|
|
409
|
+
|
|
460
410
|
execute(id, params, signal, onUpdate, ctx) {
|
|
461
411
|
return executeSubagentCollapsed(id, params, signal, onUpdate, ctx);
|
|
462
412
|
},
|
|
@@ -492,38 +442,20 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
|
|
|
492
442
|
},
|
|
493
443
|
|
|
494
444
|
renderResult(result, options, theme, context) {
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
} else {
|
|
498
|
-
clearLegacyResultAnimationTimer(context);
|
|
499
|
-
}
|
|
500
|
-
const frame = (context.state as { frame?: number } | undefined)?.frame ?? 0;
|
|
501
|
-
return renderSubagentResult(result, options, theme, frame);
|
|
445
|
+
clearLegacyResultAnimationTimer(context);
|
|
446
|
+
return renderSubagentResult(result, options, theme);
|
|
502
447
|
},
|
|
503
448
|
|
|
504
449
|
};
|
|
505
450
|
|
|
506
451
|
pi.registerTool(tool);
|
|
507
452
|
|
|
508
|
-
|
|
509
|
-
name: "wait",
|
|
510
|
-
label: "Wait",
|
|
511
|
-
description: `Block until background (async) subagent runs started in this session finish, then return.
|
|
453
|
+
registerWaitTool(pi, state, waitToolConfig.enabled);
|
|
512
454
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
• { id: "..." } — wait for one specific run (id or prefix) to finish.
|
|
518
|
-
• { timeoutMs: 600000 } — stop waiting after N ms (the runs keep going regardless; default 30 min)
|
|
519
|
-
|
|
520
|
-
wait also returns when a run needs attention (a child that went idle or blocked for a decision), not only on completion — so a stuck child never stalls the loop; the summary names the run(s) to inspect/nudge/resume/interrupt. It wakes the instant a completion or control event arrives (subscribed to Pi's event bus, with a poll fallback that reconciles crashed runners), keeps the turn alive for normal notification delivery, and resolves early if the turn is aborted.`,
|
|
521
|
-
parameters: WaitParams,
|
|
522
|
-
execute(_id, params, signal, _onUpdate, _ctx) {
|
|
523
|
-
return waitForSubagents(params, signal, { state, events: pi.events });
|
|
524
|
-
},
|
|
525
|
-
};
|
|
526
|
-
pi.registerTool(waitTool);
|
|
455
|
+
pi.on("agent_end", async (_event, ctx) => {
|
|
456
|
+
if (ctx.hasUI) return;
|
|
457
|
+
await drainOutstandingWork({ state, events: pi.events });
|
|
458
|
+
});
|
|
527
459
|
|
|
528
460
|
registerSlashCommands(pi, state);
|
|
529
461
|
|
|
@@ -540,8 +472,6 @@ wait also returns when a run needs attention (a child that went idle or blocked
|
|
|
540
472
|
}
|
|
541
473
|
}
|
|
542
474
|
}
|
|
543
|
-
registerSubagentNotify(pi, state, { batchConfig: config.completionBatch });
|
|
544
|
-
|
|
545
475
|
const existingVisibleControlNotices = globalStore[controlNoticeSeenStoreKey];
|
|
546
476
|
const visibleControlNotices = existingVisibleControlNotices instanceof Set ? existingVisibleControlNotices as Set<string> : new Set<string>();
|
|
547
477
|
globalStore[controlNoticeSeenStoreKey] = visibleControlNotices;
|
|
@@ -553,10 +483,22 @@ wait also returns when a run needs attention (a child that went idle or blocked
|
|
|
553
483
|
details: payload as SubagentControlMessageDetails,
|
|
554
484
|
});
|
|
555
485
|
};
|
|
486
|
+
const steeringNoticeHandler = (payload: unknown) => {
|
|
487
|
+
handleSubagentSteeringNotice({ pi, state, details: payload as SubagentSteeringMessageDetails });
|
|
488
|
+
};
|
|
489
|
+
const asyncStartedHandler = (payload: unknown) => {
|
|
490
|
+
handleStarted(payload);
|
|
491
|
+
fleetStatus?.refresh();
|
|
492
|
+
};
|
|
493
|
+
const asyncCompleteHandler = (payload: unknown) => {
|
|
494
|
+
handleComplete(payload);
|
|
495
|
+
fleetStatus?.refresh();
|
|
496
|
+
};
|
|
556
497
|
const eventUnsubscribes = [
|
|
557
|
-
pi.events.on(SUBAGENT_ASYNC_STARTED_EVENT,
|
|
558
|
-
pi.events.on(SUBAGENT_ASYNC_COMPLETE_EVENT,
|
|
498
|
+
pi.events.on(SUBAGENT_ASYNC_STARTED_EVENT, asyncStartedHandler),
|
|
499
|
+
pi.events.on(SUBAGENT_ASYNC_COMPLETE_EVENT, asyncCompleteHandler),
|
|
559
500
|
pi.events.on(SUBAGENT_CONTROL_EVENT, controlEventHandler),
|
|
501
|
+
pi.events.on(SUBAGENT_STEERING_NOTICE_EVENT, steeringNoticeHandler),
|
|
560
502
|
rpcBridge.dispose,
|
|
561
503
|
];
|
|
562
504
|
globalStore[eventUnsubscribeStoreKey] = eventUnsubscribes;
|
|
@@ -565,9 +507,10 @@ wait also returns when a run needs attention (a child that went idle or blocked
|
|
|
565
507
|
if (event.toolName !== "subagent") return;
|
|
566
508
|
if (!ctx.hasUI) return;
|
|
567
509
|
state.lastUiContext = ctx;
|
|
510
|
+
fleetStatus?.setContext(ctx);
|
|
511
|
+
fleetStatus?.refresh();
|
|
568
512
|
if (state.asyncJobs.size > 0) {
|
|
569
|
-
|
|
570
|
-
ctx.ui.requestRender?.();
|
|
513
|
+
refreshWidget(ctx);
|
|
571
514
|
ensurePoller();
|
|
572
515
|
}
|
|
573
516
|
});
|
|
@@ -583,11 +526,17 @@ wait also returns when a run needs attention (a child that went idle or blocked
|
|
|
583
526
|
}
|
|
584
527
|
};
|
|
585
528
|
|
|
586
|
-
const resetSessionState = (ctx: ExtensionContext) => {
|
|
587
|
-
ensureDefaultUserSubagentSettings(ctx.model);
|
|
529
|
+
const resetSessionState = (ctx: ExtensionContext, recovering: boolean) => {
|
|
588
530
|
state.baseCwd = ctx.cwd;
|
|
589
531
|
state.currentSessionId = resolveCurrentSessionId(ctx.sessionManager);
|
|
590
|
-
state.
|
|
532
|
+
state.parentSessionFile = ctx.sessionManager.getSessionFile();
|
|
533
|
+
state.subagentSpawns = {
|
|
534
|
+
sessionId: state.currentSessionId,
|
|
535
|
+
count: 0,
|
|
536
|
+
configuredLimit: resolveMaxSubagentSpawnsPerSession(config.maxSubagentSpawnsPerSession) ?? null,
|
|
537
|
+
granted: 0,
|
|
538
|
+
grantHistory: [],
|
|
539
|
+
};
|
|
591
540
|
// Set SELESAI_SUBAGENT_PARENT_SESSION for permission-system forwarding.
|
|
592
541
|
// Only set in the root session (the interactive UI session), not in
|
|
593
542
|
// child subagent processes — children inherit the parent's value
|
|
@@ -606,16 +555,23 @@ wait also returns when a run needs attention (a child that went idle or blocked
|
|
|
606
555
|
restoreActiveJobs(ctx);
|
|
607
556
|
scheduledRunManager.bindSession(ctx);
|
|
608
557
|
restoreSlashFinalSnapshots(ctx.sessionManager.getEntries());
|
|
609
|
-
|
|
558
|
+
startResultWatcher();
|
|
559
|
+
primeExistingResults({ triggerTurn: !recovering });
|
|
560
|
+
fleetStatus?.setContext(ctx);
|
|
610
561
|
};
|
|
611
562
|
|
|
612
|
-
pi.on("session_start", (
|
|
613
|
-
|
|
563
|
+
pi.on("session_start", (event, ctx) => {
|
|
564
|
+
const recovering = event.reason === "startup" || event.reason === "reload" || event.reason === "resume";
|
|
565
|
+
resetSessionState(ctx, recovering);
|
|
614
566
|
rpcBridge.emitReady(ctx);
|
|
615
567
|
supervisorChannel.start();
|
|
616
568
|
});
|
|
617
569
|
|
|
618
570
|
pi.on("session_shutdown", () => {
|
|
571
|
+
stopResultWatcher();
|
|
572
|
+
state.currentSessionId = null;
|
|
573
|
+
state.parentSessionFile = null;
|
|
574
|
+
completionNotifier.dispose();
|
|
619
575
|
delete process.env[SUBAGENT_PARENT_SESSION_ENV];
|
|
620
576
|
for (const unsubscribe of eventUnsubscribes) {
|
|
621
577
|
try {
|
|
@@ -627,7 +583,6 @@ wait also returns when a run needs attention (a child that went idle or blocked
|
|
|
627
583
|
if (globalStore[eventUnsubscribeStoreKey] === eventUnsubscribes) {
|
|
628
584
|
delete globalStore[eventUnsubscribeStoreKey];
|
|
629
585
|
}
|
|
630
|
-
stopResultWatcher();
|
|
631
586
|
scheduledRunManager.stop();
|
|
632
587
|
if (state.poller) clearInterval(state.poller);
|
|
633
588
|
state.poller = null;
|
|
@@ -643,6 +598,7 @@ wait also returns when a run needs attention (a child that went idle or blocked
|
|
|
643
598
|
promptTemplateBridge.cancelAll();
|
|
644
599
|
promptTemplateBridge.dispose();
|
|
645
600
|
supervisorChannel.dispose();
|
|
601
|
+
fleetStatus?.dispose();
|
|
646
602
|
if (globalStore[runtimeCleanupStoreKey] === runtimeCleanup) {
|
|
647
603
|
delete globalStore[runtimeCleanupStoreKey];
|
|
648
604
|
}
|
|
@@ -3,19 +3,27 @@ import type { AgentToolResult } from "@earendil-works/pi-agent-core";
|
|
|
3
3
|
import type { ExtensionContext } from "@selesai/code";
|
|
4
4
|
import { Compile } from "typebox/compile";
|
|
5
5
|
import { resolveAsyncRunLocation } from "../runs/background/async-resume.ts";
|
|
6
|
-
import {
|
|
6
|
+
import { deliverStopRequest } from "../runs/background/control-channel.ts";
|
|
7
7
|
import { reconcileAsyncRun } from "../runs/background/stale-run-reconciler.ts";
|
|
8
8
|
import type { SubagentParamsLike } from "../runs/foreground/subagent-executor.ts";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
type Details,
|
|
11
|
+
ASYNC_DIR,
|
|
12
|
+
RESULTS_DIR,
|
|
13
|
+
SUBAGENT_ASYNC_COMPLETE_EVENT,
|
|
14
|
+
SUBAGENT_PROCESS_TERMINAL_EVENT,
|
|
15
|
+
SUBAGENT_LIFECYCLE_ARTIFACT_VERSION,
|
|
16
|
+
} from "../shared/types.ts";
|
|
10
17
|
import { readStatus } from "../shared/utils.ts";
|
|
11
18
|
import { SubagentParams } from "./schemas.ts";
|
|
19
|
+
import { validateChainInput } from "./chain-validation.ts";
|
|
12
20
|
|
|
13
21
|
export const SUBAGENT_RPC_PROTOCOL_VERSION = 1;
|
|
14
22
|
export const SUBAGENT_RPC_REQUEST_EVENT = "subagents:rpc:v1:request";
|
|
15
23
|
export const SUBAGENT_RPC_READY_EVENT = "subagents:rpc:v1:ready";
|
|
16
24
|
export const SUBAGENT_RPC_REPLY_EVENT_PREFIX = "subagents:rpc:v1:reply:";
|
|
17
25
|
|
|
18
|
-
export const SUBAGENT_RPC_METHODS = ["ping", "status", "spawn", "interrupt", "stop"] as const;
|
|
26
|
+
export const SUBAGENT_RPC_METHODS = ["ping", "status", "spawn", "steer", "interrupt", "stop"] as const;
|
|
19
27
|
export type SubagentRpcMethod = typeof SUBAGENT_RPC_METHODS[number];
|
|
20
28
|
|
|
21
29
|
export interface SubagentRpcRequestEnvelope {
|
|
@@ -111,6 +119,13 @@ function assertRecordParams(params: unknown, method: SubagentRpcMethod): Record<
|
|
|
111
119
|
}
|
|
112
120
|
|
|
113
121
|
function assertSubagentParams(params: SubagentParamsLike, label: string): void {
|
|
122
|
+
// Friendly chain validation first: name the disallowed property, list allowed
|
|
123
|
+
// ones, and show a valid example instead of raw TypeBox diagnostics.
|
|
124
|
+
try {
|
|
125
|
+
validateChainInput(params);
|
|
126
|
+
} catch (error) {
|
|
127
|
+
throw new SubagentRpcError("invalid_params", `${label}: ${error instanceof Error ? error.message : String(error)}`);
|
|
128
|
+
}
|
|
114
129
|
if (subagentParamsValidator.Check(params)) return;
|
|
115
130
|
const messages = [...subagentParamsValidator.Errors(params)]
|
|
116
131
|
.slice(0, 4)
|
|
@@ -164,13 +179,18 @@ function pingData(ctx: ExtensionContext | null) {
|
|
|
164
179
|
capabilities: {
|
|
165
180
|
status: true,
|
|
166
181
|
asyncSpawn: true,
|
|
182
|
+
steer: true,
|
|
183
|
+
nonRecoveringSteer: true,
|
|
167
184
|
interrupt: true,
|
|
168
185
|
stop: true,
|
|
186
|
+
processTerminalProof: { version: 1, lifecycleArtifactVersion: SUBAGENT_LIFECYCLE_ARTIFACT_VERSION },
|
|
169
187
|
},
|
|
170
188
|
events: {
|
|
171
189
|
ready: SUBAGENT_RPC_READY_EVENT,
|
|
172
190
|
request: SUBAGENT_RPC_REQUEST_EVENT,
|
|
173
191
|
replyPrefix: SUBAGENT_RPC_REPLY_EVENT_PREFIX,
|
|
192
|
+
asyncComplete: SUBAGENT_ASYNC_COMPLETE_EVENT,
|
|
193
|
+
processTerminal: SUBAGENT_PROCESS_TERMINAL_EVENT,
|
|
174
194
|
},
|
|
175
195
|
session: sessionData(ctx),
|
|
176
196
|
};
|
|
@@ -204,6 +224,20 @@ function spawnParams(params: unknown): SubagentParamsLike {
|
|
|
204
224
|
return { ...(input as SubagentParamsLike), async: true, clarify: false };
|
|
205
225
|
}
|
|
206
226
|
|
|
227
|
+
function steerParams(params: unknown): SubagentParamsLike {
|
|
228
|
+
const input = assertRecordParams(params, "steer");
|
|
229
|
+
if (typeof input.message !== "string" || !input.message.trim())
|
|
230
|
+
throw new SubagentRpcError("invalid_params", "RPC steer requires a non-empty message.");
|
|
231
|
+
const target = normalizeTargetParams(input, "steer");
|
|
232
|
+
if (!target.id && !target.runId && !target.dir) throw new SubagentRpcError("invalid_params", "RPC steer requires id, runId, or dir.");
|
|
233
|
+
return {
|
|
234
|
+
action: "steer",
|
|
235
|
+
...target,
|
|
236
|
+
message: input.message.trim(),
|
|
237
|
+
steeringRecovery: false,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
207
241
|
function stopAsyncRun(
|
|
208
242
|
params: unknown,
|
|
209
243
|
options: RegisterSubagentRpcBridgeOptions,
|
|
@@ -247,7 +281,7 @@ function stopAsyncRun(
|
|
|
247
281
|
}
|
|
248
282
|
|
|
249
283
|
try {
|
|
250
|
-
|
|
284
|
+
deliverStopRequest({
|
|
251
285
|
asyncDir: location.asyncDir,
|
|
252
286
|
pid: status.pid,
|
|
253
287
|
kill: options.kill,
|
|
@@ -281,6 +315,9 @@ async function handleRequest(
|
|
|
281
315
|
if (request.method === "status") {
|
|
282
316
|
return executeChecked(options, ctx, request.requestId, request.method, { action: "status", ...normalizeTargetParams(request.params, "status") });
|
|
283
317
|
}
|
|
318
|
+
if (request.method === "steer") {
|
|
319
|
+
return executeChecked(options, ctx, request.requestId, request.method, steerParams(request.params));
|
|
320
|
+
}
|
|
284
321
|
if (request.method === "interrupt") {
|
|
285
322
|
return executeChecked(options, ctx, request.requestId, request.method, { action: "interrupt", ...normalizeTargetParams(request.params, "interrupt") });
|
|
286
323
|
}
|