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
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { statSync } from "node:fs";
|
|
2
2
|
import type { ExtensionAPI, ExtensionContext, ToolDefinition } from "@earendil-works/pi-coding-agent";
|
|
3
3
|
import { Text } from "@earendil-works/pi-tui";
|
|
4
|
+
import type { TObject } from "@sinclair/typebox";
|
|
4
5
|
import { Value } from "@sinclair/typebox/value";
|
|
5
6
|
import { loadConfig } from "../../config/config.ts";
|
|
7
|
+
import { findClosestKey } from "../../config/suggestions.ts";
|
|
6
8
|
import type { MetricRegistry } from "../../observability/metric-registry.ts";
|
|
7
9
|
import type { createManifestCache } from "../../runtime/manifest-cache.ts";
|
|
8
10
|
import { TeamToolParams, type TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
|
|
9
11
|
import { updatePiCrewPowerbar } from "../../ui/powerbar-publisher.ts";
|
|
10
12
|
import type { createRunSnapshotCache } from "../../ui/run-snapshot-cache.ts";
|
|
11
|
-
import { statusIcon, teamToolRenderer } from "../../ui/tool-renderers/index.ts";
|
|
13
|
+
import { statusIcon, type ToolRenderContext, teamToolRenderer } from "../../ui/tool-renderers/index.ts";
|
|
12
14
|
import type { CrewWidgetState } from "../../ui/widget/index.ts";
|
|
13
15
|
import { updateCrewWidget } from "../../ui/widget/index.ts";
|
|
14
16
|
import { resolveRealContainedPath } from "../../utils/safe-paths.ts";
|
|
@@ -29,12 +31,39 @@ async function handleTeamTool(
|
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
import { readCrewAgents } from "../../runtime/crew-agent-records.ts";
|
|
32
|
-
import {
|
|
34
|
+
import type { CrewAgentRecord } from "../../runtime/crew-agent-runtime.ts";
|
|
35
|
+
import { loadRunManifestById } from "../../state/stores/state-store.ts";
|
|
33
36
|
import { formatCompactToolProgress } from "../../ui/tool-progress-formatter.ts";
|
|
34
37
|
import { logInternalError } from "../../utils/internal-error.ts";
|
|
35
38
|
import { withSessionId } from "../team-tool/context.ts";
|
|
39
|
+
import { formatTeamToolParamError } from "../team-tool/param-error.ts";
|
|
36
40
|
import { toolResult } from "../tool-result.ts";
|
|
37
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Normalize model-generated tool params before schema validation.
|
|
44
|
+
*
|
|
45
|
+
* Calling models (esp. Claude-style tool callers, incl. deepseek-via-commandcode)
|
|
46
|
+
* routinely emit EVERY schema key with a default/empty value ("", 0, false)
|
|
47
|
+
* rather than omitting it. Strict TypeBox unions/patterns then reject the call
|
|
48
|
+
* even though the intent was "unset": e.g. `runId: ""` fails the
|
|
49
|
+
* `^[A-Za-z0-9_-]+$` pattern, `workspaceMode: ""` fails the
|
|
50
|
+
* Literal("single"|"worktree") union, `context: ""` / `scope: ""` likewise.
|
|
51
|
+
*
|
|
52
|
+
* Only EMPTY string values are dropped — non-empty strings, booleans, numbers,
|
|
53
|
+
* arrays, objects are preserved verbatim so genuine invalid values still fail
|
|
54
|
+
* validation with a helpful message.
|
|
55
|
+
*/
|
|
56
|
+
export function normalizeTeamParams(params: unknown): unknown {
|
|
57
|
+
if (typeof params !== "object" || params === null || Array.isArray(params)) return params;
|
|
58
|
+
const p = params as Record<string, unknown>;
|
|
59
|
+
const out: Record<string, unknown> = {};
|
|
60
|
+
for (const [key, value] of Object.entries(p)) {
|
|
61
|
+
if (typeof value === "string" && value.trim() === "") continue; // drop empty-string "unset" values
|
|
62
|
+
out[key] = value;
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
|
|
38
67
|
const TEAM_TOOL_PROGRESS_TICK_MS = 1000;
|
|
39
68
|
|
|
40
69
|
type OnUpdate = (chunk: { content: { type: "text"; text: string }[] }) => void;
|
|
@@ -71,22 +100,72 @@ export function resolveCwdOverride(
|
|
|
71
100
|
}
|
|
72
101
|
}
|
|
73
102
|
|
|
103
|
+
/**
|
|
104
|
+
* EXT-1: detect unrecognized (likely typo'd) parameter field names.
|
|
105
|
+
*
|
|
106
|
+
* `TeamToolParams` is declared with `additionalProperties: true`, so TypeBox
|
|
107
|
+
* `Value.Check` does NOT reject unknown keys. A mistyped call like
|
|
108
|
+
* `{ action: "run", goals: "..." }` (typo `goals` vs `goal`) passes validation,
|
|
109
|
+
* the handler then reads `params.goal` (undefined) and returns a generic
|
|
110
|
+
* "Run requires goal or task." with ZERO hint about the typo — so calling
|
|
111
|
+
* agents (LLMs) loop indefinitely on the same malformed shape.
|
|
112
|
+
*
|
|
113
|
+
* This scans `params` for keys absent from `schema.properties` (`action` is
|
|
114
|
+
* excluded — it is validated separately by the schema enum) and, for each
|
|
115
|
+
* unknown key, suggests the closest known field via Levenshtein distance.
|
|
116
|
+
*
|
|
117
|
+
* @returns A multi-line actionable error message, or `null` when every key
|
|
118
|
+
* is recognized.
|
|
119
|
+
*/
|
|
120
|
+
export function detectUnrecognizedParams(schema: TObject, params: unknown): string | null {
|
|
121
|
+
if (typeof params !== "object" || params === null || Array.isArray(params)) return null;
|
|
122
|
+
const knownKeys = Object.keys(schema.properties ?? {});
|
|
123
|
+
const knownSet = new Set(knownKeys);
|
|
124
|
+
|
|
125
|
+
const p = params as Record<string, unknown>;
|
|
126
|
+
const unknowns: string[] = [];
|
|
127
|
+
for (const key of Object.keys(p)) {
|
|
128
|
+
if (key === "action") continue; // validated separately by the schema action enum
|
|
129
|
+
if (!knownSet.has(key)) unknowns.push(key);
|
|
130
|
+
}
|
|
131
|
+
if (unknowns.length === 0) return null;
|
|
132
|
+
|
|
133
|
+
// Suggest the closest known field for each typo (action excluded as a candidate).
|
|
134
|
+
const candidates = knownKeys.filter((k) => k !== "action");
|
|
135
|
+
const hints = unknowns.map((key) => {
|
|
136
|
+
const closest = findClosestKey(key, candidates);
|
|
137
|
+
return closest ? `Unrecognized field '${key}' — did you mean '${closest}'?` : `Unrecognized field '${key}'.`;
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
return [
|
|
141
|
+
`Unrecognized team tool parameter field${unknowns.length > 1 ? "s" : ""}:`,
|
|
142
|
+
...hints.map((h) => ` • ${h}`),
|
|
143
|
+
"",
|
|
144
|
+
"Check the field name spelling against the schema. Common fields:",
|
|
145
|
+
"action, goal, team, runId, task, role, agent, workflow, model, cwd.",
|
|
146
|
+
].join("\n");
|
|
147
|
+
}
|
|
148
|
+
|
|
74
149
|
export function registerTeamTool(pi: ExtensionAPI, deps: RegisterTeamToolDeps): void {
|
|
75
150
|
const tool: ToolDefinition = {
|
|
76
151
|
name: "team",
|
|
77
152
|
label: "Team",
|
|
153
|
+
// EXT-11: do NOT embed one-off performance benchmarks ("Run #3", "~30× faster",
|
|
154
|
+
// "5.7× slower", etc.) in the tool description — they are stale, do not
|
|
155
|
+
// generalize, and mislead the calling LLM about when to reach for the
|
|
156
|
+
// team tool. Keep factual usage guidance (what the tool does, preflight
|
|
157
|
+
// advisory behavior, action='recommend').
|
|
78
158
|
description: [
|
|
79
159
|
"Coordinate Pi teams. Use proactively for complex multi-file work, planning, implementation, tests, reviews, security audits, research, async/background runs, and worktree-isolated execution. Use action='recommend' when unsure which team/workflow to choose. Destructive actions require explicit user confirmation.",
|
|
80
160
|
"",
|
|
81
161
|
"ℹ️ ADVISORY NOTE (preflight, never blocks): pi-crew prints informational notes about workflow topology. Review the note, then decide. There is no BLOCK — agents always exercise judgment.",
|
|
82
|
-
"- Single-task run: raw `Agent`
|
|
83
|
-
"-
|
|
84
|
-
"- ≥3 concurrent or complex DAG: validated good use case, pi-crew notes 'validated use case'.",
|
|
162
|
+
"- Single-task or 2–3 step sequential run: pi-crew notes that a raw `Agent` call may be simpler and faster, then proceeds anyway.",
|
|
163
|
+
"- ≥3 concurrent or complex DAG: validated good use case; pi-crew notes 'validated use case'.",
|
|
85
164
|
"If unsure, call { action: 'recommend', goal } first to get a team/workflow suggestion.",
|
|
86
165
|
].join("\n"),
|
|
87
166
|
promptSnippet: [
|
|
88
167
|
"Use the team tool for multi-agent orchestration when you need ≥3 concurrent agents or a complex DAG.",
|
|
89
|
-
"For single tasks or 2–3 sequential steps, the raw Agent tool is usually faster
|
|
168
|
+
"For single tasks or 2–3 sequential steps, the raw Agent tool is usually faster.",
|
|
90
169
|
"pi-crew notes the topology (informational only) but proceeds either way — you decide based on your context (audit trail, team coordination, etc.).",
|
|
91
170
|
"If unsure, call { action: 'recommend', goal } first.",
|
|
92
171
|
].join("\n"),
|
|
@@ -99,11 +178,21 @@ export function registerTeamTool(pi: ExtensionAPI, deps: RegisterTeamToolDeps):
|
|
|
99
178
|
signal?.addEventListener("abort", abort, { once: true });
|
|
100
179
|
const stopProgress = startTeamToolProgressBinder(onUpdate as OnUpdate | undefined);
|
|
101
180
|
try {
|
|
181
|
+
// Models emit empty-string defaults for unset keys; drop them BEFORE
|
|
182
|
+
// validation so strict unions/patterns accept "unset" as omitted.
|
|
183
|
+
const normalized = normalizeTeamParams(params);
|
|
102
184
|
// Defense-in-depth: validate params at runtime even though Pi framework already does
|
|
103
|
-
if (!Value.Check(TeamToolParams,
|
|
104
|
-
return toolResult(
|
|
185
|
+
if (!Value.Check(TeamToolParams, normalized)) {
|
|
186
|
+
return toolResult(formatTeamToolParamError(TeamToolParams, normalized), { action: "list", status: "error" }, true);
|
|
187
|
+
}
|
|
188
|
+
// EXT-1: additionalProperties:true lets unknown (typo'd) keys slip past
|
|
189
|
+
// Value.Check. Catch them here and suggest the closest known field so
|
|
190
|
+
// the caller gets an actionable hint instead of a generic handler error.
|
|
191
|
+
const typoError = detectUnrecognizedParams(TeamToolParams, normalized);
|
|
192
|
+
if (typoError) {
|
|
193
|
+
return toolResult(typoError, { action: "list", status: "error" }, true);
|
|
105
194
|
}
|
|
106
|
-
const resolved =
|
|
195
|
+
const resolved = normalized as TeamToolParamsValue;
|
|
107
196
|
const cwdOverride = resolveCwdOverride(ctx.cwd, resolved.cwd);
|
|
108
197
|
if (!cwdOverride.ok) return toolResult(cwdOverride.error, { action: resolved.action ?? "list", status: "error" }, true);
|
|
109
198
|
const toolCtx = withSessionId({ ...ctx, cwd: cwdOverride.cwd });
|
|
@@ -148,14 +237,17 @@ export function registerTeamTool(pi: ExtensionAPI, deps: RegisterTeamToolDeps):
|
|
|
148
237
|
stopProgress.stop();
|
|
149
238
|
}
|
|
150
239
|
},
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
return teamToolRenderer.renderCall(args, theme, context);
|
|
240
|
+
renderCall(args, theme, context) {
|
|
241
|
+
return teamToolRenderer.renderCall(args as Record<string, unknown>, theme, context as ToolRenderContext);
|
|
154
242
|
},
|
|
155
|
-
|
|
156
|
-
renderResult(result: any, options: any, theme: any, context: any): any {
|
|
243
|
+
renderResult(result, options, theme, context) {
|
|
157
244
|
try {
|
|
158
|
-
return teamToolRenderer.renderResult(
|
|
245
|
+
return teamToolRenderer.renderResult(
|
|
246
|
+
result as unknown as Record<string, unknown>,
|
|
247
|
+
options,
|
|
248
|
+
theme,
|
|
249
|
+
context as ToolRenderContext,
|
|
250
|
+
);
|
|
159
251
|
} catch {
|
|
160
252
|
return new Text(statusIcon("completed", theme) + " done", 0, 0);
|
|
161
253
|
}
|
|
@@ -171,7 +263,7 @@ interface TeamToolProgressBinder {
|
|
|
171
263
|
|
|
172
264
|
function startTeamToolProgressBinder(onUpdate: OnUpdate | undefined): TeamToolProgressBinder {
|
|
173
265
|
if (!onUpdate) {
|
|
174
|
-
return { attach: () =>
|
|
266
|
+
return { attach: () => undefined, stop: () => undefined };
|
|
175
267
|
}
|
|
176
268
|
const startedAt = Date.now();
|
|
177
269
|
let cwd: string | undefined;
|
|
@@ -191,7 +283,7 @@ function startTeamToolProgressBinder(onUpdate: OnUpdate | undefined): TeamToolPr
|
|
|
191
283
|
onUpdate({ content: [{ type: "text", text: msg }] });
|
|
192
284
|
return;
|
|
193
285
|
}
|
|
194
|
-
let agents;
|
|
286
|
+
let agents: CrewAgentRecord[] | undefined;
|
|
195
287
|
try {
|
|
196
288
|
agents = readCrewAgents(loaded.manifest);
|
|
197
289
|
} catch {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { loadConfig } from "../../config/config.ts";
|
|
3
3
|
import { readCrewAgents } from "../../runtime/crew-agent-records.ts";
|
|
4
|
-
import { listLiveAgents } from "../../runtime/live-agent-manager.ts";
|
|
5
|
-
import { loadRunManifestById } from "../../state/state-store.ts";
|
|
4
|
+
import { listLiveAgents } from "../../runtime/live-session/live-agent-manager.ts";
|
|
5
|
+
import { loadRunManifestById } from "../../state/stores/state-store.ts";
|
|
6
6
|
import { LiveConversationOverlay } from "../../ui/live-conversation-overlay.ts";
|
|
7
7
|
import { asCrewTheme } from "../../ui/theme-adapter.ts";
|
|
8
8
|
// Lazy-loaded: DurableTranscriptViewer is 658ms — only needed for /crew transcript command
|
|
@@ -84,9 +84,8 @@ export async function openLiveConversation(
|
|
|
84
84
|
const handle = liveAgents.find((h) => h.runId === selected.runId && (selected.taskId ? h.taskId === selected.taskId : true));
|
|
85
85
|
if (!handle) return false;
|
|
86
86
|
const theme = asCrewTheme({});
|
|
87
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
88
87
|
await ctx.ui.custom<undefined>(
|
|
89
|
-
(tui
|
|
88
|
+
(tui, _theme, _keybindings, done) => {
|
|
90
89
|
const columns = tui?.terminal?.columns ?? 80;
|
|
91
90
|
const rows = tui?.terminal?.rows ?? 24;
|
|
92
91
|
const overlay = new LiveConversationOverlay(handle, theme, columns, rows);
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
* Two small wires:
|
|
5
5
|
* • wireRpc — the in-process pi-crew RPC handle (other modules in
|
|
6
6
|
* the same extension can subscribe via `pi.events`).
|
|
7
|
-
* • wireGlobalRegistry — the
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* (
|
|
7
|
+
* • wireGlobalRegistry — the crew registry, lazily loaded from
|
|
8
|
+
* team-tool.ts (heavy module) and installed in module-scoped state so
|
|
9
|
+
* the rest of pi-crew can discover pi-crew's RPC handle at runtime
|
|
10
|
+
* (EXT-9: no longer on globalThis[Symbol.for(...)]).
|
|
11
11
|
*/
|
|
12
12
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
13
13
|
import { registerPiCrewRpc } from "../cross-extension-rpc.ts";
|
|
@@ -24,9 +24,9 @@ export function installCrossExtensionWiring(pi: ExtensionAPI, ctx: RegistrationC
|
|
|
24
24
|
};
|
|
25
25
|
ctx.rpcHandle = registerPiCrewRpc(getPiEvents(), () => ctx.currentCtx);
|
|
26
26
|
|
|
27
|
-
// Install the
|
|
28
|
-
//
|
|
29
|
-
//
|
|
27
|
+
// Install the crew registry. Lazy import keeps team-tool.ts (which pulls
|
|
28
|
+
// in the entire runtime chain) out of the cold-start module graph. EXT-9:
|
|
29
|
+
// the registry now lives in module-scoped state, not globalThis.
|
|
30
30
|
void import("../team-tool.ts").then(({ installCrewGlobalRegistry }) => {
|
|
31
31
|
const manifestCacheForRegistry = ctx.getManifestCache(ctx.currentCtx?.cwd ?? process.cwd());
|
|
32
32
|
installCrewGlobalRegistry({
|
|
@@ -134,8 +134,9 @@ export function verifyRpcSignature(payload: RpcSignedPayload, body: unknown): {
|
|
|
134
134
|
export function withHmacVerification<P extends { requestId: string }>(
|
|
135
135
|
handler: (params: P) => unknown | Promise<unknown>,
|
|
136
136
|
_channel: string,
|
|
137
|
-
): (
|
|
138
|
-
return (
|
|
137
|
+
): (raw: unknown) => unknown | Promise<unknown> {
|
|
138
|
+
return (raw: unknown) => {
|
|
139
|
+
const params = raw as P;
|
|
139
140
|
if (!isHmacEnabled()) {
|
|
140
141
|
// No secret configured → backward compat: allow unsigned.
|
|
141
142
|
// Emit a soft info note (once per process) only when an actual RPC
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isTeamRunStatus, isTeamTaskStatus } from "../state/contracts.ts";
|
|
2
|
-
import type { TeamEvent } from "../state/event-log.ts";
|
|
2
|
+
import type { TeamEvent } from "../state/event-log/event-log.ts";
|
|
3
3
|
import type { ArtifactDescriptor, TeamRunManifest, TeamTaskState } from "../state/types.ts";
|
|
4
4
|
import type { ExportedRunBundle } from "./run-export.ts";
|
|
5
5
|
|
|
@@ -52,7 +52,10 @@ function validateManifest(value: unknown, errors: string[]): value is TeamRunMan
|
|
|
52
52
|
if (value.workspaceMode !== "single" && value.workspaceMode !== "worktree")
|
|
53
53
|
errors.push("manifest.workspaceMode must be single or worktree.");
|
|
54
54
|
if (!Array.isArray(value.artifacts)) errors.push("manifest.artifacts must be an array.");
|
|
55
|
-
else
|
|
55
|
+
else
|
|
56
|
+
value.artifacts.forEach((artifact, index) => {
|
|
57
|
+
validateArtifact(artifact, index, errors);
|
|
58
|
+
});
|
|
56
59
|
return errors.length === before;
|
|
57
60
|
}
|
|
58
61
|
|
|
@@ -89,9 +92,15 @@ export function validateRunBundle(value: unknown): BundleValidationResult {
|
|
|
89
92
|
if (typeof value.exportedAt !== "string") errors.push("exportedAt must be a string.");
|
|
90
93
|
validateManifest(value.manifest, errors);
|
|
91
94
|
if (!Array.isArray(value.tasks)) errors.push("tasks must be an array.");
|
|
92
|
-
else
|
|
95
|
+
else
|
|
96
|
+
value.tasks.forEach((task, index) => {
|
|
97
|
+
validateTask(task, index, errors);
|
|
98
|
+
});
|
|
93
99
|
if (!Array.isArray(value.events)) errors.push("events must be an array.");
|
|
94
|
-
else
|
|
100
|
+
else
|
|
101
|
+
value.events.forEach((event, index) => {
|
|
102
|
+
validateEvent(event, index, errors);
|
|
103
|
+
});
|
|
95
104
|
if (!Array.isArray(value.artifactPaths) || !value.artifactPaths.every((item) => typeof item === "string"))
|
|
96
105
|
errors.push("artifactPaths must be an array of strings.");
|
|
97
106
|
return { ok: errors.length === 0, errors };
|
|
@@ -2,8 +2,8 @@ import * as crypto from "node:crypto";
|
|
|
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 {
|
|
6
|
-
import {
|
|
5
|
+
import { readEvents, type TeamEvent } from "../state/event-log/event-log.ts";
|
|
6
|
+
import { writeArtifact } from "../state/stores/artifact-store.ts";
|
|
7
7
|
import type { TeamRunManifest, TeamTaskState } from "../state/types.ts";
|
|
8
8
|
import { redactSecrets } from "../utils/redaction.ts";
|
|
9
9
|
|
|
@@ -2,8 +2,8 @@ import * as fs from "node:fs";
|
|
|
2
2
|
import * as os from "node:os";
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import { DEFAULT_PATHS } from "../config/defaults.ts";
|
|
5
|
-
import { createCancellationToken } from "../runtime/cancellation-token.ts";
|
|
6
|
-
import { activeRunEntries } from "../state/active-run-registry.ts";
|
|
5
|
+
import { createCancellationToken } from "../runtime/process/cancellation-token.ts";
|
|
6
|
+
import { activeRunEntries } from "../state/stores/active-run-registry.ts";
|
|
7
7
|
import type { TeamRunManifest } from "../state/types.ts";
|
|
8
8
|
import { findRepoRoot, projectCrewRoot, userCrewRoot } from "../utils/paths.ts";
|
|
9
9
|
import { isSafePathId, resolveRealContainedPath } from "../utils/safe-paths.ts";
|
|
@@ -124,7 +124,6 @@ export function listRunsByScope(
|
|
|
124
124
|
return projectRoot ? collectRuns(projectCrewRoot(cwd), max, signal) : [];
|
|
125
125
|
case "user":
|
|
126
126
|
return collectRuns(userCrewRoot(), max, signal);
|
|
127
|
-
case "all":
|
|
128
127
|
default:
|
|
129
128
|
return max !== undefined ? listRecentRuns(cwd, max, signal) : listRuns(cwd, signal);
|
|
130
129
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { DEFAULT_PATHS } from "../config/defaults.ts";
|
|
4
|
-
import { createCancellationToken } from "../runtime/cancellation-token.ts";
|
|
4
|
+
import { createCancellationToken } from "../runtime/process/cancellation-token.ts";
|
|
5
5
|
import type { TeamRunManifest } from "../state/types.ts";
|
|
6
6
|
import { logInternalError } from "../utils/internal-error.ts";
|
|
7
7
|
import { projectCrewRoot, userCrewRoot } from "../utils/paths.ts";
|
|
@@ -21,6 +21,56 @@ export interface PruneRunsOptions {
|
|
|
21
21
|
signal?: AbortSignal;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Default age threshold for stale .corrupt-* quarantine files: 7 days.
|
|
26
|
+
* Quarantined manifests older than this are deleted to prevent unbounded growth.
|
|
27
|
+
*/
|
|
28
|
+
export const DEFAULT_CORRUPT_FILE_TTL_MS = 7 * 24 * 60 * 60 * 1000;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Sweep and delete .corrupt-* files older than maxAgeMs in a runs directory tree.
|
|
32
|
+
*
|
|
33
|
+
* These files are created by crash-recovery's purgeStaleActiveRunIndex when a
|
|
34
|
+
* manifest fails to parse (SyntaxError) or encounters an unexpected error.
|
|
35
|
+
* Without this sweep, they accumulate indefinitely across runs.
|
|
36
|
+
*
|
|
37
|
+
* @param runsDir Absolute path to the runs directory (<crewRoot>/state/runs/)
|
|
38
|
+
* @returns count of stale .corrupt-* files deleted
|
|
39
|
+
*/
|
|
40
|
+
export function sweepStaleCorruptFiles(runsDir: string, maxAgeMs = DEFAULT_CORRUPT_FILE_TTL_MS, now = Date.now()): number {
|
|
41
|
+
let deleted = 0;
|
|
42
|
+
let runDirs: fs.Dirent[];
|
|
43
|
+
try {
|
|
44
|
+
runDirs = fs.readdirSync(runsDir, { withFileTypes: true });
|
|
45
|
+
} catch {
|
|
46
|
+
return 0;
|
|
47
|
+
}
|
|
48
|
+
for (const dir of runDirs) {
|
|
49
|
+
if (!dir.isDirectory()) continue;
|
|
50
|
+
const runDirPath = path.join(runsDir, dir.name);
|
|
51
|
+
let files: string[];
|
|
52
|
+
try {
|
|
53
|
+
files = fs.readdirSync(runDirPath);
|
|
54
|
+
} catch {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
for (const file of files) {
|
|
58
|
+
if (!file.includes(".corrupt-")) continue;
|
|
59
|
+
const filePath = path.join(runDirPath, file);
|
|
60
|
+
try {
|
|
61
|
+
const mtime = fs.statSync(filePath).mtimeMs;
|
|
62
|
+
if (now - mtime > maxAgeMs) {
|
|
63
|
+
fs.unlinkSync(filePath);
|
|
64
|
+
deleted++;
|
|
65
|
+
}
|
|
66
|
+
} catch {
|
|
67
|
+
// Best effort — file may have been removed concurrently
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return deleted;
|
|
72
|
+
}
|
|
73
|
+
|
|
24
74
|
function isFinished(run: TeamRunManifest): boolean {
|
|
25
75
|
// P3: "blocked" is NOT a terminal status — the run is waiting on something
|
|
26
76
|
// (plan approval, mailbox reply, scheduler stall) and can transition to
|
|
@@ -98,6 +148,9 @@ export function pruneFinishedRuns(cwd: string, keep: number, options: PruneRunsO
|
|
|
98
148
|
fs.rmSync(run.artifactsRoot, { recursive: true, force: true });
|
|
99
149
|
removed.push(run.runId);
|
|
100
150
|
}
|
|
151
|
+
// ST-6: Sweep stale .corrupt-* quarantine files to prevent unbounded growth.
|
|
152
|
+
sweepStaleCorruptFiles(path.join(projectCrewRoot(cwd), DEFAULT_PATHS.state.runsSubdir));
|
|
153
|
+
|
|
101
154
|
const auditPath = appendPruneAudit(cwd, {
|
|
102
155
|
action: "prune",
|
|
103
156
|
keep,
|
|
@@ -186,5 +239,8 @@ export function pruneUserLevelRuns(keep: number): PruneRunsResult {
|
|
|
186
239
|
removed.push(run.runId);
|
|
187
240
|
}
|
|
188
241
|
|
|
242
|
+
// ST-6: Sweep stale .corrupt-* quarantine files at user level too.
|
|
243
|
+
sweepStaleCorruptFiles(runsRoot);
|
|
244
|
+
|
|
189
245
|
return { kept, removed: [...removed, ...ghostRemoved] };
|
|
190
246
|
}
|
|
@@ -148,6 +148,8 @@ export async function handleTeamManagerCommand(_args: string, ctx: ExtensionComm
|
|
|
148
148
|
"Force cleanup?",
|
|
149
149
|
"Force may remove dirty worktrees. Choose false to preserve dirty worktrees and capture cleanup diffs.",
|
|
150
150
|
);
|
|
151
|
-
|
|
151
|
+
// SEC-5: confirm:true is implicit — the user explicitly invoked cleanup
|
|
152
|
+
// via the UI picker, so the self-enforcement guard is satisfied.
|
|
153
|
+
await notifyResult(ctx, await handleTeamTool({ action: "cleanup", runId, force, confirm: true }, ctx));
|
|
152
154
|
}
|
|
153
155
|
}
|
|
@@ -3,7 +3,13 @@
|
|
|
3
3
|
* Provides set/clear/status commands for anchor points.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
type AnchorManager,
|
|
8
|
+
AnchorNotFoundError,
|
|
9
|
+
type AnchorStatus,
|
|
10
|
+
createAnchorManager,
|
|
11
|
+
NoHandoffsError,
|
|
12
|
+
} from "../../runtime/anchor-manager.ts";
|
|
7
13
|
import type { HandoffSummary } from "../../runtime/handoff-manager.ts";
|
|
8
14
|
import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
|
|
9
15
|
import type { PiTeamsToolResult } from "../tool-result.ts";
|
|
@@ -130,7 +136,7 @@ export function handleAnchorStatus(params: TeamToolParamsValue, ctx: TeamContext
|
|
|
130
136
|
anchorId = cfg.anchorId as string;
|
|
131
137
|
}
|
|
132
138
|
|
|
133
|
-
let status;
|
|
139
|
+
let status: AnchorStatus | null;
|
|
134
140
|
if (anchorId) {
|
|
135
141
|
status = manager.getAnchorStatus(anchorId);
|
|
136
142
|
} else {
|