@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
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
import * as fs from "node:fs";
|
|
2
|
-
import * as path from "node:path";
|
|
3
|
-
|
|
4
|
-
export const REQUIRED_CHILD_TOOLS_ENV = "SELESAI_SUBAGENT_REQUIRED_TOOLS";
|
|
5
|
-
export const MCP_DIRECT_CHILD_TOOLS_ENV = "SELESAI_SUBAGENT_MCP_DIRECT_TOOLS";
|
|
6
|
-
export const CHILD_TOOL_DIAGNOSTIC_PATH_ENV = "SELESAI_SUBAGENT_TOOL_DIAGNOSTIC_PATH";
|
|
7
|
-
|
|
8
1
|
export interface ChildToolDiagnostic {
|
|
9
2
|
agent?: string;
|
|
10
3
|
required: string[];
|
|
@@ -13,53 +6,25 @@ export interface ChildToolDiagnostic {
|
|
|
13
6
|
missingMcpDirectTools?: string[];
|
|
14
7
|
}
|
|
15
8
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const availableNames = new Set(available);
|
|
24
|
-
const missing = required.filter((name) => !availableNames.has(name));
|
|
25
|
-
if (missing.length === 0) {
|
|
26
|
-
fs.rmSync(filePath, { force: true });
|
|
27
|
-
return undefined;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const missingMcpDirectTools = mcpDirectTools?.length
|
|
31
|
-
? missing.filter((name) => mcpDirectTools.includes(name))
|
|
32
|
-
: [];
|
|
33
|
-
const diagnostic: ChildToolDiagnostic = {
|
|
34
|
-
agent,
|
|
35
|
-
required,
|
|
36
|
-
available,
|
|
37
|
-
missing,
|
|
38
|
-
...(missingMcpDirectTools.length > 0 ? { missingMcpDirectTools } : {}),
|
|
39
|
-
};
|
|
40
|
-
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
41
|
-
fs.writeFileSync(filePath, JSON.stringify(diagnostic), { mode: 0o600 });
|
|
42
|
-
return diagnostic;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export function readChildToolDiagnostic(filePath: string | undefined): ChildToolDiagnostic | undefined {
|
|
46
|
-
if (!filePath || !fs.existsSync(filePath)) return undefined;
|
|
47
|
-
const parsed = JSON.parse(fs.readFileSync(filePath, "utf-8")) as Partial<ChildToolDiagnostic>;
|
|
48
|
-
const stringArray = (value: unknown): value is string[] => Array.isArray(value) && value.every((entry) => typeof entry === "string" && entry.length > 0);
|
|
49
|
-
if (!stringArray(parsed.required) || !stringArray(parsed.available) || !stringArray(parsed.missing) || (parsed.agent !== undefined && typeof parsed.agent !== "string") || (parsed.missingMcpDirectTools !== undefined && !stringArray(parsed.missingMcpDirectTools))) {
|
|
50
|
-
throw new Error(`Malformed child tool diagnostic at '${filePath}'.`);
|
|
51
|
-
}
|
|
52
|
-
return {
|
|
53
|
-
...(parsed.agent ? { agent: parsed.agent } : {}),
|
|
54
|
-
required: parsed.required,
|
|
55
|
-
available: parsed.available,
|
|
56
|
-
missing: parsed.missing,
|
|
57
|
-
...(parsed.missingMcpDirectTools ? { missingMcpDirectTools: parsed.missingMcpDirectTools } : {}),
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export function formatChildToolDiagnostic(diagnostic: ChildToolDiagnostic): string {
|
|
9
|
+
/**
|
|
10
|
+
* Explain missing child tools. Foreground children run inside the parent
|
|
11
|
+
* process and never load the parent's ambient extensions, so tools an ambient
|
|
12
|
+
* extension registers (MCP tools, provider tools) only exist for background
|
|
13
|
+
* children; the diagnostic says so instead of reporting a generic gap.
|
|
14
|
+
*/
|
|
15
|
+
export function formatChildToolDiagnostic(diagnostic: ChildToolDiagnostic, options: { host?: "parent" | "runner" } = {}): string {
|
|
62
16
|
const subject = diagnostic.agent ? `Agent '${diagnostic.agent}'` : "Subagent";
|
|
17
|
+
if (options.host === "parent") {
|
|
18
|
+
return [
|
|
19
|
+
`${subject} ran as a foreground child, which never loads the parent's ambient extensions, and these child tools were unavailable: ${diagnostic.missing.join(", ")}.`,
|
|
20
|
+
"The `tools` field is a strict allowlist; it does not load extension code.",
|
|
21
|
+
...(diagnostic.missingMcpDirectTools?.length
|
|
22
|
+
? [`MCP direct tools missing from the child registry: ${diagnostic.missingMcpDirectTools.join(", ")}.`]
|
|
23
|
+
: []),
|
|
24
|
+
"Agents that need MCP tools (`mcpDirectTools`, or MCP tools from an ambient adapter such as pi-mcp-adapter) or models from a provider extension must run as background children (`async: true`), which load the ambient extensions.",
|
|
25
|
+
"For extension tools a foreground child can load, add the provider path to `subagentOnlyExtensions` (child-only), `extensions`, or as a path-like entry in `tools`, while keeping each registered tool name in `tools`.",
|
|
26
|
+
].join("\n");
|
|
27
|
+
}
|
|
63
28
|
return [
|
|
64
29
|
`${subject} requested unavailable child tools: ${diagnostic.missing.join(", ")}.`,
|
|
65
30
|
"The `tools` field is a strict allowlist; it does not load extension code.",
|
|
@@ -70,12 +35,3 @@ export function formatChildToolDiagnostic(diagnostic: ChildToolDiagnostic): stri
|
|
|
70
35
|
"For MCP tools, verify the MCP adapter configuration and selected tool names. For builtin tools, verify the name against the installed Pi version.",
|
|
71
36
|
].join("\n");
|
|
72
37
|
}
|
|
73
|
-
|
|
74
|
-
export function readChildToolDiagnosticError(filePath: string | undefined): string | undefined {
|
|
75
|
-
try {
|
|
76
|
-
const diagnostic = readChildToolDiagnostic(filePath);
|
|
77
|
-
return diagnostic ? formatChildToolDiagnostic(diagnostic) : undefined;
|
|
78
|
-
} catch (error) {
|
|
79
|
-
return `Failed to read child tool availability diagnostic: ${error instanceof Error ? error.message : String(error)}`;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import type { ResolvedToolBudget, ToolBudgetConfig, ToolBudgetState } from "../../shared/types.ts";
|
|
2
2
|
|
|
3
3
|
export const DEFAULT_TOOL_BUDGET_BLOCK = ["read", "grep", "find", "ls"] as const;
|
|
4
|
-
export const TOOL_BUDGET_ENV = "SELESAI_SUBAGENT_TOOL_BUDGET";
|
|
5
|
-
export const TOOL_BUDGET_ZERO_AUTH_ENV = "SELESAI_SUBAGENT_TOOL_BUDGET_ZERO_AUTH";
|
|
6
4
|
|
|
7
5
|
export function normalizeToolBudgetBlock(block: ToolBudgetConfig["block"] | undefined): "*" | string[] {
|
|
8
6
|
if (block === "*") return "*";
|
|
@@ -66,15 +64,3 @@ export function toolBudgetSoftNudge(budget: ResolvedToolBudget, toolCount: numbe
|
|
|
66
64
|
export function toolBudgetBlockedMessage(budget: ResolvedToolBudget, toolName: string, toolCount: number): string {
|
|
67
65
|
return `Tool budget hard limit reached after ${toolCount} tool call${toolCount === 1 ? "" : "s"} (hard ${budget.hard}). The '${toolName}' tool is blocked so you can finalize from the context you already have.`;
|
|
68
66
|
}
|
|
69
|
-
|
|
70
|
-
export function encodeToolBudgetEnv(budget: ResolvedToolBudget | undefined): string | undefined {
|
|
71
|
-
return budget ? JSON.stringify(budget) : undefined;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export function decodeToolBudgetEnv(value: string | undefined, options: { allowZero?: boolean } = {}): ResolvedToolBudget | undefined {
|
|
75
|
-
if (!value?.trim()) return undefined;
|
|
76
|
-
const parsed = JSON.parse(value) as unknown;
|
|
77
|
-
const normalized = validateToolBudgetConfig(parsed, TOOL_BUDGET_ENV, options.allowZero ? { minimumHard: 0 } : undefined);
|
|
78
|
-
if (normalized.error) throw new Error(normalized.error);
|
|
79
|
-
return normalized.budget;
|
|
80
|
-
}
|
|
@@ -13,7 +13,9 @@ import type {
|
|
|
13
13
|
ParallelHandoffGroup,
|
|
14
14
|
ParallelHandoffManifest,
|
|
15
15
|
} from "../../shared/types.ts";
|
|
16
|
+
import { getAgentDir } from "../../shared/utils.ts";
|
|
16
17
|
import { isTerminalParallelHandoffChildStatus } from "./parallel-handoff.ts";
|
|
18
|
+
import { MACHINE_DIFF_OPTIONS, validateWorktreePatchRepresentsCurrentWorktree } from "./worktree.ts";
|
|
17
19
|
|
|
18
20
|
export const WORKTREE_CLEANUP_PLAN_VERSION = 1 as const;
|
|
19
21
|
export const WORKTREE_CLEANUP_PLAN_TTL_MS = 30 * 60 * 1000;
|
|
@@ -244,11 +246,24 @@ function resolveRepoRoot(repo: string): string {
|
|
|
244
246
|
}
|
|
245
247
|
|
|
246
248
|
function resolveCleanupBaseDir(repoRoot: string, configuredBaseDir: string | undefined): string {
|
|
247
|
-
const raw = configuredBaseDir ?? process.env.SELESAI_SUBAGENTS_WORKTREE_DIR
|
|
248
|
-
|
|
249
|
-
if (
|
|
250
|
-
|
|
251
|
-
|
|
249
|
+
const raw = configuredBaseDir ?? process.env.SELESAI_SUBAGENTS_WORKTREE_DIR;
|
|
250
|
+
let dedicatedRoot: string;
|
|
251
|
+
if (raw === undefined || (configuredBaseDir === undefined && !raw.trim())) {
|
|
252
|
+
dedicatedRoot = path.join(path.dirname(repoRoot), "worktrees");
|
|
253
|
+
} else {
|
|
254
|
+
const trimmed = raw.trim();
|
|
255
|
+
if (!trimmed) throw new Error("worktree base directory cannot be empty");
|
|
256
|
+
const expanded = trimmed.startsWith("~/") ? path.join(os.homedir(), trimmed.slice(2)) : trimmed;
|
|
257
|
+
dedicatedRoot = path.isAbsolute(expanded) ? expanded : path.resolve(repoRoot, expanded);
|
|
258
|
+
}
|
|
259
|
+
return path.resolve(path.join(dedicatedRoot, path.basename(repoRoot)));
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function cleanupContainmentInvalid(repoRoot: string, projectDir: string): boolean {
|
|
263
|
+
const extensionsDir = path.join(getAgentDir(), "extensions");
|
|
264
|
+
return samePath(projectDir, repoRoot)
|
|
265
|
+
|| pathInside(repoRoot, projectDir, true)
|
|
266
|
+
|| pathInside(extensionsDir, projectDir);
|
|
252
267
|
}
|
|
253
268
|
|
|
254
269
|
export function parseGitWorktreeList(raw: string): GitWorktreeRecord[] {
|
|
@@ -558,7 +573,7 @@ function resolveBranchTip(repoRoot: string, branch: string): { value?: string; e
|
|
|
558
573
|
return { value: result.stdout.trim() };
|
|
559
574
|
}
|
|
560
575
|
|
|
561
|
-
function isPatchCaptured(record: ManifestMetadataRecord, worktreePath: string): { path?: string; error?: string } {
|
|
576
|
+
function isPatchCaptured(record: ManifestMetadataRecord, worktreePath: string, baseCommit: string): { path?: string; error?: string } {
|
|
562
577
|
const patchPath = metadataPatchPath(record);
|
|
563
578
|
if (!patchPath || record.child.patch?.error !== undefined || record.child.patch?.changed !== true) return {};
|
|
564
579
|
const inspection = inspectPath(patchPath);
|
|
@@ -573,12 +588,15 @@ function isPatchCaptured(record: ManifestMetadataRecord, worktreePath: string):
|
|
|
573
588
|
if (!patchStat.isFile()) return { error: "captured handoff patch is not a file" };
|
|
574
589
|
if (pathInside(worktreePath, inspection.realpath)) return { error: "durable handoff patch lives inside the worktree" };
|
|
575
590
|
if (patchStat.size <= 0) return { error: "captured handoff patch is empty" };
|
|
591
|
+
const validationError = validateWorktreePatchRepresentsCurrentWorktree(worktreePath, baseCommit, patchPath);
|
|
592
|
+
if (validationError) return { error: `captured handoff patch failed validation: ${validationError}` };
|
|
576
593
|
return { path: patchPath };
|
|
577
594
|
}
|
|
578
595
|
|
|
579
596
|
function buildManagedEntry(input: {
|
|
580
597
|
repoRoot: string;
|
|
581
598
|
baseDir: string;
|
|
599
|
+
containmentInvalid: boolean;
|
|
582
600
|
targetHead: string;
|
|
583
601
|
rootPath: string;
|
|
584
602
|
git: GitWorktreeRecord;
|
|
@@ -605,7 +623,9 @@ function buildManagedEntry(input: {
|
|
|
605
623
|
if (pathInspection.missing) return blockedEntry(entry, "stale", "unknown", "worktree path is missing from disk");
|
|
606
624
|
if (pathInspection.symlink) return blockedEntry(entry, "unknown", "unknown", "worktree path is a symlink; cleanup requires a real directory");
|
|
607
625
|
if (!pathInspection.directory || !pathInspection.realpath) return blockedEntry(entry, "unknown", "unknown", "worktree path is not a directory");
|
|
608
|
-
|
|
626
|
+
const extensionsDir = path.join(getAgentDir(), "extensions");
|
|
627
|
+
if (pathInside(extensionsDir, pathInspection.realpath)) return blockedEntry(entry, "ineligible", "keep", `worktree real path is inside Pi extensions directory '${extensionsDir}'`);
|
|
628
|
+
if (input.containmentInvalid || !pathInside(baseDir, pathInspection.realpath, true)) return blockedEntry(entry, "ineligible", "keep", `worktree real path is outside configured base directory '${baseDir}'`);
|
|
609
629
|
|
|
610
630
|
if (rootPath === comparablePath(pathInspection.realpath)) return blockedEntry(entry, "ineligible", "keep", "worktree is the repository root");
|
|
611
631
|
if (!git.branch) return blockedEntry(entry, "unknown", "unknown", "detached worktrees have no metadata-recorded branch");
|
|
@@ -648,14 +668,14 @@ function buildManagedEntry(input: {
|
|
|
648
668
|
entry.preconditions.statusDigest = status.digest;
|
|
649
669
|
if (status.output && status.output.trim()) return blockedEntry(entry, "dirty", "keep", "worktree has uncommitted or untracked changes");
|
|
650
670
|
|
|
651
|
-
const diff = runGit(worktreePath, ["diff", "--quiet", resolvedBase.value, "--"]);
|
|
671
|
+
const diff = runGit(worktreePath, ["diff", "--quiet", ...MACHINE_DIFF_OPTIONS, resolvedBase.value, "--"]);
|
|
652
672
|
if (diff.status !== 0 && diff.status !== 1) return blockedEntry(entry, "unknown", "unknown", `git diff safety check failed: ${gitFailure(diff, "git diff")}`);
|
|
653
673
|
const ancestor = runGit(repoRoot, ["merge-base", "--is-ancestor", git.head, targetHead]);
|
|
654
674
|
if (ancestor.status !== 0 && ancestor.status !== 1) return blockedEntry(entry, "unknown", "unknown", `local merge safety check failed: ${gitFailure(ancestor, "git merge-base --is-ancestor")}`);
|
|
655
675
|
const branchTipIsAncestor = ancestor.status === 0;
|
|
656
676
|
let divergenceSafe = diff.status === 0;
|
|
657
677
|
if (!divergenceSafe) {
|
|
658
|
-
const captured = isPatchCaptured(record, worktreePath);
|
|
678
|
+
const captured = isPatchCaptured(record, worktreePath, resolvedBase.value);
|
|
659
679
|
if (captured.error) return blockedEntry(entry, "ineligible", "keep", captured.error);
|
|
660
680
|
if (captured.path) {
|
|
661
681
|
entry.patchPath = captured.path;
|
|
@@ -725,6 +745,7 @@ export function buildWorktreeCleanupPlan(input: BuildWorktreeCleanupPlanInput):
|
|
|
725
745
|
const now = input.now ?? Date.now();
|
|
726
746
|
if (!Number.isFinite(now)) throw new Error("worktree cleanup plan timestamp must be finite");
|
|
727
747
|
const baseDir = resolveCleanupBaseDir(repoRoot, input.worktreeBaseDir);
|
|
748
|
+
const containmentInvalid = cleanupContainmentInvalid(repoRoot, baseDir);
|
|
728
749
|
const gitRecords = listGitWorktrees(repoRoot);
|
|
729
750
|
const targetHead = runGitChecked(repoRoot, ["rev-parse", "HEAD"]);
|
|
730
751
|
const rootPath = comparablePath(repoRoot);
|
|
@@ -749,6 +770,7 @@ export function buildWorktreeCleanupPlan(input: BuildWorktreeCleanupPlanInput):
|
|
|
749
770
|
else entries.push(buildManagedEntry({
|
|
750
771
|
repoRoot,
|
|
751
772
|
baseDir,
|
|
773
|
+
containmentInvalid,
|
|
752
774
|
targetHead,
|
|
753
775
|
rootPath,
|
|
754
776
|
git,
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { createOwnedProcessTreeController } from "../background/owned-process-tree.ts";
|
|
3
|
+
import type { ProcessTreeTerminal } from "../../shared/types.ts";
|
|
4
|
+
|
|
5
|
+
export interface SetupCommandOptions {
|
|
6
|
+
cwd?: string;
|
|
7
|
+
env?: NodeJS.ProcessEnv;
|
|
8
|
+
input?: string;
|
|
9
|
+
/** Worktrunk uses 128 KiB; Git and hooks use spawnSync's 1 MiB default. */
|
|
10
|
+
maxBuffer?: number;
|
|
11
|
+
signal?: AbortSignal;
|
|
12
|
+
deadlineAt?: number;
|
|
13
|
+
/** Only the existing configured setup-hook timeout, not a new Git budget. */
|
|
14
|
+
hookTimeoutMs?: number;
|
|
15
|
+
/** Read-only probes may define negative answers as completed commands. */
|
|
16
|
+
acceptedExitCodes?: readonly number[];
|
|
17
|
+
onSpawn?: (process: { pid: number; processGroupId?: number }) => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface SetupCommandResult {
|
|
21
|
+
stdout: string;
|
|
22
|
+
stderr: string;
|
|
23
|
+
status: number | null;
|
|
24
|
+
signal: NodeJS.Signals | null;
|
|
25
|
+
error?: Error;
|
|
26
|
+
pid?: number;
|
|
27
|
+
processGroupId?: number;
|
|
28
|
+
/** Absent on normal completion: trusted command completion is NOT tree proof. */
|
|
29
|
+
processTree?: ProcessTreeTerminal;
|
|
30
|
+
outputIncomplete: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function commandError(message: string, code: string): NodeJS.ErrnoException {
|
|
34
|
+
return Object.assign(new Error(message), { code });
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Setup I/O only. Commands must await their descendants before reporting success.
|
|
39
|
+
* Exit 0 + natural close + complete output still requires caller JSON/path validation.
|
|
40
|
+
* Invalid output is NOT accepted completion: retain unknown ownership, never signal
|
|
41
|
+
* this completed command's PID later. Callers own compensation and admission.
|
|
42
|
+
*/
|
|
43
|
+
export async function runSetupCommand(
|
|
44
|
+
command: string,
|
|
45
|
+
args: string[],
|
|
46
|
+
options: SetupCommandOptions,
|
|
47
|
+
): Promise<SetupCommandResult> {
|
|
48
|
+
const result: SetupCommandResult = {
|
|
49
|
+
stdout: "", stderr: "", status: null, signal: null, outputIncomplete: false,
|
|
50
|
+
};
|
|
51
|
+
const maxBuffer = options.maxBuffer ?? 1024 * 1024;
|
|
52
|
+
if (!Number.isSafeInteger(maxBuffer) || maxBuffer <= 0) throw new Error("Invalid setup command maxBuffer");
|
|
53
|
+
if (options.deadlineAt !== undefined && !Number.isFinite(options.deadlineAt)) throw new Error("Invalid setup deadline");
|
|
54
|
+
if (options.hookTimeoutMs !== undefined && (!Number.isSafeInteger(options.hookTimeoutMs) || options.hookTimeoutMs <= 0)) {
|
|
55
|
+
throw new Error("Invalid setup hook timeout");
|
|
56
|
+
}
|
|
57
|
+
const cancellation = (): Error | undefined => {
|
|
58
|
+
if (options.signal?.aborted) return commandError("Worktree setup aborted", "ABORT_ERR");
|
|
59
|
+
if (options.deadlineAt !== undefined && Date.now() >= options.deadlineAt) {
|
|
60
|
+
return commandError("Worktree setup deadline exceeded", "ETIMEDOUT");
|
|
61
|
+
}
|
|
62
|
+
return undefined;
|
|
63
|
+
};
|
|
64
|
+
result.error = cancellation();
|
|
65
|
+
if (result.error) return result;
|
|
66
|
+
|
|
67
|
+
let child;
|
|
68
|
+
try {
|
|
69
|
+
child = spawn(command, args, {
|
|
70
|
+
cwd: options.cwd,
|
|
71
|
+
env: options.env ? { ...process.env, ...options.env } : process.env,
|
|
72
|
+
stdio: "pipe", shell: false, windowsHide: true,
|
|
73
|
+
// Isolated owned POSIX group, never unref'd or fire-and-forget.
|
|
74
|
+
detached: process.platform !== "win32",
|
|
75
|
+
});
|
|
76
|
+
} catch (error) {
|
|
77
|
+
result.error = error instanceof Error ? error : new Error(String(error));
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
result.pid = child.pid;
|
|
81
|
+
if (child.pid !== undefined && process.platform !== "win32") result.processGroupId = child.pid;
|
|
82
|
+
const tree = child.pid === undefined ? undefined : createOwnedProcessTreeController(child.pid);
|
|
83
|
+
let termination: Promise<ProcessTreeTerminal> | undefined;
|
|
84
|
+
let directSettled = false;
|
|
85
|
+
const releaseUnknownIO = () => {
|
|
86
|
+
if (!directSettled || result.processTree?.state !== "unknown") return;
|
|
87
|
+
result.error ??= commandError("Worktree setup process tree settlement is unverified", "PROCESS_TREE_UNVERIFIED");
|
|
88
|
+
result.outputIncomplete = true;
|
|
89
|
+
// Only local I/O is released; unknown descendant ownership remains retained.
|
|
90
|
+
child.stdin.destroy();
|
|
91
|
+
child.stdout.destroy();
|
|
92
|
+
child.stderr.destroy();
|
|
93
|
+
};
|
|
94
|
+
const terminate = () => {
|
|
95
|
+
if (termination || !tree) return;
|
|
96
|
+
if (directSettled) {
|
|
97
|
+
result.processTree = {
|
|
98
|
+
state: "unknown", reason: "verification-failed",
|
|
99
|
+
diagnostic: "Command exited before termination began; no longer safe to signal its recorded PID.",
|
|
100
|
+
};
|
|
101
|
+
releaseUnknownIO();
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
termination = tree.terminate().then((proof) => {
|
|
105
|
+
result.processTree = proof;
|
|
106
|
+
releaseUnknownIO();
|
|
107
|
+
return proof;
|
|
108
|
+
});
|
|
109
|
+
};
|
|
110
|
+
const fail = (error: Error) => {
|
|
111
|
+
result.error ??= error;
|
|
112
|
+
terminate();
|
|
113
|
+
};
|
|
114
|
+
const onAbort = () => fail(commandError("Worktree setup aborted", "ABORT_ERR"));
|
|
115
|
+
const stdout: Buffer[] = [];
|
|
116
|
+
const stderr: Buffer[] = [];
|
|
117
|
+
let capturedBytes = 0;
|
|
118
|
+
const capture = (chunks: Buffer[], chunk: Buffer) => {
|
|
119
|
+
const remaining = maxBuffer - capturedBytes;
|
|
120
|
+
if (remaining > 0) {
|
|
121
|
+
const saved = Buffer.from(chunk.subarray(0, remaining));
|
|
122
|
+
chunks.push(saved);
|
|
123
|
+
capturedBytes += saved.length;
|
|
124
|
+
}
|
|
125
|
+
if (chunk.length > remaining) {
|
|
126
|
+
result.outputIncomplete = true;
|
|
127
|
+
fail(commandError("Worktree setup command output exceeds maxBuffer", "ENOBUFS"));
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
const onStdout = (chunk: Buffer) => capture(stdout, chunk);
|
|
131
|
+
const onStderr = (chunk: Buffer) => capture(stderr, chunk);
|
|
132
|
+
child.stdout.on("data", onStdout);
|
|
133
|
+
child.stderr.on("data", onStderr);
|
|
134
|
+
child.stdin.on("error", fail);
|
|
135
|
+
const close = new Promise<void>((resolve) => child.once("close", () => resolve()));
|
|
136
|
+
const directExit = new Promise<void>((resolve) => {
|
|
137
|
+
child.once("exit", (status, signal) => {
|
|
138
|
+
directSettled = true;
|
|
139
|
+
result.status = status;
|
|
140
|
+
result.signal = signal;
|
|
141
|
+
if (status === null || !(options.acceptedExitCodes ?? [0]).includes(status)) terminate();
|
|
142
|
+
releaseUnknownIO();
|
|
143
|
+
resolve();
|
|
144
|
+
});
|
|
145
|
+
child.once("error", (error) => {
|
|
146
|
+
fail(error);
|
|
147
|
+
// A failed spawn has no direct process to await. Other errors do not prove exit.
|
|
148
|
+
if (child.pid === undefined) {
|
|
149
|
+
directSettled = true;
|
|
150
|
+
resolve();
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
155
|
+
const deadlineAt = Math.min(options.deadlineAt ?? Infinity,
|
|
156
|
+
options.hookTimeoutMs === undefined ? Infinity : Date.now() + options.hookTimeoutMs);
|
|
157
|
+
const armDeadline = () => {
|
|
158
|
+
if (deadlineAt === Infinity) return;
|
|
159
|
+
const remaining = deadlineAt - Date.now();
|
|
160
|
+
if (remaining <= 0) fail(commandError("Worktree setup command timed out", "ETIMEDOUT"));
|
|
161
|
+
else timer = setTimeout(armDeadline, Math.min(remaining, 2 ** 31 - 1));
|
|
162
|
+
};
|
|
163
|
+
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
164
|
+
try {
|
|
165
|
+
armDeadline();
|
|
166
|
+
if (options.signal?.aborted) onAbort();
|
|
167
|
+
if (child.pid !== undefined) {
|
|
168
|
+
try { options.onSpawn?.({ pid: child.pid, processGroupId: result.processGroupId }); }
|
|
169
|
+
catch (error) { fail(error instanceof Error ? error : new Error(String(error))); }
|
|
170
|
+
}
|
|
171
|
+
child.stdin.end(options.input);
|
|
172
|
+
await directExit;
|
|
173
|
+
if (termination) result.processTree = await termination;
|
|
174
|
+
releaseUnknownIO();
|
|
175
|
+
await close;
|
|
176
|
+
// Abort/overflow may arrive while draining stdio after direct exit.
|
|
177
|
+
if (termination) result.processTree = await termination;
|
|
178
|
+
const cancelled = cancellation();
|
|
179
|
+
if (cancelled) fail(cancelled);
|
|
180
|
+
result.stdout = Buffer.concat(stdout).toString("utf8");
|
|
181
|
+
result.stderr = Buffer.concat(stderr).toString("utf8");
|
|
182
|
+
return result;
|
|
183
|
+
} finally {
|
|
184
|
+
if (timer) clearTimeout(timer);
|
|
185
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
186
|
+
child.stdout.removeListener("data", onStdout);
|
|
187
|
+
child.stderr.removeListener("data", onStderr);
|
|
188
|
+
child.stdin.removeListener("error", fail);
|
|
189
|
+
}
|
|
190
|
+
}
|