pi-crew 0.9.55 → 0.9.57
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/AGENTS.md +1 -1
- package/CHANGELOG.md +58 -0
- package/README.md +53 -5
- package/dist/index.mjs +5666 -4370
- package/docs/README.md +54 -0
- package/package.json +12 -13
- package/skills/real-test-pi-crew/SKILL.md +93 -3
- package/src/agents/discover-agents.ts +68 -10
- package/src/benchmark/feedback-loop.ts +1 -1
- package/src/config/config.ts +2 -1
- package/src/config/types.ts +12 -0
- package/src/extension/action-suggestions.ts +16 -63
- package/src/extension/async-notifier.ts +3 -3
- package/src/extension/command-completions.ts +2 -2
- package/src/extension/crew-cleanup.ts +3 -3
- package/src/extension/crew-vibes/footer.ts +4 -2
- package/src/extension/cross-extension-rpc.ts +10 -5
- package/src/extension/knowledge-injection.ts +57 -10
- package/src/extension/register.ts +2 -2
- package/src/extension/registration/artifact-cleanup.ts +41 -3
- package/src/extension/registration/commands.ts +4 -4
- package/src/extension/registration/context-builder.ts +10 -10
- package/src/extension/registration/crash-recovery-cache.ts +3 -3
- package/src/extension/registration/foreground-run-controller.ts +1 -1
- package/src/extension/registration/lazy-configurers.ts +2 -2
- package/src/extension/registration/lifecycle-handlers.ts +12 -12
- package/src/extension/registration/lifecycle.ts +2 -2
- package/src/extension/registration/observability.ts +2 -2
- package/src/extension/registration/registration-types.ts +3 -3
- package/src/extension/registration/runtime-cleanup.ts +1 -1
- package/src/extension/registration/subagent-helpers.ts +2 -2
- package/src/extension/registration/subagent-manager-setup.ts +2 -2
- package/src/extension/registration/subagent-tools.ts +21 -16
- package/src/extension/registration/team-tool.ts +109 -17
- package/src/extension/registration/viewers.ts +3 -4
- package/src/extension/registration/wire-cross-extension.ts +7 -7
- package/src/extension/rpc-hmac.ts +3 -2
- package/src/extension/run-bundle-schema.ts +13 -4
- package/src/extension/run-export.ts +2 -2
- package/src/extension/run-index.ts +2 -3
- package/src/extension/run-maintenance.ts +57 -1
- package/src/extension/team-manager-command.ts +3 -1
- package/src/extension/team-tool/anchor.ts +8 -2
- package/src/extension/team-tool/api.ts +117 -39
- package/src/extension/team-tool/cancel.ts +23 -8
- package/src/extension/team-tool/chain-executor.ts +1 -1
- package/src/extension/team-tool/dispatch/automate.ts +17 -2
- package/src/extension/team-tool/dispatch/control.ts +17 -2
- package/src/extension/team-tool/dispatch/manage.ts +34 -2
- package/src/extension/team-tool/dispatch/run.ts +17 -2
- package/src/extension/team-tool/dispatch/status.ts +37 -5
- package/src/extension/team-tool/doctor.ts +2 -2
- package/src/extension/team-tool/explain.ts +1 -1
- package/src/extension/team-tool/goal-wrap.ts +5 -5
- package/src/extension/team-tool/goal.ts +30 -9
- package/src/extension/team-tool/handle-schedule.ts +37 -19
- package/src/extension/team-tool/inspect.ts +21 -5
- package/src/extension/team-tool/lifecycle-actions.ts +53 -10
- package/src/extension/team-tool/parallel-dispatch.ts +14 -5
- package/src/extension/team-tool/param-error.ts +138 -0
- package/src/extension/team-tool/respond.ts +20 -6
- package/src/extension/team-tool/run.ts +27 -17
- package/src/extension/team-tool/status.ts +17 -6
- package/src/extension/team-tool.ts +26 -19
- package/src/hooks/registry.ts +1 -1
- package/src/i18n.ts +22 -0
- package/src/observability/event-bus.ts +1 -1
- package/src/prompt/prompt-runtime.ts +2 -2
- package/src/runtime/README.md +35 -0
- package/src/runtime/agent-control.ts +1 -1
- package/src/runtime/anchor-manager.ts +0 -2
- package/src/runtime/async-runner.ts +1 -1
- package/src/runtime/attention-events.ts +3 -2
- package/src/runtime/auto-summarize.ts +0 -2
- package/src/runtime/background-runner.ts +103 -30
- package/src/runtime/{crew-broker-child.ts → broker/crew-broker-child.ts} +2 -2
- package/src/runtime/{crew-broker-client.ts → broker/crew-broker-client.ts} +4 -7
- package/src/runtime/{crew-broker.ts → broker/crew-broker.ts} +13 -21
- package/src/runtime/chain-runner.ts +50 -5
- package/src/runtime/{child-pi-constants.ts → child-pi/child-pi-constants.ts} +1 -1
- package/src/runtime/{child-pi-kill.ts → child-pi/child-pi-kill.ts} +3 -3
- package/src/runtime/{child-pi-spawn.ts → child-pi/child-pi-spawn.ts} +28 -12
- package/src/runtime/{child-pi-steering.ts → child-pi/child-pi-steering.ts} +1 -1
- package/src/runtime/{child-pi-streams.ts → child-pi/child-pi-streams.ts} +23 -4
- package/src/runtime/{child-pi-transcript.ts → child-pi/child-pi-transcript.ts} +6 -6
- package/src/runtime/{child-pi.ts → child-pi/child-pi.ts} +47 -78
- package/src/runtime/compaction/compact-stages/bounded-tail.ts +84 -0
- package/src/runtime/{compact-stages → compaction/compact-stages}/index.ts +2 -2
- package/src/runtime/{compaction-summary.ts → compaction/compaction-summary.ts} +3 -3
- package/src/runtime/{tool-output-pruner.ts → compaction/tool-output-pruner.ts} +1 -1
- package/src/runtime/crew-agent-records.ts +48 -2
- package/src/runtime/custom-tools/irc-tool.ts +2 -2
- package/src/runtime/delivery-coordinator.ts +0 -3
- package/src/runtime/diagnostic-export.ts +5 -4
- package/src/runtime/foreground-control.ts +1 -1
- package/src/runtime/foreground-watchdog.ts +1 -1
- package/src/runtime/{adaptive-plan.ts → goal-workflow/adaptive-plan.ts} +8 -8
- package/src/runtime/{dynamic-workflow-context.ts → goal-workflow/dynamic-workflow-context.ts} +16 -16
- package/src/runtime/{dynamic-workflow-runner.ts → goal-workflow/dynamic-workflow-runner.ts} +10 -10
- package/src/runtime/{goal-achievement.ts → goal-workflow/goal-achievement.ts} +3 -3
- package/src/runtime/{goal-evaluator.ts → goal-workflow/goal-evaluator.ts} +8 -8
- package/src/runtime/{goal-loop-runner.ts → goal-workflow/goal-loop-runner.ts} +27 -25
- package/src/runtime/{goal-state-store.ts → goal-workflow/goal-state-store.ts} +8 -8
- package/src/runtime/{plan-templates.ts → goal-workflow/plan-templates.ts} +1 -1
- package/src/runtime/group-join.ts +3 -3
- package/src/runtime/handoff-manager.ts +0 -2
- package/src/runtime/{heartbeat-watcher.ts → heartbeat/heartbeat-watcher.ts} +7 -7
- package/src/runtime/iteration-hooks.ts +1 -1
- package/src/runtime/{live-agent-control.ts → live-session/live-agent-control.ts} +2 -2
- package/src/runtime/{live-agent-manager.ts → live-session/live-agent-manager.ts} +4 -4
- package/src/runtime/{live-session-runtime.ts → live-session/live-session-runtime.ts} +39 -41
- package/src/runtime/manifest-cache.ts +6 -2
- package/src/runtime/{model-fallback.ts → model/model-fallback.ts} +1 -1
- package/src/runtime/{pi-args.ts → model/pi-args.ts} +20 -5
- package/src/runtime/model/provider-extensions.ts +116 -0
- package/src/runtime/{runtime-policy.ts → model/runtime-policy.ts} +2 -2
- package/src/runtime/{runtime-resolver.ts → model/runtime-resolver.ts} +3 -3
- package/src/runtime/{runtime-warmup.ts → model/runtime-warmup.ts} +8 -8
- package/src/runtime/orphan-worker-registry.ts +1 -1
- package/src/runtime/{progress-tracker.ts → output/progress-tracker.ts} +1 -1
- package/src/runtime/{result-extractor.ts → output/result-extractor.ts} +4 -4
- package/src/runtime/{sidechain-output.ts → output/sidechain-output.ts} +2 -2
- package/src/runtime/{stream-preview.ts → output/stream-preview.ts} +1 -1
- package/src/runtime/{streaming-output.ts → output/streaming-output.ts} +2 -2
- package/src/runtime/{tool-progress.ts → output/tool-progress.ts} +1 -1
- package/src/runtime/parent-guard.ts +30 -10
- package/src/runtime/pipeline-runner.ts +2 -2
- package/src/runtime/policy-engine.ts +2 -2
- package/src/runtime/{cancellation.ts → process/cancellation.ts} +1 -1
- package/src/runtime/{post-exit-stdio-guard.ts → process/post-exit-stdio-guard.ts} +1 -1
- package/src/runtime/{process-lifecycle.ts → process/process-lifecycle.ts} +3 -3
- package/src/runtime/{checkpoint.ts → recovery/checkpoint.ts} +4 -4
- package/src/runtime/{crash-recovery.ts → recovery/crash-recovery.ts} +93 -21
- package/src/runtime/{overflow-recovery.ts → recovery/overflow-recovery.ts} +1 -1
- package/src/runtime/{recovery-recipes.ts → recovery/recovery-recipes.ts} +1 -1
- package/src/runtime/{retry-executor.ts → recovery/retry-executor.ts} +2 -2
- package/src/runtime/{retry-runner.ts → recovery/retry-runner.ts} +2 -8
- package/src/runtime/run-tracker.ts +1 -1
- package/src/runtime/run-worker.ts +3 -3
- package/src/runtime/{coalesce-tasks.ts → scheduling/coalesce-tasks.ts} +3 -3
- package/src/runtime/{concurrency.ts → scheduling/concurrency.ts} +9 -3
- package/src/runtime/{parallel-research.ts → scheduling/parallel-research.ts} +4 -2
- package/src/runtime/{run-coalesced-task-group.ts → scheduling/run-coalesced-task-group.ts} +95 -36
- package/src/runtime/{semaphore.ts → scheduling/semaphore.ts} +4 -1
- package/src/runtime/{task-graph-scheduler.ts → scheduling/task-graph-scheduler.ts} +1 -1
- package/src/runtime/session-resources.ts +1 -1
- package/src/runtime/settings-store.ts +1 -1
- package/src/runtime/single-agent-compose.ts +1 -0
- package/src/runtime/stale-reconciler.ts +1 -1
- package/src/runtime/subagent-manager.ts +1 -1
- package/src/runtime/supervisor-contact.ts +28 -13
- package/src/runtime/task-output-context.ts +7 -5
- package/src/runtime/task-runner/child-executor.ts +67 -31
- package/src/runtime/task-runner/live-executor.ts +8 -8
- package/src/runtime/task-runner/post-execution.ts +12 -12
- package/src/runtime/task-runner/pre-execution.ts +6 -6
- package/src/runtime/task-runner/progress.ts +1 -1
- package/src/runtime/task-runner/run-projection.ts +1 -1
- package/src/runtime/task-runner/scaffold-executor.ts +1 -1
- package/src/runtime/task-runner/state-helpers.ts +2 -2
- package/src/runtime/task-runner.ts +4 -4
- package/src/runtime/team-runner.ts +441 -175
- package/src/runtime/{completion-guard.ts → verification/completion-guard.ts} +1 -1
- package/src/runtime/{green-contract.ts → verification/green-contract.ts} +1 -1
- package/src/runtime/{post-checks.ts → verification/post-checks.ts} +4 -4
- package/src/runtime/{verification-gates.ts → verification/verification-gates.ts} +5 -5
- package/src/runtime/{verification-integrity.ts → verification/verification-integrity.ts} +1 -1
- package/src/schema/config-schema.ts +1 -0
- package/src/schema/team-tool-schema.ts +149 -185
- package/src/state/README.md +44 -0
- package/src/state/atomic-write.ts +24 -3
- package/src/state/{locks.ts → coordination/locks.ts} +118 -38
- package/src/state/{mailbox.ts → coordination/mailbox.ts} +14 -8
- package/src/state/{schedule.ts → coordination/schedule.ts} +3 -3
- package/src/state/{task-claims.ts → coordination/task-claims.ts} +1 -1
- package/src/state/decision-ledger.ts +1 -1
- package/src/state/{event-log-rotation.ts → event-log/event-log-rotation.ts} +189 -31
- package/src/state/{event-log.ts → event-log/event-log.ts} +77 -39
- package/src/state/{jsonl-writer.ts → event-log/jsonl-writer.ts} +14 -6
- package/src/state/hook-instinct-bridge.ts +2 -2
- package/src/state/{active-run-registry.ts → stores/active-run-registry.ts} +7 -7
- package/src/state/{artifact-store.ts → stores/artifact-store.ts} +62 -4
- package/src/state/{blob-store.ts → stores/blob-store.ts} +3 -3
- package/src/state/{health-store.ts → stores/health-store.ts} +3 -3
- package/src/state/{instinct-store.ts → stores/instinct-store.ts} +3 -3
- package/src/state/{observation-store.ts → stores/observation-store.ts} +2 -2
- package/src/state/{run-cache.ts → stores/run-cache.ts} +4 -4
- package/src/state/{run-graph.ts → stores/run-graph.ts} +4 -4
- package/src/state/{run-metrics.ts → stores/run-metrics.ts} +3 -3
- package/src/state/{state-store.ts → stores/state-store.ts} +254 -21
- package/src/state/types.ts +27 -3
- package/src/ui/component.ts +55 -0
- package/src/ui/crew-select-list.ts +3 -1
- package/src/ui/dashboard-panes/agents-pane.ts +1 -1
- package/src/ui/dwf-phase-display.ts +1 -1
- package/src/ui/heartbeat-aggregator.ts +1 -1
- package/src/ui/keybinding-map.ts +179 -6
- package/src/ui/layout-primitives.ts +9 -5
- package/src/ui/live-conversation-overlay.ts +1 -1
- package/src/ui/live-run-sidebar.ts +1 -1
- package/src/ui/overlay-stack.ts +148 -0
- package/src/ui/overlays/agent-picker-overlay.ts +1 -1
- package/src/ui/overlays/mailbox-compose-overlay.ts +1 -1
- package/src/ui/overlays/mailbox-detail-overlay.ts +2 -2
- package/src/ui/powerbar-publisher.ts +1 -1
- package/src/ui/render-scheduler.ts +1 -1
- package/src/ui/run-action-dispatcher.ts +3 -3
- package/src/ui/run-dashboard.ts +5 -33
- package/src/ui/run-event-bus.ts +3 -3
- package/src/ui/run-snapshot-cache.ts +37 -18
- package/src/ui/settings-overlay.ts +13 -21
- package/src/ui/snapshot-types.ts +1 -1
- package/src/ui/status-colors.ts +0 -2
- package/src/ui/terminal-status.ts +1 -1
- package/src/ui/theme-adapter.ts +33 -13
- package/src/ui/tool-renderers/index.ts +8 -0
- package/src/ui/transcript-viewer.ts +37 -13
- package/src/ui/widget/index.ts +32 -9
- package/src/ui/widget/widget-formatters.ts +62 -4
- package/src/ui/widget/widget-model.ts +2 -2
- package/src/ui/widget/widget-renderer.ts +1 -1
- package/src/utils/conflict-detect.ts +58 -5
- package/src/utils/ndjson.ts +2 -2
- package/src/utils/redaction.ts +39 -0
- package/src/utils/socket-path.ts +1 -1
- package/src/workflows/workflow-config.ts +1 -1
- package/src/worktree/cleanup.ts +1 -1
- package/src/worktree/worktree-manager.ts +111 -47
- package/workflows/chain.workflow.md +2 -2
- package/dist/build-meta.json +0 -16807
- package/index.bundle.ts +0 -25
- package/scripts/bench-check.mjs +0 -96
- package/scripts/bench-cold-start.mjs +0 -216
- package/scripts/build-bundle.mjs +0 -92
- package/scripts/check-all-skills.ts +0 -294
- package/scripts/check-bundle-size.mjs +0 -38
- package/scripts/check-bundle-staleness.mjs +0 -97
- package/scripts/check-conflict-markers.mjs +0 -91
- package/scripts/check-lazy-imports.mjs +0 -28
- package/scripts/dev-runner.mjs +0 -106
- package/scripts/profile-startup.mjs +0 -125
- package/scripts/release-smoke.mjs +0 -74
- package/scripts/run-bench.mjs +0 -47
- package/scripts/run-real-chain.ts +0 -41
- package/scripts/test-issue-29-crash.ts +0 -111
- package/scripts/test-issue-29-e2e.ts +0 -183
- package/scripts/test-issue-29-real-runtime.ts +0 -330
- package/scripts/test-issue-29-real-tasks.ts +0 -387
- package/scripts/test-issue-29-team-tool.ts +0 -105
- package/scripts/test-runner.mjs +0 -84
- package/scripts/verify-flicker-fix.ts +0 -109
- package/scripts/verify-skill.ts +0 -550
- package/scripts/watch-bundle.mjs +0 -259
- package/scripts/watchdog-harness.ts +0 -119
- package/src/adapters/claude-adapter.ts +0 -23
- package/src/adapters/codex-adapter.ts +0 -21
- package/src/adapters/cursor-adapter.ts +0 -17
- package/src/adapters/export-util.ts +0 -143
- package/src/adapters/index.ts +0 -15
- package/src/adapters/registry.ts +0 -18
- package/src/adapters/types.ts +0 -23
- package/src/runtime/code-summary.ts +0 -292
- package/src/runtime/cross-extension-rpc.ts +0 -143
- package/src/runtime/hidden-handoff.ts +0 -407
- package/src/runtime/prose-compressor.ts +0 -162
- package/src/subagents/async-entry.ts +0 -1
- package/src/subagents/index.ts +0 -3
- package/src/subagents/live/control.ts +0 -1
- package/src/subagents/live/manager.ts +0 -1
- package/src/subagents/live/realtime.ts +0 -1
- package/src/subagents/live/session-runtime.ts +0 -1
- package/src/subagents/manager.ts +0 -1
- package/src/subagents/spawn.ts +0 -1
- package/test-integration-check.ts +0 -118
- /package/src/runtime/{broker-issuer.ts → broker/broker-issuer.ts} +0 -0
- /package/src/runtime/{crew-broker-tokens.ts → broker/crew-broker-tokens.ts} +0 -0
- /package/src/runtime/{child-pi-pool.ts → child-pi/child-pi-pool.ts} +0 -0
- /package/src/runtime/{compact-pipeline.ts → compaction/compact-pipeline.ts} +0 -0
- /package/src/runtime/{compact-stages → compaction/compact-stages}/ansi-strip-stage.ts +0 -0
- /package/src/runtime/{compact-stages → compaction/compact-stages}/blank-collapse-stage.ts +0 -0
- /package/src/runtime/{compact-stages → compaction/compact-stages}/deduplicate-stage.ts +0 -0
- /package/src/runtime/{compact-stages → compaction/compact-stages}/head-snap-stage.ts +0 -0
- /package/src/runtime/{compact-stages → compaction/compact-stages}/tail-capture-stage.ts +0 -0
- /package/src/runtime/{compact-stages → compaction/compact-stages}/truncation-stage.ts +0 -0
- /package/src/runtime/{important-line-classifier.ts → compaction/important-line-classifier.ts} +0 -0
- /package/src/runtime/{heartbeat-gradient.ts → heartbeat/heartbeat-gradient.ts} +0 -0
- /package/src/runtime/{worker-heartbeat.ts → heartbeat/worker-heartbeat.ts} +0 -0
- /package/src/runtime/{worker-startup.ts → heartbeat/worker-startup.ts} +0 -0
- /package/src/runtime/{intercom-bridge.ts → live-session/intercom-bridge.ts} +0 -0
- /package/src/runtime/{live-control-realtime.ts → live-session/live-control-realtime.ts} +0 -0
- /package/src/runtime/{live-extension-bridge.ts → live-session/live-extension-bridge.ts} +0 -0
- /package/src/runtime/{live-irc.ts → live-session/live-irc.ts} +0 -0
- /package/src/runtime/{live-session-health.ts → live-session/live-session-health.ts} +0 -0
- /package/src/runtime/{model-resolver.ts → model/model-resolver.ts} +0 -0
- /package/src/runtime/{model-scope.ts → model/model-scope.ts} +0 -0
- /package/src/runtime/{output-validator.ts → output/output-validator.ts} +0 -0
- /package/src/runtime/{pi-json-output.ts → output/pi-json-output.ts} +0 -0
- /package/src/runtime/{progress-event-coalescer.ts → output/progress-event-coalescer.ts} +0 -0
- /package/src/runtime/{cancellation-token.ts → process/cancellation-token.ts} +0 -0
- /package/src/runtime/{zombie-scanner.ts → process/zombie-scanner.ts} +0 -0
- /package/src/runtime/{crash-classification.ts → recovery/crash-classification.ts} +0 -0
- /package/src/runtime/{batch-barrier.ts → scheduling/batch-barrier.ts} +0 -0
- /package/src/runtime/{global-worker-cap.ts → scheduling/global-worker-cap.ts} +0 -0
- /package/src/runtime/{parallel-utils.ts → scheduling/parallel-utils.ts} +0 -0
- /package/src/runtime/{scheduler.ts → scheduling/scheduler.ts} +0 -0
- /package/src/runtime/{task-graph.ts → scheduling/task-graph.ts} +0 -0
- /package/src/runtime/{verification-worktree.ts → verification/verification-worktree.ts} +0 -0
- /package/src/state/{event-reconstructor.ts → event-log/event-reconstructor.ts} +0 -0
- /package/src/state/{worker-atomic-writer.ts → event-log/worker-atomic-writer.ts} +0 -0
|
@@ -2,16 +2,17 @@ import { spawn } from "node:child_process";
|
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import * as os from "node:os";
|
|
4
4
|
import * as path from "node:path";
|
|
5
|
-
import type { AgentConfig } from "
|
|
6
|
-
import { DEFAULT_CHILD_PI } from "
|
|
7
|
-
import { registerChildProcess, unregisterChildProcess } from "
|
|
8
|
-
import { atomicWriteFile } from "
|
|
9
|
-
import type { WorkerExitStatus } from "
|
|
10
|
-
import { logInternalError } from "
|
|
11
|
-
import { redactSecretString } from "
|
|
12
|
-
import { getActiveBrokerIssuer } from "
|
|
5
|
+
import type { AgentConfig } from "../../agents/agent-config.ts";
|
|
6
|
+
import { DEFAULT_CHILD_PI } from "../../config/defaults.ts";
|
|
7
|
+
import { registerChildProcess, unregisterChildProcess } from "../../extension/crew-cleanup.ts";
|
|
8
|
+
import { atomicWriteFile } from "../../state/atomic-write.ts";
|
|
9
|
+
import type { WorkerExitStatus } from "../../state/types.ts";
|
|
10
|
+
import { logInternalError } from "../../utils/internal-error.ts";
|
|
11
|
+
import { redactSecretString } from "../../utils/redaction.ts";
|
|
12
|
+
import { getActiveBrokerIssuer } from "../broker/broker-issuer.ts";
|
|
13
|
+
import { BoundedTail } from "../compaction/compact-stages/bounded-tail.ts";
|
|
13
14
|
import { FINAL_DRAIN_MS, HARD_KILL_MS, POST_EXIT_STDIO_GUARD_MS, RESPONSE_TIMEOUT_MS } from "./child-pi-constants.ts";
|
|
14
|
-
import {
|
|
15
|
+
import { clearHardKillTimer, killProcessTree, registerActiveChild, unregisterActiveChild } from "./child-pi-kill.ts";
|
|
15
16
|
import { buildFinalChildPiSpawnOptions, prepareSpawnContext } from "./child-pi-spawn.ts";
|
|
16
17
|
import { ChildPiSteeringController } from "./child-pi-steering.ts";
|
|
17
18
|
// Internal helpers for active-child bookkeeping (extracted to child-pi-kill.ts).
|
|
@@ -32,10 +33,9 @@ export { buildChildPiSpawnOptions, buildFinalChildPiSpawnOptions } from "./child
|
|
|
32
33
|
// ── Re-export from child-pi-streams.ts (H-7 decomposition step 4) ──
|
|
33
34
|
export { ChildPiLineObserver } from "./child-pi-streams.ts";
|
|
34
35
|
|
|
35
|
-
import {
|
|
36
|
-
import {
|
|
37
|
-
|
|
38
|
-
import { attachPostExitStdioGuard, trySignalChild } from "./post-exit-stdio-guard.ts";
|
|
36
|
+
import { checkCrewDepth, cleanupTempDir } from "../model/pi-args.ts";
|
|
37
|
+
import { attachPostExitStdioGuard, trySignalChild } from "../process/post-exit-stdio-guard.ts";
|
|
38
|
+
import { classifyProcessCrash } from "../recovery/crash-classification.ts";
|
|
39
39
|
|
|
40
40
|
/** Maximum size (bytes) for the ChildPiLineObserver's line accumulation buffer.
|
|
41
41
|
* When exceeded, the buffer is force-flushed to prevent unbounded memory growth
|
|
@@ -420,10 +420,15 @@ export async function runChildPi(input: ChildPiRunInput): Promise<ChildPiRunResu
|
|
|
420
420
|
pid: child.pid,
|
|
421
421
|
ts: new Date().toISOString(),
|
|
422
422
|
});
|
|
423
|
-
// Register with cleanup handler for graceful shutdown
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
423
|
+
// Register with cleanup handler for graceful shutdown (RT-11):
|
|
424
|
+
// ALWAYS register — every spawned child must be visible to host-SIGTERM
|
|
425
|
+
// cleanup. Use synthetic IDs when the caller omitted runId/agentId so the
|
|
426
|
+
// PID is still tracked for killProcessPid on session shutdown.
|
|
427
|
+
registerChildProcess(
|
|
428
|
+
child.pid,
|
|
429
|
+
input.runId ?? `untracked-run-${child.pid}`,
|
|
430
|
+
input.agentId ?? `untracked-agent-${child.pid}`,
|
|
431
|
+
);
|
|
427
432
|
} else {
|
|
428
433
|
input.onLifecycleEvent?.({
|
|
429
434
|
type: "spawn_error",
|
|
@@ -431,8 +436,10 @@ export async function runChildPi(input: ChildPiRunInput): Promise<ChildPiRunResu
|
|
|
431
436
|
ts: new Date().toISOString(),
|
|
432
437
|
});
|
|
433
438
|
}
|
|
434
|
-
|
|
435
|
-
|
|
439
|
+
// P0-1: O(1)-amortized bounded accumulators (segment ring) — replaces the O(n²)
|
|
440
|
+
// appendBoundedTail rebuild-per-line pattern that re-scanned 512 KiB every line.
|
|
441
|
+
const stdoutTail = new BoundedTail();
|
|
442
|
+
const stderrTail = new BoundedTail();
|
|
436
443
|
let settled = false;
|
|
437
444
|
let childExited = false;
|
|
438
445
|
let postExitGuardCleanup: (() => void) | undefined;
|
|
@@ -473,37 +480,6 @@ export async function runChildPi(input: ChildPiRunInput): Promise<ChildPiRunResu
|
|
|
473
480
|
let hardKilled = false;
|
|
474
481
|
const cleanupErrors: string[] = [];
|
|
475
482
|
const steeringController = new ChildPiSteeringController(input.maxTurns, input.graceTurns);
|
|
476
|
-
// Track in-flight operations for proper rejection on unexpected exit
|
|
477
|
-
interface PendingOperation {
|
|
478
|
-
id: string;
|
|
479
|
-
type: "prompt" | "steer" | "json_event";
|
|
480
|
-
startedAt: number;
|
|
481
|
-
}
|
|
482
|
-
const pendingOperations = new Map<string, PendingOperation>();
|
|
483
|
-
let operationIdCounter = 0;
|
|
484
|
-
|
|
485
|
-
const startOperation = (type: PendingOperation["type"]): string => {
|
|
486
|
-
const id = `op-${++operationIdCounter}`;
|
|
487
|
-
pendingOperations.set(id, { id, type, startedAt: Date.now() });
|
|
488
|
-
return id;
|
|
489
|
-
};
|
|
490
|
-
|
|
491
|
-
const completeOperation = (id: string): void => {
|
|
492
|
-
pendingOperations.delete(id);
|
|
493
|
-
};
|
|
494
|
-
|
|
495
|
-
const rejectPendingOperations = (error: Error): void => {
|
|
496
|
-
pendingOperations.forEach((op, id) => {
|
|
497
|
-
logInternalError(
|
|
498
|
-
"child-pi.pending-operation-rejected",
|
|
499
|
-
error,
|
|
500
|
-
`opId=${id} type=${op.type} elapsed=${Date.now() - op.startedAt}ms`,
|
|
501
|
-
);
|
|
502
|
-
});
|
|
503
|
-
pendingOperations.clear();
|
|
504
|
-
};
|
|
505
|
-
|
|
506
|
-
const steerInjectionFailed = false;
|
|
507
483
|
let abortDueToParentSignal = false;
|
|
508
484
|
// CP-1: track whether the turn-limit hard-abort has been initiated. Once
|
|
509
485
|
// true, we must NOT restart the no-response timer — the child is already
|
|
@@ -526,6 +502,8 @@ export async function runChildPi(input: ChildPiRunInput): Promise<ChildPiRunResu
|
|
|
526
502
|
if (noResponseTimer) clearTimeout(noResponseTimer);
|
|
527
503
|
noResponseTimer = setTimeout(() => {
|
|
528
504
|
responseTimeoutHit = true;
|
|
505
|
+
// P0-1: snapshot the bounded stderr accumulator once for this timer fire.
|
|
506
|
+
const stderr = stderrTail.value();
|
|
529
507
|
// Capture stderr at timeout moment for debugging
|
|
530
508
|
// SEC-1: redact secrets before embedding in lifecycle event so
|
|
531
509
|
// worker-emitted secrets (API keys etc.) don't bypass redaction.
|
|
@@ -569,8 +547,8 @@ export async function runChildPi(input: ChildPiRunInput): Promise<ChildPiRunResu
|
|
|
569
547
|
const timeoutErr = `Child Pi produced no new output for ${responseTimeoutMs}ms; killed but did not exit within ${SAFETY_SETTLE_MS}ms (possible zombie).`;
|
|
570
548
|
void settle({
|
|
571
549
|
exitCode: null,
|
|
572
|
-
stdout,
|
|
573
|
-
stderr,
|
|
550
|
+
stdout: stdoutTail.value(),
|
|
551
|
+
stderr: stderrTail.value(),
|
|
574
552
|
error: timeoutErr,
|
|
575
553
|
exitStatus: {
|
|
576
554
|
exitCode: null,
|
|
@@ -600,26 +578,19 @@ export async function runChildPi(input: ChildPiRunInput): Promise<ChildPiRunResu
|
|
|
600
578
|
...input,
|
|
601
579
|
onStdoutLine: (line) => {
|
|
602
580
|
if (!steeringController.isHardAbortInitiated()) restartNoResponseTimer();
|
|
603
|
-
|
|
581
|
+
stdoutTail.push(`${line}\n`);
|
|
604
582
|
input.onStdoutLine?.(line);
|
|
605
583
|
},
|
|
606
584
|
onJsonEvent: (event) => {
|
|
607
585
|
if (!steeringController.isHardAbortInitiated()) restartNoResponseTimer();
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
if (
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
const action = steeringController.onTurnEnd(child.pid, child, input.steeringFile);
|
|
616
|
-
if (action.kind === "hardAbort") killProcessTree(action.pid, action.child);
|
|
617
|
-
}
|
|
586
|
+
// Turn-count-based steering: soft limit steer + hard abort after graceTurns
|
|
587
|
+
if (event && typeof event === "object" && !Array.isArray(event)) {
|
|
588
|
+
const obj = event as Record<string, unknown>;
|
|
589
|
+
if (obj.type === "turn_end") {
|
|
590
|
+
// H-7 step 5: steering state machine extracted to ChildPiSteeringController.
|
|
591
|
+
const action = steeringController.onTurnEnd(child.pid, child, input.steeringFile);
|
|
592
|
+
if (action.kind === "hardAbort") killProcessTree(action.pid, action.child);
|
|
618
593
|
}
|
|
619
|
-
completeOperation(eventOpId);
|
|
620
|
-
} catch (err) {
|
|
621
|
-
completeOperation(eventOpId);
|
|
622
|
-
throw err;
|
|
623
594
|
}
|
|
624
595
|
// F12: capture monotonic timestamp BEFORE dispatching — any stdout
|
|
625
596
|
// JSON event counts as activity. This lets the quiet-window
|
|
@@ -913,15 +884,16 @@ export async function runChildPi(input: ChildPiRunInput): Promise<ChildPiRunResu
|
|
|
913
884
|
});
|
|
914
885
|
child.stderr?.on("data", (chunk: Buffer) => {
|
|
915
886
|
if (!steeringController.isHardAbortInitiated()) restartNoResponseTimer();
|
|
916
|
-
|
|
887
|
+
stderrTail.push(chunk.toString("utf-8"));
|
|
917
888
|
});
|
|
918
889
|
child.on("error", (error) => {
|
|
919
|
-
//
|
|
890
|
+
// P0-1: snapshot the bounded accumulators once for this handler.
|
|
891
|
+
const stdout = stdoutTail.value();
|
|
892
|
+
const stderr = stderrTail.value();
|
|
920
893
|
// SEC-1: redact stderr secrets embedded in the error message + excerpt.
|
|
921
894
|
const processError = new Error(
|
|
922
895
|
`Child Pi process error: ${error.message}. Stderr: ${redactStderrExcerpt(stderr, 500) || "(none)"}`,
|
|
923
896
|
);
|
|
924
|
-
rejectPendingOperations(processError);
|
|
925
897
|
try {
|
|
926
898
|
input.onLifecycleEvent?.({
|
|
927
899
|
type: "spawn_error",
|
|
@@ -956,6 +928,8 @@ export async function runChildPi(input: ChildPiRunInput): Promise<ChildPiRunResu
|
|
|
956
928
|
});
|
|
957
929
|
});
|
|
958
930
|
child.on("exit", (code, signal) => {
|
|
931
|
+
// P0-1: snapshot the bounded stderr accumulator once for this handler.
|
|
932
|
+
const stderr = stderrTail.value();
|
|
959
933
|
if (child.pid) {
|
|
960
934
|
unregisterActiveChild(child.pid);
|
|
961
935
|
clearHardKillTimer(child.pid);
|
|
@@ -975,9 +949,6 @@ export async function runChildPi(input: ChildPiRunInput): Promise<ChildPiRunResu
|
|
|
975
949
|
`Stderr: ${redactStderrExcerpt(stderr, 1000) || "(none)"}`,
|
|
976
950
|
)
|
|
977
951
|
: null;
|
|
978
|
-
if (exitError) {
|
|
979
|
-
rejectPendingOperations(exitError);
|
|
980
|
-
}
|
|
981
952
|
try {
|
|
982
953
|
// Phase-0 diagnostic (HB-003a): capture signal + drain timing in the
|
|
983
954
|
// exit lifecycle event so the exit-null race is diagnosable instead of
|
|
@@ -1017,6 +988,9 @@ export async function runChildPi(input: ChildPiRunInput): Promise<ChildPiRunResu
|
|
|
1017
988
|
}
|
|
1018
989
|
});
|
|
1019
990
|
child.on("close", (exitCode) => {
|
|
991
|
+
// P0-1: snapshot the bounded accumulators once for this handler.
|
|
992
|
+
const stdout = stdoutTail.value();
|
|
993
|
+
const stderr = stderrTail.value();
|
|
1020
994
|
if (child.pid) {
|
|
1021
995
|
unregisterActiveChild(child.pid);
|
|
1022
996
|
clearHardKillTimer(child.pid);
|
|
@@ -1059,10 +1033,6 @@ export async function runChildPi(input: ChildPiRunInput): Promise<ChildPiRunResu
|
|
|
1059
1033
|
steeringController.getTurnCount() >=
|
|
1060
1034
|
(steeringController.getMaxTurns() ?? 0) + (steeringController.getGraceTurns() ?? 5);
|
|
1061
1035
|
const wasParentAborted = abortDueToParentSignal && !wasGraceAborted;
|
|
1062
|
-
// steerInjectionFailed is now always false (Phase-1 fix: steer backpressure
|
|
1063
|
-
// is logged, not fatal). The steerError branch is retained for safety in
|
|
1064
|
-
// case a future change reintroduces a fatal steer path.
|
|
1065
|
-
const steerError = steerInjectionFailed ? "Steer injection failed due to stdin backpressure; process killed" : undefined;
|
|
1066
1036
|
// P0 crash taxonomy: classify the exit so callers/dashboards can bucket
|
|
1067
1037
|
// failure modes (timeout vs cancel vs native panic vs signal …).
|
|
1068
1038
|
// The classifier is a pure function; this is the single integration point.
|
|
@@ -1080,7 +1050,6 @@ export async function runChildPi(input: ChildPiRunInput): Promise<ChildPiRunResu
|
|
|
1080
1050
|
stdout,
|
|
1081
1051
|
stderr,
|
|
1082
1052
|
...(timeoutError ? { error: timeoutError.error } : {}),
|
|
1083
|
-
...(steerError ? { error: steerError } : {}),
|
|
1084
1053
|
aborted: wasGraceAborted || wasParentAborted,
|
|
1085
1054
|
steered: steeringController.isSoftLimitReached() && !wasGraceAborted,
|
|
1086
1055
|
exitStatus: {
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BoundedTail — O(1)-amortized bounded string accumulator (segment ring + running
|
|
3
|
+
* byte counter).
|
|
4
|
+
*
|
|
5
|
+
* Replaces the O(n²) `appendBoundedTail` rebuild-per-line pattern on the child stdout/stderr
|
|
6
|
+
* hot path. The defect (P0-1, verified 2026-07-29): the old accumulator did
|
|
7
|
+
* `new TailCaptureStage(...).apply(current + chunk)` on EVERY output line, so once the
|
|
8
|
+
* buffer filled to the 512 KiB cap each line re-scanned the whole buffer with
|
|
9
|
+
* `Buffer.byteLength` AND ran a per-character `while(...) tail = tail.slice(0,-1)` trim
|
|
10
|
+
* — 2.3 s (ASCII) to 112 s (multi-byte) of main-thread block per task.
|
|
11
|
+
*
|
|
12
|
+
* `push(chunk)` is O(chunk): it appends the segment and shifts whole leading segments
|
|
13
|
+
* while over cap, recomputing byte length only for the dropped segment — never the full
|
|
14
|
+
* buffer, never per-character. The single byte-exact boundary trim runs ONCE, in
|
|
15
|
+
* `value()`, which is read only at result-build / error time (rare).
|
|
16
|
+
*
|
|
17
|
+
* Output parity with the old `TailCaptureStage`-based path is preserved: under cap →
|
|
18
|
+
* verbatim; over cap → `[pi-crew captured output truncated to last X KiB]\n` + the last
|
|
19
|
+
* ≤maxBytes bytes snapped to a UTF-8 char boundary.
|
|
20
|
+
*/
|
|
21
|
+
import { DEFAULT_CHILD_PI } from "../../../config/defaults.ts";
|
|
22
|
+
|
|
23
|
+
const DEFAULT_MAX_BYTES = DEFAULT_CHILD_PI.maxCaptureBytes;
|
|
24
|
+
|
|
25
|
+
/** Default marker, identical to the old appendBoundedTail/TailCaptureStage wording. */
|
|
26
|
+
function defaultMarker(maxBytes: number): string {
|
|
27
|
+
return `[pi-crew captured output truncated to last ${Math.round(maxBytes / 1024)} KiB]`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export class BoundedTail {
|
|
31
|
+
readonly #maxBytes: number;
|
|
32
|
+
readonly #marker: string;
|
|
33
|
+
#segs: string[] = [];
|
|
34
|
+
#bytes = 0;
|
|
35
|
+
#dropped = false;
|
|
36
|
+
#cached: string | undefined;
|
|
37
|
+
#dirty = false;
|
|
38
|
+
|
|
39
|
+
constructor(maxBytes: number = DEFAULT_MAX_BYTES, marker?: string) {
|
|
40
|
+
if (!(maxBytes > 0)) throw new Error(`BoundedTail: maxBytes must be > 0, got ${maxBytes}`);
|
|
41
|
+
this.#maxBytes = maxBytes;
|
|
42
|
+
this.#marker = marker ?? defaultMarker(maxBytes);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Append a chunk. O(chunk) amortized; never scans the full buffer. */
|
|
46
|
+
push(chunk: string): this {
|
|
47
|
+
if (!chunk) return this;
|
|
48
|
+
this.#segs.push(chunk);
|
|
49
|
+
this.#bytes += Buffer.byteLength(chunk, "utf-8");
|
|
50
|
+
// Drop whole leading segments while over cap. Stop at length 1 so a single
|
|
51
|
+
// oversized segment is trimmed exactly once in value() instead of per-char.
|
|
52
|
+
while (this.#bytes > this.#maxBytes && this.#segs.length > 1) {
|
|
53
|
+
const dropped = this.#segs.shift() as string;
|
|
54
|
+
this.#bytes -= Buffer.byteLength(dropped, "utf-8");
|
|
55
|
+
this.#dropped = true;
|
|
56
|
+
}
|
|
57
|
+
this.#dirty = true;
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Materialize the bounded string. Computed at most once per push; cached otherwise. */
|
|
62
|
+
value(): string {
|
|
63
|
+
if (!this.#dirty && this.#cached !== undefined) return this.#cached;
|
|
64
|
+
const body = this.#segs.join("");
|
|
65
|
+
const result = this.#bound(body);
|
|
66
|
+
this.#cached = result;
|
|
67
|
+
this.#dirty = false;
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Byte-exact bound with marker parity vs the old TailCaptureStage path. */
|
|
72
|
+
#bound(body: string): string {
|
|
73
|
+
if (Buffer.byteLength(body, "utf-8") <= this.#maxBytes) {
|
|
74
|
+
// Under cap: add the marker only if we dropped earlier segments.
|
|
75
|
+
return this.#dropped ? `${this.#marker}\n${body}` : body;
|
|
76
|
+
}
|
|
77
|
+
// Over cap (single segment larger than max, or a boundary segment): keep the
|
|
78
|
+
// last ≤maxBytes bytes snapped forward past any UTF-8 continuation bytes.
|
|
79
|
+
const buf = Buffer.from(body, "utf-8");
|
|
80
|
+
let start = Math.max(0, buf.length - this.#maxBytes);
|
|
81
|
+
while (start < buf.length && (buf[start] & 0xc0) === 0x80) start++;
|
|
82
|
+
return `${this.#marker}\n${buf.subarray(start).toString("utf-8")}`;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Barrel re-exports for the compact-stages module.
|
|
3
3
|
*
|
|
4
|
-
* Callers import from `../../runtime/compact-stages/index.ts` (or just
|
|
5
|
-
* `../../runtime/compact-stages/`) rather than reaching into individual
|
|
4
|
+
* Callers import from `../../runtime/compaction/compact-stages/index.ts` (or just
|
|
5
|
+
* `../../runtime/compaction/compact-stages/`) rather than reaching into individual
|
|
6
6
|
* stage files, so internal refactors do not break the public surface.
|
|
7
7
|
*/
|
|
8
8
|
export { ANSI_STRIP_STAGE, AnsiStripStage } from "./ansi-strip-stage.ts";
|
|
@@ -14,9 +14,9 @@ class GiantLineFallbackError extends Error {
|
|
|
14
14
|
|
|
15
15
|
import * as fs from "node:fs";
|
|
16
16
|
import * as path from "node:path";
|
|
17
|
-
import { readJsonFile } from "
|
|
18
|
-
import type { TeamEvent } from "
|
|
19
|
-
import type { TeamRunManifest, TeamTaskState } from "
|
|
17
|
+
import { readJsonFile } from "../../state/atomic-write.ts";
|
|
18
|
+
import type { TeamEvent } from "../../state/event-log/event-log.ts";
|
|
19
|
+
import type { TeamRunManifest, TeamTaskState } from "../../state/types.ts";
|
|
20
20
|
|
|
21
21
|
/** Maximum number of events to read from the tail of events.jsonl. */
|
|
22
22
|
const MAX_TAIL_EVENTS = 100;
|
|
@@ -90,7 +90,7 @@ export interface PruneResult {
|
|
|
90
90
|
// Token estimation (rough char/4 heuristic, matching gajae-code)
|
|
91
91
|
// ---------------------------------------------------------------------------
|
|
92
92
|
|
|
93
|
-
import { countTokens } from "
|
|
93
|
+
import { countTokens } from "../../utils/token-counter.ts";
|
|
94
94
|
|
|
95
95
|
function estimateTokens(text: string): number {
|
|
96
96
|
return countTokens(text);
|
|
@@ -26,14 +26,39 @@ export function agentStateDir(manifest: TeamRunManifest, taskId: string): string
|
|
|
26
26
|
return path.join(agentsRoot(manifest), safeAgentTaskId(taskId));
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
// P1-5: per-task path memoization. The agent state dir + file paths cannot
|
|
30
|
+
// change within a task, so the mkdir/lstat/resolveRealContainedPath validation
|
|
31
|
+
// (≈30 syscalls each, incl. a full ancestor walk) only needs to run ONCE per
|
|
32
|
+
// task — not on every event/output line (was ~60 syscalls/event for the double
|
|
33
|
+
// ensureAgentStateDir call alone). FIFO-bounded so the cache can't grow with
|
|
34
|
+
// run count.
|
|
35
|
+
const ensuredAgentDirs = new Map<string, string>();
|
|
36
|
+
const resolvedAgentFiles = new Map<string, string>();
|
|
37
|
+
const AGENT_PATH_CACHE_MAX = 512;
|
|
38
|
+
|
|
39
|
+
function bumpAgentPathCache(): void {
|
|
40
|
+
if (ensuredAgentDirs.size > AGENT_PATH_CACHE_MAX) {
|
|
41
|
+
const oldest = ensuredAgentDirs.keys().next().value;
|
|
42
|
+
if (oldest !== undefined) ensuredAgentDirs.delete(oldest);
|
|
43
|
+
}
|
|
44
|
+
if (resolvedAgentFiles.size > AGENT_PATH_CACHE_MAX) {
|
|
45
|
+
const oldest = resolvedAgentFiles.keys().next().value;
|
|
46
|
+
if (oldest !== undefined) resolvedAgentFiles.delete(oldest);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
29
50
|
export function ensureAgentStateDir(manifest: TeamRunManifest, taskId: string): string {
|
|
30
51
|
const root = agentsRoot(manifest);
|
|
52
|
+
const dir = agentStateDir(manifest, taskId);
|
|
53
|
+
const cachedDir = ensuredAgentDirs.get(dir);
|
|
54
|
+
if (cachedDir !== undefined) return cachedDir;
|
|
31
55
|
fs.mkdirSync(root, { recursive: true });
|
|
32
56
|
if (fs.lstatSync(root).isSymbolicLink()) throw new Error(`Invalid agents root: ${root}`);
|
|
33
|
-
const dir = agentStateDir(manifest, taskId);
|
|
34
57
|
fs.mkdirSync(dir, { recursive: true });
|
|
35
58
|
if (fs.lstatSync(dir).isSymbolicLink()) throw new Error(`Invalid agent state directory: ${dir}`);
|
|
36
59
|
resolveRealContainedPath(root, path.basename(dir));
|
|
60
|
+
ensuredAgentDirs.set(dir, dir);
|
|
61
|
+
bumpAgentPathCache();
|
|
37
62
|
return dir;
|
|
38
63
|
}
|
|
39
64
|
|
|
@@ -45,8 +70,26 @@ function safeExistingAgentFile(manifest: TeamRunManifest, taskId: string, fileNa
|
|
|
45
70
|
}
|
|
46
71
|
|
|
47
72
|
export function agentStateFile(manifest: TeamRunManifest, taskId: string, fileName: string): string {
|
|
73
|
+
const dir = agentStateDir(manifest, taskId);
|
|
74
|
+
const cacheKey = `${dir}\0${fileName}`;
|
|
75
|
+
const cached = resolvedAgentFiles.get(cacheKey);
|
|
76
|
+
if (cached !== undefined) return cached;
|
|
48
77
|
ensureAgentStateDir(manifest, taskId);
|
|
49
|
-
|
|
78
|
+
const resolved = safeExistingAgentFile(manifest, taskId, fileName);
|
|
79
|
+
resolvedAgentFiles.set(cacheKey, resolved);
|
|
80
|
+
bumpAgentPathCache();
|
|
81
|
+
return resolved;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** @internal Test-only: clear the path memoization cache. */
|
|
85
|
+
export function __test_clearAgentPathCache(): void {
|
|
86
|
+
ensuredAgentDirs.clear();
|
|
87
|
+
resolvedAgentFiles.clear();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** @internal Test-only: inspect cache occupancy (regression guard for P1-5). */
|
|
91
|
+
export function __test_agentPathCacheStats(): { dirs: number; files: number } {
|
|
92
|
+
return { dirs: ensuredAgentDirs.size, files: resolvedAgentFiles.size };
|
|
50
93
|
}
|
|
51
94
|
|
|
52
95
|
export function agentStatusPath(manifest: TeamRunManifest, taskId: string): string {
|
|
@@ -250,6 +293,9 @@ export async function readCrewAgentsAsync(manifest: TeamRunManifest): Promise<Cr
|
|
|
250
293
|
}
|
|
251
294
|
|
|
252
295
|
export function saveCrewAgents(manifest: TeamRunManifest, records: CrewAgentRecord[]): void {
|
|
296
|
+
// P0-3: flush any pending coalesced (best-effort) write first so a stale
|
|
297
|
+
// debounced progress snapshot can't clobber this durable write.
|
|
298
|
+
flushPendingAgentWrites();
|
|
253
299
|
withAgentsLock(manifest, () => {
|
|
254
300
|
fs.mkdirSync(manifest.stateRoot, { recursive: true });
|
|
255
301
|
const filePath = agentsPath(manifest);
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
import { defineTool, type ToolDefinition } from "@earendil-works/pi-coding-agent";
|
|
16
16
|
import { type Static, Type } from "@sinclair/typebox";
|
|
17
|
-
import { broadcastIrcMessage, listLiveAgents, respondAsBackground, sendIrcMessage } from "../live-agent-manager.ts";
|
|
18
|
-
import type { IrcMessage } from "../live-irc.ts";
|
|
17
|
+
import { broadcastIrcMessage, listLiveAgents, respondAsBackground, sendIrcMessage } from "../live-session/live-agent-manager.ts";
|
|
18
|
+
import type { IrcMessage } from "../live-session/live-irc.ts";
|
|
19
19
|
|
|
20
20
|
const IrcParams = Type.Object({
|
|
21
21
|
op: Type.Union(
|
|
@@ -28,21 +28,18 @@ export class DeliveryCoordinator {
|
|
|
28
28
|
private readonly deps: DeliveryCoordinatorDeps;
|
|
29
29
|
private ttlTimer: ReturnType<typeof setInterval> | undefined;
|
|
30
30
|
private timerStarted = false;
|
|
31
|
-
private ownerSessionId: string | undefined = undefined;
|
|
32
31
|
|
|
33
32
|
constructor(deps: DeliveryCoordinatorDeps) {
|
|
34
33
|
this.deps = deps;
|
|
35
34
|
}
|
|
36
35
|
|
|
37
36
|
activate(sessionId: string): void {
|
|
38
|
-
this.ownerSessionId = sessionId;
|
|
39
37
|
this.active = true;
|
|
40
38
|
this.flushQueuedResults();
|
|
41
39
|
}
|
|
42
40
|
|
|
43
41
|
deactivate(): void {
|
|
44
42
|
this.active = false;
|
|
45
|
-
this.ownerSessionId = undefined;
|
|
46
43
|
this.generation += 1;
|
|
47
44
|
}
|
|
48
45
|
|
|
@@ -4,14 +4,15 @@ import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
|
4
4
|
import type { MetricRegistry } from "../observability/metric-registry.ts";
|
|
5
5
|
import type { MetricSnapshot } from "../observability/metrics-primitives.ts";
|
|
6
6
|
import { atomicWriteFile } from "../state/atomic-write.ts";
|
|
7
|
-
import {
|
|
8
|
-
import { loadRunManifestById } from "../state/state-store.ts";
|
|
7
|
+
import type { TeamEvent } from "../state/event-log/event-log.ts";
|
|
8
|
+
import { loadRunManifestById } from "../state/stores/state-store.ts";
|
|
9
9
|
import type { TeamRunManifest, TeamTaskState } from "../state/types.ts";
|
|
10
10
|
import { type HeartbeatSummary, summarizeHeartbeats } from "../ui/heartbeat-aggregator.ts";
|
|
11
11
|
import type { RunUiSnapshot } from "../ui/snapshot-types.ts";
|
|
12
|
+
import { readJsonlTail } from "../utils/incremental-reader.ts";
|
|
12
13
|
import { isSecretKey, redactSecrets } from "../utils/redaction.ts";
|
|
13
14
|
import { readCrewAgents } from "./crew-agent-records.ts";
|
|
14
|
-
import { buildRecoveryLedger, type RecoveryLedgerEntry } from "./recovery-recipes.ts";
|
|
15
|
+
import { buildRecoveryLedger, type RecoveryLedgerEntry } from "./recovery/recovery-recipes.ts";
|
|
15
16
|
|
|
16
17
|
export { isSecretKey, redactSecrets } from "../utils/redaction.ts";
|
|
17
18
|
|
|
@@ -92,7 +93,7 @@ export async function exportDiagnostic(
|
|
|
92
93
|
if (!loaded) throw new Error(`Run '${runId}' not found.`);
|
|
93
94
|
const exportedAt = new Date().toISOString();
|
|
94
95
|
const safeTimestamp = exportedAt.replace(/[:.]/g, "-");
|
|
95
|
-
const recentEvents =
|
|
96
|
+
const recentEvents = readJsonlTail<TeamEvent>(loaded.manifest.eventsPath, 256 * 1024).items.slice(-200);
|
|
96
97
|
const metricsSnapshot = options.registry?.snapshot();
|
|
97
98
|
const taskDiagnostics: Record<string, Record<string, unknown>> = {};
|
|
98
99
|
const terminalEvidence: Record<string, TeamTaskState["terminalEvidence"]> = {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { atomicWriteFile } from "../state/atomic-write.ts";
|
|
4
|
-
import { appendEvent } from "../state/event-log.ts";
|
|
4
|
+
import { appendEvent } from "../state/event-log/event-log.ts";
|
|
5
5
|
import type { TeamRunManifest, TeamTaskState } from "../state/types.ts";
|
|
6
6
|
import { logInternalError } from "../utils/internal-error.ts";
|
|
7
7
|
import { sleepSync } from "../utils/sleep.ts";
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* 3. Cleans up after itself when the run completes or the session ends.
|
|
13
13
|
*/
|
|
14
14
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
15
|
-
import { loadRunManifestById } from "../state/state-store.ts";
|
|
15
|
+
import { loadRunManifestById } from "../state/stores/state-store.ts";
|
|
16
16
|
import { readCrewAgents } from "./crew-agent-records.ts";
|
|
17
17
|
import { isActiveRunStatus, isLikelyOrphanedActiveRun } from "./process-status.ts";
|
|
18
18
|
|
|
@@ -15,14 +15,14 @@
|
|
|
15
15
|
// `__test__parseAdaptivePlan` and `__test__repairAdaptivePlan` are re-exported
|
|
16
16
|
// from team-runner.ts so existing test imports keep working.
|
|
17
17
|
import * as fs from "node:fs";
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import { saveRunManifestAsync } from "
|
|
21
|
-
import type { TeamRunManifest, TeamTaskState } from "
|
|
22
|
-
import type { TeamConfig } from "
|
|
23
|
-
import type { WorkflowConfig, WorkflowStep } from "
|
|
18
|
+
import { appendEventAsync, appendEventFireAndForget } from "../../state/event-log/event-log.ts";
|
|
19
|
+
import { writeArtifact } from "../../state/stores/artifact-store.ts";
|
|
20
|
+
import { saveRunManifestAsync } from "../../state/stores/state-store.ts";
|
|
21
|
+
import type { TeamRunManifest, TeamTaskState } from "../../state/types.ts";
|
|
22
|
+
import type { TeamConfig } from "../../teams/team-config.ts";
|
|
23
|
+
import type { WorkflowConfig, WorkflowStep } from "../../workflows/workflow-config.ts";
|
|
24
|
+
import { refreshTaskGraphQueues } from "../scheduling/task-graph-scheduler.ts";
|
|
24
25
|
import { getPlanTemplate, renderPlanTemplate } from "./plan-templates.ts";
|
|
25
|
-
import { refreshTaskGraphQueues } from "./task-graph-scheduler.ts";
|
|
26
26
|
|
|
27
27
|
export interface AdaptivePlanTask {
|
|
28
28
|
role: string;
|
|
@@ -557,7 +557,7 @@ export async function injectAdaptivePlanIfReady(input: InjectAdaptivePlanInput):
|
|
|
557
557
|
|
|
558
558
|
// Test compatibility: original team-runner.ts exposed these names. Keep
|
|
559
559
|
// matching exports here; team-runner.ts re-exports them so existing test
|
|
560
|
-
// imports (`import { __test__parseAdaptivePlan } from "
|
|
560
|
+
// imports (`import { __test__parseAdaptivePlan } from "../../../src/runtime/team-runner.ts"`)
|
|
561
561
|
// keep working without churn.
|
|
562
562
|
export const __test__parseAdaptivePlan = parseAdaptivePlan;
|
|
563
563
|
export const __test__repairAdaptivePlan = repairAdaptivePlan;
|
package/src/runtime/{dynamic-workflow-context.ts → goal-workflow/dynamic-workflow-context.ts}
RENAMED
|
@@ -24,23 +24,23 @@
|
|
|
24
24
|
|
|
25
25
|
import { randomBytes } from "node:crypto";
|
|
26
26
|
import type { TSchema } from "@sinclair/typebox";
|
|
27
|
-
import type { AgentConfig } from "
|
|
28
|
-
import { allAgents, discoverAgents } from "
|
|
29
|
-
import {
|
|
30
|
-
import { appendEvent } from "
|
|
31
|
-
import {
|
|
32
|
-
import type { TeamRunManifest } from "
|
|
33
|
-
import type { TeamConfig } from "
|
|
34
|
-
import { logInternalError } from "
|
|
35
|
-
import { cleanupAgentWorktreeAsync, prepareAgentWorktreeAsync } from "
|
|
36
|
-
import type { DwfCheckpointState } from "
|
|
37
|
-
import {
|
|
38
|
-
import {
|
|
27
|
+
import type { AgentConfig } from "../../agents/agent-config.ts";
|
|
28
|
+
import { allAgents, discoverAgents } from "../../agents/discover-agents.ts";
|
|
29
|
+
import { appendMailboxMessage, readMailbox } from "../../state/coordination/mailbox.ts";
|
|
30
|
+
import { appendEvent } from "../../state/event-log/event-log.ts";
|
|
31
|
+
import { writeArtifact } from "../../state/stores/artifact-store.ts";
|
|
32
|
+
import type { TeamRunManifest } from "../../state/types.ts";
|
|
33
|
+
import type { TeamConfig } from "../../teams/team-config.ts";
|
|
34
|
+
import { logInternalError } from "../../utils/internal-error.ts";
|
|
35
|
+
import { cleanupAgentWorktreeAsync, prepareAgentWorktreeAsync } from "../../worktree/worktree-manager.ts";
|
|
36
|
+
import type { DwfCheckpointState } from "../dwf-state-store.ts";
|
|
37
|
+
import { parsePiJsonOutput } from "../output/pi-json-output.ts";
|
|
38
|
+
import { extractStructuredResult } from "../output/result-extractor.ts";
|
|
39
|
+
import { executeWithRetry } from "../recovery/retry-executor.ts";
|
|
40
|
+
import { runWorker } from "../run-worker.ts";
|
|
41
|
+
import { mapConcurrent } from "../scheduling/parallel-utils.ts";
|
|
42
|
+
import { Semaphore } from "../scheduling/semaphore.ts";
|
|
39
43
|
import { renderPlanTemplate } from "./plan-templates.ts";
|
|
40
|
-
import { extractStructuredResult } from "./result-extractor.ts";
|
|
41
|
-
import { executeWithRetry } from "./retry-executor.ts";
|
|
42
|
-
import { runWorker } from "./run-worker.ts";
|
|
43
|
-
import { Semaphore } from "./semaphore.ts";
|
|
44
44
|
|
|
45
45
|
export interface AgentCallOpts {
|
|
46
46
|
prompt: string;
|
|
@@ -20,22 +20,22 @@
|
|
|
20
20
|
import { readFileSync } from "node:fs";
|
|
21
21
|
import { join } from "node:path";
|
|
22
22
|
import { transformSync } from "esbuild";
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import type { TeamRunManifest, TeamTaskState } from "
|
|
26
|
-
import { logInternalError } from "
|
|
27
|
-
import { packageRoot, projectCrewRoot, userPiRoot } from "
|
|
28
|
-
import { resolveRealContainedPath } from "
|
|
29
|
-
import type { DynamicWorkflowConfig } from "
|
|
30
|
-
import { assertDeterministicScript, isDeterminismCheckEnabled } from "
|
|
31
|
-
import { DwfStore } from "
|
|
23
|
+
import { appendEvent } from "../../state/event-log/event-log.ts";
|
|
24
|
+
import { writeArtifact } from "../../state/stores/artifact-store.ts";
|
|
25
|
+
import type { TeamRunManifest, TeamTaskState } from "../../state/types.ts";
|
|
26
|
+
import { logInternalError } from "../../utils/internal-error.ts";
|
|
27
|
+
import { packageRoot, projectCrewRoot, userPiRoot } from "../../utils/paths.ts";
|
|
28
|
+
import { resolveRealContainedPath } from "../../utils/safe-paths.ts";
|
|
29
|
+
import type { DynamicWorkflowConfig } from "../../workflows/workflow-config.ts";
|
|
30
|
+
import { assertDeterministicScript, isDeterminismCheckEnabled } from "../deterministic-ast.ts";
|
|
31
|
+
import { DwfStore } from "../dwf-state-store.ts";
|
|
32
32
|
import { getWorkflowFinalResult, getWorkflowPhaseState, makeWorkflowCtx } from "./dynamic-workflow-context.ts";
|
|
33
33
|
|
|
34
34
|
export interface RunDynamicWorkflowInput {
|
|
35
35
|
manifest: TeamRunManifest;
|
|
36
36
|
workflow: DynamicWorkflowConfig;
|
|
37
37
|
/** Optional team for role resolution (G4 tier 2). */
|
|
38
|
-
team?: import("
|
|
38
|
+
team?: import("../../teams/team-config.ts").TeamConfig;
|
|
39
39
|
signal: AbortSignal;
|
|
40
40
|
concurrency?: number;
|
|
41
41
|
modelOverride?: string;
|
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
* without breaking a legitimately-no-op run.
|
|
19
19
|
*/
|
|
20
20
|
import { spawnSync } from "node:child_process";
|
|
21
|
-
import type { TeamRunManifest, TeamTaskState } from "
|
|
22
|
-
import { findRepoRoot } from "
|
|
23
|
-
import type { WorkflowConfig } from "
|
|
21
|
+
import type { TeamRunManifest, TeamTaskState } from "../../state/types.ts";
|
|
22
|
+
import { findRepoRoot } from "../../utils/paths.ts";
|
|
23
|
+
import type { WorkflowConfig } from "../../workflows/workflow-config.ts";
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* Roles whose job is to EDIT project source/test files (changes that appear in
|