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
|
@@ -19,14 +19,14 @@
|
|
|
19
19
|
|
|
20
20
|
import { loadConfig } from "../../config/config.ts";
|
|
21
21
|
import type { GoalWrapWorkflowConfig } from "../../config/types.ts";
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
22
|
+
import { spawnBackgroundTeamRun } from "../../runtime/async-runner.ts";
|
|
23
|
+
import { GoalStore } from "../../runtime/goal-workflow/goal-state-store.ts";
|
|
24
|
+
import { snapshotManifests } from "../../runtime/verification/verification-integrity.ts";
|
|
24
25
|
import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
|
|
25
26
|
import { atomicWriteJson } from "../../state/atomic-write.ts";
|
|
26
|
-
import { appendEvent } from "../../state/event-log.ts";
|
|
27
|
-
import { createRunPaths, saveRunManifestAsync } from "../../state/state-store.ts";
|
|
27
|
+
import { appendEvent } from "../../state/event-log/event-log.ts";
|
|
28
|
+
import { createRunPaths, saveRunManifestAsync } from "../../state/stores/state-store.ts";
|
|
28
29
|
import type { GoalLoopState, TeamRunManifest } from "../../state/types.ts";
|
|
29
|
-
import { spawnBackgroundTeamRun } from "../../subagents/async-entry.ts";
|
|
30
30
|
import { logInternalError } from "../../utils/internal-error.ts";
|
|
31
31
|
import type { WorkflowConfig } from "../../workflows/workflow-config.ts";
|
|
32
32
|
import { result, type TeamContext } from "./context.ts";
|
|
@@ -14,16 +14,17 @@
|
|
|
14
14
|
* §0c C11 (control path: cooperative flag + handleCancel(currentRunId) via abortOwned).
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
17
|
+
import { spawnBackgroundTeamRun } from "../../runtime/async-runner.ts";
|
|
18
|
+
import { GoalStore } from "../../runtime/goal-workflow/goal-state-store.ts";
|
|
19
|
+
import { snapshotManifests } from "../../runtime/verification/verification-integrity.ts";
|
|
19
20
|
import { isWorkspaceBusy } from "../../runtime/workspace-lock.ts";
|
|
20
21
|
import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
|
|
21
|
-
import { appendEvent } from "../../state/event-log.ts";
|
|
22
|
-
import { createRunPaths, saveRunManifestAsync } from "../../state/state-store.ts";
|
|
22
|
+
import { appendEvent } from "../../state/event-log/event-log.ts";
|
|
23
|
+
import { createRunPaths, saveRunManifestAsync } from "../../state/stores/state-store.ts";
|
|
23
24
|
import type { GoalLoopState, GoalLoopStatus, TeamRunManifest } from "../../state/types.ts";
|
|
24
|
-
import { spawnBackgroundTeamRun } from "../../subagents/async-entry.ts";
|
|
25
25
|
import { logInternalError } from "../../utils/internal-error.ts";
|
|
26
26
|
import { result, type TeamContext } from "./context.ts";
|
|
27
|
+
import { paramRequired } from "./param-error.ts";
|
|
27
28
|
|
|
28
29
|
const MAX_GOAL_OBJECTIVE_CHARS = 4000;
|
|
29
30
|
|
|
@@ -296,7 +297,12 @@ function assertGoalOwnership(goal: GoalLoopState, ctx: TeamContext, action: stri
|
|
|
296
297
|
function handleStateFlip(input: GoalSubActionInput, nextState: GoalLoopStatus, label: string): ReturnType<typeof result> {
|
|
297
298
|
const { params, ctx, store } = input;
|
|
298
299
|
const goalId = params.config?.goalId as string | undefined;
|
|
299
|
-
if (!goalId)
|
|
300
|
+
if (!goalId)
|
|
301
|
+
return result(
|
|
302
|
+
paramRequired(label, "config.goalId", "{ action: 'goal', config: { goalId: '...' } }"),
|
|
303
|
+
{ action: "goal", status: "error" },
|
|
304
|
+
true,
|
|
305
|
+
);
|
|
300
306
|
const existing = store.load(goalId);
|
|
301
307
|
if (!existing) return result(`Goal '${goalId}' not found.`, { action: "goal", status: "error" }, true);
|
|
302
308
|
if (params.force !== true) {
|
|
@@ -325,7 +331,12 @@ function handleStateFlip(input: GoalSubActionInput, nextState: GoalLoopStatus, l
|
|
|
325
331
|
async function handleStop(input: GoalSubActionInput): Promise<ReturnType<typeof result>> {
|
|
326
332
|
const { params, ctx, store } = input;
|
|
327
333
|
const goalId = params.config?.goalId as string | undefined;
|
|
328
|
-
if (!goalId)
|
|
334
|
+
if (!goalId)
|
|
335
|
+
return result(
|
|
336
|
+
paramRequired("stop", "config.goalId", "{ action: 'goal', config: { subAction: 'stop', goalId: '...' } }"),
|
|
337
|
+
{ action: "goal", status: "error" },
|
|
338
|
+
true,
|
|
339
|
+
);
|
|
329
340
|
const eventsPath = createRunPaths(ctx.cwd, goalId).eventsPath;
|
|
330
341
|
const before = store.load(goalId);
|
|
331
342
|
if (!before) return result(`Goal '${goalId}' not found.`, { action: "goal", status: "error" }, true);
|
|
@@ -386,7 +397,12 @@ async function handleStop(input: GoalSubActionInput): Promise<ReturnType<typeof
|
|
|
386
397
|
async function handleResume(input: GoalSubActionInput): Promise<ReturnType<typeof result>> {
|
|
387
398
|
const { params, ctx, store } = input;
|
|
388
399
|
const goalId = params.config?.goalId as string | undefined;
|
|
389
|
-
if (!goalId)
|
|
400
|
+
if (!goalId)
|
|
401
|
+
return result(
|
|
402
|
+
paramRequired("resume", "config.goalId", "{ action: 'goal', config: { subAction: 'resume', goalId: '...' } }"),
|
|
403
|
+
{ action: "goal", status: "error" },
|
|
404
|
+
true,
|
|
405
|
+
);
|
|
390
406
|
const existing = store.load(goalId);
|
|
391
407
|
if (!existing) return result(`Goal '${goalId}' not found.`, { action: "goal", status: "error" }, true);
|
|
392
408
|
if (params.force !== true) {
|
|
@@ -510,7 +526,12 @@ export async function handleGoal(params: TeamToolParamsValue, ctx: TeamContext):
|
|
|
510
526
|
// Fix P1-3 + round-5 P2: remove the goal file. But refuse if the loop is still
|
|
511
527
|
// running (would leave a zombie background process). Require stop first.
|
|
512
528
|
const clearGoalId = params.config?.goalId as string | undefined;
|
|
513
|
-
if (!clearGoalId)
|
|
529
|
+
if (!clearGoalId)
|
|
530
|
+
return result(
|
|
531
|
+
paramRequired("clear", "config.goalId", "{ action: 'goal', config: { subAction: 'clear', goalId: '...' } }"),
|
|
532
|
+
{ action: "goal", status: "error" },
|
|
533
|
+
true,
|
|
534
|
+
);
|
|
514
535
|
const existing = store.load(clearGoalId);
|
|
515
536
|
if (!existing) return result(`Goal '${clearGoalId}' not found (already cleared?).`, { action: "goal", status: "error" }, true);
|
|
516
537
|
if (params.force !== true) {
|
|
@@ -1,28 +1,39 @@
|
|
|
1
1
|
import * as crypto from "node:crypto";
|
|
2
|
-
import { humanizeSchedule, nextRunTime, parseSchedule } from "../../runtime/scheduler.ts";
|
|
2
|
+
import { humanizeSchedule, nextRunTime, parseSchedule } from "../../runtime/scheduling/scheduler.ts";
|
|
3
3
|
import { type CrewSettings, updateCrewSettings } from "../../runtime/settings-store.ts";
|
|
4
4
|
import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
|
|
5
5
|
import type { PiTeamsToolResult } from "../tool-result.ts";
|
|
6
6
|
import { result, type TeamContext } from "./context.ts";
|
|
7
|
+
import { paramRequired } from "./param-error.ts";
|
|
7
8
|
|
|
8
|
-
//
|
|
9
|
-
|
|
9
|
+
// Module-scoped scheduler reference — one per extension load (EXT-9).
|
|
10
|
+
// Previously this lived on `globalThis[Symbol.for("pi-crew:scheduler")]`, which
|
|
11
|
+
// was fragile (cross-realm, no lifecycle, peer extensions could overwrite it).
|
|
10
12
|
type SchedulerRef = {
|
|
11
|
-
add(job: import("../../runtime/scheduler.ts").ScheduledJob): void;
|
|
12
|
-
list(): import("../../runtime/scheduler.ts").ScheduledJob[];
|
|
13
|
+
add(job: import("../../runtime/scheduling/scheduler.ts").ScheduledJob): void;
|
|
14
|
+
list(): import("../../runtime/scheduling/scheduler.ts").ScheduledJob[];
|
|
13
15
|
remove(id: string): boolean;
|
|
14
16
|
update(
|
|
15
17
|
id: string,
|
|
16
|
-
patch: Partial<import("../../runtime/scheduler.ts").ScheduledJob>,
|
|
17
|
-
): import("../../runtime/scheduler.ts").ScheduledJob | undefined;
|
|
18
|
+
patch: Partial<import("../../runtime/scheduling/scheduler.ts").ScheduledJob>,
|
|
19
|
+
): import("../../runtime/scheduling/scheduler.ts").ScheduledJob | undefined;
|
|
18
20
|
};
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
// Module-scoped scheduler instance — one per extension load (EXT-9).
|
|
23
|
+
let crewSchedulerInstance: SchedulerRef | undefined;
|
|
24
|
+
|
|
25
|
+
/** @internal — exported for lifecycle tests. */
|
|
26
|
+
export function getCrewScheduler(): SchedulerRef | undefined {
|
|
27
|
+
return crewSchedulerInstance;
|
|
22
28
|
}
|
|
23
29
|
|
|
24
30
|
export function registerCrewScheduler(scheduler: SchedulerRef): void {
|
|
25
|
-
|
|
31
|
+
crewSchedulerInstance = scheduler;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Remove the scheduler singleton. Call during session cleanup. */
|
|
35
|
+
export function unregisterCrewScheduler(): void {
|
|
36
|
+
crewSchedulerInstance = undefined;
|
|
26
37
|
}
|
|
27
38
|
|
|
28
39
|
interface ScheduleParams {
|
|
@@ -35,9 +46,9 @@ interface ScheduleParams {
|
|
|
35
46
|
}
|
|
36
47
|
|
|
37
48
|
function buildScheduleSpec(params: ScheduleParams): {
|
|
38
|
-
spec: import("../../runtime/scheduler.ts").ScheduleSpec;
|
|
49
|
+
spec: import("../../runtime/scheduling/scheduler.ts").ScheduleSpec;
|
|
39
50
|
schedule: string;
|
|
40
|
-
scheduleType: import("../../runtime/scheduler.ts").ScheduleType;
|
|
51
|
+
scheduleType: import("../../runtime/scheduling/scheduler.ts").ScheduleType;
|
|
41
52
|
intervalMs?: number;
|
|
42
53
|
} {
|
|
43
54
|
// Priority: cron > interval > once
|
|
@@ -100,7 +111,12 @@ export function handleSchedule(params: TeamToolParamsValue, ctx: TeamContext): P
|
|
|
100
111
|
|
|
101
112
|
const team = params.team ?? "default";
|
|
102
113
|
const goal = params.goal ?? params.task ?? "";
|
|
103
|
-
if (!goal)
|
|
114
|
+
if (!goal)
|
|
115
|
+
return result(
|
|
116
|
+
paramRequired("schedule", "goal or task", "{ action: 'schedule', goal: '...', cron: '0 9 * * *' }"),
|
|
117
|
+
{ action: "schedule", status: "error" },
|
|
118
|
+
true,
|
|
119
|
+
);
|
|
104
120
|
|
|
105
121
|
let specResult: ReturnType<typeof buildScheduleSpec>;
|
|
106
122
|
try {
|
|
@@ -121,7 +137,7 @@ export function handleSchedule(params: TeamToolParamsValue, ctx: TeamContext): P
|
|
|
121
137
|
if ("error" in next) return result(next.error, { action: "schedule", status: "error" }, true);
|
|
122
138
|
|
|
123
139
|
// Build the ScheduledJob
|
|
124
|
-
const job: import("../../runtime/scheduler.ts").ScheduledJob = {
|
|
140
|
+
const job: import("../../runtime/scheduling/scheduler.ts").ScheduledJob = {
|
|
125
141
|
id: crypto.randomUUID(),
|
|
126
142
|
name: `${team}: ${goal.slice(0, 60)}`,
|
|
127
143
|
description: `Scheduled run for team '${team}'`,
|
|
@@ -190,11 +206,13 @@ export function handleSchedule(params: TeamToolParamsValue, ctx: TeamContext): P
|
|
|
190
206
|
);
|
|
191
207
|
}
|
|
192
208
|
|
|
193
|
-
function scheduledJobsOf(settings: CrewSettings): import("../../runtime/scheduler.ts").ScheduledJob[] {
|
|
194
|
-
return Array.isArray(settings.scheduledJobs)
|
|
209
|
+
function scheduledJobsOf(settings: CrewSettings): import("../../runtime/scheduling/scheduler.ts").ScheduledJob[] {
|
|
210
|
+
return Array.isArray(settings.scheduledJobs)
|
|
211
|
+
? (settings.scheduledJobs as import("../../runtime/scheduling/scheduler.ts").ScheduledJob[])
|
|
212
|
+
: [];
|
|
195
213
|
}
|
|
196
214
|
|
|
197
|
-
function persistScheduledJob(cwd: string, job: import("../../runtime/scheduler.ts").ScheduledJob): void {
|
|
215
|
+
function persistScheduledJob(cwd: string, job: import("../../runtime/scheduling/scheduler.ts").ScheduledJob): void {
|
|
198
216
|
try {
|
|
199
217
|
updateCrewSettings(cwd, (settings) => ({
|
|
200
218
|
...settings,
|
|
@@ -206,7 +224,7 @@ function persistScheduledJob(cwd: string, job: import("../../runtime/scheduler.t
|
|
|
206
224
|
}
|
|
207
225
|
|
|
208
226
|
/** Update an existing scheduled job in persistent settings. */
|
|
209
|
-
export function persistScheduledJobUpdate(cwd: string, job: import("../../runtime/scheduler.ts").ScheduledJob): void {
|
|
227
|
+
export function persistScheduledJobUpdate(cwd: string, job: import("../../runtime/scheduling/scheduler.ts").ScheduledJob): void {
|
|
210
228
|
try {
|
|
211
229
|
updateCrewSettings(cwd, (settings) => ({
|
|
212
230
|
...settings,
|
|
@@ -309,7 +327,7 @@ export function handleUpdateScheduled(params: TeamToolParamsValue, ctx: TeamCont
|
|
|
309
327
|
return result("Scheduler not running.", { action: "schedule", status: "error" }, true);
|
|
310
328
|
}
|
|
311
329
|
|
|
312
|
-
const patch: Partial<import("../../runtime/scheduler.ts").ScheduledJob> = {};
|
|
330
|
+
const patch: Partial<import("../../runtime/scheduling/scheduler.ts").ScheduledJob> = {};
|
|
313
331
|
if (subAction === "disable") patch.enabled = false;
|
|
314
332
|
if (subAction === "enable") patch.enabled = true;
|
|
315
333
|
// For generic "update", allow patch of cron / interval / goal.
|
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
|
|
2
|
-
import { readEvents } from "../../state/event-log.ts";
|
|
3
|
-
import { loadRunManifestById } from "../../state/state-store.ts";
|
|
2
|
+
import { readEvents } from "../../state/event-log/event-log.ts";
|
|
3
|
+
import { loadRunManifestById } from "../../state/stores/state-store.ts";
|
|
4
4
|
import { aggregateUsage, formatCostReport, formatUsage } from "../../state/usage.ts";
|
|
5
5
|
import { locateRunCwd } from "../team-tool.ts";
|
|
6
6
|
import type { PiTeamsToolResult } from "../tool-result.ts";
|
|
7
7
|
import { result, type TeamContext } from "./context.ts";
|
|
8
8
|
import { formatFailurePatterns } from "./failure-patterns.ts";
|
|
9
|
+
import { paramRequired } from "./param-error.ts";
|
|
9
10
|
import { RUN_NOT_FOUND_HINT } from "./run-not-found.ts";
|
|
10
11
|
|
|
11
12
|
export function handleEvents(params: TeamToolParamsValue, ctx: TeamContext): PiTeamsToolResult {
|
|
12
|
-
if (!params.runId)
|
|
13
|
+
if (!params.runId)
|
|
14
|
+
return result(
|
|
15
|
+
paramRequired("events", "runId", "{ action: 'events', runId: 'team_...' }"),
|
|
16
|
+
{ action: "events", status: "error" },
|
|
17
|
+
true,
|
|
18
|
+
);
|
|
13
19
|
const runCwd = locateRunCwd(params.runId, ctx.cwd);
|
|
14
20
|
if (!runCwd) return result(`Run '${params.runId}' not found.${RUN_NOT_FOUND_HINT}`, { action: "events", status: "error" }, true);
|
|
15
21
|
const loaded = loadRunManifestById(runCwd, params.runId); // NOTE: no withRunLock - best-effort only; concurrent writes may cause inconsistency
|
|
@@ -33,7 +39,12 @@ export function handleEvents(params: TeamToolParamsValue, ctx: TeamContext): PiT
|
|
|
33
39
|
}
|
|
34
40
|
|
|
35
41
|
export function handleArtifacts(params: TeamToolParamsValue, ctx: TeamContext): PiTeamsToolResult {
|
|
36
|
-
if (!params.runId)
|
|
42
|
+
if (!params.runId)
|
|
43
|
+
return result(
|
|
44
|
+
paramRequired("artifacts", "runId", "{ action: 'artifacts', runId: 'team_...' }"),
|
|
45
|
+
{ action: "artifacts", status: "error" },
|
|
46
|
+
true,
|
|
47
|
+
);
|
|
37
48
|
const runCwd = locateRunCwd(params.runId, ctx.cwd);
|
|
38
49
|
if (!runCwd) return result(`Run '${params.runId}' not found.${RUN_NOT_FOUND_HINT}`, { action: "artifacts", status: "error" }, true);
|
|
39
50
|
const loaded = loadRunManifestById(runCwd, params.runId); // NOTE: no withRunLock - best-effort only; concurrent writes may cause inconsistency
|
|
@@ -56,7 +67,12 @@ export function handleArtifacts(params: TeamToolParamsValue, ctx: TeamContext):
|
|
|
56
67
|
}
|
|
57
68
|
|
|
58
69
|
export function handleSummary(params: TeamToolParamsValue, ctx: TeamContext): PiTeamsToolResult {
|
|
59
|
-
if (!params.runId)
|
|
70
|
+
if (!params.runId)
|
|
71
|
+
return result(
|
|
72
|
+
paramRequired("summary", "runId", "{ action: 'summary', runId: 'team_...' }"),
|
|
73
|
+
{ action: "summary", status: "error" },
|
|
74
|
+
true,
|
|
75
|
+
);
|
|
60
76
|
const runCwd = locateRunCwd(params.runId, ctx.cwd);
|
|
61
77
|
if (!runCwd) return result(`Run '${params.runId}' not found.${RUN_NOT_FOUND_HINT}`, { action: "summary", status: "error" }, true);
|
|
62
78
|
const loaded = loadRunManifestById(runCwd, params.runId); // NOTE: no withRunLock - best-effort only; concurrent writes may cause inconsistency
|
|
@@ -2,11 +2,11 @@ import * as fs from "node:fs";
|
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { removeGuidance } from "../../config/markers.ts";
|
|
4
4
|
import { appendHookEvent, executeHook } from "../../hooks/registry.ts";
|
|
5
|
-
import { killProcessPid } from "../../runtime/child-pi.ts";
|
|
6
|
-
import { terminateLiveAgentsForRun } from "../../runtime/live-agent-manager.ts";
|
|
5
|
+
import { killProcessPid } from "../../runtime/child-pi/child-pi.ts";
|
|
6
|
+
import { terminateLiveAgentsForRun } from "../../runtime/live-session/live-agent-manager.ts";
|
|
7
7
|
import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
|
|
8
|
-
import { appendEvent } from "../../state/event-log.ts";
|
|
9
|
-
import { loadRunManifestById } from "../../state/state-store.ts";
|
|
8
|
+
import { appendEvent } from "../../state/event-log/event-log.ts";
|
|
9
|
+
import { loadRunManifestById } from "../../state/stores/state-store.ts";
|
|
10
10
|
import { logInternalError } from "../../utils/internal-error.ts";
|
|
11
11
|
import { projectCrewRoot, userCrewRoot, userPiRoot } from "../../utils/paths.ts";
|
|
12
12
|
import { resolveRealContainedPath } from "../../utils/safe-paths.ts";
|
|
@@ -18,10 +18,16 @@ import { pruneFinishedRuns } from "../run-maintenance.ts";
|
|
|
18
18
|
import type { PiTeamsToolResult } from "../tool-result.ts";
|
|
19
19
|
import { configRecord, result, type TeamContext } from "./context.ts";
|
|
20
20
|
import { enforceDestructiveIntent, intentFromConfig } from "./intent-policy.ts";
|
|
21
|
+
import { paramRequired } from "./param-error.ts";
|
|
21
22
|
import { RUN_NOT_FOUND_HINT } from "./run-not-found.ts";
|
|
22
23
|
|
|
23
24
|
export function handleWorktrees(params: TeamToolParamsValue, ctx: TeamContext): PiTeamsToolResult {
|
|
24
|
-
if (!params.runId)
|
|
25
|
+
if (!params.runId)
|
|
26
|
+
return result(
|
|
27
|
+
paramRequired("worktrees", "runId", "{ action: 'worktrees', runId: 'team_...' }"),
|
|
28
|
+
{ action: "worktrees", status: "error" },
|
|
29
|
+
true,
|
|
30
|
+
);
|
|
25
31
|
const loaded = loadRunManifestById(ctx.cwd, params.runId); // NOTE: no withRunLock - best-effort only; concurrent writes may cause inconsistency
|
|
26
32
|
if (!loaded) return result(`Run '${params.runId}' not found.${RUN_NOT_FOUND_HINT}`, { action: "worktrees", status: "error" }, true);
|
|
27
33
|
const withWorktrees = loaded.tasks.filter((task) => task.worktree);
|
|
@@ -59,7 +65,16 @@ export function handleImports(_params: TeamToolParamsValue, ctx: TeamContext): P
|
|
|
59
65
|
export function handleImport(params: TeamToolParamsValue, ctx: TeamContext): PiTeamsToolResult {
|
|
60
66
|
const cfg = configRecord(params.config);
|
|
61
67
|
const bundlePath = typeof cfg.path === "string" ? cfg.path : typeof cfg.bundlePath === "string" ? cfg.bundlePath : undefined;
|
|
62
|
-
if (!bundlePath)
|
|
68
|
+
if (!bundlePath)
|
|
69
|
+
return result(
|
|
70
|
+
paramRequired(
|
|
71
|
+
"import",
|
|
72
|
+
"config.path pointing at run-export.json",
|
|
73
|
+
"{ action: 'import', config: { path: '/path/to/run-export.json' } }",
|
|
74
|
+
),
|
|
75
|
+
{ action: "import", status: "error" },
|
|
76
|
+
true,
|
|
77
|
+
);
|
|
63
78
|
const scope = cfg.scope === "user" ? "user" : "project";
|
|
64
79
|
try {
|
|
65
80
|
const imported = importRunBundle(ctx.cwd, bundlePath, scope);
|
|
@@ -74,7 +89,12 @@ export function handleImport(params: TeamToolParamsValue, ctx: TeamContext): PiT
|
|
|
74
89
|
}
|
|
75
90
|
|
|
76
91
|
export async function handleExport(params: TeamToolParamsValue, ctx: TeamContext): Promise<PiTeamsToolResult> {
|
|
77
|
-
if (!params.runId)
|
|
92
|
+
if (!params.runId)
|
|
93
|
+
return result(
|
|
94
|
+
paramRequired("export", "runId", "{ action: 'export', runId: 'team_...' }"),
|
|
95
|
+
{ action: "export", status: "error" },
|
|
96
|
+
true,
|
|
97
|
+
);
|
|
78
98
|
const loaded = loadRunManifestById(ctx.cwd, params.runId); // NOTE: no withRunLock - best-effort only; concurrent writes may cause inconsistency
|
|
79
99
|
if (!loaded) return result(`Run '${params.runId}' not found.${RUN_NOT_FOUND_HINT}`, { action: "export", status: "error" }, true);
|
|
80
100
|
|
|
@@ -126,7 +146,12 @@ export async function handleExport(params: TeamToolParamsValue, ctx: TeamContext
|
|
|
126
146
|
export async function handlePrune(params: TeamToolParamsValue, ctx: TeamContext): Promise<PiTeamsToolResult> {
|
|
127
147
|
const intentError = enforceDestructiveIntent("prune", params, ctx.config);
|
|
128
148
|
if (intentError) return intentError;
|
|
129
|
-
if (!params.confirm)
|
|
149
|
+
if (!params.confirm)
|
|
150
|
+
return result(
|
|
151
|
+
paramRequired("prune", "confirm: true", "{ action: 'prune', confirm: true }"),
|
|
152
|
+
{ action: "prune", status: "error" },
|
|
153
|
+
true,
|
|
154
|
+
);
|
|
130
155
|
const keep = params.keep ?? 20;
|
|
131
156
|
if (keep < 0 || !Number.isInteger(keep)) return result("keep must be an integer >= 0.", { action: "prune", status: "error" }, true);
|
|
132
157
|
const intent = intentFromConfig(params.config);
|
|
@@ -164,8 +189,18 @@ export async function handlePrune(params: TeamToolParamsValue, ctx: TeamContext)
|
|
|
164
189
|
export async function handleForget(params: TeamToolParamsValue, ctx: TeamContext): Promise<PiTeamsToolResult> {
|
|
165
190
|
const intentError = enforceDestructiveIntent("forget", params, ctx.config);
|
|
166
191
|
if (intentError) return intentError;
|
|
167
|
-
if (!params.runId)
|
|
168
|
-
|
|
192
|
+
if (!params.runId)
|
|
193
|
+
return result(
|
|
194
|
+
paramRequired("forget", "runId", "{ action: 'forget', runId: 'team_...', confirm: true }"),
|
|
195
|
+
{ action: "forget", status: "error" },
|
|
196
|
+
true,
|
|
197
|
+
);
|
|
198
|
+
if (!params.confirm)
|
|
199
|
+
return result(
|
|
200
|
+
paramRequired("forget", "confirm: true", "{ action: 'forget', runId: 'team_...', confirm: true }"),
|
|
201
|
+
{ action: "forget", status: "error" },
|
|
202
|
+
true,
|
|
203
|
+
);
|
|
169
204
|
const loaded = loadRunManifestById(ctx.cwd, params.runId); // NOTE: no withRunLock - best-effort only; concurrent writes may cause inconsistency
|
|
170
205
|
if (!loaded) return result(`Run '${params.runId}' not found.${RUN_NOT_FOUND_HINT}`, { action: "forget", status: "error" }, true);
|
|
171
206
|
|
|
@@ -269,6 +304,14 @@ export async function handleCleanup(params: TeamToolParamsValue, ctx: TeamContex
|
|
|
269
304
|
// can stay focused on their own logic.
|
|
270
305
|
const intentError = enforceDestructiveIntent("cleanup", params, ctx.config);
|
|
271
306
|
if (intentError) return intentError;
|
|
307
|
+
// SEC-5: self-enforce confirm:true (defense-in-depth), matching handlePrune/handleForget.
|
|
308
|
+
// dryRun:true is a non-destructive preview and is always allowed.
|
|
309
|
+
if (params.confirm !== true && params.dryRun !== true)
|
|
310
|
+
return result(
|
|
311
|
+
paramRequired("cleanup", "confirm: true", "{ action: 'cleanup', confirm: true }"),
|
|
312
|
+
{ action: "cleanup", status: "error" },
|
|
313
|
+
true,
|
|
314
|
+
);
|
|
272
315
|
// Three cleanup modes:
|
|
273
316
|
// 1. WITH runId → per-run worktree cleanup (existing behavior).
|
|
274
317
|
// 2. WITHOUT runId, scope=project (default) → PROJECT-LEVEL uninstall:
|
|
@@ -8,11 +8,11 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { discoverAgents } from "../../agents/discover-agents.ts";
|
|
10
10
|
import { loadConfig } from "../../config/config.ts";
|
|
11
|
-
import {
|
|
11
|
+
import { spawnBackgroundTeamRun } from "../../runtime/async-runner.ts";
|
|
12
|
+
import { resolveCrewRuntime } from "../../runtime/model/runtime-resolver.ts";
|
|
12
13
|
import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
|
|
13
|
-
import { appendEvent } from "../../state/event-log.ts";
|
|
14
|
-
import { createRunManifest } from "../../state/state-store.ts";
|
|
15
|
-
import { spawnBackgroundTeamRun } from "../../subagents/async-entry.ts";
|
|
14
|
+
import { appendEvent } from "../../state/event-log/event-log.ts";
|
|
15
|
+
import { createRunManifest } from "../../state/stores/state-store.ts";
|
|
16
16
|
import { discoverTeams } from "../../teams/discover-teams.ts";
|
|
17
17
|
import type { TeamConfig } from "../../teams/team-config.ts";
|
|
18
18
|
import { discoverWorkflows } from "../../workflows/discover-workflows.ts";
|
|
@@ -20,6 +20,7 @@ import type { WorkflowConfig } from "../../workflows/workflow-config.ts";
|
|
|
20
20
|
import { resolveCwdOverride } from "../registration/team-tool.ts";
|
|
21
21
|
import type { PiTeamsToolResult } from "../tool-result.ts";
|
|
22
22
|
import { result, type TeamContext } from "./context.ts";
|
|
23
|
+
import { paramRequired } from "./param-error.ts";
|
|
23
24
|
|
|
24
25
|
const MAX_CONCURRENCY = 8;
|
|
25
26
|
const DEFAULT_CONCURRENCY = 4;
|
|
@@ -29,7 +30,15 @@ const DEFAULT_AGENT = "explorer";
|
|
|
29
30
|
export async function handleParallel(params: TeamToolParamsValue, ctx: TeamContext): Promise<PiTeamsToolResult> {
|
|
30
31
|
const tasksParam = params.config?.tasks;
|
|
31
32
|
if (!Array.isArray(tasksParam) || tasksParam.length === 0) {
|
|
32
|
-
return result(
|
|
33
|
+
return result(
|
|
34
|
+
paramRequired(
|
|
35
|
+
"parallel",
|
|
36
|
+
"config.tasks: [{goal, agent?}]",
|
|
37
|
+
"{ action: 'parallel', config: { tasks: [{ goal: '...', agent: 'explorer' }] } }",
|
|
38
|
+
),
|
|
39
|
+
{ action: "parallel", status: "error" },
|
|
40
|
+
true,
|
|
41
|
+
);
|
|
33
42
|
}
|
|
34
43
|
|
|
35
44
|
const concurrency = Math.min(Math.max(1, Math.floor((params.config?.concurrency as number) ?? DEFAULT_CONCURRENCY)), MAX_CONCURRENCY);
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Friendly team-tool parameter validation error formatting.
|
|
3
|
+
*
|
|
4
|
+
* The team tool validates every call with `Value.Check(TeamToolParams, ...)`.
|
|
5
|
+
* On failure it used to return the opaque `"Invalid team tool parameters"` —
|
|
6
|
+
* which gave calling agents (LLMs) no clue WHAT was wrong, so they retried the
|
|
7
|
+
* same malformed shape indefinitely (observed in the wild: agents passing
|
|
8
|
+
* `goal` as an array/object, or `action` with wrong casing, then looping).
|
|
9
|
+
*
|
|
10
|
+
* `formatTeamToolParamError` produces an actionable message:
|
|
11
|
+
* 1. Targeted heuristics for the COMMON mistakes (action casing; goal/team/
|
|
12
|
+
* runId passed as a non-string) — pinpoint the exact field, because the
|
|
13
|
+
* TypeBox Union reports only a root-level "Expected union value".
|
|
14
|
+
* 2. TypeBox `Value.Errors` output (catches anything the heuristics miss).
|
|
15
|
+
* 3. Concrete correct-call examples for the common actions.
|
|
16
|
+
* Agents can self-correct from this instead of looping.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import type { TSchema } from "@sinclair/typebox";
|
|
20
|
+
import { Value } from "@sinclair/typebox/value";
|
|
21
|
+
|
|
22
|
+
/** Short human description of a received value (for error messages). */
|
|
23
|
+
function describeValue(v: unknown): string {
|
|
24
|
+
if (v === null) return "null";
|
|
25
|
+
if (Array.isArray(v)) return `array (length ${v.length})`;
|
|
26
|
+
if (typeof v === "object") return "object";
|
|
27
|
+
if (typeof v === "string") return `string "${v.length > 40 ? `${v.slice(0, 37)}...` : v}"`;
|
|
28
|
+
return `${typeof v} (${String(v).slice(0, 40)})`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Pinpoint the common agent mistakes that TypeBox Union can't field-locate. */
|
|
32
|
+
function diagnoseCommonMistakes(params: unknown): string[] {
|
|
33
|
+
const hints: string[] = [];
|
|
34
|
+
if (typeof params !== "object" || params === null || Array.isArray(params)) {
|
|
35
|
+
return hints;
|
|
36
|
+
}
|
|
37
|
+
const p = params as Record<string, unknown>;
|
|
38
|
+
|
|
39
|
+
// action: casing / non-string
|
|
40
|
+
if ("action" in p) {
|
|
41
|
+
const a = p.action;
|
|
42
|
+
if (typeof a !== "string") {
|
|
43
|
+
hints.push(` • 'action': must be a lowercase string (e.g. "run", "status", "list") — got ${describeValue(a)}.`);
|
|
44
|
+
} else if (a !== a.toLowerCase()) {
|
|
45
|
+
hints.push(` • 'action': "${a}" has wrong casing — action is case-sensitive. Use "${a.toLowerCase()}".`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Flat-string fields that agents commonly pass as objects/arrays
|
|
50
|
+
const stringFields = ["goal", "team", "runId", "task", "role", "agent", "workflow", "model", "cwd", "chain"];
|
|
51
|
+
for (const f of stringFields) {
|
|
52
|
+
if (!(f in p)) continue;
|
|
53
|
+
const v = p[f];
|
|
54
|
+
if (typeof v === "string") continue;
|
|
55
|
+
if (Array.isArray(v)) {
|
|
56
|
+
hints.push(
|
|
57
|
+
` • '${f}': must be a single flat string — got an array (length ${v.length}). Pass e.g. "${f}": "<value>", not a list.`,
|
|
58
|
+
);
|
|
59
|
+
} else if (typeof v === "object" && v !== null) {
|
|
60
|
+
hints.push(` • '${f}': must be a single flat string — got an object. Pass e.g. "${f}": "<value>".`);
|
|
61
|
+
} else {
|
|
62
|
+
hints.push(` • '${f}': must be a string — got ${describeValue(v)}.`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return hints;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Build a helpful validation-failure message for a team-tool call.
|
|
70
|
+
*
|
|
71
|
+
* @param schema The TypeBox schema (TeamToolParams) that rejected the params.
|
|
72
|
+
* @param params The raw params the caller passed.
|
|
73
|
+
* @returns A multi-line message: what went wrong + correct-call examples.
|
|
74
|
+
*/
|
|
75
|
+
export function formatTeamToolParamError(schema: TSchema, params: unknown): string {
|
|
76
|
+
const issues = [...diagnoseCommonMistakes(params)];
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
const errors = [...Value.Errors(schema, params)];
|
|
80
|
+
const seen = new Set<string>();
|
|
81
|
+
for (const e of errors) {
|
|
82
|
+
if (issues.length >= 8) break;
|
|
83
|
+
const key = `${e.path}|${e.type}`;
|
|
84
|
+
if (seen.has(key)) continue;
|
|
85
|
+
seen.add(key);
|
|
86
|
+
const pathLabel = e.path ? `'${e.path}'` : "(schema)";
|
|
87
|
+
issues.push(` • ${pathLabel}: ${e.message} — received ${describeValue(e.value)}`);
|
|
88
|
+
}
|
|
89
|
+
} catch {
|
|
90
|
+
/* Value.Errors itself threw — the heuristic issues are still shown */
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (issues.length === 0) {
|
|
94
|
+
issues.push(" • params did not match any valid team-tool action shape");
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return [
|
|
98
|
+
"Invalid team tool parameters — the call was rejected by schema validation.",
|
|
99
|
+
"",
|
|
100
|
+
"What went wrong:",
|
|
101
|
+
...issues,
|
|
102
|
+
"",
|
|
103
|
+
"Correct call shapes — `action` is case-sensitive (lowercase); `goal`,",
|
|
104
|
+
"`team`, `runId`, `task`, `role` MUST be flat strings, never objects/arrays:",
|
|
105
|
+
' • Run a team: { "action": "run", "goal": "<what to achieve>", "team": "implementation" }',
|
|
106
|
+
' • Suggest a team: { "action": "recommend", "goal": "<what to achieve>" }',
|
|
107
|
+
' • List recent runs: { "action": "list" }',
|
|
108
|
+
' • Run status: { "action": "status", "runId": "<runId>" }',
|
|
109
|
+
' • Direct one agent: { "action": "run", "role": "<agent>", "task": "<one task>" }',
|
|
110
|
+
"",
|
|
111
|
+
'Common mistakes: `action` uppercase (use "run" not "Run"); `goal` passed',
|
|
112
|
+
"as an array/object instead of a single string; params nested instead of flat.",
|
|
113
|
+
].join("\n");
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Build a runtime handler error string for a MISSING REQUIRED FIELD, including
|
|
118
|
+
* a concrete example shape so the calling agent (LLM) can self-correct instead
|
|
119
|
+
* of looping on the same malformed call.
|
|
120
|
+
*
|
|
121
|
+
* The schema-validation path (`formatTeamToolParamError` above) already
|
|
122
|
+
* provides rich examples, but runtime handler errors used to return a plain
|
|
123
|
+
* `"X requires Y."` with NO example — giving LLMs worse guidance for the MORE
|
|
124
|
+
* COMMON failure (valid action, missing field). This helper closes that
|
|
125
|
+
* two-tier error-quality gap (AUDIT-2026-07-30 EXT-2).
|
|
126
|
+
*
|
|
127
|
+
* @param action The team-tool action (e.g. "status", "cancel").
|
|
128
|
+
* @param field The required field/fields (e.g. "runId", "goal or task").
|
|
129
|
+
* @param example Optional concrete example shape,
|
|
130
|
+
* e.g. `{ action: 'status', runId: 'team_...' }`.
|
|
131
|
+
* @returns An error string like
|
|
132
|
+
* `"Status requires runId. Example: { action: 'status', runId: 'team_...' }"`.
|
|
133
|
+
*/
|
|
134
|
+
export function paramRequired(action: string, field: string, example?: string): string {
|
|
135
|
+
const subject = action.charAt(0).toUpperCase() + action.slice(1);
|
|
136
|
+
const base = `${subject} requires ${field}.`;
|
|
137
|
+
return example ? `${base} Example: ${example}` : base;
|
|
138
|
+
}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { readCrewAgents, recordFromTask, saveCrewAgents } from "../../runtime/crew-agent-records.ts";
|
|
2
2
|
import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { loadRunManifestById, saveRunTasks, updateRunStatus } from "../../state/state-store.ts";
|
|
3
|
+
import { withRunLockSync } from "../../state/coordination/locks.ts";
|
|
4
|
+
import { appendMailboxMessage, updateMailboxMessageReply } from "../../state/coordination/mailbox.ts";
|
|
5
|
+
import { appendEvent } from "../../state/event-log/event-log.ts";
|
|
6
|
+
import { loadRunManifestById, saveRunTasks, updateRunStatus } from "../../state/stores/state-store.ts";
|
|
7
7
|
import { logInternalError } from "../../utils/internal-error.ts";
|
|
8
8
|
import { locateRunCwd } from "../team-tool.ts";
|
|
9
9
|
import type { PiTeamsToolResult } from "../tool-result.ts";
|
|
10
10
|
import { result, type TeamContext } from "./context.ts";
|
|
11
|
+
import { paramRequired } from "./param-error.ts";
|
|
11
12
|
import { RUN_NOT_FOUND_HINT } from "./run-not-found.ts";
|
|
12
13
|
|
|
13
14
|
/**
|
|
@@ -16,9 +17,22 @@ import { RUN_NOT_FOUND_HINT } from "./run-not-found.ts";
|
|
|
16
17
|
* mailbox and the task is re-queued for durable scheduler resume.
|
|
17
18
|
*/
|
|
18
19
|
export function handleRespond(params: TeamToolParamsValue, ctx: TeamContext): PiTeamsToolResult {
|
|
19
|
-
if (!params.runId)
|
|
20
|
+
if (!params.runId)
|
|
21
|
+
return result(
|
|
22
|
+
paramRequired("respond", "runId", "{ action: 'respond', runId: 'team_...', message: '...' }"),
|
|
23
|
+
{ action: "respond", status: "error" },
|
|
24
|
+
true,
|
|
25
|
+
);
|
|
20
26
|
if (!params.message && !params.taskId)
|
|
21
|
-
return result(
|
|
27
|
+
return result(
|
|
28
|
+
paramRequired(
|
|
29
|
+
"respond",
|
|
30
|
+
"taskId and/or message",
|
|
31
|
+
"{ action: 'respond', runId: 'team_...', taskId: '01_agent', message: '...' }",
|
|
32
|
+
),
|
|
33
|
+
{ action: "respond", status: "error" },
|
|
34
|
+
true,
|
|
35
|
+
);
|
|
22
36
|
|
|
23
37
|
const runCwd = locateRunCwd(params.runId, ctx.cwd);
|
|
24
38
|
if (!runCwd) return result(`Run '${params.runId}' not found.${RUN_NOT_FOUND_HINT}`, { action: "respond", status: "error" }, true);
|