@selesai/code 0.13.15 → 0.13.18
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/CHANGELOG.md +37 -0
- package/README.md +2 -14
- package/dist/bun/cli.d.ts +3 -1
- package/dist/bun/cli.js +3 -9
- package/dist/bun/{register-bedrock.js → runtime-setup.js} +5 -0
- package/dist/bun/sandbox-env-setup.d.ts +1 -0
- package/dist/bun/sandbox-env-setup.js +3 -0
- package/dist/cli/auth-command.d.ts +23 -0
- package/dist/cli/auth-command.js +102 -0
- package/dist/cli/config-selector.js +2 -1
- package/dist/cli/setup.d.ts +1 -0
- package/dist/cli/setup.js +11 -0
- package/dist/cli.js +2 -14
- package/dist/config.d.ts +3 -2
- package/dist/config.js +9 -4
- package/dist/core/agent-session-runtime.js +15 -7
- package/dist/core/agent-session.d.ts +2 -6
- package/dist/core/agent-session.js +15 -4
- package/dist/core/compaction/branch-summarization.d.ts +1 -1
- package/dist/core/compaction/branch-summarization.js +2 -1
- package/dist/core/extensions/loader.js +3 -0
- package/dist/core/extensions/types.d.ts +16 -2
- package/dist/core/http-dispatcher.js +2 -0
- package/dist/core/keybindings.d.ts +5 -0
- package/dist/core/keybindings.js +4 -0
- package/dist/core/messages.d.ts +1 -1
- package/dist/core/model-config.d.ts +15 -0
- package/dist/core/model-config.js +3 -0
- package/dist/core/model-runtime.d.ts +1 -0
- package/dist/core/model-runtime.js +5 -2
- package/dist/core/provider-composer.js +8 -2
- package/dist/core/session-export.d.ts +3 -0
- package/dist/core/session-export.js +31 -0
- package/dist/core/session-manager.d.ts +3 -2
- package/dist/core/session-manager.js +40 -13
- package/dist/core/skills.d.ts +1 -1
- package/dist/core/skills.js +4 -2
- package/dist/core/system-prompt.js +10 -10
- package/dist/core/tools/bash.js +3 -117
- package/dist/core/tools/edit.d.ts +1 -12
- package/dist/core/tools/edit.js +5 -163
- package/dist/core/tools/find.js +4 -55
- package/dist/core/tools/grep.js +4 -60
- package/dist/core/tools/ls.js +4 -49
- package/dist/core/tools/read.d.ts +4 -0
- package/dist/core/tools/read.js +10 -122
- package/dist/core/tools/renderers/bash.d.ts +11 -0
- package/dist/core/tools/renderers/bash.js +129 -0
- package/dist/core/tools/renderers/edit.d.ts +22 -0
- package/dist/core/tools/renderers/edit.js +166 -0
- package/dist/core/tools/renderers/find.d.ts +9 -0
- package/dist/core/tools/renderers/find.js +63 -0
- package/dist/core/tools/renderers/grep.d.ts +9 -0
- package/dist/core/tools/renderers/grep.js +68 -0
- package/dist/core/tools/renderers/index.d.ts +27 -0
- package/dist/core/tools/renderers/index.js +46 -0
- package/dist/core/tools/renderers/ls.d.ts +9 -0
- package/dist/core/tools/renderers/ls.js +57 -0
- package/dist/core/tools/renderers/read.d.ts +10 -0
- package/dist/core/tools/renderers/read.js +128 -0
- package/dist/core/tools/renderers/write.d.ts +9 -0
- package/dist/core/tools/renderers/write.js +152 -0
- package/dist/core/tools/write.js +5 -146
- package/dist/extensions/capability-gateway/index.ts +12 -1
- package/dist/extensions/capability-gateway/integration.test.ts +23 -0
- package/dist/extensions/pi-hermes-memory/CHANGELOG.md +18 -0
- package/dist/extensions/pi-hermes-memory/README.md +16 -12
- package/dist/extensions/pi-hermes-memory/docs/ROADMAP.md +1 -1
- package/dist/extensions/pi-hermes-memory/package-lock.json +587 -62
- package/dist/extensions/pi-hermes-memory/package.json +4 -4
- package/dist/extensions/pi-hermes-memory/src/config.ts +32 -0
- package/dist/extensions/pi-hermes-memory/src/constants.ts +12 -2
- package/dist/extensions/pi-hermes-memory/src/handlers/background-review.ts +109 -51
- package/dist/extensions/pi-hermes-memory/src/handlers/index-sessions.ts +9 -3
- package/dist/extensions/pi-hermes-memory/src/handlers/review-memory-ops.ts +257 -98
- package/dist/extensions/pi-hermes-memory/src/handlers/session-backfill.ts +9 -2
- package/dist/extensions/pi-hermes-memory/src/handlers/sync-markdown-memories.ts +5 -0
- package/dist/extensions/pi-hermes-memory/src/index.ts +22 -2
- package/dist/extensions/pi-hermes-memory/src/paths.ts +1 -1
- package/dist/extensions/pi-hermes-memory/src/store/db.ts +6 -0
- package/dist/extensions/pi-hermes-memory/src/store/fts-query.ts +58 -1
- package/dist/extensions/pi-hermes-memory/src/store/memory-store.ts +60 -8
- package/dist/extensions/pi-hermes-memory/src/store/session-indexer.ts +169 -7
- package/dist/extensions/pi-hermes-memory/src/store/session-search.ts +7 -21
- package/dist/extensions/pi-hermes-memory/src/store/sqlite-memory-store.ts +134 -15
- package/dist/extensions/pi-hermes-memory/src/tools/memory-search-tool.ts +4 -2
- package/dist/extensions/pi-hermes-memory/src/tools/memory-tool.ts +24 -9
- package/dist/extensions/pi-hermes-memory/src/types.ts +11 -0
- package/dist/extensions/pi-hermes-memory/tests/config.test.ts +42 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/background-review.test.ts +159 -3
- package/dist/extensions/pi-hermes-memory/tests/handlers/review-memory-ops.test.ts +452 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/session-backfill.test.ts +39 -0
- package/dist/extensions/pi-hermes-memory/tests/integration/corruption-recovery-integration.test.ts +91 -0
- package/dist/extensions/pi-hermes-memory/tests/store/db.test.ts +29 -0
- package/dist/extensions/pi-hermes-memory/tests/store/fts-query.test.ts +116 -0
- package/dist/extensions/pi-hermes-memory/tests/store/memory-store.test.ts +163 -0
- package/dist/extensions/pi-hermes-memory/tests/store/session-indexer.test.ts +233 -0
- package/dist/extensions/pi-hermes-memory/tests/store/session-search.test.ts +12 -0
- package/dist/extensions/pi-hermes-memory/tests/store/sqlite-memory-store.test.ts +175 -0
- package/dist/extensions/pi-hermes-memory/tests/store/sqlite-native.test.ts +2 -2
- package/dist/extensions/pi-hermes-memory/tests/tools/memory-search-tool.test.ts +22 -0
- package/dist/extensions/pi-hermes-memory/tests/tools/memory-tool.test.ts +37 -1
- package/dist/extensions/pi-intercom/CHANGELOG.md +13 -0
- package/dist/extensions/pi-intercom/README.md +16 -2
- package/dist/extensions/pi-intercom/broker/spawn.test.ts +19 -2
- package/dist/extensions/pi-intercom/broker/spawn.ts +4 -4
- package/dist/extensions/pi-intercom/index.ts +1 -1
- package/dist/extensions/pi-intercom/intercom.integration.test.ts +121 -2
- package/dist/extensions/pi-intercom/package.json +1 -1
- package/dist/extensions/pi-intercom/project-agent.test.ts +1 -1
- package/dist/extensions/pi-intercom/project-agent.ts +1 -6
- package/dist/extensions/pi-intercom/skills/pi-intercom/SKILL.md +7 -6
- package/dist/extensions/pi-rewind-hook/index.test.ts +7 -0
- package/dist/extensions/pi-subagents/.github/workflows/test.yml +36 -4
- package/dist/extensions/pi-subagents/CHANGELOG.md +120 -0
- package/dist/extensions/pi-subagents/README.md +3 -3
- package/dist/extensions/pi-subagents/agents/researcher.md +23 -13
- package/dist/extensions/pi-subagents/agents/reviewer.md +1 -1
- package/dist/extensions/pi-subagents/agents/scout.md +1 -1
- package/dist/extensions/pi-subagents/docs/agents.md +32 -16
- package/dist/extensions/pi-subagents/docs/configuration.md +41 -15
- package/dist/extensions/pi-subagents/docs/extension-api.md +109 -6
- package/dist/extensions/pi-subagents/docs/missions.md +2 -0
- package/dist/extensions/pi-subagents/docs/models.md +58 -1
- package/dist/extensions/pi-subagents/docs/observability.md +50 -12
- package/dist/extensions/pi-subagents/docs/tool-reference.md +17 -10
- package/dist/extensions/pi-subagents/docs/watchdog.md +1 -1
- package/dist/extensions/pi-subagents/docs/workflows.md +26 -9
- package/dist/extensions/pi-subagents/package-lock.json +747 -177
- package/dist/extensions/pi-subagents/package.json +6 -4
- package/dist/extensions/pi-subagents/runner-server-preload.mjs +13 -0
- package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +2 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +1 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +21 -4
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +2 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/multi-lane-orchestration.md +2 -0
- package/dist/extensions/pi-subagents/src/agents/advertised-agent-prompt.ts +63 -0
- package/dist/extensions/pi-subagents/src/agents/agent-management.ts +61 -16
- package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +2 -0
- package/dist/extensions/pi-subagents/src/agents/agents.ts +8 -0
- package/dist/extensions/pi-subagents/src/api/capability-ceiling.ts +0 -1
- package/dist/extensions/pi-subagents/src/api/{pi-args.ts → child-tool-plan.ts} +1 -1
- package/dist/extensions/pi-subagents/src/api/preflight.ts +7 -4
- package/dist/extensions/pi-subagents/src/api/shared-types.ts +2 -2
- package/dist/extensions/pi-subagents/src/api/workflow-resources.ts +6 -0
- package/dist/extensions/pi-subagents/src/extension/config.ts +4 -2
- package/dist/extensions/pi-subagents/src/extension/doctor.ts +2 -10
- package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +9 -11
- package/dist/extensions/pi-subagents/src/extension/index.ts +99 -10
- package/dist/extensions/pi-subagents/src/extension/public-execution.ts +13 -0
- package/dist/extensions/pi-subagents/src/extension/rpc.ts +7 -23
- package/dist/extensions/pi-subagents/src/extension/schemas.ts +11 -8
- package/dist/extensions/pi-subagents/src/extension/tool-description.ts +25 -7
- package/dist/extensions/pi-subagents/src/integrations/pi-web-session-liveness.ts +73 -0
- package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +228 -136
- package/dist/extensions/pi-subagents/src/intercom/supervisor-ui.ts +244 -0
- package/dist/extensions/pi-subagents/src/missions/workflow-state.ts +37 -16
- package/dist/extensions/pi-subagents/src/runs/background/active-async-capacity.ts +18 -18
- package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +51 -25
- package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +46 -3
- package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +14 -3
- package/dist/extensions/pi-subagents/src/runs/background/async-retention.ts +9 -0
- package/dist/extensions/pi-subagents/src/runs/background/async-status-snapshot.ts +10 -12
- package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +18 -15
- package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +40 -29
- package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +8 -0
- package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +79 -247
- package/dist/extensions/pi-subagents/src/runs/background/notify.ts +88 -12
- package/dist/extensions/pi-subagents/src/runs/background/owned-process-tree.ts +6 -6
- package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +24 -24
- package/dist/extensions/pi-subagents/src/runs/background/retained-nested-route-tracker.ts +96 -0
- package/dist/extensions/pi-subagents/src/runs/background/run-child-session.ts +642 -0
- package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +75 -6
- package/dist/extensions/pi-subagents/src/runs/background/runner-aliases.ts +163 -0
- package/dist/extensions/pi-subagents/src/runs/background/runner-child-launch.ts +86 -0
- package/dist/extensions/pi-subagents/src/runs/background/runner-child-sessions.ts +31 -0
- package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +18 -4
- package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +3 -1
- package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +597 -1092
- package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +3 -0
- package/dist/extensions/pi-subagents/src/runs/background/wait-completions.ts +4 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +20 -17
- package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +296 -394
- package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +4 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/foreground-history.ts +3 -1
- package/dist/extensions/pi-subagents/src/runs/foreground/prompt-audit.ts +9 -5
- package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +630 -283
- package/dist/extensions/pi-subagents/src/runs/foreground/workflow-detach-reconcile.ts +8 -5
- package/dist/extensions/pi-subagents/src/runs/foreground/workflow-foreground-steering.ts +78 -98
- package/dist/extensions/pi-subagents/src/runs/shared/abort-recovery.ts +3 -3
- package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +16 -3
- package/dist/extensions/pi-subagents/src/runs/shared/agent-contract.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/shared/async-status-projection.ts +47 -47
- package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +1 -2
- package/dist/extensions/pi-subagents/src/runs/shared/child-hooks.ts +174 -0
- package/dist/extensions/pi-subagents/src/runs/shared/child-identity.ts +14 -3
- package/dist/extensions/pi-subagents/src/runs/shared/child-launch.ts +319 -0
- package/dist/extensions/pi-subagents/src/runs/shared/child-lifecycle.ts +25 -0
- package/dist/extensions/pi-subagents/src/runs/shared/child-runtime-config.ts +126 -0
- package/dist/extensions/pi-subagents/src/runs/shared/child-session.ts +373 -0
- package/dist/extensions/pi-subagents/src/runs/shared/child-tool-plan.ts +530 -0
- package/dist/extensions/pi-subagents/src/runs/shared/completion-evidence.ts +2 -2
- package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +2 -1
- package/dist/extensions/pi-subagents/src/runs/shared/external-cli-preflight.ts +16 -0
- package/dist/extensions/pi-subagents/src/runs/shared/host-step-status.ts +11 -11
- package/dist/extensions/pi-subagents/src/runs/shared/llm-intent-arbiter.ts +30 -20
- package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +5 -4
- package/dist/extensions/pi-subagents/src/runs/shared/model-exclusions.ts +84 -15
- package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +88 -12
- package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +37 -53
- package/dist/extensions/pi-subagents/src/runs/shared/nested-path.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/shared/orca-progress-tabs.ts +18 -7
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +57 -12
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +3 -4
- package/dist/extensions/pi-subagents/src/runs/shared/permissions.ts +0 -11
- package/dist/extensions/pi-subagents/src/runs/shared/process-signal.ts +4 -1
- package/dist/extensions/pi-subagents/src/runs/shared/readonly-drain-observation.ts +42 -0
- package/dist/extensions/pi-subagents/src/runs/shared/readonly-model-continuation.ts +69 -0
- package/dist/extensions/pi-subagents/src/runs/shared/readonly-session-evidence.ts +307 -0
- package/dist/extensions/pi-subagents/src/runs/shared/run-fanout-budget.ts +8 -21
- package/dist/extensions/pi-subagents/src/runs/shared/runtime-acknowledged-extensions.ts +3 -30
- package/dist/extensions/pi-subagents/src/runs/shared/structured-output.ts +17 -4
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +2 -0
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +99 -386
- package/dist/extensions/pi-subagents/src/runs/shared/tool-availability.ts +18 -62
- package/dist/extensions/pi-subagents/src/runs/shared/tool-budget.ts +0 -14
- package/dist/extensions/pi-subagents/src/runs/shared/worktree-cleanup-plan.ts +31 -9
- package/dist/extensions/pi-subagents/src/runs/shared/worktree-setup-command.ts +190 -0
- package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +506 -226
- package/dist/extensions/pi-subagents/src/shared/child-session-name.ts +1 -1
- package/dist/extensions/pi-subagents/src/shared/jsonl-writer.ts +11 -0
- package/dist/extensions/pi-subagents/src/shared/model-response-aliases.ts +13 -0
- package/dist/extensions/pi-subagents/src/shared/thinking-ceiling.ts +0 -6
- package/dist/extensions/pi-subagents/src/shared/types.ts +145 -89
- package/dist/extensions/pi-subagents/src/shared/utils.ts +13 -6
- package/dist/extensions/pi-subagents/src/shared/watch-strategy.ts +2 -0
- package/dist/extensions/pi-subagents/src/shared/workflow-child-permit.ts +18 -13
- package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +0 -6
- package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +1 -1
- package/dist/extensions/pi-subagents/src/tui/fleet.ts +11 -6
- package/dist/extensions/pi-subagents/src/tui/render.ts +277 -46
- package/dist/extensions/pi-subagents/src/watchdog/child-status.ts +0 -1
- package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +12 -12
- package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +3 -3
- package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +116 -15
- package/dist/extensions/pi-subagents/src/workflows/workflow-checklist.ts +15 -18
- package/dist/extensions/pi-subagents/src/workflows/workflow-child-summary.ts +57 -8
- package/dist/extensions/pi-subagents/src/workflows/workflow-preflight.ts +19 -19
- package/dist/extensions/pi-subagents/src/workflows/workflow-receipt.ts +3 -3
- package/dist/extensions/pi-subagents/src/workflows/workflow-resources.ts +97 -22
- package/dist/extensions/pi-subagents/src/workflows/workflow-settlement.ts +3 -0
- package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +336 -21
- package/dist/extensions/pi-subagents/test/integration/async-execution.part-1.test.ts +1181 -0
- package/dist/extensions/pi-subagents/test/integration/async-execution.part-2.test.ts +2240 -0
- package/dist/extensions/pi-subagents/test/integration/async-execution.part-3.test.ts +2268 -0
- package/dist/extensions/pi-subagents/test/integration/async-execution.part-4.test.ts +1512 -0
- package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +231 -16
- package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +4 -18
- package/dist/extensions/pi-subagents/test/integration/foreign-workflow-steering.test.ts +95 -0
- package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +9 -15
- package/dist/extensions/pi-subagents/test/integration/in-process-child.test.ts +374 -0
- package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +20 -10
- package/dist/extensions/pi-subagents/test/integration/orca-progress-tabs.test.ts +18 -6
- package/dist/extensions/pi-subagents/test/integration/recovered-assistant-error.test.ts +151 -0
- package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +42 -1
- package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +150 -25
- package/dist/extensions/pi-subagents/test/integration/result-publication.test.ts +354 -0
- package/dist/extensions/pi-subagents/test/integration/shared-cwd-terminal-evidence.test.ts +117 -0
- package/dist/extensions/pi-subagents/test/integration/single-execution.part-1.test.ts +3678 -0
- package/dist/extensions/pi-subagents/test/integration/{single-execution.test.ts → single-execution.part-2.test.ts} +500 -4207
- package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +1 -2
- package/dist/extensions/pi-subagents/test/integration/workflow-result-publication.test.ts +127 -0
- package/dist/extensions/pi-subagents/test/integration/workflow-steer-inbox.test.ts +365 -0
- package/dist/extensions/pi-subagents/test/smoke/pi085-child.ts +31 -0
- package/dist/extensions/pi-subagents/test/smoke/pi085-clean-install.mjs +74 -0
- package/dist/extensions/pi-subagents/test/smoke/pi085-extension.ts +16 -0
- package/dist/extensions/pi-subagents/test/support/async-execution-fixture.ts +699 -0
- package/dist/extensions/pi-subagents/test/support/fake-child-session.ts +418 -0
- package/dist/extensions/pi-subagents/test/support/foreign-workflow-steer-host.mjs +13 -0
- package/dist/extensions/pi-subagents/test/support/mock-pi.ts +30 -76
- package/dist/extensions/pi-subagents/test/support/notify-diagnostics-fixture.ts +84 -0
- package/dist/extensions/pi-subagents/test/support/result-publication-capacity-preload.mjs +70 -0
- package/dist/extensions/pi-subagents/test/support/runner-child-session-factory.ts +17 -0
- package/dist/extensions/pi-subagents/test/support/single-execution-fixture.ts +390 -0
- package/dist/extensions/pi-subagents/test/unit/acceptance-compaction.test.ts +120 -0
- package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +24 -3
- package/dist/extensions/pi-subagents/test/unit/advertised-agent-prompt.test.ts +87 -0
- package/dist/extensions/pi-subagents/test/unit/advertised-agent-refresh.test.ts +163 -0
- package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +70 -31
- package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +78 -3
- package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +2 -8
- package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +73 -66
- package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +51 -1
- package/dist/extensions/pi-subagents/test/unit/async-retention.test.ts +49 -1
- package/dist/extensions/pi-subagents/test/unit/async-spawn-preload.test.ts +103 -0
- package/dist/extensions/pi-subagents/test/unit/async-status-projection.test.ts +3 -3
- package/dist/extensions/pi-subagents/test/unit/capability-ceiling-agent-allowlist.test.ts +9 -8
- package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +10 -7
- package/dist/extensions/pi-subagents/test/unit/chain-root-attachment.test.ts +48 -6
- package/dist/extensions/pi-subagents/test/unit/child-runtime-config.test.ts +90 -0
- package/dist/extensions/pi-subagents/test/unit/{pi-args-permission-system.test.ts → child-tool-plan-permission-system.test.ts} +48 -86
- package/dist/extensions/pi-subagents/test/unit/child-tool-plan.test.ts +33 -0
- package/dist/extensions/pi-subagents/test/unit/compaction-resume.test.ts +18 -18
- package/dist/extensions/pi-subagents/test/unit/completion-evidence.test.ts +9 -9
- package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +8 -7
- package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +225 -65
- package/dist/extensions/pi-subagents/test/unit/extension-bindings.test.ts +17 -22
- package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +11 -1
- package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +47 -3
- package/dist/extensions/pi-subagents/test/unit/foreign-workflow-steering.test.ts +74 -0
- package/dist/extensions/pi-subagents/test/unit/fork-cache-key.test.ts +23 -29
- package/dist/extensions/pi-subagents/test/unit/host-peer-runtime-imports.test.ts +96 -4
- package/dist/extensions/pi-subagents/test/unit/host-step-status.test.ts +4 -4
- package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +116 -55
- package/dist/extensions/pi-subagents/test/unit/index-segment.test.ts +58 -1
- package/dist/extensions/pi-subagents/test/unit/llm-intent-arbiter.test.ts +104 -3
- package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +10 -1
- package/dist/extensions/pi-subagents/test/unit/mission-store.test.ts +31 -1
- package/dist/extensions/pi-subagents/test/unit/model-exclusions.test.ts +102 -51
- package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +196 -6
- package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +181 -38
- package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +62 -70
- package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +58 -53
- package/dist/extensions/pi-subagents/test/unit/notify-diagnostics.test.ts +42 -0
- package/dist/extensions/pi-subagents/test/unit/notify.test.ts +84 -0
- package/dist/extensions/pi-subagents/test/unit/orca-progress-tabs.test.ts +13 -5
- package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +21 -5
- package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +5 -4
- package/dist/extensions/pi-subagents/test/unit/permissions.test.ts +2 -6
- package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +28 -2
- package/dist/extensions/pi-subagents/test/unit/pi-web-session-liveness.test.ts +209 -0
- package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +38 -1
- package/dist/extensions/pi-subagents/test/unit/prompt-audit-optional-peers.test.ts +43 -0
- package/dist/extensions/pi-subagents/test/unit/public-execution.test.ts +24 -2
- package/dist/extensions/pi-subagents/test/unit/readonly-drain-observation.test.ts +174 -0
- package/dist/extensions/pi-subagents/test/unit/readonly-model-continuation.test.ts +94 -0
- package/dist/extensions/pi-subagents/test/unit/readonly-session-evidence.test.ts +1329 -0
- package/dist/extensions/pi-subagents/test/unit/recursion-guard.test.ts +29 -80
- package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +11 -8
- package/dist/extensions/pi-subagents/test/unit/result-files.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/retained-nested-route-tracker.test.ts +175 -0
- package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +38 -12
- package/dist/extensions/pi-subagents/test/unit/run-fanout-budget.test.ts +2 -5
- package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +89 -1
- package/dist/extensions/pi-subagents/test/unit/runtime-acknowledged-extensions.test.ts +2 -16
- package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +27 -3
- package/dist/extensions/pi-subagents/test/unit/scheduled-supervisor-demand.test.ts +215 -0
- package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +15 -11
- package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +237 -1
- package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +2 -5
- package/dist/extensions/pi-subagents/test/unit/streamed-progress-bounds.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/subagent-guide.test.ts +14 -1
- package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +130 -739
- package/dist/extensions/pi-subagents/test/unit/supervisor-ask-registration.test.ts +682 -0
- package/dist/extensions/pi-subagents/test/unit/supervisor-ui.test.ts +137 -0
- package/dist/extensions/pi-subagents/test/unit/tool-budget.test.ts +1 -11
- package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +23 -3
- package/dist/extensions/pi-subagents/test/unit/wait-completions.test.ts +8 -1
- package/dist/extensions/pi-subagents/test/unit/watchdog-tool-actions.test.ts +19 -1
- package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +72 -4
- package/dist/extensions/pi-subagents/test/unit/workflow-checklist.test.ts +17 -3
- package/dist/extensions/pi-subagents/test/unit/workflow-child-summary.test.ts +34 -0
- package/dist/extensions/pi-subagents/test/unit/workflow-detach-reconcile.test.ts +12 -2
- package/dist/extensions/pi-subagents/test/unit/workflow-launch-params.test.ts +46 -6
- package/dist/extensions/pi-subagents/test/unit/workflow-receipt.test.ts +3 -3
- package/dist/extensions/pi-subagents/test/unit/workflow-resources.test.ts +133 -1
- package/dist/extensions/pi-subagents/test/unit/workflow-resume-hint.test.ts +53 -2
- package/dist/extensions/pi-subagents/test/unit/worktree-cleanup-plan.test.ts +222 -14
- package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +526 -85
- package/dist/extensions/pi-web-agent/src/backends/config.ts +1 -0
- package/dist/extensions/pi-web-agent/src/backends/settings-reader.ts +5 -3
- package/dist/extensions/pi-web-agent/src/search/tokenin.ts +7 -3
- package/dist/extensions/pi-web-agent/src/types.ts +1 -1
- package/dist/extensions/pi-zentui/README.md +17 -0
- package/dist/extensions/pi-zentui/assets/screenshots/footer-status-hyperlink.png +0 -0
- package/dist/extensions/pi-zentui/docs/configuration.md +71 -2
- package/dist/extensions/pi-zentui/extensions/zentui/config.ts +11 -0
- package/dist/extensions/pi-zentui/extensions/zentui/editor-transfer.ts +14 -0
- package/dist/extensions/pi-zentui/extensions/zentui/extension-status.ts +29 -13
- package/dist/extensions/pi-zentui/extensions/zentui/footer-layout.ts +5 -4
- package/dist/extensions/pi-zentui/extensions/zentui/footer-text.ts +11 -0
- package/dist/extensions/pi-zentui/extensions/zentui/footer.ts +11 -10
- package/dist/extensions/pi-zentui/extensions/zentui/index.ts +77 -3
- package/dist/extensions/pi-zentui/extensions/zentui/presets.ts +77 -0
- package/dist/extensions/pi-zentui/extensions/zentui/settings-command.ts +103 -2
- package/dist/extensions/pi-zentui/extensions/zentui/working-line-extension-segments.ts +115 -0
- package/dist/extensions/pi-zentui/extensions/zentui/working-line.ts +87 -5
- package/dist/extensions/pi-zentui/package-lock.json +277 -517
- package/dist/extensions/pi-zentui/package.json +7 -4
- package/dist/extensions/pi-zentui/test/config-presets.test.ts +238 -0
- package/dist/extensions/pi-zentui/test/editor-transfer.test.ts +24 -1
- package/dist/extensions/pi-zentui/test/extension-compliance.test.ts +570 -2
- package/dist/extensions/pi-zentui/test/extension-status.test.ts +90 -0
- package/dist/extensions/pi-zentui/test/footer-hyperlink.test.ts +243 -0
- package/dist/extensions/pi-zentui/test/package-contents.mjs +1 -0
- package/dist/extensions/pi-zentui/test/presets.test.ts +121 -0
- package/dist/extensions/pi-zentui/test/settings-command.test.ts +205 -1
- package/dist/extensions/pi-zentui/test/working-line-extension-segments.test.ts +139 -0
- package/dist/extensions/pi-zentui/test/working-line-lifecycle.integration.test.ts +237 -3
- package/dist/extensions/pi-zentui/test/working-line.test.ts +94 -2
- package/dist/index.d.ts +1 -1
- package/dist/main.js +4 -1
- package/dist/modes/interactive/chat-viewport.d.ts +19 -0
- package/dist/modes/interactive/chat-viewport.js +27 -0
- package/dist/modes/interactive/components/assistant-message.d.ts +6 -2
- package/dist/modes/interactive/components/assistant-message.js +30 -13
- package/dist/modes/interactive/components/custom-editor.d.ts +10 -1
- package/dist/modes/interactive/components/custom-editor.js +39 -1
- package/dist/modes/interactive/components/first-time-setup.js +1 -1
- package/dist/modes/interactive/components/index.d.ts +1 -1
- package/dist/modes/interactive/components/markdown-transform.d.ts +2 -0
- package/dist/modes/interactive/components/markdown-transform.js +18 -0
- package/dist/modes/interactive/components/model-selector.js +19 -17
- package/dist/modes/interactive/components/scoped-models-selector.js +21 -23
- package/dist/modes/interactive/components/settings-selector.d.ts +7 -1
- package/dist/modes/interactive/components/settings-selector.js +128 -20
- package/dist/modes/interactive/components/settings-submenu.d.ts +71 -0
- package/dist/modes/interactive/components/settings-submenu.js +164 -0
- package/dist/modes/interactive/components/status-indicator.d.ts +3 -1
- package/dist/modes/interactive/components/status-indicator.js +10 -3
- package/dist/modes/interactive/components/thinking-selector.d.ts +15 -3
- package/dist/modes/interactive/components/thinking-selector.js +75 -18
- package/dist/modes/interactive/components/tool-execution.d.ts +21 -4
- package/dist/modes/interactive/components/tool-execution.js +35 -33
- package/dist/modes/interactive/components/trust-selector.js +2 -2
- package/dist/modes/interactive/interactive-mode.d.ts +13 -15
- package/dist/modes/interactive/interactive-mode.js +144 -80
- package/dist/modes/interactive/session-share.d.ts +15 -0
- package/dist/modes/interactive/session-share.js +183 -0
- package/dist/modes/interactive/theme/dark.json +2 -1
- package/dist/modes/interactive/theme/light.json +2 -1
- package/dist/modes/interactive/theme/theme-controller.d.ts +1 -0
- package/dist/modes/interactive/theme/theme-controller.js +5 -0
- package/dist/modes/interactive/theme/theme-json.d.ts +83 -0
- package/dist/modes/interactive/theme/theme-json.js +129 -0
- package/dist/modes/interactive/theme/theme-schema.json +9 -1
- package/dist/modes/interactive/theme/theme.d.ts +14 -5
- package/dist/modes/interactive/theme/theme.js +18 -119
- package/dist/modes/interactive/tui-renderer.d.ts +20 -0
- package/dist/modes/interactive/tui-renderer.js +65 -0
- package/dist/utils/exif-orientation.js +2 -3
- package/dist/utils/management-http.d.ts +24 -0
- package/dist/utils/management-http.js +53 -0
- package/dist/utils/text.d.ts +7 -0
- package/dist/utils/text.js +8 -0
- package/dist/utils/tools-manager.d.ts +1 -0
- package/dist/utils/tools-manager.js +43 -21
- package/docs/docs.json +0 -4
- package/package.json +4 -4
- package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +0 -415
- package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +0 -1059
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +0 -116
- package/dist/extensions/pi-subagents/src/shared/post-exit-stdio-guard.ts +0 -85
- package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +0 -224
- package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +0 -6986
- package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +0 -447
- package/dist/extensions/pi-subagents/test/support/real-session-child-cli.mjs +0 -185
- package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +0 -311
- package/dist/extensions/pi-subagents/test/unit/capability-ceiling-pi-args.test.ts +0 -84
- package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +0 -202
- package/dist/extensions/pi-subagents/test/unit/close-grace-timer.test.ts +0 -101
- package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +0 -2347
- package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +0 -104
- package/dist/extensions/pi-subagents/test/unit/windows-hide-spawn.test.ts +0 -49
- package/dist/skills/imagegen-frontend-mobile/SKILL.md +0 -1465
- package/dist/skills/imagegen-frontend-web/SKILL.md +0 -987
- package/dist/skills/implanger/SKILL.md +0 -70
- package/dist/skills/output/SKILL.md +0 -49
- package/dist/skills/planger/SKILL.md +0 -167
- package/dist/skills/workflow/SKILL.md +0 -95
- package/docs/workflows.md +0 -18
- /package/dist/bun/{register-bedrock.d.ts → runtime-setup.d.ts} +0 -0
|
@@ -4,9 +4,10 @@ import * as path from "node:path";
|
|
|
4
4
|
import { afterEach, describe, it } from "node:test";
|
|
5
5
|
import { registerExternalJobProvider } from "../../src/api/external-job-provider.ts";
|
|
6
6
|
import { getArtifactsDir } from "../../src/shared/artifacts.ts";
|
|
7
|
-
import { SUBAGENT_CHILD_STATUS_EVENT } from "../../src/shared/types.ts";
|
|
7
|
+
import { SUBAGENT_CHILD_STATUS_EVENT, SUBAGENT_CONTROL_EVENT, type ControlEvent } from "../../src/shared/types.ts";
|
|
8
8
|
import { ACTIVE_RUN_INDEX_DIR, updateActiveRunIndex } from "../../src/runs/background/active-run-index.ts";
|
|
9
9
|
import { EXTERNAL_JOB_BRIDGE_REQUEST_DIR } from "../../src/runs/shared/external-job-bridge.ts";
|
|
10
|
+
import { createNativeSupervisorChannel, ensureSupervisorChannelDir, resolveSupervisorChannelDir } from "../../src/intercom/native-supervisor-channel.ts";
|
|
10
11
|
import { SubagentFleetComponent } from "../../src/tui/fleet.ts";
|
|
11
12
|
import { createNestedRoute } from "../../src/runs/shared/nested-events.ts";
|
|
12
13
|
import { createTempDir, removeTempDir, tryImport } from "../support/helpers.ts";
|
|
@@ -26,6 +27,7 @@ interface AsyncJobTrackerModule {
|
|
|
26
27
|
watch?: typeof fs.watch;
|
|
27
28
|
kill?: (pid: number, signal?: NodeJS.Signals | 0) => boolean;
|
|
28
29
|
now?: () => number;
|
|
30
|
+
supervisorRequestState?: (event: ControlEvent) => "pending" | "resolved" | "unknown";
|
|
29
31
|
},
|
|
30
32
|
): {
|
|
31
33
|
ensurePoller(): void;
|
|
@@ -89,6 +91,85 @@ function createEventRecorder() {
|
|
|
89
91
|
};
|
|
90
92
|
}
|
|
91
93
|
|
|
94
|
+
function writeSupervisorRequest(input: { sessionId: string; runId: string; toolCallId: string }): { channelDir: string; requestId: string } {
|
|
95
|
+
const channelDir = resolveSupervisorChannelDir(input.runId, "worker", 0);
|
|
96
|
+
ensureSupervisorChannelDir(channelDir);
|
|
97
|
+
const requestId = `request-${input.toolCallId}`;
|
|
98
|
+
fs.writeFileSync(path.join(channelDir, "requests", `${requestId}.json`), JSON.stringify({
|
|
99
|
+
type: "subagent.supervisor.request",
|
|
100
|
+
id: requestId,
|
|
101
|
+
createdAt: Date.now(),
|
|
102
|
+
reason: "need_decision",
|
|
103
|
+
message: "Need a decision",
|
|
104
|
+
expectsReply: true,
|
|
105
|
+
orchestratorSessionId: input.sessionId,
|
|
106
|
+
runId: input.runId,
|
|
107
|
+
agent: "worker",
|
|
108
|
+
childIndex: 0,
|
|
109
|
+
toolCallId: input.toolCallId,
|
|
110
|
+
}), "utf-8");
|
|
111
|
+
return { channelDir, requestId };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function writeControlRecord(runDir: string, event: ControlEvent): void {
|
|
115
|
+
fs.appendFileSync(path.join(runDir, "events.jsonl"), `${JSON.stringify({ type: "subagent.control", channels: ["event"], event })}\n`, "utf-8");
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function supervisorControlEvent(runId: string, toolCallId: string, currentTool = "contact_supervisor"): ControlEvent {
|
|
119
|
+
return {
|
|
120
|
+
type: "needs_attention",
|
|
121
|
+
to: "needs_attention",
|
|
122
|
+
ts: Date.now(),
|
|
123
|
+
runId,
|
|
124
|
+
agent: "worker",
|
|
125
|
+
index: 0,
|
|
126
|
+
message: "worker is waiting for a supervisor reply",
|
|
127
|
+
reason: "supervisor_request",
|
|
128
|
+
currentTool,
|
|
129
|
+
toolCallId,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function writeRunningAsyncStatus(runDir: string, runId: string, sessionId: string): void {
|
|
134
|
+
fs.mkdirSync(runDir, { recursive: true });
|
|
135
|
+
fs.writeFileSync(path.join(runDir, "status.json"), JSON.stringify({
|
|
136
|
+
runId,
|
|
137
|
+
mode: "single",
|
|
138
|
+
state: "running",
|
|
139
|
+
sessionId,
|
|
140
|
+
startedAt: Date.now(),
|
|
141
|
+
lastUpdate: Date.now(),
|
|
142
|
+
steps: [{ agent: "worker", status: "running" }],
|
|
143
|
+
}), "utf-8");
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function createNativeSupervisorHarness(sessionId: string) {
|
|
147
|
+
const nativeState = createState();
|
|
148
|
+
(nativeState as { currentSessionId: string; lastUiContext: unknown }).currentSessionId = sessionId;
|
|
149
|
+
(nativeState as { supervisorOwnerSessionId: string }).supervisorOwnerSessionId = sessionId;
|
|
150
|
+
(nativeState as { currentSessionId: string; lastUiContext: unknown }).lastUiContext = {
|
|
151
|
+
hasUI: false,
|
|
152
|
+
sessionManager: {
|
|
153
|
+
getSessionId: () => sessionId,
|
|
154
|
+
getSessionFile: () => null,
|
|
155
|
+
getEntries: () => [],
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
const tools = new Map<string, { execute: (id: string, params: Record<string, unknown>) => Promise<unknown> }>();
|
|
159
|
+
const sent: Array<{ customType?: string; options?: { triggerTurn?: boolean } }> = [];
|
|
160
|
+
const pi = {
|
|
161
|
+
getAllTools: () => [...tools.keys()].map((name) => ({ name })),
|
|
162
|
+
registerTool: (tool: { name: string; execute: (...args: unknown[]) => Promise<unknown> }) => {
|
|
163
|
+
tools.set(tool.name, { execute: (id, params) => tool.execute(id, params) });
|
|
164
|
+
},
|
|
165
|
+
sendMessage: (message: { customType?: string }, options?: { triggerTurn?: boolean }) => {
|
|
166
|
+
sent.push({ customType: message.customType, options });
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
const channel = createNativeSupervisorChannel(pi as never, nativeState as never, { platform: "win32" });
|
|
170
|
+
return { channel, tools, sent };
|
|
171
|
+
}
|
|
172
|
+
|
|
92
173
|
function pidGone(): never {
|
|
93
174
|
const error = new Error("missing") as NodeJS.ErrnoException;
|
|
94
175
|
error.code = "ESRCH";
|
|
@@ -430,7 +511,7 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
|
|
|
430
511
|
updateActiveRunIndex(runDir, "running");
|
|
431
512
|
const state = createState();
|
|
432
513
|
state.currentSessionId = "session-restored-nested";
|
|
433
|
-
const tracker = createTracker(createEventRecorder().
|
|
514
|
+
const tracker = createTracker(createEventRecorder().pi, state as never, asyncRoot, { pollIntervalMs: 60_000 });
|
|
434
515
|
tracker.restoreActiveJobs();
|
|
435
516
|
assert.equal(state.asyncJobs.get("run-restored-nested")?.nestedRoute?.eventSink, nestedRoute.eventSink);
|
|
436
517
|
|
|
@@ -483,7 +564,7 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
|
|
|
483
564
|
updateActiveRunIndex(runDir, "running");
|
|
484
565
|
const state = createState();
|
|
485
566
|
state.currentSessionId = "session-workflow";
|
|
486
|
-
const tracker = createTracker(createEventRecorder().
|
|
567
|
+
const tracker = createTracker(createEventRecorder().pi, state as never, asyncRoot, { pollIntervalMs: 60_000 });
|
|
487
568
|
tracker.restoreActiveJobs();
|
|
488
569
|
assert.deepEqual(state.asyncJobs.get("workflow-run")?.workflow?.emits, [{ stage: "scan" }]);
|
|
489
570
|
assert.equal(state.asyncJobs.get("workflow-run")?.sessionRoot, "/trusted/workflow-sessions");
|
|
@@ -513,7 +594,7 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
|
|
|
513
594
|
fs.mkdirSync(runDir, { recursive: true });
|
|
514
595
|
const state = createState();
|
|
515
596
|
state.currentSessionId = "session-late-status";
|
|
516
|
-
const tracker = createTracker(createEventRecorder().
|
|
597
|
+
const tracker = createTracker(createEventRecorder().pi, state as never, asyncRoot, { pollIntervalMs: 60_000 });
|
|
517
598
|
tracker.handleStarted({ id: "late-status-run", asyncDir: runDir, sessionId: "session-late-status", agent: "worker" });
|
|
518
599
|
|
|
519
600
|
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
@@ -548,7 +629,7 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
|
|
|
548
629
|
steps: [{ agent: "worker", status: "running" }],
|
|
549
630
|
}), "utf-8");
|
|
550
631
|
const state = createState();
|
|
551
|
-
const tracker = createTracker(createEventRecorder().
|
|
632
|
+
const tracker = createTracker(createEventRecorder().pi, state as never, asyncRoot, {
|
|
552
633
|
pollIntervalMs: 10,
|
|
553
634
|
watch: (() => { throw new Error("native watcher disabled for test"); }) as never,
|
|
554
635
|
});
|
|
@@ -609,7 +690,7 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
|
|
|
609
690
|
reattach: () => ({ providerJobId: "provider-job", state: "completed" }),
|
|
610
691
|
});
|
|
611
692
|
const state = createState();
|
|
612
|
-
const tracker = createTracker(createEventRecorder().
|
|
693
|
+
const tracker = createTracker(createEventRecorder().pi, state as never, asyncRoot, {
|
|
613
694
|
pollIntervalMs: 10,
|
|
614
695
|
watch: (() => { throw new Error("native watcher disabled for test"); }) as never,
|
|
615
696
|
});
|
|
@@ -642,7 +723,7 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
|
|
|
642
723
|
steps: [{ agent: "worker", status: "running", runner: { type: "external-job", provider: "tracker-provider-late", options: {} } }],
|
|
643
724
|
}), "utf-8");
|
|
644
725
|
const state = createState();
|
|
645
|
-
const tracker = createTracker(createEventRecorder().
|
|
726
|
+
const tracker = createTracker(createEventRecorder().pi, state as never, asyncRoot, {
|
|
646
727
|
pollIntervalMs: 10,
|
|
647
728
|
watch: (() => { throw new Error("native watcher disabled for test"); }) as never,
|
|
648
729
|
});
|
|
@@ -692,7 +773,7 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
|
|
|
692
773
|
fs.mkdirSync(path.join(runDir, EXTERNAL_JOB_BRIDGE_REQUEST_DIR), { recursive: true });
|
|
693
774
|
fs.writeFileSync(path.join(runDir, EXTERNAL_JOB_BRIDGE_REQUEST_DIR, "malformed.json"), "{malformed", "utf-8");
|
|
694
775
|
const state = createState();
|
|
695
|
-
const tracker = createTracker(createEventRecorder().
|
|
776
|
+
const tracker = createTracker(createEventRecorder().pi, state as never, asyncRoot, {
|
|
696
777
|
pollIntervalMs: 10,
|
|
697
778
|
watch: (() => { throw new Error("native watcher disabled for test"); }) as never,
|
|
698
779
|
});
|
|
@@ -724,11 +805,16 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
|
|
|
724
805
|
}), "utf-8");
|
|
725
806
|
const state = createState();
|
|
726
807
|
const ui = createUiContext();
|
|
727
|
-
const tracker = createTracker(createEventRecorder().
|
|
808
|
+
const tracker = createTracker(createEventRecorder().pi, state as never, asyncRoot, {
|
|
809
|
+
pollIntervalMs: 10,
|
|
810
|
+
watch: (() => { throw new Error("native watcher disabled for test"); }) as never,
|
|
811
|
+
});
|
|
728
812
|
tracker.resetJobs(ui.ctx as never);
|
|
729
813
|
tracker.handleStarted({ id: "quiet-run", asyncDir: runDir, agent: "worker" });
|
|
730
814
|
|
|
815
|
+
const rendersAfterStart = ui.renderRequests;
|
|
731
816
|
await waitForCondition(() => state.asyncJobs.get("quiet-run")?.status === "running", "quiet running job refresh");
|
|
817
|
+
await waitForCondition(() => ui.renderRequests > rendersAfterStart, "quiet running widget redraw");
|
|
732
818
|
const renderRequests = ui.renderRequests;
|
|
733
819
|
await new Promise((resolve) => setTimeout(resolve, 120));
|
|
734
820
|
|
|
@@ -755,7 +841,7 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
|
|
|
755
841
|
const state = createState();
|
|
756
842
|
let nativeWatchCalls = 0;
|
|
757
843
|
let terminalHooks = 0;
|
|
758
|
-
const tracker = createTracker(createEventRecorder().
|
|
844
|
+
const tracker = createTracker(createEventRecorder().pi, state as never, asyncRoot, {
|
|
759
845
|
platform: "darwin",
|
|
760
846
|
pollIntervalMs: 10,
|
|
761
847
|
onJobTerminal: () => terminalHooks++,
|
|
@@ -804,7 +890,7 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
|
|
|
804
890
|
};
|
|
805
891
|
fs.writeFileSync(statusPath, JSON.stringify(statusPayload), "utf-8");
|
|
806
892
|
const state = createState();
|
|
807
|
-
const tracker = createTracker(createEventRecorder().
|
|
893
|
+
const tracker = createTracker(createEventRecorder().pi, state as never, asyncRoot, { pollIntervalMs: 60_000 });
|
|
808
894
|
tracker.handleStarted({ id: "run-nested-events", asyncDir: runDir, agent: "worker", nestedRoute });
|
|
809
895
|
|
|
810
896
|
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
@@ -854,7 +940,7 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
|
|
|
854
940
|
updateActiveRunIndex(runDir, "running");
|
|
855
941
|
const state = createState();
|
|
856
942
|
state.currentSessionId = "session-workflow";
|
|
857
|
-
const tracker = createTracker(createEventRecorder().
|
|
943
|
+
const tracker = createTracker(createEventRecorder().pi, state as never, asyncRoot, { pollIntervalMs: 10 });
|
|
858
944
|
tracker.restoreActiveJobs();
|
|
859
945
|
assert.equal(state.asyncJobs.get("workflow-child")?.parentWorkflowRunId, "workflow-parent");
|
|
860
946
|
assert.equal(state.asyncJobs.get("workflow-child")?.workflowKey, "review");
|
|
@@ -892,7 +978,7 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
|
|
|
892
978
|
|
|
893
979
|
const state = createState();
|
|
894
980
|
state.currentSessionId = "session-owner";
|
|
895
|
-
const tracker = createTracker(createEventRecorder().
|
|
981
|
+
const tracker = createTracker(createEventRecorder().pi, state as never, asyncRoot, {
|
|
896
982
|
pollIntervalMs: 10,
|
|
897
983
|
});
|
|
898
984
|
tracker.restoreActiveJobs();
|
|
@@ -909,7 +995,7 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
|
|
|
909
995
|
try {
|
|
910
996
|
const state = createState();
|
|
911
997
|
state.currentSessionId = "session-owner";
|
|
912
|
-
const tracker = createTracker(createEventRecorder().
|
|
998
|
+
const tracker = createTracker(createEventRecorder().pi, state as never, asyncRoot, {
|
|
913
999
|
completionRetentionMs: 5,
|
|
914
1000
|
pollIntervalMs: 10,
|
|
915
1001
|
});
|
|
@@ -1205,7 +1291,7 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
|
|
|
1205
1291
|
try {
|
|
1206
1292
|
const runDir = path.join(asyncRoot, "run-late-dir");
|
|
1207
1293
|
const state = createState();
|
|
1208
|
-
const tracker = createTracker(createEventRecorder().
|
|
1294
|
+
const tracker = createTracker(createEventRecorder().pi, state as never, asyncRoot, {
|
|
1209
1295
|
completionRetentionMs: 5,
|
|
1210
1296
|
pollIntervalMs: 60_000,
|
|
1211
1297
|
});
|
|
@@ -1472,6 +1558,135 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
|
|
|
1472
1558
|
}
|
|
1473
1559
|
});
|
|
1474
1560
|
|
|
1561
|
+
it("suppresses a resolved native supervisor notice before async replay", async () => {
|
|
1562
|
+
const asyncRoot = createTempDir("pi-async-job-supervisor-replay-resolved-");
|
|
1563
|
+
const sessionId = `session-${Date.now()}`;
|
|
1564
|
+
const runId = `run-${Date.now()}`;
|
|
1565
|
+
const toolCallId = `call-${Date.now()}`;
|
|
1566
|
+
const { channel, tools, sent } = createNativeSupervisorHarness(sessionId);
|
|
1567
|
+
const { channelDir, requestId } = writeSupervisorRequest({ sessionId, runId, toolCallId });
|
|
1568
|
+
try {
|
|
1569
|
+
const runDir = path.join(asyncRoot, runId);
|
|
1570
|
+
writeRunningAsyncStatus(runDir, runId, sessionId);
|
|
1571
|
+
const event = supervisorControlEvent(runId, toolCallId);
|
|
1572
|
+
writeControlRecord(runDir, event);
|
|
1573
|
+
|
|
1574
|
+
channel.start();
|
|
1575
|
+
assert.equal(channel.getSupervisorRequestState(event), "pending");
|
|
1576
|
+
const state = createState();
|
|
1577
|
+
const recorder = createEventRecorder();
|
|
1578
|
+
const tracker = createTracker(recorder.pi, state as never, asyncRoot, {
|
|
1579
|
+
pollIntervalMs: 10,
|
|
1580
|
+
supervisorRequestState: channel.getSupervisorRequestState,
|
|
1581
|
+
});
|
|
1582
|
+
tracker.handleStarted({ id: runId, asyncDir: runDir, agent: "worker", sessionId });
|
|
1583
|
+
await tools.get("subagent_supervisor")!.execute("reply", { action: "reply", replyTo: requestId, message: "Approved" });
|
|
1584
|
+
assert.equal(channel.getSupervisorRequestState(event), "resolved");
|
|
1585
|
+
await waitForCondition(() => (state.asyncJobs.get(runId)?.controlEventCursor ?? 0) > 0, "resolved control event cursor");
|
|
1586
|
+
|
|
1587
|
+
assert.equal(recorder.events.some((entry) => entry.channel === SUBAGENT_CONTROL_EVENT), false);
|
|
1588
|
+
assert.deepEqual(sent, [{ customType: "subagent_supervisor_request", options: { triggerTurn: true } }]);
|
|
1589
|
+
} finally {
|
|
1590
|
+
channel.dispose();
|
|
1591
|
+
fs.rmSync(channelDir, { recursive: true, force: true });
|
|
1592
|
+
removeTempDir(asyncRoot);
|
|
1593
|
+
}
|
|
1594
|
+
});
|
|
1595
|
+
|
|
1596
|
+
it("delivers a native supervisor notice while its request is pending through replay", async () => {
|
|
1597
|
+
const asyncRoot = createTempDir("pi-async-job-supervisor-replay-pending-");
|
|
1598
|
+
const sessionId = `session-${Date.now()}`;
|
|
1599
|
+
const runId = `run-${Date.now()}`;
|
|
1600
|
+
const toolCallId = `call-${Date.now()}`;
|
|
1601
|
+
const { channel, sent } = createNativeSupervisorHarness(sessionId);
|
|
1602
|
+
const { channelDir } = writeSupervisorRequest({ sessionId, runId, toolCallId });
|
|
1603
|
+
try {
|
|
1604
|
+
const runDir = path.join(asyncRoot, runId);
|
|
1605
|
+
writeRunningAsyncStatus(runDir, runId, sessionId);
|
|
1606
|
+
const event = supervisorControlEvent(runId, toolCallId);
|
|
1607
|
+
writeControlRecord(runDir, event);
|
|
1608
|
+
|
|
1609
|
+
channel.start();
|
|
1610
|
+
assert.equal(channel.getSupervisorRequestState(event), "pending");
|
|
1611
|
+
const state = createState();
|
|
1612
|
+
const recorder = createEventRecorder();
|
|
1613
|
+
const tracker = createTracker(recorder.pi, state as never, asyncRoot, {
|
|
1614
|
+
pollIntervalMs: 10,
|
|
1615
|
+
supervisorRequestState: channel.getSupervisorRequestState,
|
|
1616
|
+
});
|
|
1617
|
+
tracker.handleStarted({ id: runId, asyncDir: runDir, agent: "worker", sessionId });
|
|
1618
|
+
await waitForCondition(() => recorder.events.some((entry) => entry.channel === SUBAGENT_CONTROL_EVENT), "pending control event replay");
|
|
1619
|
+
|
|
1620
|
+
const payload = recorder.events.find((entry) => entry.channel === SUBAGENT_CONTROL_EVENT)?.data as { event?: ControlEvent } | undefined;
|
|
1621
|
+
assert.equal(payload?.event?.toolCallId, toolCallId);
|
|
1622
|
+
assert.deepEqual(sent.map((entry) => entry.customType), ["subagent_supervisor_request"]);
|
|
1623
|
+
} finally {
|
|
1624
|
+
channel.dispose();
|
|
1625
|
+
fs.rmSync(channelDir, { recursive: true, force: true });
|
|
1626
|
+
removeTempDir(asyncRoot);
|
|
1627
|
+
}
|
|
1628
|
+
});
|
|
1629
|
+
|
|
1630
|
+
it("keeps the first native supervisor notice after resolution and suppresses later replay", async () => {
|
|
1631
|
+
const asyncRoot = createTempDir("pi-async-job-supervisor-replay-late-");
|
|
1632
|
+
const sessionId = `session-${Date.now()}`;
|
|
1633
|
+
const runId = `run-${Date.now()}`;
|
|
1634
|
+
const toolCallId = `call-${Date.now()}`;
|
|
1635
|
+
const { channel, tools } = createNativeSupervisorHarness(sessionId);
|
|
1636
|
+
const { channelDir, requestId } = writeSupervisorRequest({ sessionId, runId, toolCallId });
|
|
1637
|
+
try {
|
|
1638
|
+
const runDir = path.join(asyncRoot, runId);
|
|
1639
|
+
writeRunningAsyncStatus(runDir, runId, sessionId);
|
|
1640
|
+
const event = supervisorControlEvent(runId, toolCallId);
|
|
1641
|
+
writeControlRecord(runDir, event);
|
|
1642
|
+
|
|
1643
|
+
channel.start();
|
|
1644
|
+
const state = createState();
|
|
1645
|
+
const recorder = createEventRecorder();
|
|
1646
|
+
const tracker = createTracker(recorder.pi, state as never, asyncRoot, {
|
|
1647
|
+
pollIntervalMs: 10,
|
|
1648
|
+
supervisorRequestState: channel.getSupervisorRequestState,
|
|
1649
|
+
});
|
|
1650
|
+
tracker.handleStarted({ id: runId, asyncDir: runDir, agent: "worker", sessionId });
|
|
1651
|
+
await waitForCondition(() => recorder.events.filter((entry) => entry.channel === SUBAGENT_CONTROL_EVENT).length === 1, "first control event replay");
|
|
1652
|
+
|
|
1653
|
+
await tools.get("subagent_supervisor")!.execute("reply", { action: "reply", replyTo: requestId, message: "Approved" });
|
|
1654
|
+
writeControlRecord(runDir, event);
|
|
1655
|
+
const eventSize = fs.statSync(path.join(runDir, "events.jsonl")).size;
|
|
1656
|
+
await waitForCondition(() => (state.asyncJobs.get(runId)?.controlEventCursor ?? 0) >= eventSize, "resolved replay cursor");
|
|
1657
|
+
assert.equal(recorder.events.filter((entry) => entry.channel === SUBAGENT_CONTROL_EVENT).length, 1);
|
|
1658
|
+
} finally {
|
|
1659
|
+
channel.dispose();
|
|
1660
|
+
fs.rmSync(channelDir, { recursive: true, force: true });
|
|
1661
|
+
removeTempDir(asyncRoot);
|
|
1662
|
+
}
|
|
1663
|
+
});
|
|
1664
|
+
|
|
1665
|
+
it("delivers an external intercom ask with the native lifecycle lookup enabled", async () => {
|
|
1666
|
+
const asyncRoot = createTempDir("pi-async-job-supervisor-replay-external-");
|
|
1667
|
+
const sessionId = `session-${Date.now()}`;
|
|
1668
|
+
const runId = `run-${Date.now()}`;
|
|
1669
|
+
const { channel } = createNativeSupervisorHarness(sessionId);
|
|
1670
|
+
try {
|
|
1671
|
+
const runDir = path.join(asyncRoot, runId);
|
|
1672
|
+
writeRunningAsyncStatus(runDir, runId, sessionId);
|
|
1673
|
+
const event = supervisorControlEvent(runId, "external-call", "intercom");
|
|
1674
|
+
writeControlRecord(runDir, event);
|
|
1675
|
+
assert.equal(channel.getSupervisorRequestState(event), "unknown");
|
|
1676
|
+
const state = createState();
|
|
1677
|
+
const recorder = createEventRecorder();
|
|
1678
|
+
const tracker = createTracker(recorder.pi, state as never, asyncRoot, {
|
|
1679
|
+
pollIntervalMs: 10,
|
|
1680
|
+
supervisorRequestState: channel.getSupervisorRequestState,
|
|
1681
|
+
});
|
|
1682
|
+
tracker.handleStarted({ id: runId, asyncDir: runDir, agent: "worker", sessionId });
|
|
1683
|
+
await waitForCondition(() => recorder.events.some((entry) => entry.channel === SUBAGENT_CONTROL_EVENT), "external control event replay");
|
|
1684
|
+
} finally {
|
|
1685
|
+
channel.dispose();
|
|
1686
|
+
removeTempDir(asyncRoot);
|
|
1687
|
+
}
|
|
1688
|
+
});
|
|
1689
|
+
|
|
1475
1690
|
it("keeps incomplete async control event lines for the next poll", async () => {
|
|
1476
1691
|
const asyncRoot = createTempDir("pi-async-job-tracker-");
|
|
1477
1692
|
try {
|
|
@@ -1997,4 +2212,4 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
|
|
|
1997
2212
|
removeTempDir(asyncRoot);
|
|
1998
2213
|
}
|
|
1999
2214
|
});
|
|
2000
|
-
});
|
|
2215
|
+
});
|
|
@@ -130,13 +130,13 @@ describe("runSync error handling", { skip: !piAvailable ? "pi packages not avail
|
|
|
130
130
|
removeTempDir(tempDir);
|
|
131
131
|
});
|
|
132
132
|
|
|
133
|
-
it("
|
|
133
|
+
it("reports a child session failure as the run error", async () => {
|
|
134
134
|
mockPi.onCall({ exitCode: 2, stderr: "Fatal: out of memory" });
|
|
135
135
|
const agents = makeAgentConfigs(["crash"]);
|
|
136
136
|
|
|
137
137
|
const result = await runSync(tempDir, agents, "crash", "Do heavy work", {});
|
|
138
138
|
|
|
139
|
-
assert.equal(result.exitCode,
|
|
139
|
+
assert.equal(result.exitCode, 1);
|
|
140
140
|
assert.ok(result.error?.includes("out of memory"));
|
|
141
141
|
});
|
|
142
142
|
|
|
@@ -170,25 +170,11 @@ describe("runSync error handling", { skip: !piAvailable ? "pi packages not avail
|
|
|
170
170
|
const result = await runSync(tempDir, agents, "worker", "Do work", {});
|
|
171
171
|
|
|
172
172
|
assert.equal(result.exitCode, 1);
|
|
173
|
-
assert.match(result.error ?? "", /
|
|
173
|
+
assert.match(result.error ?? "", /ended during 'bash' tool execution before the tool completed/);
|
|
174
174
|
assert.match(result.error ?? "", /Earlier assistant output is not a terminal result/);
|
|
175
175
|
assert.doesNotMatch(result.error ?? "", /cold-start/);
|
|
176
176
|
});
|
|
177
177
|
|
|
178
|
-
it("includes an unexpected process signal in a mid-tool exit diagnosis", { skip: process.platform === "win32" ? "signal delivery differs on Windows" : undefined }, async () => {
|
|
179
|
-
mockPi.onCall({
|
|
180
|
-
jsonl: [events.toolStart("bash", { command: "wait" })],
|
|
181
|
-
signal: "SIGTERM",
|
|
182
|
-
});
|
|
183
|
-
const agents = makeAgentConfigs(["worker"]);
|
|
184
|
-
|
|
185
|
-
const result = await runSync(tempDir, agents, "worker", "Do work", {});
|
|
186
|
-
|
|
187
|
-
assert.equal(result.exitCode, 1);
|
|
188
|
-
assert.match(result.error ?? "", /exited during 'bash' tool execution/);
|
|
189
|
-
assert.match(result.error ?? "", /signal SIGTERM/);
|
|
190
|
-
});
|
|
191
|
-
|
|
192
178
|
it("keeps a terminal answer authoritative over an earlier tool timeout", async () => {
|
|
193
179
|
mockPi.onCall({
|
|
194
180
|
steps: [
|
|
@@ -278,4 +264,4 @@ describe("runSync error handling", { skip: !piAvailable ? "pi packages not avail
|
|
|
278
264
|
assert.ok(elapsed < 5000, `should abort early, took ${elapsed}ms`);
|
|
279
265
|
assert.doesNotMatch(result.error ?? "", /exited during 'bash' tool execution/);
|
|
280
266
|
});
|
|
281
|
-
});
|
|
267
|
+
});
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { describe, it } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import * as fs from "node:fs";
|
|
4
|
+
import * as path from "node:path";
|
|
5
|
+
import { execFile } from "node:child_process";
|
|
6
|
+
import { promisify } from "node:util";
|
|
7
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
8
|
+
import { events, makeAgent, makeMinimalCtx, createEventBus } from "../support/helpers.ts";
|
|
9
|
+
import { installAsyncExecutionHooks, available, createSubagentExecutor, waitForMockPiCall, waitForAsyncState, ASYNC_DIR, tempDir, mockPi } from "../support/async-execution-fixture.ts";
|
|
10
|
+
import { steerRequestsDir } from "../../src/runs/background/control-channel.ts";
|
|
11
|
+
const repo = fileURLToPath(new URL("../../", import.meta.url));
|
|
12
|
+
const execFileAsync = promisify(execFile);
|
|
13
|
+
async function hostB(sessionFile: string, params: object, label: string, policy = "auto"): Promise<any> {
|
|
14
|
+
const output = path.join(tempDir, `${label}.json`);
|
|
15
|
+
await execFileAsync(process.execPath, ["--experimental-strip-types", "--import", pathToFileURL(path.join(repo, "test/support/register-loader.mjs")).href, path.join(repo, "test/support/foreign-workflow-steer-host.mjs"), tempDir, sessionFile, JSON.stringify(params), output, policy], { cwd: repo, env: process.env, timeout: 15000, killSignal: "SIGKILL" });
|
|
16
|
+
return JSON.parse(fs.readFileSync(output, "utf8"));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
describe("foreign workflow tool steering (separate processes)", () => {
|
|
20
|
+
installAsyncExecutionHooks();
|
|
21
|
+
it("delivers ID and directory requests with file-preferred identity; refuses wrong sessions and terminal runs", { timeout: 60000 }, async () => {
|
|
22
|
+
assert.ok(available && createSubagentExecutor, "fixture must not skip");
|
|
23
|
+
const release = path.join(tempDir, "release");
|
|
24
|
+
mockPi.onCall({ steps: [{ waitForPath: release, jsonl: [events.assistantMessage("done")] }] });
|
|
25
|
+
const sessionFile = path.join(tempDir, "parent-session.jsonl");
|
|
26
|
+
const ctx = makeMinimalCtx(tempDir);
|
|
27
|
+
ctx.sessionManager.getSessionFile = () => sessionFile;
|
|
28
|
+
ctx.sessionManager.getSessionId = () => "different-runtime-id-in-owner";
|
|
29
|
+
const state: any = { baseCwd: tempDir, currentSessionId: null, asyncJobs: new Map(), foregroundControls: new Map(), lastForegroundControlId: null };
|
|
30
|
+
const executor = createSubagentExecutor({ pi: { events: createEventBus(), getSessionName: () => undefined }, state, config: {}, asyncByDefault: false, tempArtifactsDir: tempDir, getSubagentSessionRoot: () => tempDir, expandTilde: p => p, discoverAgents: () => ({ agents: [makeAgent("worker", { completionGuard: false })] }) });
|
|
31
|
+
const launch = await executor.execute("owner", { workflowScript: 'return await runs.run("A", { agent: "worker", task: "Wait" });', async: true, mission: false }, new AbortController().signal, undefined, ctx);
|
|
32
|
+
assert.notEqual(launch.isError, true, JSON.stringify(launch));
|
|
33
|
+
const runId = launch.details.asyncId!;
|
|
34
|
+
const dir = path.join(ASYNC_DIR, runId);
|
|
35
|
+
try {
|
|
36
|
+
await waitForMockPiCall(mockPi, 0, 10000);
|
|
37
|
+
assert.equal(state.workflowControllers.has(runId), true);
|
|
38
|
+
const status = JSON.parse(fs.readFileSync(path.join(dir, "status.json"), "utf8"));
|
|
39
|
+
assert.equal(status.sessionId, sessionFile);
|
|
40
|
+
for (const [label, params] of [["id", { id: runId }], ["dir", { dir, index: 0 }]] as const) {
|
|
41
|
+
const b = await hostB(sessionFile, params, label);
|
|
42
|
+
assert.notEqual(b.pid, process.pid);
|
|
43
|
+
assert.notEqual(b.completionOwnerId, status.completionOwnerId);
|
|
44
|
+
assert.equal(b.sessionId, sessionFile);
|
|
45
|
+
assert.equal(b.controllers, 0); assert.equal(b.controls, 0);
|
|
46
|
+
assert.notEqual(b.result.isError, true, JSON.stringify(b));
|
|
47
|
+
assert.equal(b.result.details.steering.state, "delivered");
|
|
48
|
+
const receipt = JSON.parse(fs.readFileSync(path.join(dir, "status.json"), "utf8")).steering.recent.find((r: any) => r.id === b.result.details.steering.requestId);
|
|
49
|
+
assert.equal(receipt.targets[0].state, "delivered");
|
|
50
|
+
}
|
|
51
|
+
assert.match(fs.readFileSync(path.join(mockPi.dir, "steers.jsonl"), "utf8"), /B actual tool route/);
|
|
52
|
+
const wrong = await hostB(`${sessionFile}-wrong`, { id: runId }, "wrong");
|
|
53
|
+
assert.equal(wrong.result.isError, true);
|
|
54
|
+
assert.match(wrong.result.content[0].text, /active session/);
|
|
55
|
+
const malformed = await hostB(sessionFile, { dir, index: 0.5 }, "malformed");
|
|
56
|
+
assert.equal(malformed.result.isError, true);
|
|
57
|
+
assert.deepEqual(fs.readdirSync(steerRequestsDir(dir)), []);
|
|
58
|
+
fs.writeFileSync(release, "go");
|
|
59
|
+
await waitForAsyncState(runId, s => s.state === "complete", 10000);
|
|
60
|
+
const terminal = await hostB(sessionFile, { dir }, "terminal");
|
|
61
|
+
assert.equal(terminal.result.isError, true);
|
|
62
|
+
assert.match(terminal.result.content[0].text, /not running or queued/);
|
|
63
|
+
} finally { fs.writeFileSync(release, "go"); }
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("leaves an unavailable owner's request pending without reconciliation or recovery", { timeout: 20000 }, async () => {
|
|
67
|
+
const runId = "foreign-unacknowledged";
|
|
68
|
+
const dir = path.join(ASYNC_DIR, runId);
|
|
69
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
70
|
+
const sessionFile = path.join(tempDir, "parent.jsonl");
|
|
71
|
+
const status = JSON.stringify({ runId, mode: "workflow", state: "running", sessionId: sessionFile, completionOwnerId: "unavailable-owner", pid: 99999999, updatedAt: 1, steps: [{ status: "running", workflowKey: "A" }, { status: "running", workflowKey: "B" }] });
|
|
72
|
+
fs.writeFileSync(path.join(dir, "status.json"), status);
|
|
73
|
+
for (const policy of ["forbid", "confirm"]) {
|
|
74
|
+
const refused = await hostB(sessionFile, { dir }, policy, policy);
|
|
75
|
+
assert.equal(refused.result.isError, true);
|
|
76
|
+
assert.match(refused.result.content[0].text, /Authority policy/);
|
|
77
|
+
assert.equal(fs.existsSync(steerRequestsDir(dir)), false);
|
|
78
|
+
}
|
|
79
|
+
const mismatch = await hostB(sessionFile, { dir, id: "another-workflow" }, "mismatch");
|
|
80
|
+
assert.equal(mismatch.result.isError, true);
|
|
81
|
+
assert.match(mismatch.result.content[0].text, /does not match directory/);
|
|
82
|
+
const b = await hostB(sessionFile, { id: runId }, "noack");
|
|
83
|
+
assert.notEqual(b.result.isError, true, JSON.stringify(b));
|
|
84
|
+
assert.equal(b.result.details.steering.state, "pending");
|
|
85
|
+
assert.equal(b.result.details.steering.deliveryStatus, "queued");
|
|
86
|
+
assert.deepEqual(b.result.details.steering.targets, []);
|
|
87
|
+
assert.equal(fs.readFileSync(path.join(dir, "status.json"), "utf8"), status);
|
|
88
|
+
const requests = fs.readdirSync(steerRequestsDir(dir));
|
|
89
|
+
assert.equal(requests.length, 1);
|
|
90
|
+
const request = JSON.parse(fs.readFileSync(path.join(steerRequestsDir(dir), requests[0]!), "utf8"));
|
|
91
|
+
assert.equal(request.id, b.result.details.steering.requestId);
|
|
92
|
+
assert.equal(request.targetIndex, undefined); assert.equal(request.targetIndexes, undefined);
|
|
93
|
+
assert.deepEqual(fs.readdirSync(dir).sort(), ["control", "status.json"]);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
@@ -192,10 +192,6 @@ describe("fork context execution wiring", { skip: !available ? "subagent executo
|
|
|
192
192
|
.filter((sessionFile): sessionFile is string => Boolean(sessionFile));
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
-
function isTaskFileArg(arg: string): boolean {
|
|
196
|
-
return arg.startsWith("@") && arg.endsWith("task.md");
|
|
197
|
-
}
|
|
198
|
-
|
|
199
195
|
function readSessionArg(args: string[]): string {
|
|
200
196
|
const sessionIndex = args.indexOf("--session");
|
|
201
197
|
assert.notEqual(sessionIndex, -1);
|
|
@@ -309,11 +305,10 @@ describe("fork context execution wiring", { skip: !available ? "subagent executo
|
|
|
309
305
|
assert.equal(result.isError, undefined);
|
|
310
306
|
const args = readAllCallArgs()[0] ?? [];
|
|
311
307
|
const taskArg = args.at(-1) ?? "";
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
}
|
|
308
|
+
assert.equal(taskArg, "Task: ");
|
|
309
|
+
const systemIndex = args.findIndex((arg) => arg === "--system-prompt" || arg === "--append-system-prompt");
|
|
310
|
+
assert.notEqual(systemIndex, -1);
|
|
311
|
+
assert.match(args[systemIndex + 1] ?? "", /## Acceptance Contract/);
|
|
317
312
|
});
|
|
318
313
|
|
|
319
314
|
it("fails pruned fork model auth before child spawn", async () => {
|
|
@@ -1315,11 +1310,10 @@ describe("fork context execution wiring", { skip: !available ? "subagent executo
|
|
|
1315
1310
|
assert.equal(result.isError, undefined);
|
|
1316
1311
|
const args = readAllCallArgs()[0] ?? [];
|
|
1317
1312
|
const taskArg = args.at(-1) ?? "";
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
}
|
|
1313
|
+
assert.equal(taskArg, `Task: ${task}`);
|
|
1314
|
+
const systemIndex = args.findIndex((arg) => arg === "--system-prompt" || arg === "--append-system-prompt");
|
|
1315
|
+
assert.notEqual(systemIndex, -1);
|
|
1316
|
+
assert.match(args[systemIndex + 1] ?? "", /## Acceptance Contract/);
|
|
1323
1317
|
const modelIndex = args.indexOf("--model");
|
|
1324
1318
|
assert.notEqual(modelIndex, -1);
|
|
1325
1319
|
assert.equal(args[modelIndex + 1], "anthropic/claude-haiku-4-5");
|
|
@@ -1353,4 +1347,4 @@ describe("fork context execution wiring", { skip: !available ? "subagent executo
|
|
|
1353
1347
|
removeTempDir(tempHome);
|
|
1354
1348
|
}
|
|
1355
1349
|
});
|
|
1356
|
-
});
|
|
1350
|
+
});
|