@selesai/code 0.13.0 → 0.13.2
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 +22 -0
- package/dist/core/agent-session.d.ts +1 -1
- package/dist/core/agent-session.js +1 -1
- package/dist/core/sdk.d.ts +2 -2
- package/dist/core/sdk.js +1 -1
- package/dist/core/system-prompt.d.ts +1 -1
- package/dist/core/system-prompt.js +1 -1
- package/dist/extensions/package.json +1 -2
- package/dist/extensions/pi-hermes-memory/CHANGELOG.md +371 -0
- package/dist/extensions/pi-hermes-memory/LICENSE +21 -0
- package/dist/extensions/pi-hermes-memory/README.md +643 -0
- package/dist/extensions/pi-hermes-memory/docs/0.1/TASKS.md +197 -0
- package/dist/extensions/pi-hermes-memory/docs/0.2/PLAN.md +290 -0
- package/dist/extensions/pi-hermes-memory/docs/0.2/TASKS.md +134 -0
- package/dist/extensions/pi-hermes-memory/docs/0.2/TEST-PLAN.md +216 -0
- package/dist/extensions/pi-hermes-memory/docs/0.3/PLAN.md +330 -0
- package/dist/extensions/pi-hermes-memory/docs/0.3/TASKS.md +125 -0
- package/dist/extensions/pi-hermes-memory/docs/0.4/PLAN.md +160 -0
- package/dist/extensions/pi-hermes-memory/docs/0.4/TASKS.md +113 -0
- package/dist/extensions/pi-hermes-memory/docs/0.6/CHANGELOG.md +57 -0
- package/dist/extensions/pi-hermes-memory/docs/0.6/PLAN.md +202 -0
- package/dist/extensions/pi-hermes-memory/docs/0.6/TASKS.md +144 -0
- package/dist/extensions/pi-hermes-memory/docs/0.7/PLAN.md +349 -0
- package/dist/extensions/pi-hermes-memory/docs/0.7/TASKS.md +110 -0
- package/dist/extensions/pi-hermes-memory/docs/PUBLISHING.md +149 -0
- package/dist/extensions/pi-hermes-memory/docs/ROADMAP.md +468 -0
- package/dist/extensions/pi-hermes-memory/docs/images/memory-architecture.svg +1 -0
- package/dist/extensions/pi-hermes-memory/docs/images/pi-logo.svg +22 -0
- package/dist/extensions/pi-hermes-memory/docs/images/pi_memory.png +0 -0
- package/dist/extensions/pi-hermes-memory/docs/images/pi_memory.svg +19 -0
- package/dist/extensions/pi-hermes-memory/docs/images/security-flow.svg +1 -0
- package/dist/extensions/pi-hermes-memory/docs/images/session-lifecycle.svg +1 -0
- package/dist/extensions/pi-hermes-memory/docs/images/source-architecture.svg +1 -0
- package/dist/extensions/pi-hermes-memory/docs/mermaid/memory-architecture.mmd +49 -0
- package/dist/extensions/pi-hermes-memory/docs/mermaid/security-flow.mmd +40 -0
- package/dist/extensions/pi-hermes-memory/docs/mermaid/session-lifecycle.mmd +56 -0
- package/dist/extensions/pi-hermes-memory/docs/mermaid/source-architecture.mmd +54 -0
- package/dist/extensions/pi-hermes-memory/package-lock.json +3799 -0
- package/dist/extensions/pi-hermes-memory/package.json +66 -0
- package/dist/extensions/pi-hermes-memory/scripts/check-min-sdk.mjs +99 -0
- package/dist/extensions/pi-hermes-memory/scripts/ensure-dev.mjs +57 -0
- package/dist/extensions/pi-hermes-memory/src/auto-consolidation-warning.ts +6 -0
- package/dist/extensions/pi-hermes-memory/src/config.ts +178 -0
- package/dist/extensions/pi-hermes-memory/src/constants.ts +424 -0
- package/dist/extensions/pi-hermes-memory/src/extension-root-migration.ts +639 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/auto-consolidate.ts +401 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/background-review.ts +297 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/child-process-watchdog.mjs +90 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/correction-detector.ts +300 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/index-sessions.ts +86 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/insights.ts +78 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/interview.ts +37 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/learn-memory.ts +186 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/message-parts.ts +27 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/pi-child-process.ts +485 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/preview-context.ts +105 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/review-memory-ops.ts +506 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/session-backfill.ts +145 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/session-flush.ts +151 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/session-live-index.ts +94 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/skills-command.ts +1334 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/standing-pin.ts +111 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/switch-project.ts +75 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/sync-markdown-memories.ts +266 -0
- package/dist/extensions/pi-hermes-memory/src/index.ts +378 -0
- package/dist/extensions/pi-hermes-memory/src/lifecycle-timing.ts +54 -0
- package/dist/extensions/pi-hermes-memory/src/paths.ts +61 -0
- package/dist/extensions/pi-hermes-memory/src/project-context.ts +13 -0
- package/dist/extensions/pi-hermes-memory/src/project-memory-migration.ts +93 -0
- package/dist/extensions/pi-hermes-memory/src/project.ts +157 -0
- package/dist/extensions/pi-hermes-memory/src/prompt-context.ts +55 -0
- package/dist/extensions/pi-hermes-memory/src/store/atomic-lock-coordinator.ts +375 -0
- package/dist/extensions/pi-hermes-memory/src/store/canonical-storage-path.ts +54 -0
- package/dist/extensions/pi-hermes-memory/src/store/content-scanner.ts +101 -0
- package/dist/extensions/pi-hermes-memory/src/store/db.ts +1180 -0
- package/dist/extensions/pi-hermes-memory/src/store/fts-query.ts +101 -0
- package/dist/extensions/pi-hermes-memory/src/store/markdown-mutation-lock.ts +38 -0
- package/dist/extensions/pi-hermes-memory/src/store/memory-lookup.ts +24 -0
- package/dist/extensions/pi-hermes-memory/src/store/memory-store.ts +1191 -0
- package/dist/extensions/pi-hermes-memory/src/store/recovery-maintenance.ts +66 -0
- package/dist/extensions/pi-hermes-memory/src/store/schema.ts +118 -0
- package/dist/extensions/pi-hermes-memory/src/store/session-anchor-search.ts +472 -0
- package/dist/extensions/pi-hermes-memory/src/store/session-indexer.ts +511 -0
- package/dist/extensions/pi-hermes-memory/src/store/session-parser.ts +213 -0
- package/dist/extensions/pi-hermes-memory/src/store/session-search.ts +234 -0
- package/dist/extensions/pi-hermes-memory/src/store/skill-store.ts +950 -0
- package/dist/extensions/pi-hermes-memory/src/store/skill-utils.ts +133 -0
- package/dist/extensions/pi-hermes-memory/src/store/sqlite-memory-store.ts +1002 -0
- package/dist/extensions/pi-hermes-memory/src/store/sqlite-native.ts +241 -0
- package/dist/extensions/pi-hermes-memory/src/store/standing-instructions.ts +247 -0
- package/dist/extensions/pi-hermes-memory/src/tools/memory-search-tool.ts +95 -0
- package/dist/extensions/pi-hermes-memory/src/tools/memory-tool.ts +469 -0
- package/dist/extensions/pi-hermes-memory/src/tools/session-search-tool.ts +246 -0
- package/dist/extensions/pi-hermes-memory/src/tools/shared-output-view.ts +170 -0
- package/dist/extensions/pi-hermes-memory/src/tools/skill-tool.ts +333 -0
- package/dist/extensions/pi-hermes-memory/src/tools/tool-result-views.ts +105 -0
- package/dist/extensions/pi-hermes-memory/src/types.ts +214 -0
- package/dist/extensions/pi-hermes-memory/tests/config.test.ts +434 -0
- package/dist/extensions/pi-hermes-memory/tests/extension-root-migration.test.ts +368 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/auto-consolidate.test.ts +984 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/background-review.test.ts +950 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/correction-detector.test.ts +671 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/insights.test.ts +157 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/interview.test.ts +127 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/pi-child-process.test.ts +905 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/preview-context.test.ts +152 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/prompt-context.test.ts +166 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/resources-discover.test.ts +71 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/review-memory-ops.test.ts +614 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/session-backfill.test.ts +192 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/session-flush.test.ts +677 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/session-live-index.test.ts +225 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/skills-command.test.ts +827 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/standing-pin.test.ts +134 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/sync-markdown-memories.test.ts +491 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/system-prompt.test.ts +199 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/thinking-max.test.ts +64 -0
- package/dist/extensions/pi-hermes-memory/tests/index.test.ts +30 -0
- package/dist/extensions/pi-hermes-memory/tests/integration/flow.test.ts +126 -0
- package/dist/extensions/pi-hermes-memory/tests/lifecycle-timing.test.ts +76 -0
- package/dist/extensions/pi-hermes-memory/tests/paths.test.ts +23 -0
- package/dist/extensions/pi-hermes-memory/tests/project-memory-migration.test.ts +80 -0
- package/dist/extensions/pi-hermes-memory/tests/project-rebinding.test.ts +115 -0
- package/dist/extensions/pi-hermes-memory/tests/project.test.ts +120 -0
- package/dist/extensions/pi-hermes-memory/tests/run-all-timeout.test.ts +107 -0
- package/dist/extensions/pi-hermes-memory/tests/run-all.sh +45 -0
- package/dist/extensions/pi-hermes-memory/tests/store/atomic-lock-coordinator.test.ts +381 -0
- package/dist/extensions/pi-hermes-memory/tests/store/content-scanner.test.ts +388 -0
- package/dist/extensions/pi-hermes-memory/tests/store/db.test.ts +1046 -0
- package/dist/extensions/pi-hermes-memory/tests/store/markdown-mutation-lock.test.ts +34 -0
- package/dist/extensions/pi-hermes-memory/tests/store/memory-store.test.ts +2150 -0
- package/dist/extensions/pi-hermes-memory/tests/store/recovery-maintenance.test.ts +170 -0
- package/dist/extensions/pi-hermes-memory/tests/store/session-anchor-search.test.ts +210 -0
- package/dist/extensions/pi-hermes-memory/tests/store/session-indexer.test.ts +643 -0
- package/dist/extensions/pi-hermes-memory/tests/store/session-parser.test.ts +282 -0
- package/dist/extensions/pi-hermes-memory/tests/store/session-search.test.ts +287 -0
- package/dist/extensions/pi-hermes-memory/tests/store/skill-store.test.ts +678 -0
- package/dist/extensions/pi-hermes-memory/tests/store/skill-utils.test.ts +21 -0
- package/dist/extensions/pi-hermes-memory/tests/store/sqlite-lazy-load.test.ts +78 -0
- package/dist/extensions/pi-hermes-memory/tests/store/sqlite-memory-store.test.ts +543 -0
- package/dist/extensions/pi-hermes-memory/tests/store/sqlite-native.test.ts +164 -0
- package/dist/extensions/pi-hermes-memory/tests/store/standing-instructions.test.ts +171 -0
- package/dist/extensions/pi-hermes-memory/tests/tools/memory-search-tool.test.ts +84 -0
- package/dist/extensions/pi-hermes-memory/tests/tools/memory-tool.test.ts +709 -0
- package/dist/extensions/pi-hermes-memory/tests/tools/session-search-tool.test.ts +345 -0
- package/dist/extensions/pi-hermes-memory/tests/tools/shared-output-view.test.ts +362 -0
- package/dist/extensions/pi-hermes-memory/tests/tools/skill-tool.test.ts +478 -0
- package/dist/extensions/pi-hermes-memory/tests/tools/tool-result-renderer-wiring.test.ts +40 -0
- package/dist/extensions/pi-hermes-memory/tsconfig.json +19 -0
- package/dist/extensions/pi-rewind-hook/README.md +4 -1
- package/dist/extensions/pi-rewind-hook/index.ts +151 -21
- package/dist/extensions/pi-rewind-hook/package.json +5 -3
- package/dist/extensions/pi-subagents/.oxlintrc.json +43 -0
- package/dist/extensions/pi-subagents/AGENTS.md +5 -0
- package/dist/extensions/pi-subagents/CHANGELOG.md +157 -0
- package/dist/extensions/pi-subagents/README.md +12 -6
- package/dist/extensions/pi-subagents/VISION.md +81 -0
- package/dist/extensions/pi-subagents/agents/claude-code-writer.md +15 -0
- package/dist/extensions/pi-subagents/agents/claude-code.md +15 -0
- package/dist/extensions/pi-subagents/agents/codex-exec-writer.md +15 -0
- package/dist/extensions/pi-subagents/agents/codex-exec.md +15 -0
- package/dist/extensions/pi-subagents/agents/cursor-agent-writer.md +14 -0
- package/dist/extensions/pi-subagents/agents/cursor-agent.md +14 -0
- package/dist/extensions/pi-subagents/agents/reviewer.md +1 -3
- package/dist/extensions/pi-subagents/docs/agents.md +488 -0
- package/dist/extensions/pi-subagents/docs/configuration.md +46 -9
- package/dist/extensions/pi-subagents/docs/extension-api.md +42 -3
- package/dist/extensions/pi-subagents/docs/models.md +27 -4
- package/dist/extensions/pi-subagents/docs/observability.md +10 -9
- package/dist/extensions/pi-subagents/docs/tool-reference.md +102 -6
- package/dist/extensions/pi-subagents/docs/workflows.md +135 -0
- package/dist/extensions/pi-subagents/package-lock.json +389 -2
- package/dist/extensions/pi-subagents/package.json +3 -1
- package/dist/extensions/pi-subagents/prompts/review-loop.md +2 -2
- package/dist/extensions/pi-subagents/skills/council-mode/SKILL.md +1 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +3 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +7 -3
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +2 -2
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +26 -5
- package/dist/extensions/pi-subagents/src/agents/agent-management.ts +41 -22
- package/dist/extensions/pi-subagents/src/agents/agent-refinements.ts +4 -4
- package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +9 -2
- package/dist/extensions/pi-subagents/src/agents/agents.ts +322 -75
- package/dist/extensions/pi-subagents/src/agents/builtin-names.ts +6 -0
- package/dist/extensions/pi-subagents/src/agents/runtime-agent-events.ts +70 -0
- package/dist/extensions/pi-subagents/src/agents/runtime-agent-registry.ts +27 -20
- package/dist/extensions/pi-subagents/src/api/agents.ts +10 -5
- package/dist/extensions/pi-subagents/src/api/background-work.ts +5 -1
- package/dist/extensions/pi-subagents/src/api/delegation.ts +0 -7
- package/dist/extensions/pi-subagents/src/api/preflight.ts +34 -12
- package/dist/extensions/pi-subagents/src/extension/config.ts +70 -0
- package/dist/extensions/pi-subagents/src/extension/doctor.ts +3 -3
- package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +5 -3
- package/dist/extensions/pi-subagents/src/extension/index.ts +83 -30
- package/dist/extensions/pi-subagents/src/extension/public-execution.ts +44 -15
- package/dist/extensions/pi-subagents/src/extension/rpc.ts +55 -19
- package/dist/extensions/pi-subagents/src/extension/schemas.ts +41 -15
- package/dist/extensions/pi-subagents/src/extension/tool-description.ts +28 -31
- package/dist/extensions/pi-subagents/src/inspectors/herdr/actions.ts +2 -1
- package/dist/extensions/pi-subagents/src/inspectors/herdr/inspector-runner.ts +2 -10
- package/dist/extensions/pi-subagents/src/inspectors/herdr/session-roots-codec.ts +42 -0
- package/dist/extensions/pi-subagents/src/integrations/herdr-status.ts +51 -7
- package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +2 -0
- package/dist/extensions/pi-subagents/src/profiles/profiles.ts +5 -6
- package/dist/extensions/pi-subagents/src/runs/background/active-async-capacity.ts +77 -10
- package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +176 -53
- package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +19 -12
- package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +29 -27
- package/dist/extensions/pi-subagents/src/runs/background/async-retention.ts +20 -3
- package/dist/extensions/pi-subagents/src/runs/background/async-status-snapshot.ts +23 -261
- package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +73 -7
- package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +8 -3
- package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +74 -8
- package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +37 -21
- package/dist/extensions/pi-subagents/src/runs/background/inspect-rpc.ts +8 -8
- package/dist/extensions/pi-subagents/src/runs/background/notify.ts +184 -9
- package/dist/extensions/pi-subagents/src/runs/background/result-delivery-ownership.ts +45 -0
- package/dist/extensions/pi-subagents/src/runs/background/result-files.ts +28 -14
- package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +38 -15
- package/dist/extensions/pi-subagents/src/runs/background/resume-guidance.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/background/retained-children.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +50 -13
- package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +93 -8
- package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +10 -4
- package/dist/extensions/pi-subagents/src/runs/background/steering.ts +4 -14
- package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +549 -377
- package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +58 -10
- package/dist/extensions/pi-subagents/src/runs/background/terminal-run-index.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/background/wait-completions.ts +26 -1
- package/dist/extensions/pi-subagents/src/runs/background/wait-config.ts +23 -9
- package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +9 -2
- package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +2 -2
- package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +204 -129
- package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +9 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/foreground-history.ts +23 -1
- package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +773 -311
- package/dist/extensions/pi-subagents/src/runs/foreground/workflow-detach-reconcile.ts +140 -115
- package/dist/extensions/pi-subagents/src/runs/shared/abort-recovery.ts +119 -0
- package/dist/extensions/pi-subagents/src/runs/shared/async-status-projection.ts +463 -0
- package/dist/extensions/pi-subagents/src/runs/shared/child-identity.ts +19 -4
- package/dist/extensions/pi-subagents/src/runs/shared/child-launch-plan.ts +151 -0
- package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +21 -7
- package/dist/extensions/pi-subagents/src/runs/shared/claude-code-adapter.ts +129 -0
- package/dist/extensions/pi-subagents/src/runs/shared/codex-exec-adapter.ts +129 -0
- package/dist/extensions/pi-subagents/src/runs/shared/completion-evidence.ts +89 -0
- package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +5 -4
- package/dist/extensions/pi-subagents/src/runs/shared/cursor-agent-adapter.ts +114 -0
- package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +3 -3
- package/dist/extensions/pi-subagents/src/runs/shared/external-cli-contract.ts +167 -0
- package/dist/extensions/pi-subagents/src/runs/shared/external-cli-preflight.ts +122 -0
- package/dist/extensions/pi-subagents/src/runs/shared/external-cli-runner.ts +348 -55
- package/dist/extensions/pi-subagents/src/runs/shared/fast-mode-extension.ts +5 -5
- package/dist/extensions/pi-subagents/src/runs/shared/host-step-status.ts +230 -0
- package/dist/extensions/pi-subagents/src/runs/shared/lane-metadata.ts +105 -0
- package/dist/extensions/pi-subagents/src/runs/shared/launch-cwd.ts +16 -0
- package/dist/extensions/pi-subagents/src/runs/shared/long-running-guard.ts +2 -1
- package/dist/extensions/pi-subagents/src/runs/shared/mcp-config-sources.ts +422 -0
- package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +221 -158
- package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-grant.ts +197 -0
- package/dist/extensions/pi-subagents/src/runs/shared/model-exclusions.ts +69 -7
- package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +47 -6
- package/dist/extensions/pi-subagents/src/runs/shared/mutation-evidence.ts +7 -2
- package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +9 -3
- package/dist/extensions/pi-subagents/src/runs/shared/nested-render.ts +9 -5
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +419 -7
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +15 -1
- package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +81 -8
- package/dist/extensions/pi-subagents/src/runs/shared/process-signal.ts +13 -0
- package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +21 -1
- package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +44 -4
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +98 -13
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/shared/worktree-cleanup-plan.ts +847 -0
- package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +18 -0
- package/dist/extensions/pi-subagents/src/shared/child-session-name.ts +46 -0
- package/dist/extensions/pi-subagents/src/shared/extension-context.ts +24 -0
- package/dist/extensions/pi-subagents/src/shared/fork-context.ts +21 -0
- package/dist/extensions/pi-subagents/src/shared/formatters.ts +18 -3
- package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +5 -1
- package/dist/extensions/pi-subagents/src/shared/pruned-fork.ts +450 -0
- package/dist/extensions/pi-subagents/src/shared/session-file-trust.ts +19 -0
- package/dist/extensions/pi-subagents/src/shared/session-tokens.ts +14 -3
- package/dist/extensions/pi-subagents/src/shared/settings.ts +19 -105
- package/dist/extensions/pi-subagents/src/shared/shortcuts.ts +17 -0
- package/dist/extensions/pi-subagents/src/shared/types.ts +359 -40
- package/dist/extensions/pi-subagents/src/shared/utils.ts +41 -84
- package/dist/extensions/pi-subagents/src/shared/workflow-child-permit.ts +116 -0
- package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +1 -9
- package/dist/extensions/pi-subagents/src/slash/delegation-request.ts +0 -4
- package/dist/extensions/pi-subagents/src/slash/slash-bridge.ts +1 -2
- package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +378 -88
- package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +22 -11
- package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +3 -0
- package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +147 -79
- package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +11 -5
- package/dist/extensions/pi-subagents/src/tui/fleet.ts +39 -18
- package/dist/extensions/pi-subagents/src/tui/render.ts +369 -46
- package/dist/extensions/pi-subagents/src/watchdog/turn-delta.ts +1 -1
- package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +6 -3
- package/dist/extensions/pi-subagents/src/workflows/host-command.ts +230 -0
- package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +740 -58
- package/dist/extensions/pi-subagents/src/workflows/workflow-child-summary.ts +121 -0
- package/dist/extensions/pi-subagents/src/workflows/workflow-preflight.ts +270 -0
- package/dist/extensions/pi-subagents/src/workflows/workflow-receipt.ts +195 -6
- package/dist/extensions/pi-subagents/src/workflows/workflow-settlement.ts +246 -0
- package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +1114 -260
- package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +34 -0
- package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +150 -3
- package/dist/extensions/pi-subagents/test/integration/claude-code-smoke.test.ts +52 -0
- package/dist/extensions/pi-subagents/test/integration/claude-code-writer-smoke.test.ts +55 -0
- package/dist/extensions/pi-subagents/test/integration/codex-exec-smoke.test.ts +53 -0
- package/dist/extensions/pi-subagents/test/integration/codex-exec-writer-smoke.test.ts +57 -0
- package/dist/extensions/pi-subagents/test/integration/cursor-agent-smoke.test.ts +59 -0
- package/dist/extensions/pi-subagents/test/integration/cursor-agent-writer-smoke.test.ts +62 -0
- package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +57 -1
- package/dist/extensions/pi-subagents/test/integration/external-cli-runner.test.ts +1 -0
- package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +20 -0
- package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +4 -3
- package/dist/extensions/pi-subagents/test/integration/orca-progress-tabs.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +54 -4
- package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +482 -4
- package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +157 -9
- package/dist/extensions/pi-subagents/test/integration/session-tokens.test.ts +5 -5
- package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +1508 -291
- package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +423 -1
- package/dist/extensions/pi-subagents/test/integration/template-resolution.test.ts +8 -0
- package/dist/extensions/pi-subagents/test/support/cursor-smoke-inputs.ts +51 -0
- package/dist/extensions/pi-subagents/test/support/helpers.ts +2 -0
- package/dist/extensions/pi-subagents/test/support/mock-pi.ts +5 -5
- package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +6 -6
- package/dist/extensions/pi-subagents/test/unit/abort-recovery.test.ts +152 -0
- package/dist/extensions/pi-subagents/test/unit/active-async-capacity.test.ts +48 -0
- package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +184 -6
- package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +66 -6
- package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +77 -0
- package/dist/extensions/pi-subagents/test/unit/agent-refinements.test.ts +18 -0
- package/dist/extensions/pi-subagents/test/unit/anti-slop-oxlint.test.ts +86 -0
- package/dist/extensions/pi-subagents/test/unit/artifacts.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +101 -1
- package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +121 -0
- package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +28 -0
- package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +14 -7
- package/dist/extensions/pi-subagents/test/unit/async-retention.test.ts +53 -0
- package/dist/extensions/pi-subagents/test/unit/async-status-projection.test.ts +190 -0
- package/dist/extensions/pi-subagents/test/unit/async-status-snapshot.test.ts +42 -0
- package/dist/extensions/pi-subagents/test/unit/auto-drain.test.ts +8 -4
- package/dist/extensions/pi-subagents/test/unit/background-work.test.ts +23 -0
- package/dist/extensions/pi-subagents/test/unit/chain-root-attachment.test.ts +78 -1
- package/dist/extensions/pi-subagents/test/unit/child-launch-plan.test.ts +94 -0
- package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +21 -0
- package/dist/extensions/pi-subagents/test/unit/child-session-name.test.ts +50 -0
- package/dist/extensions/pi-subagents/test/unit/claude-code-adapter.test.ts +245 -0
- package/dist/extensions/pi-subagents/test/unit/codex-exec-adapter.test.ts +192 -0
- package/dist/extensions/pi-subagents/test/unit/compaction-resume.test.ts +27 -0
- package/dist/extensions/pi-subagents/test/unit/completion-evidence.test.ts +150 -0
- package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +21 -0
- package/dist/extensions/pi-subagents/test/unit/cursor-agent-adapter.test.ts +259 -0
- package/dist/extensions/pi-subagents/test/unit/cursor-smoke-inputs.test.ts +77 -0
- package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +1 -4
- package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/extension-context.test.ts +27 -0
- package/dist/extensions/pi-subagents/test/unit/external-cli-runner.test.ts +223 -0
- package/dist/extensions/pi-subagents/test/unit/fast-mode-extension.test.ts +27 -0
- package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +208 -2
- package/dist/extensions/pi-subagents/test/unit/fleet-transcript.test.ts +29 -1
- package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +110 -1
- package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +10 -0
- package/dist/extensions/pi-subagents/test/unit/formatters.test.ts +14 -0
- package/dist/extensions/pi-subagents/test/unit/herdr-inspector.test.ts +18 -9
- package/dist/extensions/pi-subagents/test/unit/herdr-session-roots-codec.test.ts +63 -0
- package/dist/extensions/pi-subagents/test/unit/herdr-shell-command.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/herdr-status-bridge.test.ts +136 -6
- package/dist/extensions/pi-subagents/test/unit/host-command.test.ts +156 -0
- package/dist/extensions/pi-subagents/test/unit/host-step-status.test.ts +98 -0
- package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +178 -26
- package/dist/extensions/pi-subagents/test/unit/index-segment.test.ts +2 -1
- package/dist/extensions/pi-subagents/test/unit/inspect-rpc.test.ts +21 -0
- package/dist/extensions/pi-subagents/test/unit/mcp-direct-tool-grant.test.ts +138 -0
- package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/model-exclusions.test.ts +91 -0
- package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +72 -7
- package/dist/extensions/pi-subagents/test/unit/mutation-evidence.test.ts +21 -0
- package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +1 -0
- package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +20 -2
- package/dist/extensions/pi-subagents/test/unit/notify.test.ts +129 -1
- package/dist/extensions/pi-subagents/test/unit/orca-progress-tabs.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +4 -0
- package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +358 -0
- package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +574 -21
- package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +109 -1
- package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +71 -1
- package/dist/extensions/pi-subagents/test/unit/profiles.test.ts +7 -7
- package/dist/extensions/pi-subagents/test/unit/pruned-fork.test.ts +214 -0
- package/dist/extensions/pi-subagents/test/unit/public-execution.test.ts +29 -8
- package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +53 -0
- package/dist/extensions/pi-subagents/test/unit/result-delivery-ownership.test.ts +34 -0
- package/dist/extensions/pi-subagents/test/unit/result-files.test.ts +101 -3
- package/dist/extensions/pi-subagents/test/unit/retained-children.test.ts +1 -0
- package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +10 -8
- package/dist/extensions/pi-subagents/test/unit/run-fanout-budget.test.ts +71 -1
- package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +41 -7
- package/dist/extensions/pi-subagents/test/unit/runtime-agent-registration.test.ts +136 -2
- package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +137 -0
- package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +33 -12
- package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +504 -1
- package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +8 -0
- package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +12 -1
- package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +3 -5
- package/dist/extensions/pi-subagents/test/unit/steering.test.ts +5 -6
- package/dist/extensions/pi-subagents/test/unit/subagent-action-recovery.test.ts +0 -8
- package/dist/extensions/pi-subagents/test/unit/subagent-guide.test.ts +5 -0
- package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +157 -2
- package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +63 -4
- package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +27 -23
- package/dist/extensions/pi-subagents/test/unit/wait-completions.test.ts +44 -0
- package/dist/extensions/pi-subagents/test/unit/wait-subscriptions.test.ts +1 -0
- package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +7 -5
- package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +106 -0
- package/dist/extensions/pi-subagents/test/unit/workflow-detach-reconcile.test.ts +484 -9
- package/dist/extensions/pi-subagents/test/unit/workflow-launch-params.test.ts +38 -4
- package/dist/extensions/pi-subagents/test/unit/workflow-preflight.test.ts +155 -0
- package/dist/extensions/pi-subagents/test/unit/workflow-receipt.test.ts +318 -0
- package/dist/extensions/pi-subagents/test/unit/workflow-resume-hint.test.ts +365 -0
- package/dist/extensions/pi-subagents/test/unit/worktree-cleanup-plan.test.ts +349 -0
- package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +21 -0
- package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +2 -7
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/effect/index.ts +13 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/effect/rules/no-service-constructor-imports.ts +52 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/index.ts +41 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-chained-type-assertions.ts +77 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-conditional-empty-object-spread.ts +49 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-known-value-widening.ts +247 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-module-mocking.ts +91 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-object-parameters.ts +126 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-reflect-apply.ts +28 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-reflect-get.ts +28 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-runtime-typeof.ts +67 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-shape-in-symbol-names.ts +39 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unknown-parameters.ts +83 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unknown-returns.ts +115 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unknown-type-aliases.ts +72 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unsafe-dictionary-type.ts +134 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-widen-then-assert.ts +366 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/require-safety-comment-for-type-assertion.ts +62 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/shared/dictionary-types.ts +502 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/shared/lexical-type-parameters.ts +60 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/shared/reflect-method.ts +35 -0
- package/dist/extensions/pi-tool-display/tests/capabilities.test.ts +1 -1
- package/dist/extensions/pi-tool-display/tests/settings-inspector.test.ts +2 -2
- package/dist/extensions/pi-tool-display/tests/tool-overrides-mcp.test.ts +1 -1
- package/dist/modes/interactive/interactive-mode.js +7 -7
- package/dist/skills/workflow/SKILL.md +65 -50
- package/package.json +112 -110
- package/dist/extensions/enable-readonly-tools.test.ts +0 -63
- package/dist/extensions/enable-readonly-tools.ts +0 -24
- package/dist/extensions/model-prompt-injector/config.json +0 -16
- package/dist/extensions/model-prompt-injector/index.test.ts +0 -102
- package/dist/extensions/model-prompt-injector/index.ts +0 -148
- package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +0 -98
- package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +0 -250
|
@@ -18,6 +18,7 @@ import { readStatus } from "../../shared/utils.ts";
|
|
|
18
18
|
import { formatNestedRunStatusLines } from "../shared/nested-render.ts";
|
|
19
19
|
import { contextModeLabel, summarizeContextModes } from "../shared/context-mode.ts";
|
|
20
20
|
import { formatAsyncRunOutputPath, formatAsyncRunProgressLabel, listAsyncRuns, type AsyncRunSummary } from "./async-status.ts";
|
|
21
|
+
import { isTrustedRecordedSessionFile } from "../../shared/session-file-trust.ts";
|
|
21
22
|
|
|
22
23
|
const DEFAULT_TRANSCRIPT_LINES = 80;
|
|
23
24
|
const MAX_TRANSCRIPT_LINES = 500;
|
|
@@ -43,6 +44,8 @@ interface TranscriptOptions {
|
|
|
43
44
|
index?: number;
|
|
44
45
|
lines?: number;
|
|
45
46
|
sessionRoots?: string[];
|
|
47
|
+
trustedSessionFiles?: string[];
|
|
48
|
+
trustedSessionFileRoot?: string;
|
|
46
49
|
}
|
|
47
50
|
|
|
48
51
|
interface TextTailResult {
|
|
@@ -69,6 +72,14 @@ function uniqueStrings(values: Array<string | undefined>): string[] {
|
|
|
69
72
|
return result;
|
|
70
73
|
}
|
|
71
74
|
|
|
75
|
+
function fleetChildDisplayName(child: { agent?: string; sessionName?: string }, fallback = "subagent"): string {
|
|
76
|
+
return child.sessionName?.trim() || child.agent || fallback;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function fleetStepDisplayName(step: Pick<AsyncJobStep, "agent" | "sessionName" | "label">): string {
|
|
80
|
+
return step.sessionName?.trim() || (step.label ? `${step.label} (${step.agent})` : step.agent);
|
|
81
|
+
}
|
|
82
|
+
|
|
72
83
|
function resolveMaybeRelative(asyncDir: string, filePath: string | undefined): string | undefined {
|
|
73
84
|
if (!filePath) return undefined;
|
|
74
85
|
return path.resolve(asyncDir, filePath);
|
|
@@ -120,10 +131,13 @@ function readTextTail(filePath: string, maxLines: number): TextTailResult {
|
|
|
120
131
|
}
|
|
121
132
|
}
|
|
122
133
|
|
|
123
|
-
function readContainedTextTail(filePath: string, maxLines: number, trustedRoots: string[], label: string): TextTailResult {
|
|
124
|
-
if (trustedRoots.length === 0) return { path: filePath, lines: [], truncated: false, error: `Refusing to read ${label} transcript path without a trusted root: ${filePath}` };
|
|
134
|
+
function readContainedTextTail(filePath: string, maxLines: number, trustedRoots: string[], label: string, trustedFiles: string[] = [], trustedFileRoot?: string): TextTailResult {
|
|
135
|
+
if (trustedRoots.length === 0 && (!trustedFileRoot || trustedFiles.length === 0)) return { path: filePath, lines: [], truncated: false, error: `Refusing to read ${label} transcript path without a trusted root: ${filePath}` };
|
|
125
136
|
const resolvedPath = path.resolve(filePath);
|
|
126
|
-
|
|
137
|
+
const recordedCandidate = trustedFileRoot
|
|
138
|
+
&& pathWithin(trustedFileRoot, resolvedPath)
|
|
139
|
+
&& trustedFiles.some((file) => path.resolve(file) === resolvedPath);
|
|
140
|
+
if (!trustedRoots.some((root) => pathWithin(root, resolvedPath)) && !recordedCandidate) {
|
|
127
141
|
return { path: filePath, lines: [], truncated: false, error: `Refusing to read ${label} transcript path outside trusted roots: ${filePath}` };
|
|
128
142
|
}
|
|
129
143
|
let lstat: fs.Stats;
|
|
@@ -143,7 +157,7 @@ function readContainedTextTail(filePath: string, maxLines: number, trustedRoots:
|
|
|
143
157
|
} catch (error) {
|
|
144
158
|
return { path: filePath, lines: [], truncated: false, error: getErrorMessage(error) };
|
|
145
159
|
}
|
|
146
|
-
if (!realRoots.some((root) => pathWithin(root, realPath))) {
|
|
160
|
+
if (!realRoots.some((root) => pathWithin(root, realPath)) && !isTrustedRecordedSessionFile(realPath, trustedFiles, trustedFileRoot)) {
|
|
147
161
|
return { path: filePath, lines: [], truncated: false, error: `Refusing to read ${label} transcript path outside trusted roots: ${filePath}` };
|
|
148
162
|
}
|
|
149
163
|
return readTextTail(resolvedPath, maxLines);
|
|
@@ -213,8 +227,8 @@ function sessionMessageLine(record: unknown): string | undefined {
|
|
|
213
227
|
|
|
214
228
|
/** Structured session tail: parsed content parts, newest last, bounded by
|
|
215
229
|
* maxMessages. Same trusted-root containment as the prose transcript tail. */
|
|
216
|
-
export function readSessionMessagesTail(sessionFile: string, maxMessages: number, trustedRoots: string[]): { messages: SessionTranscriptMessage[]; warnings: string[]; truncated: boolean } {
|
|
217
|
-
const tail = readContainedTextTail(sessionFile, Math.max(maxMessages * 4, maxMessages), trustedRoots, "session");
|
|
230
|
+
export function readSessionMessagesTail(sessionFile: string, maxMessages: number, trustedRoots: string[], trustedFiles: string[] = [], trustedFileRoot?: string): { messages: SessionTranscriptMessage[]; warnings: string[]; truncated: boolean } {
|
|
231
|
+
const tail = readContainedTextTail(sessionFile, Math.max(maxMessages * 4, maxMessages), trustedRoots, "session", trustedFiles, trustedFileRoot);
|
|
218
232
|
const warnings: string[] = [];
|
|
219
233
|
if (tail.error) warnings.push(`Session read failed for ${sessionFile}: ${tail.error}`);
|
|
220
234
|
const parsedMessages: SessionTranscriptMessage[] = [];
|
|
@@ -235,8 +249,8 @@ export function readSessionMessagesTail(sessionFile: string, maxMessages: number
|
|
|
235
249
|
return { messages, warnings, truncated: tail.truncated || parsedMessages.length > messages.length };
|
|
236
250
|
}
|
|
237
251
|
|
|
238
|
-
function readSessionTranscriptTail(sessionFile: string, maxLines: number, trustedRoots: string[]): { lines: string[]; warnings: string[] } {
|
|
239
|
-
const tail = readContainedTextTail(sessionFile, Math.max(maxLines * 4, maxLines), trustedRoots, "session");
|
|
252
|
+
function readSessionTranscriptTail(sessionFile: string, maxLines: number, trustedRoots: string[], trustedFiles: string[] = [], trustedFileRoot?: string): { lines: string[]; warnings: string[] } {
|
|
253
|
+
const tail = readContainedTextTail(sessionFile, Math.max(maxLines * 4, maxLines), trustedRoots, "session", trustedFiles, trustedFileRoot);
|
|
240
254
|
const warnings: string[] = [];
|
|
241
255
|
if (tail.error) warnings.push(`Session read failed for ${sessionFile}: ${tail.error}`);
|
|
242
256
|
const lines: string[] = [];
|
|
@@ -277,7 +291,8 @@ function formatActivityFacts(input: {
|
|
|
277
291
|
}
|
|
278
292
|
|
|
279
293
|
function foregroundModeName(control: ForegroundControl): string {
|
|
280
|
-
|
|
294
|
+
const currentDisplayName = control.sessionName?.trim() || control.currentAgent;
|
|
295
|
+
if (control.mode === "single" && currentDisplayName) return currentDisplayName;
|
|
281
296
|
return control.mode;
|
|
282
297
|
}
|
|
283
298
|
|
|
@@ -296,7 +311,8 @@ function formatForegroundFleetLines(controls: ForegroundControl[]): string[] {
|
|
|
296
311
|
toolCount: control.toolCount,
|
|
297
312
|
...(control.tokens !== undefined ? { tokens: { total: control.tokens } } : {}),
|
|
298
313
|
});
|
|
299
|
-
const
|
|
314
|
+
const currentDisplayName = control.sessionName?.trim() || control.currentAgent;
|
|
315
|
+
const current = currentDisplayName ? ` | ${currentDisplayName}${control.currentIndex !== undefined ? ` #${control.currentIndex}` : ""}` : "";
|
|
300
316
|
lines.push(`- ${control.runId} | running | ${foregroundModeName(control)}${current}${activity ? ` | ${activity}` : ""}`);
|
|
301
317
|
lines.push(` status: subagent({ action: "status", id: "${control.runId}" })`);
|
|
302
318
|
lines.push(" transcript: live in the expanded foreground result; persisted session transcript appears after completion when sessions are enabled.");
|
|
@@ -311,7 +327,7 @@ function formatDetachedForegroundFleetLines(runs: ForegroundRun[]): string[] {
|
|
|
311
327
|
const ordered = [...runs].sort((left, right) => right.updatedAt - left.updatedAt);
|
|
312
328
|
for (const run of ordered) {
|
|
313
329
|
const detachedChildren = run.children.filter((child) => child.status === "detached");
|
|
314
|
-
const childSummary = detachedChildren.map((child) => `${child
|
|
330
|
+
const childSummary = detachedChildren.map((child) => `${fleetChildDisplayName(child)} #${child.index}`).join(", ");
|
|
315
331
|
lines.push(`- ${run.runId} | detached | ${run.mode}${childSummary ? ` | ${childSummary}` : ""}`);
|
|
316
332
|
lines.push(` status: subagent({ action: "status", id: "${run.runId}" })`);
|
|
317
333
|
lines.push(` recovery: reply to the supervisor request first, then wait with subagent_wait({ id: "${run.runId}" }); do not resume or launch a replacement while any child remains detached.`);
|
|
@@ -332,7 +348,7 @@ function formatAsyncFleetLines(runs: AsyncRunSummary[]): string[] {
|
|
|
332
348
|
lines.push(` status: subagent({ action: "status", id: "${run.id}" })`);
|
|
333
349
|
lines.push(` transcript: subagent({ action: "status", id: "${run.id}", view: "transcript" })`);
|
|
334
350
|
for (const step of run.steps) {
|
|
335
|
-
const display =
|
|
351
|
+
const display = fleetStepDisplayName(step);
|
|
336
352
|
const stepContext = contextModeLabel(step.context);
|
|
337
353
|
const phase = step.phase ? `[${step.phase}] ` : "";
|
|
338
354
|
const stepActivity = formatActivityFacts(step);
|
|
@@ -429,7 +445,7 @@ function selectTranscriptStep(status: AsyncStatus, options: TranscriptOptions):
|
|
|
429
445
|
}
|
|
430
446
|
const step = selectedIndex !== undefined ? steps[selectedIndex] : undefined;
|
|
431
447
|
const hint = options.index === undefined && steps.length > 1
|
|
432
|
-
? `Tip: pass index to inspect a specific child transcript (${steps.map((candidate, index) => `${index}=${candidate
|
|
448
|
+
? `Tip: pass index to inspect a specific child transcript (${steps.map((candidate, index) => `${index}=${fleetChildDisplayName(candidate)}`).join(", ")}).`
|
|
433
449
|
: undefined;
|
|
434
450
|
return { index: selectedIndex, step, hint };
|
|
435
451
|
}
|
|
@@ -439,7 +455,7 @@ function stepStateLine(mode: SubagentRunMode, index: number | undefined, step: A
|
|
|
439
455
|
const modelThinking = formatModelThinking(step.model, step.thinking);
|
|
440
456
|
const context = contextModeLabel(step.context);
|
|
441
457
|
const parts = [
|
|
442
|
-
`${mode === "parallel" ? "Agent" : "Step"}: ${index} (${step
|
|
458
|
+
`${mode === "parallel" ? "Agent" : "Step"}: ${index} (${fleetChildDisplayName(step)})${context ? ` ${context}` : ""}`,
|
|
443
459
|
step.status,
|
|
444
460
|
formatActivityFacts(step),
|
|
445
461
|
modelThinking,
|
|
@@ -523,7 +539,7 @@ export function formatAsyncRunTranscript(status: AsyncStatus, asyncDir: string,
|
|
|
523
539
|
transcriptSource = "Recent output from status.json";
|
|
524
540
|
}
|
|
525
541
|
if (transcriptLines.length === 0 && sessionFile) {
|
|
526
|
-
const sessionTail = readSessionTranscriptTail(sessionFile, lineLimit, options.sessionRoots ?? []);
|
|
542
|
+
const sessionTail = readSessionTranscriptTail(sessionFile, lineLimit, options.sessionRoots ?? [], options.trustedSessionFiles, options.trustedSessionFileRoot);
|
|
527
543
|
transcriptLines = sessionTail.lines;
|
|
528
544
|
warnings.push(...sessionTail.warnings);
|
|
529
545
|
if (transcriptLines.length > 0) transcriptSource = `Session transcript tail from ${sessionFile}`;
|
|
@@ -547,14 +563,14 @@ export function formatNestedRunTranscript(run: NestedRunSummary, options: Transc
|
|
|
547
563
|
`Nested run: ${run.id}`,
|
|
548
564
|
`State: ${run.state}`,
|
|
549
565
|
run.mode ? `Mode: ${run.mode}` : undefined,
|
|
550
|
-
run.agent ? `Agent: ${run.agent}` : run.agents?.length ? `Agents: ${run.agents.join(", ")}` : undefined,
|
|
566
|
+
run.sessionName?.trim() ? `Agent: ${run.sessionName.trim()}` : run.agent ? `Agent: ${run.agent}` : run.agents?.length ? `Agents: ${run.agents.join(", ")}` : undefined,
|
|
551
567
|
].filter((line): line is string => Boolean(line));
|
|
552
568
|
appendKnownArtifacts(lines, { outputPaths: [], sessionFile: run.sessionFile });
|
|
553
569
|
if (!run.sessionFile) {
|
|
554
570
|
appendTranscriptBody(lines, "Transcript tail", [], false);
|
|
555
571
|
return safeTranscriptLines(lines);
|
|
556
572
|
}
|
|
557
|
-
const sessionTail = readSessionTranscriptTail(run.sessionFile, lineLimit, options.sessionRoots ?? []);
|
|
573
|
+
const sessionTail = readSessionTranscriptTail(run.sessionFile, lineLimit, options.sessionRoots ?? [], options.trustedSessionFiles, options.trustedSessionFileRoot);
|
|
558
574
|
if (sessionTail.warnings.length) {
|
|
559
575
|
lines.push("Warnings:");
|
|
560
576
|
for (const warning of sessionTail.warnings) lines.push(` ${warning}`);
|
|
@@ -573,14 +589,14 @@ export function formatAsyncResultTranscript(data: {
|
|
|
573
589
|
sessionFile?: string;
|
|
574
590
|
agent?: string;
|
|
575
591
|
exitCode?: number | null;
|
|
576
|
-
results?: Array<{ agent?: string; output?: string; summary?: string; sessionFile?: string; state?: string; success?: boolean; exitCode?: number | null }>;
|
|
592
|
+
results?: Array<{ agent?: string; sessionName?: string; output?: string; summary?: string; sessionFile?: string; state?: string; success?: boolean; exitCode?: number | null }>;
|
|
577
593
|
}, resultPath: string, options: TranscriptOptions = {}): string {
|
|
578
594
|
const lineLimit = transcriptLineLimit(options.lines);
|
|
579
595
|
const runId = data.runId ?? data.id ?? path.basename(resultPath, ".json");
|
|
580
596
|
const children = Array.isArray(data.results)
|
|
581
597
|
? data.results
|
|
582
598
|
: data.agent
|
|
583
|
-
? [{ agent: data.agent, output: data.output, summary: data.summary, sessionFile: data.sessionFile, state: data.state, success: data.success, exitCode: data.exitCode }]
|
|
599
|
+
? [{ agent: data.agent, sessionName: undefined, output: data.output, summary: data.summary, sessionFile: data.sessionFile, state: data.state, success: data.success, exitCode: data.exitCode }]
|
|
584
600
|
: [];
|
|
585
601
|
let index = options.index;
|
|
586
602
|
if (index !== undefined && !Number.isInteger(index)) throw new Error("Transcript index must be an integer.");
|
|
@@ -595,8 +611,8 @@ export function formatAsyncResultTranscript(data: {
|
|
|
595
611
|
const lines = [
|
|
596
612
|
`Run: ${runId}`,
|
|
597
613
|
`State: ${data.state ?? (data.success ? "complete" : "failed")}`,
|
|
598
|
-
index !== undefined && child ? `Child: ${index} (${child
|
|
599
|
-
index === undefined && children.length > 1 ? `Tip: pass index to inspect a specific child transcript (${children.map((candidate, childIndex) => `${childIndex}=${candidate
|
|
614
|
+
index !== undefined && child ? `Child: ${index} (${fleetChildDisplayName(child)})` : undefined,
|
|
615
|
+
index === undefined && children.length > 1 ? `Tip: pass index to inspect a specific child transcript (${children.map((candidate, childIndex) => `${childIndex}=${fleetChildDisplayName(candidate)}`).join(", ")}).` : undefined,
|
|
600
616
|
].filter((line): line is string => Boolean(line));
|
|
601
617
|
appendKnownArtifacts(lines, { outputPaths: [], sessionFile, resultPath });
|
|
602
618
|
appendTranscriptBody(lines, "Result transcript tail", transcriptLines.filter((line) => line.trim()), output.split(/\r?\n/).length > lineLimit);
|
|
@@ -218,19 +218,19 @@ function readOutputArtifact(outputPath: string): { output?: string; errorText?:
|
|
|
218
218
|
}
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
-
function readSessionBackedOutput(sessionPath: string, trustedRoots: string[]): { output?: string } {
|
|
222
|
-
if (trustedRoots.length === 0) return {};
|
|
221
|
+
function readSessionBackedOutput(sessionPath: string, trustedRoots: string[], trustedSessionFileRoot?: string): { output?: string } {
|
|
222
|
+
if (trustedRoots.length === 0 && !trustedSessionFileRoot) return {};
|
|
223
223
|
// The archive retains the child's session file as its output record. The
|
|
224
224
|
// final answer is the terminal assistant message's text — all text parts
|
|
225
225
|
// of that one session record, not just the last part.
|
|
226
|
-
const tail = readSessionMessagesTail(sessionPath, MAX_MESSAGE_LINES, trustedRoots);
|
|
226
|
+
const tail = readSessionMessagesTail(sessionPath, MAX_MESSAGE_LINES, trustedRoots, [sessionPath], trustedSessionFileRoot);
|
|
227
227
|
const last = tail.messages.findLast((message) => message.role === "assistant" && message.kind === "text");
|
|
228
228
|
if (!last) return {};
|
|
229
229
|
const parts = tail.messages.filter((message) => message.recordIndex === last.recordIndex && message.kind === "text");
|
|
230
230
|
return { output: parts.map((part) => part.text).join("\n") };
|
|
231
231
|
}
|
|
232
232
|
|
|
233
|
-
function readResultOutput(resultsDir: string, sessionId: string, runId: string, stepIndex: number | undefined, trustedRoots: string[], stepAgent: string | undefined, now: () => number): { output?: string; errorText?: string } {
|
|
233
|
+
function readResultOutput(resultsDir: string, sessionId: string, runId: string, stepIndex: number | undefined, trustedRoots: string[], stepAgent: string | undefined, now: () => number, trustedSessionFileRoot?: string): { output?: string; errorText?: string } {
|
|
234
234
|
const resultPath = resultPayloadPathForSessionRun(resultsDir, sessionId, runId);
|
|
235
235
|
if (resultPath) return resultOutput(JSON.parse(fs.readFileSync(resultPath, "utf-8")) as unknown, stepIndex);
|
|
236
236
|
// Read the raw record first: readCompletionReplay best-effort deletes
|
|
@@ -284,7 +284,7 @@ function readResultOutput(resultsDir: string, sessionId: string, runId: string,
|
|
|
284
284
|
if (artifactPath) return readOutputArtifact(artifactPath);
|
|
285
285
|
const sessionEntry = archive?.entries.find((entry) => entry.source === "session" && matches(entry));
|
|
286
286
|
const sessionPath = sessionEntry?.source === "session" ? sessionEntry.path : undefined;
|
|
287
|
-
if (sessionPath) return readSessionBackedOutput(sessionPath, trustedRoots);
|
|
287
|
+
if (sessionPath) return readSessionBackedOutput(sessionPath, trustedRoots, trustedSessionFileRoot);
|
|
288
288
|
const output = archive?.entries.find((entry) => entry.source === "result-tail" && matches(entry))?.text;
|
|
289
289
|
return output ? { output } : {};
|
|
290
290
|
}
|
|
@@ -377,8 +377,8 @@ export function buildInspectReply(request: InspectRequest, deps: InspectDeps = {
|
|
|
377
377
|
|
|
378
378
|
let messages: InspectReplyMessage[] | undefined;
|
|
379
379
|
let task: string | undefined;
|
|
380
|
-
if (sessionFile && trustedRoots.length > 0) {
|
|
381
|
-
const tail = readSessionMessagesTail(sessionFile, lineLimit, trustedRoots);
|
|
380
|
+
if (sessionFile && (trustedRoots.length > 0 || deps.state?.trustedSessionFileRoot)) {
|
|
381
|
+
const tail = readSessionMessagesTail(sessionFile, lineLimit, trustedRoots, [sessionFile], deps.state?.trustedSessionFileRoot);
|
|
382
382
|
if (tail.messages.length > 0) {
|
|
383
383
|
messages = tail.messages.map(toReplyMessage);
|
|
384
384
|
// The delegated task is the child session's first user message, but
|
|
@@ -393,7 +393,7 @@ export function buildInspectReply(request: InspectRequest, deps: InspectDeps = {
|
|
|
393
393
|
}
|
|
394
394
|
}
|
|
395
395
|
|
|
396
|
-
const result = readResultOutput(resultsDir, currentSessionId, node.status.runId, node.stepIndex, trustedRoots, step?.agent, deps.now ?? Date.now);
|
|
396
|
+
const result = readResultOutput(resultsDir, currentSessionId, node.status.runId, node.stepIndex, trustedRoots, step?.agent, deps.now ?? Date.now, deps.state?.trustedSessionFileRoot);
|
|
397
397
|
const failedText = step?.error ?? node.status.error;
|
|
398
398
|
if (result.output === undefined && result.errorText === undefined && failedText !== undefined) {
|
|
399
399
|
return errorReply(request, "internal", "Inspection could not read the async run artifacts.");
|
|
@@ -15,7 +15,21 @@ import {
|
|
|
15
15
|
resolveCompletionBatchConfig,
|
|
16
16
|
} from "./completion-batcher.ts";
|
|
17
17
|
import { SUBAGENT_ASYNC_COMPLETE_EVENT, SUBAGENT_FOREGROUND_COMPLETE_EVENT, type ParallelHandoffReference, type ScheduleOrigin, type SubagentState } from "../../shared/types.ts";
|
|
18
|
+
import { safeTerminalText } from "../../shared/display-text.ts";
|
|
19
|
+
import { resolveSubagentResultStatus } from "../../intercom/result-intercom.ts";
|
|
18
20
|
import { isUnexplainedProcessSignal } from "../shared/process-signal.ts";
|
|
21
|
+
import type { ResultDeliveryOwnership } from "./result-delivery-ownership.ts";
|
|
22
|
+
|
|
23
|
+
export interface SubagentNotifyChildOutput {
|
|
24
|
+
workflowKey?: string;
|
|
25
|
+
runId?: string;
|
|
26
|
+
agent?: string;
|
|
27
|
+
status: string;
|
|
28
|
+
savedOutputPath?: string;
|
|
29
|
+
preview: string;
|
|
30
|
+
previewTruncated?: boolean;
|
|
31
|
+
previewUnavailableReason?: string;
|
|
32
|
+
}
|
|
19
33
|
|
|
20
34
|
export interface SubagentNotifyDetails {
|
|
21
35
|
agent: string;
|
|
@@ -26,6 +40,7 @@ export interface SubagentNotifyDetails {
|
|
|
26
40
|
durationMs?: number;
|
|
27
41
|
workflowRunId?: string;
|
|
28
42
|
childRuns?: Array<{ runId: string; workflowKey?: string; agent?: string; status?: string }>;
|
|
43
|
+
childOutputs?: SubagentNotifyChildOutput[];
|
|
29
44
|
reconciledFromDetachedChild?: string;
|
|
30
45
|
sessionLabel?: string;
|
|
31
46
|
sessionValue?: string;
|
|
@@ -56,7 +71,14 @@ export interface CompletionNotification {
|
|
|
56
71
|
workflowKey?: string;
|
|
57
72
|
agent?: string;
|
|
58
73
|
status?: string;
|
|
74
|
+
state?: string;
|
|
59
75
|
success?: boolean;
|
|
76
|
+
output?: string;
|
|
77
|
+
structuredOutput?: unknown;
|
|
78
|
+
outputState?: "present" | "absent" | "unknown";
|
|
79
|
+
outputReference?: string | { path?: string };
|
|
80
|
+
artifactPaths?: { outputPath?: string };
|
|
81
|
+
detached?: boolean;
|
|
60
82
|
exitCode?: number | null;
|
|
61
83
|
processSignal?: string | null;
|
|
62
84
|
interrupted?: boolean;
|
|
@@ -91,6 +113,7 @@ export interface RegisterSubagentNotifyOptions {
|
|
|
91
113
|
batchConfig?: CompletionBatchConfig;
|
|
92
114
|
timers?: NotifyTimerApi;
|
|
93
115
|
now?: () => number;
|
|
116
|
+
ownership?: Pick<ResultDeliveryOwnership, "owns">;
|
|
94
117
|
}
|
|
95
118
|
|
|
96
119
|
export interface CompletionNotifier {
|
|
@@ -98,6 +121,115 @@ export interface CompletionNotifier {
|
|
|
98
121
|
dispose(): void;
|
|
99
122
|
}
|
|
100
123
|
|
|
124
|
+
const CHILD_OUTPUT_PREVIEW_MAX_BYTES = 4 * 1024;
|
|
125
|
+
const CHILD_OUTPUT_PREVIEW_COUNT = 8;
|
|
126
|
+
const PREVIEW_TRUNCATION_MARKER = "...[preview truncated]";
|
|
127
|
+
type CompletionChild = NonNullable<CompletionNotification["results"]>[number];
|
|
128
|
+
|
|
129
|
+
function truncateUtf8Head(value: string, maxBytes: number): { text: string; truncated: boolean } {
|
|
130
|
+
const bytes = Buffer.from(value, "utf8");
|
|
131
|
+
if (bytes.length <= maxBytes) return { text: value, truncated: false };
|
|
132
|
+
const markerBytes = Buffer.byteLength(PREVIEW_TRUNCATION_MARKER, "utf8");
|
|
133
|
+
const contentBytes = Math.max(0, maxBytes - markerBytes);
|
|
134
|
+
let end = contentBytes;
|
|
135
|
+
while (end > 0 && (bytes[end]! & 0xc0) === 0x80) end -= 1;
|
|
136
|
+
return {
|
|
137
|
+
text: `${bytes.subarray(0, end).toString("utf8")}${PREVIEW_TRUNCATION_MARKER}`,
|
|
138
|
+
truncated: true,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function boundedSafeText(value: string, maxBytes = 1_024): string {
|
|
143
|
+
return truncateUtf8Head(safeTerminalText(value).replace(/\n/g, "\\n"), maxBytes).text;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function outputPathFromReference(value: CompletionChild["outputReference"]): string | undefined {
|
|
147
|
+
if (typeof value === "string" && value.trim()) return value.trim();
|
|
148
|
+
if (value && typeof value === "object" && typeof value.path === "string" && value.path.trim()) return value.path.trim();
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function childSavedOutputPath(child: CompletionChild): string | undefined {
|
|
153
|
+
return outputPathFromReference(child.outputReference);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function childStatus(child: CompletionChild, workflowState?: string): string {
|
|
157
|
+
const knownStatus = child.status === "complete"
|
|
158
|
+
? "completed"
|
|
159
|
+
: child.status === "completed" || child.status === "failed" || child.status === "paused" || child.status === "stopped" || child.status === "detached"
|
|
160
|
+
? child.status
|
|
161
|
+
: undefined;
|
|
162
|
+
if (knownStatus) return knownStatus;
|
|
163
|
+
return resolveSubagentResultStatus({
|
|
164
|
+
success: child.success,
|
|
165
|
+
state: child.state ?? (child.success === undefined ? workflowState : undefined),
|
|
166
|
+
interrupted: child.interrupted,
|
|
167
|
+
detached: child.detached,
|
|
168
|
+
processSignal: child.processSignal,
|
|
169
|
+
timedOut: child.timedOut,
|
|
170
|
+
stopped: child.stopped,
|
|
171
|
+
turnBudgetExceeded: child.turnBudgetExceeded,
|
|
172
|
+
exitCode: typeof child.exitCode === "number" ? child.exitCode : undefined,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function structuredOutputText(value: unknown): string | undefined {
|
|
177
|
+
if (value === undefined) return undefined;
|
|
178
|
+
try {
|
|
179
|
+
const serialized = JSON.stringify(value, null, 2);
|
|
180
|
+
return typeof serialized === "string" ? serialized : undefined;
|
|
181
|
+
} catch {
|
|
182
|
+
return undefined;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function childInlinePreview(child: CompletionChild): { preview?: string; truncated?: boolean; unavailableReason?: string } {
|
|
187
|
+
const output = typeof child.output === "string" ? child.output : "";
|
|
188
|
+
const outputReference = childSavedOutputPath(child);
|
|
189
|
+
const referenceOnly = Boolean(outputReference && output.trim().startsWith("Output saved to:"));
|
|
190
|
+
const raw = child.outputState === "absent" || referenceOnly ? structuredOutputText(child.structuredOutput) : output || structuredOutputText(child.structuredOutput);
|
|
191
|
+
if (!raw?.trim()) {
|
|
192
|
+
return { unavailableReason: referenceOnly ? "saved output is file-only" : "no safe inline output" };
|
|
193
|
+
}
|
|
194
|
+
const safe = safeTerminalText(raw);
|
|
195
|
+
if (!safe.trim()) return { unavailableReason: "no safe inline output" };
|
|
196
|
+
const bounded = truncateUtf8Head(safe, CHILD_OUTPUT_PREVIEW_MAX_BYTES);
|
|
197
|
+
return { preview: bounded.text, ...(bounded.truncated ? { truncated: true } : {}) };
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function formatChildOutputBlock(children: SubagentNotifyChildOutput[] | undefined): string | undefined {
|
|
201
|
+
if (!children?.length) return undefined;
|
|
202
|
+
const lines = ["Child outputs:"];
|
|
203
|
+
for (let index = 0; index < children.length; index++) {
|
|
204
|
+
const child = children[index]!;
|
|
205
|
+
const key = child.workflowKey ? boundedSafeText(child.workflowKey) : "unavailable";
|
|
206
|
+
const runId = child.runId ? boundedSafeText(child.runId) : "unavailable";
|
|
207
|
+
const status = boundedSafeText(child.status) || "unavailable";
|
|
208
|
+
lines.push(`- key=${key} run=${runId} status=${status}`);
|
|
209
|
+
lines.push(` Saved output: ${child.savedOutputPath ? boundedSafeText(child.savedOutputPath) : "unavailable"}`);
|
|
210
|
+
if (index >= CHILD_OUTPUT_PREVIEW_COUNT) {
|
|
211
|
+
lines.push(" Preview: unavailable (notice preview budget exceeded)");
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
if (!child.preview) {
|
|
215
|
+
lines.push(` Preview: unavailable (${child.previewUnavailableReason ?? "no safe inline output"})`);
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
lines.push(" Preview:");
|
|
219
|
+
for (const line of child.preview.split("\n")) lines.push(` | ${line}`);
|
|
220
|
+
}
|
|
221
|
+
if (children.length > CHILD_OUTPUT_PREVIEW_COUNT) {
|
|
222
|
+
lines.push(`- ${children.length - CHILD_OUTPUT_PREVIEW_COUNT} additional child preview(s) omitted by notice budget; child run metadata is retained below.`);
|
|
223
|
+
}
|
|
224
|
+
return lines.join("\n");
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function formatResultPreview(details: SubagentNotifyDetails): string {
|
|
228
|
+
const summary = details.resultPreview.trim() ? details.resultPreview : "(no output)";
|
|
229
|
+
const childOutputs = formatChildOutputBlock(details.childOutputs);
|
|
230
|
+
return childOutputs ? `${summary}\n\n${childOutputs}` : summary;
|
|
231
|
+
}
|
|
232
|
+
|
|
101
233
|
function formatSessionLine(details: SubagentNotifyDetails): string | undefined {
|
|
102
234
|
if (!details.sessionValue) return undefined;
|
|
103
235
|
return details.sessionLabel ? `${details.sessionLabel}: ${details.sessionValue}` : details.sessionValue;
|
|
@@ -129,7 +261,7 @@ export function formatSingleCompletion(details: SubagentNotifyDetails): string {
|
|
|
129
261
|
"",
|
|
130
262
|
scheduleLine,
|
|
131
263
|
scheduleLine ? "" : undefined,
|
|
132
|
-
|
|
264
|
+
formatResultPreview(details),
|
|
133
265
|
details.handoffPath ? "" : undefined,
|
|
134
266
|
details.handoffPath ? `Parallel handoff: ${details.handoffPath}` : undefined,
|
|
135
267
|
correlationLines.length && !details.handoffPath ? "" : undefined,
|
|
@@ -216,7 +348,7 @@ export function formatGroupedCompletion(details: SubagentNotifyDetails[]): strin
|
|
|
216
348
|
if (!detail) continue;
|
|
217
349
|
const sessionLine = formatSessionLine(detail);
|
|
218
350
|
blocks.push(`${index + 1}. ${detail.agent}${detail.taskInfo ?? ""}${detail.scheduleOrigin ? ` — scheduled run from ${detail.scheduleOrigin.name ?? detail.scheduleOrigin.id} (schedule ${detail.scheduleOrigin.id})` : ""}`);
|
|
219
|
-
blocks.push(
|
|
351
|
+
blocks.push(formatResultPreview(detail));
|
|
220
352
|
if (detail.handoffPath) blocks.push(`Parallel handoff: ${detail.handoffPath}`);
|
|
221
353
|
blocks.push(...formatCorrelationLines(detail));
|
|
222
354
|
if (sessionLine) blocks.push(sessionLine);
|
|
@@ -228,6 +360,8 @@ export function formatGroupedCompletion(details: SubagentNotifyDetails[]): strin
|
|
|
228
360
|
interface PendingCompletion {
|
|
229
361
|
key: string;
|
|
230
362
|
details: SubagentNotifyDetails;
|
|
363
|
+
sessionId: string;
|
|
364
|
+
completionOwnerId: unknown;
|
|
231
365
|
triggerTurn: boolean;
|
|
232
366
|
resolve(accepted: boolean): void;
|
|
233
367
|
}
|
|
@@ -271,6 +405,7 @@ export function buildCompletionDetails(result: CompletionNotification): Subagent
|
|
|
271
405
|
const paused = !stopped && !result.success && (
|
|
272
406
|
result.exitCode === 0
|
|
273
407
|
|| result.state === "paused"
|
|
408
|
+
|| result.interrupted === true
|
|
274
409
|
|| summary.startsWith("Paused after interrupt.")
|
|
275
410
|
);
|
|
276
411
|
const status = stopped ? "stopped" : paused ? "paused" : result.success ? "completed" : "failed";
|
|
@@ -286,14 +421,34 @@ export function buildCompletionDetails(result: CompletionNotification): Subagent
|
|
|
286
421
|
const rawRunId = typeof result.runId === "string" ? result.runId : typeof result.id === "string" ? result.id : undefined;
|
|
287
422
|
const workflowRunId = (result.mode === "workflow" || agent === "workflow") && rawRunId ? rawRunId : undefined;
|
|
288
423
|
const childRuns = result.results?.flatMap((child) => {
|
|
289
|
-
|
|
424
|
+
const runId = typeof child.runId === "string" && child.runId.trim() ? child.runId.trim() : undefined;
|
|
425
|
+
const workflowKey = typeof child.workflowKey === "string" && child.workflowKey.trim() ? child.workflowKey.trim() : undefined;
|
|
426
|
+
if (!runId && (!workflowRunId || !workflowKey)) return [];
|
|
290
427
|
return [{
|
|
291
|
-
runId:
|
|
292
|
-
...(
|
|
428
|
+
runId: runId ?? "unavailable",
|
|
429
|
+
...(workflowKey ? { workflowKey } : {}),
|
|
293
430
|
...(typeof child.agent === "string" ? { agent: child.agent } : {}),
|
|
294
|
-
|
|
431
|
+
status: childStatus(child, workflowRunId ? result.state : undefined),
|
|
295
432
|
}];
|
|
296
433
|
}) ?? [];
|
|
434
|
+
const childOutputs = workflowRunId && result.results?.length
|
|
435
|
+
? result.results.map((child) => {
|
|
436
|
+
const inline = childInlinePreview(child);
|
|
437
|
+
const workflowKey = typeof child.workflowKey === "string" && child.workflowKey.trim() ? child.workflowKey.trim() : undefined;
|
|
438
|
+
const runId = typeof child.runId === "string" && child.runId.trim() ? child.runId.trim() : undefined;
|
|
439
|
+
const savedOutputPath = childSavedOutputPath(child);
|
|
440
|
+
return {
|
|
441
|
+
...(workflowKey ? { workflowKey } : {}),
|
|
442
|
+
...(runId ? { runId } : {}),
|
|
443
|
+
...(typeof child.agent === "string" ? { agent: child.agent } : {}),
|
|
444
|
+
status: childStatus(child, result.state),
|
|
445
|
+
...(savedOutputPath ? { savedOutputPath } : {}),
|
|
446
|
+
...(inline.preview ? { preview: inline.preview } : { preview: "" }),
|
|
447
|
+
...(inline.truncated ? { previewTruncated: true } : {}),
|
|
448
|
+
...(inline.unavailableReason ? { previewUnavailableReason: inline.unavailableReason } : {}),
|
|
449
|
+
};
|
|
450
|
+
})
|
|
451
|
+
: undefined;
|
|
297
452
|
const reconciledFromDetachedChild = typeof result.reconciledFromDetachedChild === "string" ? result.reconciledFromDetachedChild : undefined;
|
|
298
453
|
const session =
|
|
299
454
|
result.shareUrl
|
|
@@ -318,6 +473,7 @@ export function buildCompletionDetails(result: CompletionNotification): Subagent
|
|
|
318
473
|
...(handoffPath ? { handoffPath } : {}),
|
|
319
474
|
...(workflowRunId ? { workflowRunId } : {}),
|
|
320
475
|
...(childRuns.length ? { childRuns } : {}),
|
|
476
|
+
...(childOutputs?.length ? { childOutputs } : {}),
|
|
321
477
|
...(reconciledFromDetachedChild ? { reconciledFromDetachedChild } : {}),
|
|
322
478
|
...(session ? { sessionLabel: session.label, sessionValue: session.value } : {}),
|
|
323
479
|
};
|
|
@@ -335,6 +491,10 @@ export default function registerSubagentNotify(
|
|
|
335
491
|
const batchConfig = resolveCompletionBatchConfig(options.batchConfig);
|
|
336
492
|
const batchers = new Map<string, CompletionBatcher<PendingCompletion>>();
|
|
337
493
|
let disposed = false;
|
|
494
|
+
const ownsResult = options.ownership?.owns
|
|
495
|
+
?? ((sessionId: string, completionOwnerId: unknown) => sessionId === state.currentSessionId
|
|
496
|
+
&& typeof completionOwnerId === "string"
|
|
497
|
+
&& completionOwnerId === state.completionOwnerId);
|
|
338
498
|
|
|
339
499
|
const settle = (items: PendingCompletion[], accepted: boolean) => {
|
|
340
500
|
for (const item of items) {
|
|
@@ -343,7 +503,18 @@ export default function registerSubagentNotify(
|
|
|
343
503
|
item.resolve(accepted);
|
|
344
504
|
}
|
|
345
505
|
};
|
|
346
|
-
const emit = (items: PendingCompletion[]) =>
|
|
506
|
+
const emit = (items: PendingCompletion[]) => {
|
|
507
|
+
const accepted: PendingCompletion[] = [];
|
|
508
|
+
const rejected: PendingCompletion[] = [];
|
|
509
|
+
for (const item of items) {
|
|
510
|
+
const owned = item.details.source === "foreground"
|
|
511
|
+
? item.sessionId === state.currentSessionId
|
|
512
|
+
: ownsResult(item.sessionId, item.completionOwnerId);
|
|
513
|
+
(owned ? accepted : rejected).push(item);
|
|
514
|
+
}
|
|
515
|
+
settle(rejected, false);
|
|
516
|
+
settle(accepted, sendCompletion(pi, accepted));
|
|
517
|
+
};
|
|
347
518
|
const getBatcher = (result: CompletionNotification) => {
|
|
348
519
|
const key = completionBatchKey(result);
|
|
349
520
|
let batcher = batchers.get(key);
|
|
@@ -360,8 +531,10 @@ export default function registerSubagentNotify(
|
|
|
360
531
|
};
|
|
361
532
|
|
|
362
533
|
const deliver = (result: CompletionNotification): Promise<boolean> => {
|
|
363
|
-
if (disposed || typeof result.sessionId !== "string"
|
|
364
|
-
if (result.source
|
|
534
|
+
if (disposed || typeof result.sessionId !== "string") return Promise.resolve(false);
|
|
535
|
+
if (result.source === "foreground") {
|
|
536
|
+
if (result.sessionId !== state.currentSessionId) return Promise.resolve(false);
|
|
537
|
+
} else if (!ownsResult(result.sessionId, result.completionOwnerId)) return Promise.resolve(false);
|
|
365
538
|
if (result.intercomDelivered === true) return Promise.resolve(true);
|
|
366
539
|
const key = buildCompletionKey(result, "notify");
|
|
367
540
|
const seenAt = seen.get(key);
|
|
@@ -376,6 +549,8 @@ export default function registerSubagentNotify(
|
|
|
376
549
|
const item: PendingCompletion = {
|
|
377
550
|
key,
|
|
378
551
|
details,
|
|
552
|
+
sessionId: result.sessionId,
|
|
553
|
+
completionOwnerId: result.completionOwnerId,
|
|
379
554
|
triggerTurn: result.triggerTurn !== false,
|
|
380
555
|
resolve,
|
|
381
556
|
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { SubagentState } from "../../shared/types.ts";
|
|
2
|
+
|
|
3
|
+
const MAX_CLAIMED_PREDECESSOR_SESSIONS = 8;
|
|
4
|
+
|
|
5
|
+
type ResultDeliveryState = Pick<SubagentState, "currentSessionId" | "completionOwnerId">;
|
|
6
|
+
|
|
7
|
+
export interface ResultDeliveryOwnership {
|
|
8
|
+
owns(sessionId: string, completionOwnerId: unknown): boolean;
|
|
9
|
+
claimedSessionIds(): readonly string[];
|
|
10
|
+
claimPredecessor(previousSessionFile: string | undefined, previousRuntimeSessionId: string | null): boolean;
|
|
11
|
+
clear(): void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function createResultDeliveryOwnership(state: ResultDeliveryState): ResultDeliveryOwnership {
|
|
15
|
+
const claimed = new Map<string, string>();
|
|
16
|
+
|
|
17
|
+
const currentOwner = (): string | undefined => typeof state.completionOwnerId === "string" && state.completionOwnerId
|
|
18
|
+
? state.completionOwnerId
|
|
19
|
+
: undefined;
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
owns(sessionId, completionOwnerId) {
|
|
23
|
+
const owner = currentOwner();
|
|
24
|
+
if (!owner || completionOwnerId !== owner) return false;
|
|
25
|
+
return sessionId === state.currentSessionId || claimed.get(sessionId) === owner;
|
|
26
|
+
},
|
|
27
|
+
claimedSessionIds() {
|
|
28
|
+
const owner = currentOwner();
|
|
29
|
+
if (!owner) return [];
|
|
30
|
+
return [...claimed].flatMap(([sessionId, claimedOwner]) => claimedOwner === owner ? [sessionId] : []);
|
|
31
|
+
},
|
|
32
|
+
claimPredecessor(previousSessionFile, previousRuntimeSessionId) {
|
|
33
|
+
const owner = currentOwner();
|
|
34
|
+
if (!owner || !previousSessionFile || !previousRuntimeSessionId) return false;
|
|
35
|
+
if (previousSessionFile !== previousRuntimeSessionId || state.currentSessionId !== previousRuntimeSessionId) return false;
|
|
36
|
+
claimed.delete(previousRuntimeSessionId);
|
|
37
|
+
claimed.set(previousRuntimeSessionId, owner);
|
|
38
|
+
while (claimed.size > MAX_CLAIMED_PREDECESSOR_SESSIONS) claimed.delete(claimed.keys().next().value!);
|
|
39
|
+
return true;
|
|
40
|
+
},
|
|
41
|
+
clear() {
|
|
42
|
+
claimed.clear();
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|