@selesai/code 0.13.16 → 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 +30 -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/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-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
|
@@ -6,14 +6,13 @@ import * as path from "node:path";
|
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
7
|
import { describe, it } from "node:test";
|
|
8
8
|
import { WAIT_TOOL_ENABLED_ENV } from "../../src/runs/background/subagent-wait.ts";
|
|
9
|
-
import { SUBAGENT_CHILD_ENV
|
|
9
|
+
import { SUBAGENT_CHILD_ENV } from "../../src/runs/shared/child-runtime-config.ts";
|
|
10
10
|
|
|
11
11
|
const projectRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
12
12
|
|
|
13
13
|
function parentToolEnv(agentDir?: string): NodeJS.ProcessEnv {
|
|
14
14
|
const env = { ...process.env };
|
|
15
15
|
delete env[SUBAGENT_CHILD_ENV];
|
|
16
|
-
delete env[SUBAGENT_FANOUT_CHILD_ENV];
|
|
17
16
|
delete env[WAIT_TOOL_ENABLED_ENV];
|
|
18
17
|
if (agentDir) env.SELESAI_CODING_AGENT_DIR = agentDir;
|
|
19
18
|
return env;
|
|
@@ -554,7 +553,7 @@ describe("subagent extension child mode", () => {
|
|
|
554
553
|
const events = { on(channel, handler) { eventHandlers.set(channel, handler); return () => {}; }, emit() {} };
|
|
555
554
|
const fakePi = new Proxy({
|
|
556
555
|
events,
|
|
557
|
-
on(channel, handler) { handlers.set(channel, handler); },
|
|
556
|
+
on(channel, handler) { handlers.set(channel, [...(handlers.get(channel) ?? []), handler]); },
|
|
558
557
|
registerTool() {}, registerCommand() {}, registerShortcut() {}, registerMessageRenderer() {},
|
|
559
558
|
sendMessage() {}, getSessionName() { return undefined; },
|
|
560
559
|
}, { get(target, prop) { return prop in target ? target[prop] : () => undefined; } });
|
|
@@ -566,13 +565,13 @@ describe("subagent extension child mode", () => {
|
|
|
566
565
|
modelRegistry: { getAvailable() { return []; } },
|
|
567
566
|
};
|
|
568
567
|
registerSubagentExtension(fakePi);
|
|
569
|
-
handlers.get("session_start")({}, ctx);
|
|
568
|
+
for (const handler of handlers.get("session_start")) await handler({}, ctx);
|
|
570
569
|
widgets.length = 0;
|
|
571
570
|
eventHandlers.get("subagent:async-started")({ id: "widget-run", pid: 1, sessionId: "session-widget", mode: "single", agent: "worker", asyncDir: "/tmp/widget-run" });
|
|
572
|
-
handlers.get("tool_result")({ toolName: "subagent" }, ctx);
|
|
571
|
+
for (const handler of handlers.get("tool_result")) await handler({ toolName: "subagent" }, ctx);
|
|
573
572
|
const asyncWidgets = widgets.filter((entry) => entry.key === "subagent-async");
|
|
574
573
|
if (asyncWidgets.length < 2 || asyncWidgets.some((entry) => entry.value !== undefined)) throw new Error("async widget rendered despite disabled config: " + JSON.stringify(asyncWidgets));
|
|
575
|
-
handlers.get("session_shutdown")();
|
|
574
|
+
for (const handler of handlers.get("session_shutdown")) await handler();
|
|
576
575
|
`;
|
|
577
576
|
const env = parentToolEnv();
|
|
578
577
|
env.SELESAI_CODING_AGENT_DIR = agentDir;
|
|
@@ -595,7 +594,7 @@ describe("subagent extension child mode", () => {
|
|
|
595
594
|
const events = { on(channel, handler) { eventHandlers.set(channel, handler); return () => {}; }, emit() {} };
|
|
596
595
|
const fakePi = new Proxy({
|
|
597
596
|
events,
|
|
598
|
-
on(channel, handler) { handlers.set(channel, handler); },
|
|
597
|
+
on(channel, handler) { handlers.set(channel, [...(handlers.get(channel) ?? []), handler]); },
|
|
599
598
|
registerTool() {}, registerCommand() {}, registerShortcut() {}, registerMessageRenderer() {},
|
|
600
599
|
sendMessage() {}, getSessionName() { return undefined; },
|
|
601
600
|
}, { get(target, prop) { return prop in target ? target[prop] : () => undefined; } });
|
|
@@ -607,13 +606,13 @@ describe("subagent extension child mode", () => {
|
|
|
607
606
|
modelRegistry: { getAvailable() { return []; } },
|
|
608
607
|
};
|
|
609
608
|
registerSubagentExtension(fakePi);
|
|
610
|
-
handlers.get("session_start")({}, ctx);
|
|
609
|
+
for (const handler of handlers.get("session_start")) await handler({}, ctx);
|
|
611
610
|
widgets.length = 0;
|
|
612
611
|
eventHandlers.get("subagent:async-started")({ id: "widget-run", pid: 1, sessionId: "session-widget", mode: "workflow", agent: "worker", asyncDir: "/tmp/widget-run" });
|
|
613
|
-
handlers.get("tool_result")({ toolName: "subagent" }, ctx);
|
|
612
|
+
for (const handler of handlers.get("tool_result")) await handler({ toolName: "subagent" }, ctx);
|
|
614
613
|
const asyncWidgets = widgets.filter((entry) => entry.key === "subagent-async");
|
|
615
614
|
if (!asyncWidgets.some((entry) => entry.value !== undefined)) throw new Error("async widget was not rendered with FleetView enabled: " + JSON.stringify(asyncWidgets));
|
|
616
|
-
handlers.get("session_shutdown")();
|
|
615
|
+
for (const handler of handlers.get("session_shutdown")) await handler();
|
|
617
616
|
`;
|
|
618
617
|
const env = parentToolEnv();
|
|
619
618
|
env.SELESAI_CODING_AGENT_DIR = agentDir;
|
|
@@ -639,7 +638,7 @@ describe("subagent extension child mode", () => {
|
|
|
639
638
|
process.env.HERDR_PANE_ID = "w1:p1";
|
|
640
639
|
const fakePi = new Proxy({
|
|
641
640
|
events,
|
|
642
|
-
on(channel, handler) { handlers.set(channel, handler); },
|
|
641
|
+
on(channel, handler) { handlers.set(channel, [...(handlers.get(channel) ?? []), handler]); },
|
|
643
642
|
exec(command, args) { herdrCommands.push({ command, args }); return Promise.resolve({ code: 0, stdout: "", stderr: "", killed: false }); },
|
|
644
643
|
registerTool() {}, registerCommand() {}, registerShortcut() {}, registerMessageRenderer() {},
|
|
645
644
|
sendMessage() {}, getSessionName() { return undefined; },
|
|
@@ -655,7 +654,7 @@ describe("subagent extension child mode", () => {
|
|
|
655
654
|
const asyncDir = path.join(DIRS.async, runId);
|
|
656
655
|
fs.rmSync(asyncDir, { recursive: true, force: true });
|
|
657
656
|
registerSubagentExtension(fakePi);
|
|
658
|
-
handlers.get("session_start")({}, ctx);
|
|
657
|
+
for (const handler of handlers.get("session_start")) await handler({}, ctx);
|
|
659
658
|
widgets.length = 0;
|
|
660
659
|
fs.mkdirSync(asyncDir, { recursive: true });
|
|
661
660
|
fs.writeFileSync(path.join(asyncDir, "status.json"), JSON.stringify({
|
|
@@ -663,19 +662,81 @@ describe("subagent extension child mode", () => {
|
|
|
663
662
|
startedAt: Date.now(), lastUpdate: Date.now(), cwd: process.cwd(), pid: process.pid,
|
|
664
663
|
}), "utf-8");
|
|
665
664
|
updateActiveRunIndex(asyncDir, "running");
|
|
666
|
-
handlers.get("tool_result")({ toolName: "subagent" }, ctx);
|
|
665
|
+
for (const handler of handlers.get("tool_result")) await handler({ toolName: "subagent" }, ctx);
|
|
667
666
|
const fleetWidgets = widgets.filter((entry) => entry.key === "subagent-fleet-status");
|
|
668
667
|
if (!fleetWidgets.some((entry) => typeof entry.value === "function")) throw new Error("management result did not restore active fleet status: " + JSON.stringify(fleetWidgets));
|
|
669
668
|
if (!herdrCommands.some(({ args }) => args.includes("summary=⏳ 1 subagent"))) throw new Error("management result did not restore Herdr status: " + JSON.stringify(herdrCommands));
|
|
670
669
|
const herdrCommandCount = herdrCommands.length;
|
|
671
|
-
handlers.get("tool_result")({ toolName: "subagent" }, ctx);
|
|
670
|
+
for (const handler of handlers.get("tool_result")) await handler({ toolName: "subagent" }, ctx);
|
|
672
671
|
if (herdrCommands.length !== herdrCommandCount) throw new Error("unchanged active jobs redundantly refreshed Herdr status: " + JSON.stringify(herdrCommands));
|
|
673
|
-
handlers.get("session_shutdown")();
|
|
672
|
+
for (const handler of handlers.get("session_shutdown")) await handler();
|
|
674
673
|
fs.rmSync(asyncDir, { recursive: true, force: true });
|
|
675
674
|
`;
|
|
676
675
|
execFileSync(process.execPath, ["--experimental-strip-types", "--import", "./test/support/register-loader.mjs", "--input-type=module", "--eval", script], { cwd: projectRoot, env: parentToolEnv(), stdio: "pipe" });
|
|
677
676
|
});
|
|
678
677
|
|
|
678
|
+
it("registers pi-web liveness for the current session and releases it on shutdown", () => {
|
|
679
|
+
const script = String.raw`
|
|
680
|
+
import registerSubagentExtension from "./index.ts";
|
|
681
|
+
import { currentCompletionOwnerId } from "./src/shared/completion-owner.ts";
|
|
682
|
+
const handlers = new Map();
|
|
683
|
+
const listeners = new Map();
|
|
684
|
+
const events = {
|
|
685
|
+
on(channel, handler) {
|
|
686
|
+
let set = listeners.get(channel);
|
|
687
|
+
if (!set) listeners.set(channel, set = new Set());
|
|
688
|
+
set.add(handler);
|
|
689
|
+
return () => set.delete(handler);
|
|
690
|
+
},
|
|
691
|
+
emit(channel, payload) {
|
|
692
|
+
for (const handler of [...(listeners.get(channel) ?? [])]) handler(payload);
|
|
693
|
+
},
|
|
694
|
+
};
|
|
695
|
+
const pi = new Proxy({
|
|
696
|
+
events,
|
|
697
|
+
on(channel, handler) { handlers.set(channel, [...(handlers.get(channel) ?? []), handler]); },
|
|
698
|
+
registerTool() {}, registerCommand() {}, registerShortcut() {}, registerMessageRenderer() {},
|
|
699
|
+
sendMessage() {}, getSessionName() { return undefined; },
|
|
700
|
+
}, { get(target, prop) { return prop in target ? target[prop] : () => undefined; } });
|
|
701
|
+
const sessionId = "liveness-" + crypto.randomUUID();
|
|
702
|
+
const sessionFile = "/tmp/" + sessionId + ".jsonl";
|
|
703
|
+
let provider;
|
|
704
|
+
let released = 0;
|
|
705
|
+
const registryKey = Symbol.for("@agegr/pi-web/session-liveness/v1");
|
|
706
|
+
globalThis[registryKey] = {
|
|
707
|
+
version: 1,
|
|
708
|
+
register(value) {
|
|
709
|
+
provider = value;
|
|
710
|
+
return () => { released += 1; };
|
|
711
|
+
},
|
|
712
|
+
};
|
|
713
|
+
const ctx = {
|
|
714
|
+
cwd: process.cwd(), hasUI: false,
|
|
715
|
+
ui: { setWidget() {}, requestRender() {}, theme: { fg(_name, text) { return text; }, bg(_name, text) { return text; }, bold(text) { return text; } } },
|
|
716
|
+
sessionManager: { getSessionId() { return sessionId; }, getSessionFile() { return sessionFile; }, getEntries() { return []; } },
|
|
717
|
+
modelRegistry: { getAvailable() { return []; } },
|
|
718
|
+
};
|
|
719
|
+
registerSubagentExtension(pi);
|
|
720
|
+
for (const handler of handlers.get("session_start")) await handler({ reason: "startup" }, ctx);
|
|
721
|
+
if (provider?.name !== "pi-subagents" || provider?.sessionId !== sessionId || provider?.sessionFile !== sessionFile) {
|
|
722
|
+
throw new Error("liveness provider did not preserve exact session identity: " + JSON.stringify(provider));
|
|
723
|
+
}
|
|
724
|
+
if (provider.isActive()) throw new Error("idle runtime reported live work");
|
|
725
|
+
const completionOwnerId = currentCompletionOwnerId();
|
|
726
|
+
events.emit("subagent:async-started", { id: "run-1", sessionId: sessionFile, completionOwnerId, mode: "single", agent: "worker", asyncDir: "/tmp/" + sessionId + "-run" });
|
|
727
|
+
if (!provider.isActive()) throw new Error("queued async work was not reported live");
|
|
728
|
+
events.emit("subagent:async-complete", { id: "run-1", sessionId: sessionFile, completionOwnerId, success: true, summary: "done" });
|
|
729
|
+
if (!provider.isActive()) throw new Error("pending completion delivery was not reported live");
|
|
730
|
+
const deliveryDeadline = Date.now() + 2000;
|
|
731
|
+
while (provider.isActive() && Date.now() < deliveryDeadline) await new Promise((resolve) => setTimeout(resolve, 10));
|
|
732
|
+
if (provider.isActive()) throw new Error("retained terminal work was reported live after delivery");
|
|
733
|
+
for (const handler of handlers.get("session_shutdown")) await handler({ reason: "quit" });
|
|
734
|
+
if (released !== 1) throw new Error("liveness registration was not released exactly once: " + released);
|
|
735
|
+
delete globalThis[registryKey];
|
|
736
|
+
`;
|
|
737
|
+
execFileSync(process.execPath, ["--experimental-strip-types", "--import", "./test/support/register-loader.mjs", "--input-type=module", "--eval", script], { cwd: projectRoot, env: parentToolEnv(), stdio: "pipe" });
|
|
738
|
+
});
|
|
739
|
+
|
|
679
740
|
it("keeps independent extension runtimes active in one process", () => {
|
|
680
741
|
const script = String.raw`
|
|
681
742
|
import registerSubagentExtension from "./index.ts";
|
|
@@ -701,7 +762,7 @@ describe("subagent extension child mode", () => {
|
|
|
701
762
|
};
|
|
702
763
|
const pi = new Proxy({
|
|
703
764
|
events,
|
|
704
|
-
on(channel, handler) { handlers.set(channel, handler); },
|
|
765
|
+
on(channel, handler) { handlers.set(channel, [...(handlers.get(channel) ?? []), handler]); },
|
|
705
766
|
registerTool() {}, registerCommand() {}, registerShortcut() {}, registerMessageRenderer() {},
|
|
706
767
|
sendMessage() {}, getSessionName() { return undefined; },
|
|
707
768
|
}, { get(target, prop) { return prop in target ? target[prop] : () => undefined; } });
|
|
@@ -721,7 +782,7 @@ describe("subagent extension child mode", () => {
|
|
|
721
782
|
|
|
722
783
|
const first = createRuntime("independent-first");
|
|
723
784
|
registerSubagentExtension(first.pi);
|
|
724
|
-
first.handlers.get("session_start")({ reason: "startup" }, first.ctx);
|
|
785
|
+
for (const handler of first.handlers.get("session_start")) await handler({ reason: "startup" }, first.ctx);
|
|
725
786
|
first.events.emit("subagent:async-complete", {
|
|
726
787
|
id: "independent-baseline", agent: "worker", success: true, summary: "Baseline",
|
|
727
788
|
exitCode: 0, timestamp: Date.now(), sessionId: "independent-first", completionOwnerId,
|
|
@@ -730,9 +791,9 @@ describe("subagent extension child mode", () => {
|
|
|
730
791
|
if (baselineDeliveries === 0) throw new Error("first runtime did not register async-complete listeners");
|
|
731
792
|
const second = createRuntime("independent-second");
|
|
732
793
|
registerSubagentExtension(second.pi);
|
|
733
|
-
second.handlers.get("session_start")({ reason: "startup" }, second.ctx);
|
|
794
|
+
for (const handler of second.handlers.get("session_start")) await handler({ reason: "startup" }, second.ctx);
|
|
734
795
|
|
|
735
|
-
|
|
796
|
+
for (const handler of first.handlers.get("agent_end")) await handler({}, first.ctx);
|
|
736
797
|
first.events.emit("subagent:async-complete", {
|
|
737
798
|
id: "independent-completion", agent: "worker", success: true, summary: "Done",
|
|
738
799
|
exitCode: 0, timestamp: Date.now(), sessionId: "independent-first", completionOwnerId,
|
|
@@ -741,11 +802,11 @@ describe("subagent extension child mode", () => {
|
|
|
741
802
|
throw new Error("first runtime no longer received async-complete after second registration");
|
|
742
803
|
}
|
|
743
804
|
|
|
744
|
-
|
|
805
|
+
for (const handler of first.handlers.get("session_shutdown")) await handler();
|
|
745
806
|
if (process.env.SELESAI_SUBAGENT_PARENT_SESSION !== "independent-second") {
|
|
746
807
|
throw new Error("independent shutdown cleared another runtime's parent session identity");
|
|
747
808
|
}
|
|
748
|
-
|
|
809
|
+
for (const handler of second.handlers.get("agent_end")) await handler({}, second.ctx);
|
|
749
810
|
second.events.emit("subagent:async-complete", {
|
|
750
811
|
id: "independent-second-completion", agent: "reviewer", success: true, summary: "Done",
|
|
751
812
|
exitCode: 0, timestamp: Date.now(), sessionId: "independent-second", completionOwnerId,
|
|
@@ -753,7 +814,7 @@ describe("subagent extension child mode", () => {
|
|
|
753
814
|
if ((second.eventDeliveries.get("subagent:async-complete") ?? 0) === 0) {
|
|
754
815
|
throw new Error("first runtime shutdown removed the second runtime's event subscription");
|
|
755
816
|
}
|
|
756
|
-
|
|
817
|
+
for (const handler of second.handlers.get("session_shutdown")) await handler();
|
|
757
818
|
if (process.env.SELESAI_SUBAGENT_PARENT_SESSION !== undefined) {
|
|
758
819
|
throw new Error("owning shutdown left its parent session identity active");
|
|
759
820
|
}
|
|
@@ -775,7 +836,7 @@ describe("subagent extension child mode", () => {
|
|
|
775
836
|
const events = { on() { return () => {}; }, emit() {} };
|
|
776
837
|
const pi = new Proxy({
|
|
777
838
|
events,
|
|
778
|
-
on(channel, handler) { handlers.set(channel, handler); },
|
|
839
|
+
on(channel, handler) { handlers.set(channel, [...(handlers.get(channel) ?? []), handler]); },
|
|
779
840
|
registerTool() {}, registerCommand() {}, registerShortcut() {}, registerMessageRenderer() {},
|
|
780
841
|
sendMessage() {}, getSessionName() { return undefined; },
|
|
781
842
|
}, { get(target, prop) { return prop in target ? target[prop] : () => undefined; } });
|
|
@@ -791,18 +852,18 @@ describe("subagent extension child mode", () => {
|
|
|
791
852
|
const first = createRuntime("slash-first");
|
|
792
853
|
const second = createRuntime("slash-second");
|
|
793
854
|
registerSubagentExtension(first.pi);
|
|
794
|
-
first.handlers.get("session_start")({ reason: "startup" }, first.ctx);
|
|
855
|
+
for (const handler of first.handlers.get("session_start")) await handler({ reason: "startup" }, first.ctx);
|
|
795
856
|
registerSubagentExtension(second.pi);
|
|
796
|
-
second.handlers.get("session_start")({ reason: "startup" }, second.ctx);
|
|
857
|
+
for (const handler of second.handlers.get("session_start")) await handler({ reason: "startup" }, second.ctx);
|
|
797
858
|
const details = buildSlashInitialResult("slash-isolation", { agent: "worker", task: "Keep this snapshot" });
|
|
798
859
|
const liveVersion = getSlashRenderableSnapshot(details).version;
|
|
799
860
|
if (liveVersion <= 0) throw new Error("slash snapshot was not populated");
|
|
800
861
|
|
|
801
|
-
|
|
862
|
+
for (const handler of first.handlers.get("session_shutdown")) await handler({ reason: "shutdown" });
|
|
802
863
|
if (getSlashRenderableSnapshot(details).version !== liveVersion) {
|
|
803
864
|
throw new Error("one runtime shutdown cleared another active runtime's slash snapshot");
|
|
804
865
|
}
|
|
805
|
-
|
|
866
|
+
for (const handler of second.handlers.get("session_shutdown")) await handler({ reason: "shutdown" });
|
|
806
867
|
if (getSlashRenderableSnapshot(details).version !== 0) {
|
|
807
868
|
throw new Error("last runtime shutdown did not clear slash snapshots");
|
|
808
869
|
}
|
|
@@ -849,7 +910,7 @@ describe("subagent extension child mode", () => {
|
|
|
849
910
|
const sent = [];
|
|
850
911
|
const fakePi = new Proxy({
|
|
851
912
|
events,
|
|
852
|
-
on(channel, handler) { handlers.set(channel, handler); },
|
|
913
|
+
on(channel, handler) { handlers.set(channel, [...(handlers.get(channel) ?? []), handler]); },
|
|
853
914
|
registerTool() {}, registerCommand() {}, registerShortcut() {}, registerMessageRenderer() {},
|
|
854
915
|
sendMessage(message) { sent.push(message); }, getSessionName() { return undefined; },
|
|
855
916
|
}, { get(target, prop) { return prop in target ? target[prop] : () => undefined; } });
|
|
@@ -860,7 +921,7 @@ describe("subagent extension child mode", () => {
|
|
|
860
921
|
modelRegistry: { getAvailable() { return []; } },
|
|
861
922
|
};
|
|
862
923
|
registerSubagentExtension(fakePi);
|
|
863
|
-
handlers.get("session_start")({}, ctx);
|
|
924
|
+
for (const handler of handlers.get("session_start")) await handler({}, ctx);
|
|
864
925
|
sent.length = 0;
|
|
865
926
|
events.emit("subagent:async-complete", {
|
|
866
927
|
id: "shutdown-held-completion", agent: "worker", success: true, summary: "Done",
|
|
@@ -869,7 +930,7 @@ describe("subagent extension child mode", () => {
|
|
|
869
930
|
if (sent.length !== 0) throw new Error("completion was not queued before shutdown");
|
|
870
931
|
const heldTimers = [...pendingTimers.values()];
|
|
871
932
|
if (heldTimers.length === 0) throw new Error("completion did not schedule a timer");
|
|
872
|
-
handlers.get("session_shutdown")();
|
|
933
|
+
for (const handler of handlers.get("session_shutdown")) await handler();
|
|
873
934
|
if (pendingTimers.size !== 0) throw new Error("shutdown left completion timers pending");
|
|
874
935
|
for (const handler of heldTimers) handler();
|
|
875
936
|
if (sent.length !== 0) throw new Error("stale completion sent after shutdown");
|
|
@@ -930,7 +991,7 @@ describe("subagent extension child mode", () => {
|
|
|
930
991
|
const sent = [];
|
|
931
992
|
const pi = new Proxy({
|
|
932
993
|
events,
|
|
933
|
-
on(channel, handler) { handlers.set(channel, handler); },
|
|
994
|
+
on(channel, handler) { handlers.set(channel, [...(handlers.get(channel) ?? []), handler]); },
|
|
934
995
|
registerTool() {}, registerCommand() {}, registerShortcut() {}, registerMessageRenderer() {},
|
|
935
996
|
sendMessage(message) { sent.push(message); }, getSessionName() { return undefined; },
|
|
936
997
|
}, { get(target, prop) { return prop in target ? target[prop] : () => undefined; } });
|
|
@@ -945,7 +1006,7 @@ describe("subagent extension child mode", () => {
|
|
|
945
1006
|
|
|
946
1007
|
const oldRuntime = createRuntime();
|
|
947
1008
|
registerSubagentExtension(oldRuntime.pi);
|
|
948
|
-
oldRuntime.handlers.get("session_start")({ reason: "startup" }, oldRuntime.ctx);
|
|
1009
|
+
for (const handler of oldRuntime.handlers.get("session_start")) await handler({ reason: "startup" }, oldRuntime.ctx);
|
|
949
1010
|
const oldListenerCount = eventListeners.get("subagent:async-complete")?.size ?? 0;
|
|
950
1011
|
if (oldListenerCount === 0) throw new Error("old runtime did not register async-complete listeners");
|
|
951
1012
|
oldRuntime.sent.length = 0;
|
|
@@ -960,13 +1021,13 @@ describe("subagent extension child mode", () => {
|
|
|
960
1021
|
|
|
961
1022
|
const newRuntime = createRuntime();
|
|
962
1023
|
registerSubagentExtension(newRuntime.pi);
|
|
963
|
-
newRuntime.handlers.get("session_start")({ reason: "reload" }, newRuntime.ctx);
|
|
1024
|
+
for (const handler of newRuntime.handlers.get("session_start")) await handler({ reason: "reload" }, newRuntime.ctx);
|
|
964
1025
|
if (eventListeners.get("subagent:async-complete")?.size !== oldListenerCount) {
|
|
965
1026
|
throw new Error("replacement runtime did not restore its event subscriptions");
|
|
966
1027
|
}
|
|
967
1028
|
for (const [, handler] of oldCompletionTimers) handler();
|
|
968
1029
|
if (oldRuntime.sent.length !== 0) throw new Error("stale completion sent after runtime cleanup");
|
|
969
|
-
|
|
1030
|
+
for (const handler of oldRuntime.handlers.get("session_shutdown")) await handler({ reason: "reload" });
|
|
970
1031
|
if (eventListeners.get("subagent:async-complete")?.size !== oldListenerCount
|
|
971
1032
|
|| process.env.SELESAI_SUBAGENT_PARENT_SESSION !== "notify-reload-session") {
|
|
972
1033
|
throw new Error("stale shutdown changed the replacement runtime");
|
|
@@ -984,7 +1045,7 @@ describe("subagent extension child mode", () => {
|
|
|
984
1045
|
handler();
|
|
985
1046
|
}
|
|
986
1047
|
if (newRuntime.sent.length !== 1) throw new Error("new notifier was not active after reload cleanup");
|
|
987
|
-
|
|
1048
|
+
for (const handler of newRuntime.handlers.get("session_shutdown")) await handler({ reason: "shutdown" });
|
|
988
1049
|
globalThis.setTimeout = realSetTimeout;
|
|
989
1050
|
globalThis.clearTimeout = realClearTimeout;
|
|
990
1051
|
`;
|
|
@@ -1013,7 +1074,7 @@ describe("subagent extension child mode", () => {
|
|
|
1013
1074
|
const events = { on() { return () => {}; }, emit() {} };
|
|
1014
1075
|
const fakePi = new Proxy({
|
|
1015
1076
|
events,
|
|
1016
|
-
on(channel, handler) { handlers.set(channel, handler); },
|
|
1077
|
+
on(channel, handler) { handlers.set(channel, [...(handlers.get(channel) ?? []), handler]); },
|
|
1017
1078
|
registerTool() {}, registerCommand() {}, registerShortcut() {}, registerMessageRenderer() {},
|
|
1018
1079
|
sendMessage() {}, getSessionName() { return undefined; },
|
|
1019
1080
|
}, { get(target, prop) { return prop in target ? target[prop] : () => undefined; } });
|
|
@@ -1032,9 +1093,9 @@ describe("subagent extension child mode", () => {
|
|
|
1032
1093
|
modelRegistry: { getAvailable() { return []; } },
|
|
1033
1094
|
};
|
|
1034
1095
|
registerSubagentExtension(fakePi);
|
|
1035
|
-
handlers.get("session_start")({ reason: "startup" }, ctx);
|
|
1096
|
+
for (const handler of handlers.get("session_start")) await handler({ reason: "startup" }, ctx);
|
|
1036
1097
|
stale = true;
|
|
1037
|
-
handlers.get("session_shutdown")({ reason: "reload" });
|
|
1098
|
+
for (const handler of handlers.get("session_shutdown")) await handler({ reason: "reload" });
|
|
1038
1099
|
`;
|
|
1039
1100
|
|
|
1040
1101
|
try {
|
|
@@ -1069,7 +1130,7 @@ describe("subagent extension child mode", () => {
|
|
|
1069
1130
|
const sent = [];
|
|
1070
1131
|
const pi = new Proxy({
|
|
1071
1132
|
events,
|
|
1072
|
-
on(channel, handler) { handlers.set(channel, handler); },
|
|
1133
|
+
on(channel, handler) { handlers.set(channel, [...(handlers.get(channel) ?? []), handler]); },
|
|
1073
1134
|
registerTool() {}, registerCommand() {}, registerShortcut() {}, registerMessageRenderer() {},
|
|
1074
1135
|
sendMessage(message) { sent.push(message); }, getSessionName() { return undefined; },
|
|
1075
1136
|
}, { get(target, prop) { return prop in target ? target[prop] : () => undefined; } });
|
|
@@ -1083,14 +1144,14 @@ describe("subagent extension child mode", () => {
|
|
|
1083
1144
|
const sessionManager = { getSessionId() { return path.basename(currentSession); }, getSessionFile() { return currentSession; }, getEntries() { return []; } };
|
|
1084
1145
|
const ctx = { cwd: process.cwd(), hasUI: false, ui: { setWidget() {}, requestRender() {}, theme: { fg(_name, text) { return text; }, bg(_name, text) { return text; }, bold(text) { return text; } } }, sessionManager, modelRegistry: { getAvailable() { return []; } } };
|
|
1085
1146
|
registerSubagentExtension(pi);
|
|
1086
|
-
handlers.get("session_start")({ reason: "startup" }, ctx);
|
|
1147
|
+
for (const handler of handlers.get("session_start")) await handler({ reason: "startup" }, ctx);
|
|
1087
1148
|
currentSession = newSession;
|
|
1088
|
-
handlers.get("session_start")({ reason: "new", previousSessionFile: oldSession }, ctx);
|
|
1149
|
+
for (const handler of handlers.get("session_start")) await handler({ reason: "new", previousSessionFile: oldSession }, ctx);
|
|
1089
1150
|
const owner = currentCompletionOwnerId();
|
|
1090
1151
|
events.emit("subagent:async-complete", { id: "old-owned", agent: "worker", success: true, summary: "old", timestamp: 1, sessionId: oldSession, completionOwnerId: owner });
|
|
1091
1152
|
events.emit("subagent:async-complete", { id: "foreign", agent: "worker", success: true, summary: "foreign", timestamp: 2, sessionId: path.join(sessions, "foreign.jsonl"), completionOwnerId: owner });
|
|
1092
1153
|
if (sent.length !== 1) throw new Error("expected only the claimed predecessor completion, got " + sent.length);
|
|
1093
|
-
|
|
1154
|
+
for (const handler of handlers.get("session_shutdown")) await handler({ reason: "quit" });
|
|
1094
1155
|
`;
|
|
1095
1156
|
|
|
1096
1157
|
try {
|
|
@@ -1108,12 +1169,14 @@ describe("subagent extension child mode", () => {
|
|
|
1108
1169
|
const events = { on() { return () => {}; }, emit() {} };
|
|
1109
1170
|
const commands = [];
|
|
1110
1171
|
const renderers = [];
|
|
1172
|
+
const entryRenderers = [];
|
|
1111
1173
|
const fakePi = new Proxy({
|
|
1112
1174
|
events,
|
|
1113
1175
|
registerTool() {},
|
|
1114
1176
|
registerCommand(name) { commands.push(name); },
|
|
1115
1177
|
registerShortcut() {},
|
|
1116
1178
|
registerMessageRenderer(type) { renderers.push(type); },
|
|
1179
|
+
registerEntryRenderer(type) { entryRenderers.push(type); },
|
|
1117
1180
|
sendMessage() {},
|
|
1118
1181
|
getSessionName() { return undefined; },
|
|
1119
1182
|
}, {
|
|
@@ -1125,6 +1188,8 @@ describe("subagent extension child mode", () => {
|
|
|
1125
1188
|
registerSubagentExtension(fakePi);
|
|
1126
1189
|
if (!commands.includes("subagents-watchdog")) throw new Error("watchdog command not registered: " + commands.join(", "));
|
|
1127
1190
|
if (!renderers.includes("subagent_watchdog_warning")) throw new Error("watchdog renderer not registered: " + renderers.join(", "));
|
|
1191
|
+
if (!renderers.includes("subagent_supervisor_request")) throw new Error("supervisor request renderer not registered: " + renderers.join(", "));
|
|
1192
|
+
if (!entryRenderers.includes("subagent_supervisor_reply")) throw new Error("supervisor reply entry renderer not registered: " + entryRenderers.join(", "));
|
|
1128
1193
|
`;
|
|
1129
1194
|
|
|
1130
1195
|
execFileSync(
|
|
@@ -1141,7 +1206,7 @@ describe("subagent extension child mode", () => {
|
|
|
1141
1206
|
);
|
|
1142
1207
|
});
|
|
1143
1208
|
|
|
1144
|
-
it("returns before registering anything
|
|
1209
|
+
it("returns before registering anything in a child-hosting process", () => {
|
|
1145
1210
|
const script = String.raw`
|
|
1146
1211
|
import registerSubagentExtension from "./index.ts";
|
|
1147
1212
|
const calls = [];
|
|
@@ -1169,16 +1234,15 @@ describe("subagent extension child mode", () => {
|
|
|
1169
1234
|
"--eval",
|
|
1170
1235
|
script,
|
|
1171
1236
|
],
|
|
1172
|
-
{ cwd: projectRoot, env: { ...parentToolEnv(), [SUBAGENT_CHILD_ENV]: "1"
|
|
1237
|
+
{ cwd: projectRoot, env: { ...parentToolEnv(), [SUBAGENT_CHILD_ENV]: "1" }, stdio: "pipe" },
|
|
1173
1238
|
);
|
|
1174
1239
|
});
|
|
1175
1240
|
|
|
1176
|
-
it("returns before registering anything
|
|
1241
|
+
it("returns before registering anything when the child host flag is set after import", () => {
|
|
1177
1242
|
const script = String.raw`
|
|
1178
1243
|
import registerSubagentExtension from "./index.ts";
|
|
1179
|
-
import { SUBAGENT_CHILD_ENV
|
|
1244
|
+
import { SUBAGENT_CHILD_ENV } from "./src/runs/shared/child-runtime-config.ts";
|
|
1180
1245
|
process.env[SUBAGENT_CHILD_ENV] = "1";
|
|
1181
|
-
process.env[SUBAGENT_FANOUT_CHILD_ENV] = "1";
|
|
1182
1246
|
const calls = [];
|
|
1183
1247
|
const fakePi = new Proxy({}, {
|
|
1184
1248
|
get(target, prop) {
|
|
@@ -1213,9 +1277,9 @@ describe("subagent extension child mode", () => {
|
|
|
1213
1277
|
const script = String.raw`
|
|
1214
1278
|
import registerSubagentExtension from "./index.ts";
|
|
1215
1279
|
import registerFanoutChildSubagentExtension from "./src/extension/fanout-child.ts";
|
|
1216
|
-
import { SUBAGENT_CHILD_ENV
|
|
1280
|
+
import { SUBAGENT_CHILD_ENV } from "./src/runs/shared/child-runtime-config.ts";
|
|
1217
1281
|
process.env[SUBAGENT_CHILD_ENV] = "1";
|
|
1218
|
-
|
|
1282
|
+
const childRuntime = { fanoutChild: true, depth: 1, waitTool: { enabled: true }, fast: false };
|
|
1219
1283
|
|
|
1220
1284
|
const registeredNames = new Set();
|
|
1221
1285
|
const registrations = [];
|
|
@@ -1234,7 +1298,7 @@ describe("subagent extension child mode", () => {
|
|
|
1234
1298
|
}
|
|
1235
1299
|
|
|
1236
1300
|
registerSubagentExtension(makePi("index.ts"));
|
|
1237
|
-
registerFanoutChildSubagentExtension(makePi("fanout-child.ts"));
|
|
1301
|
+
registerFanoutChildSubagentExtension(makePi("fanout-child.ts"), childRuntime);
|
|
1238
1302
|
if (registrations.length !== 1 || registrations[0].name !== "subagent" || registrations[0].source !== "fanout-child.ts") {
|
|
1239
1303
|
throw new Error("expected only fanout-child.ts to register subagent, got " + JSON.stringify(registrations));
|
|
1240
1304
|
}
|
|
@@ -1258,16 +1322,13 @@ describe("subagent extension child mode", () => {
|
|
|
1258
1322
|
const script = String.raw`
|
|
1259
1323
|
import assert from "node:assert/strict";
|
|
1260
1324
|
import registerFanoutChildSubagentExtension from "./src/extension/fanout-child.ts";
|
|
1261
|
-
import { SUBAGENT_CHILD_ENV, SUBAGENT_FANOUT_CHILD_ENV } from "./src/runs/shared/pi-args.ts";
|
|
1262
|
-
process.env[SUBAGENT_CHILD_ENV] = "1";
|
|
1263
|
-
process.env[SUBAGENT_FANOUT_CHILD_ENV] = "1";
|
|
1264
1325
|
let registeredTool;
|
|
1265
1326
|
const fakePi = {
|
|
1266
1327
|
events: { on() { return () => {}; }, emit() {} },
|
|
1267
1328
|
registerTool(tool) { registeredTool = tool; },
|
|
1268
1329
|
getSessionName() { return undefined; },
|
|
1269
1330
|
};
|
|
1270
|
-
registerFanoutChildSubagentExtension(fakePi);
|
|
1331
|
+
registerFanoutChildSubagentExtension(fakePi, { fanoutChild: true, depth: 1, waitTool: { enabled: true }, fast: false });
|
|
1271
1332
|
if (!registeredTool) throw new Error("tool not registered");
|
|
1272
1333
|
const ctx = {
|
|
1273
1334
|
cwd: process.cwd(),
|
|
@@ -1304,4 +1365,4 @@ describe("subagent extension child mode", () => {
|
|
|
1304
1365
|
{ cwd: projectRoot, stdio: "pipe" },
|
|
1305
1366
|
);
|
|
1306
1367
|
});
|
|
1307
|
-
});
|
|
1368
|
+
});
|
|
@@ -6,6 +6,7 @@ import * as path from "node:path";
|
|
|
6
6
|
import { describe, it } from "node:test";
|
|
7
7
|
import { ACTIVE_RUN_INDEX_DIR, readActiveRunToolCallIndex, releaseActiveRunIndex, updateActiveRunIndex } from "../../src/runs/background/active-run-index.ts";
|
|
8
8
|
import { encodeIndexSegment, indexSegmentAliases, MAX_INDEX_SEGMENT_BYTES } from "../../src/runs/background/index-segment.ts";
|
|
9
|
+
import { readStatus } from "../../src/shared/utils.ts";
|
|
9
10
|
|
|
10
11
|
describe("bounded index segments", () => {
|
|
11
12
|
it("preserves legacy encoding for short values and hashes oversized opaque ids", () => {
|
|
@@ -93,4 +94,60 @@ describe("bounded index segments", () => {
|
|
|
93
94
|
fs.rmSync(root, { recursive: true, force: true });
|
|
94
95
|
}
|
|
95
96
|
});
|
|
96
|
-
|
|
97
|
+
|
|
98
|
+
it("readStatus safely handles oversized directory paths without throwing ENAMETOOLONG", () => {
|
|
99
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), "pi-read-status-long-path-"));
|
|
100
|
+
try {
|
|
101
|
+
const longSegment = "x".repeat(300);
|
|
102
|
+
const longDir = path.join(root, longSegment);
|
|
103
|
+
assert.doesNotThrow(() => {
|
|
104
|
+
const status = readStatus(longDir);
|
|
105
|
+
assert.equal(status, null);
|
|
106
|
+
});
|
|
107
|
+
} finally {
|
|
108
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("surfaces unrelated ENAMETOOLONG errors from status inspection", (t) => {
|
|
113
|
+
const error = new Error("unrelated status path too long") as NodeJS.ErrnoException;
|
|
114
|
+
error.code = "ENAMETOOLONG";
|
|
115
|
+
t.mock.method(fsDefault, "statSync", () => {
|
|
116
|
+
throw error;
|
|
117
|
+
});
|
|
118
|
+
syncBuiltinESMExports();
|
|
119
|
+
try {
|
|
120
|
+
assert.throws(() => readStatus(path.join(os.tmpdir(), "short-status-id")), (thrown) =>
|
|
121
|
+
thrown instanceof Error
|
|
122
|
+
&& /Failed to inspect async status file/.test(thrown.message)
|
|
123
|
+
&& (thrown as Error & { cause?: unknown }).cause === error);
|
|
124
|
+
} finally {
|
|
125
|
+
t.mock.restoreAll();
|
|
126
|
+
syncBuiltinESMExports();
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it("surfaces ENAMETOOLONG errors from status reads", (t) => {
|
|
131
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), "pi-read-status-read-error-"));
|
|
132
|
+
const asyncDir = path.join(root, "short-status-id");
|
|
133
|
+
const statusPath = path.join(asyncDir, "status.json");
|
|
134
|
+
const error = new Error("unrelated status read path too long") as NodeJS.ErrnoException;
|
|
135
|
+
error.code = "ENAMETOOLONG";
|
|
136
|
+
try {
|
|
137
|
+
fs.mkdirSync(asyncDir);
|
|
138
|
+
fs.writeFileSync(statusPath, "{}", "utf-8");
|
|
139
|
+
t.mock.method(fsDefault, "readFileSync", () => {
|
|
140
|
+
throw error;
|
|
141
|
+
});
|
|
142
|
+
syncBuiltinESMExports();
|
|
143
|
+
assert.throws(() => readStatus(asyncDir), (thrown) =>
|
|
144
|
+
thrown instanceof Error
|
|
145
|
+
&& /Failed to read async status file/.test(thrown.message)
|
|
146
|
+
&& (thrown as Error & { cause?: unknown }).cause === error);
|
|
147
|
+
} finally {
|
|
148
|
+
t.mock.restoreAll();
|
|
149
|
+
syncBuiltinESMExports();
|
|
150
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
});
|