pi-crew 0.2.2 → 0.2.4
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 +57 -32
- package/CHANGELOG.md +466 -413
- package/LICENSE +21 -21
- package/NOTICE.md +16 -16
- package/README.md +323 -323
- package/docs/FEATURE_INTAKE.md +126 -0
- package/docs/HARNESS.md +86 -0
- package/docs/HARNESS_BACKLOG.md +41 -0
- package/docs/TEST_MATRIX.md +49 -0
- package/docs/actions-reference.md +595 -595
- package/docs/architecture.md +180 -180
- package/docs/code-review-2026-05-11.md +592 -0
- package/docs/commands-reference.md +347 -347
- package/docs/comparison-pi-subagents-vs-pi-crew.md +303 -0
- package/docs/decisions/0001-durable-state.md +41 -0
- package/docs/decisions/0002-child-process-for-async.md +42 -0
- package/docs/decisions/0003-depth-guard.md +36 -0
- package/docs/decisions/0004-execfile-over-exec.md +34 -0
- package/docs/decisions/0005-no-parameter-properties.md +49 -0
- package/docs/decisions/0006-publish-bundled-esm.md +63 -0
- package/docs/decisions/0007-active-run-binary-index.md +54 -0
- package/docs/decisions/0008-child-pi-warm-pool.md +61 -0
- package/docs/decisions/README.md +23 -0
- package/docs/followup-plan-2026-05-12.md +463 -0
- package/docs/followup-review-2026-05-12.md +297 -0
- package/docs/followup-review-round3-2026-05-12.md +342 -0
- package/docs/followup-review-round4-2026-05-13.md +107 -0
- package/docs/implementation-plan-top3.md +333 -0
- package/docs/live-mailbox-runtime.md +36 -36
- package/docs/next-upgrade-roadmap.md +808 -808
- package/docs/oh-my-pi-research.md +509 -0
- package/docs/perf/baseline-2026-05.md +113 -0
- package/docs/perf/final-report-2026-05.md +206 -0
- package/docs/perf/sprint-1-report.md +71 -0
- package/docs/perf/sprint-2-report.md +81 -0
- package/docs/perf/sprint-2.5-report.md +53 -0
- package/docs/perf/sprint-3-report.md +36 -0
- package/docs/perf/sprint-4-report.md +47 -0
- package/docs/perf/sprint-5-report.md +51 -0
- package/docs/perf/sprint-6-report.md +94 -0
- package/docs/perf/sprint-7-report.md +74 -0
- package/docs/perf/upgrade-plan-2026-05.md +147 -0
- package/docs/pi-subagents3-deep-analysis.md +508 -0
- package/docs/product/README.md +31 -0
- package/docs/product/platform.md +27 -0
- package/docs/product/runtime-safety.md +37 -0
- package/docs/product/team-run.md +39 -0
- package/docs/product/team-tool.md +37 -0
- package/docs/publishing.md +65 -65
- package/docs/resource-formats.md +134 -134
- package/docs/runtime-analysis-child-vs-live.md +171 -0
- package/docs/runtime-flow.md +148 -148
- package/docs/runtime-migration-in-process-analysis.md +250 -0
- package/docs/stories/README.md +30 -0
- package/docs/stories/backlog.md +36 -0
- package/docs/templates/decision.md +27 -0
- package/docs/templates/story.md +44 -0
- package/docs/templates/validation-report.md +32 -0
- package/docs/usage.md +238 -238
- package/index.ts +7 -6
- package/install.mjs +65 -65
- package/package.json +107 -99
- package/schema.json +222 -222
- package/skills/child-pi-spawning/SKILL.md +213 -0
- package/skills/context-artifact-hygiene/SKILL.md +32 -0
- package/skills/event-log-tracing/SKILL.md +299 -0
- package/skills/git-master/SKILL.md +225 -24
- package/skills/live-agent-lifecycle/SKILL.md +192 -0
- package/skills/mailbox-interactive/SKILL.md +300 -19
- package/skills/model-routing-context/SKILL.md +94 -0
- package/skills/multi-perspective-review/SKILL.md +88 -0
- package/skills/read-only-explorer/SKILL.md +250 -26
- package/skills/safe-bash/SKILL.md +307 -21
- package/skills/verification-before-done/SKILL.md +11 -2
- package/skills/widget-rendering/SKILL.md +258 -0
- package/skills/workspace-isolation/SKILL.md +202 -0
- package/skills/worktree-isolation/SKILL.md +202 -18
- package/src/adapters/claude-adapter.ts +25 -25
- package/src/adapters/codex-adapter.ts +21 -21
- package/src/adapters/cursor-adapter.ts +17 -17
- package/src/adapters/export-util.ts +137 -137
- package/src/adapters/index.ts +15 -15
- package/src/adapters/registry.ts +18 -18
- package/src/adapters/types.ts +23 -23
- package/src/agents/agent-config.ts +38 -38
- package/src/agents/agent-serializer.ts +38 -38
- package/src/agents/discover-agents.ts +121 -118
- package/src/config/config.ts +740 -858
- package/src/config/defaults.ts +96 -96
- package/src/config/drift-detector.ts +211 -211
- package/src/config/markers.ts +327 -327
- package/src/config/resilient-parser.ts +109 -108
- package/src/config/suggestions.ts +74 -74
- package/src/config/types.ts +199 -0
- package/src/extension/async-notifier.ts +123 -89
- package/src/extension/autonomous-policy.ts +169 -169
- package/src/extension/cross-extension-rpc.ts +104 -103
- package/src/extension/help.ts +47 -47
- package/src/extension/import-index.ts +69 -69
- package/src/extension/management.ts +395 -382
- package/src/extension/notification-router.ts +116 -116
- package/src/extension/notification-sink.ts +51 -51
- package/src/extension/project-init.ts +168 -168
- package/src/extension/register.ts +859 -668
- package/src/extension/registration/artifact-cleanup.ts +15 -15
- package/src/extension/registration/command-utils.ts +54 -54
- package/src/extension/registration/commands.ts +559 -452
- package/src/extension/registration/compaction-guard.ts +125 -125
- package/src/extension/registration/subagent-helpers.ts +102 -102
- package/src/extension/registration/subagent-tools.ts +220 -158
- package/src/extension/registration/team-tool.ts +159 -98
- package/src/extension/registration/viewers.ts +29 -0
- package/src/extension/result-watcher.ts +128 -128
- package/src/extension/run-bundle-schema.ts +89 -89
- package/src/extension/run-export.ts +73 -73
- package/src/extension/run-import.ts +84 -84
- package/src/extension/run-index.ts +94 -94
- package/src/extension/run-maintenance.ts +142 -142
- package/src/extension/session-summary.ts +8 -8
- package/src/extension/team-manager-command.ts +96 -95
- package/src/extension/team-recommendation.ts +188 -188
- package/src/extension/team-tool/api.ts +5 -2
- package/src/extension/team-tool/cancel.ts +224 -209
- package/src/extension/team-tool/config-patch.ts +36 -36
- package/src/extension/team-tool/context.ts +60 -60
- package/src/extension/team-tool/doctor.ts +242 -242
- package/src/extension/team-tool/handle-settings.ts +421 -195
- package/src/extension/team-tool/inspect.ts +41 -41
- package/src/extension/team-tool/lifecycle-actions.ts +139 -139
- package/src/extension/team-tool/parallel-dispatch.ts +156 -156
- package/src/extension/team-tool/plan.ts +19 -19
- package/src/extension/team-tool/respond.ts +112 -111
- package/src/extension/team-tool/run.ts +246 -228
- package/src/extension/team-tool/status.ts +110 -110
- package/src/extension/team-tool-types.ts +13 -13
- package/src/extension/team-tool.ts +16 -4
- package/src/extension/tool-result.ts +16 -16
- package/src/extension/validate-resources.ts +77 -77
- package/src/hooks/registry.ts +61 -61
- package/src/hooks/types.ts +40 -40
- package/src/i18n.ts +184 -184
- package/src/observability/correlation.ts +35 -35
- package/src/observability/event-to-metric.ts +68 -68
- package/src/observability/exporters/adapter.ts +30 -30
- package/src/observability/exporters/otlp-exporter.ts +106 -92
- package/src/observability/exporters/prometheus-exporter.ts +54 -54
- package/src/observability/metric-registry.ts +87 -87
- package/src/observability/metric-retention.ts +54 -54
- package/src/observability/metric-sink.ts +81 -56
- package/src/observability/metrics-primitives.ts +167 -167
- package/src/prompt/prompt-runtime.ts +72 -72
- package/src/runtime/adaptive-plan.ts +338 -0
- package/src/runtime/agent-control.ts +169 -169
- package/src/runtime/agent-memory.ts +72 -72
- package/src/runtime/agent-observability.ts +114 -114
- package/src/runtime/async-marker.ts +26 -26
- package/src/runtime/async-runner.ts +153 -79
- package/src/runtime/attention-events.ts +28 -28
- package/src/runtime/auto-resume.ts +100 -100
- package/src/runtime/background-runner.ts +122 -88
- package/src/runtime/cancellation.ts +61 -61
- package/src/runtime/capability-inventory.ts +116 -116
- package/src/runtime/child-pi-pool.ts +68 -0
- package/src/runtime/child-pi.ts +541 -463
- package/src/runtime/code-summary.ts +247 -247
- package/src/runtime/compaction-summary.ts +271 -271
- package/src/runtime/concurrency.ts +58 -58
- package/src/runtime/crash-recovery.ts +317 -301
- package/src/runtime/crew-agent-records.ts +379 -281
- package/src/runtime/crew-agent-runtime.ts +60 -60
- package/src/runtime/cross-extension-rpc.ts +72 -0
- package/src/runtime/custom-tools/irc-tool.ts +201 -201
- package/src/runtime/custom-tools/submit-result-tool.ts +90 -90
- package/src/runtime/deadletter.ts +47 -47
- package/src/runtime/delivery-coordinator.ts +176 -176
- package/src/runtime/delta-conflict.ts +360 -360
- package/src/runtime/diagnostic-export.ts +102 -102
- package/src/runtime/direct-run.ts +35 -35
- package/src/runtime/effectiveness.ts +82 -81
- package/src/runtime/errors/crew-errors.ts +166 -0
- package/src/runtime/event-stream-bridge.ts +92 -92
- package/src/runtime/foreground-control.ts +82 -82
- package/src/runtime/green-contract.ts +46 -46
- package/src/runtime/group-join.ts +234 -106
- package/src/runtime/heartbeat-watcher.ts +145 -124
- package/src/runtime/iteration-hooks.ts +267 -264
- package/src/runtime/live-agent-control.ts +88 -88
- package/src/runtime/live-agent-manager.ts +377 -179
- package/src/runtime/live-control-realtime.ts +36 -36
- package/src/runtime/live-session-runtime.ts +676 -599
- package/src/runtime/loop-gates.ts +129 -129
- package/src/runtime/manifest-cache.ts +263 -263
- package/src/runtime/mcp-proxy.ts +113 -113
- package/src/runtime/metric-parser.ts +40 -40
- package/src/runtime/model-fallback.ts +282 -274
- package/src/runtime/model-resolver.ts +118 -0
- package/src/runtime/output-validator.ts +187 -187
- package/src/runtime/overflow-recovery.ts +175 -175
- package/src/runtime/parallel-research.ts +44 -44
- package/src/runtime/parallel-utils.ts +156 -156
- package/src/runtime/parent-guard.ts +80 -80
- package/src/runtime/phase-progress.ts +217 -217
- package/src/runtime/pi-args.ts +165 -165
- package/src/runtime/pi-json-output.ts +111 -111
- package/src/runtime/pi-spawn.ts +167 -167
- package/src/runtime/policy-engine.ts +79 -79
- package/src/runtime/post-checks.ts +125 -122
- package/src/runtime/post-exit-stdio-guard.ts +86 -86
- package/src/runtime/process-status.ts +97 -73
- package/src/runtime/progress-event-coalescer.ts +43 -43
- package/src/runtime/recovery-recipes.ts +74 -74
- package/src/runtime/retry-executor.ts +81 -81
- package/src/runtime/role-permission.ts +39 -39
- package/src/runtime/run-tracker.ts +99 -0
- package/src/runtime/runtime-policy.ts +21 -0
- package/src/runtime/runtime-resolver.ts +94 -90
- package/src/runtime/scheduler.ts +294 -0
- package/src/runtime/semaphore.ts +131 -131
- package/src/runtime/sensitive-paths.ts +92 -92
- package/src/runtime/session-usage.ts +79 -79
- package/src/runtime/settings-store.ts +103 -0
- package/src/runtime/sidechain-output.ts +29 -29
- package/src/runtime/skill-instructions.ts +222 -222
- package/src/runtime/stale-reconciler.ts +198 -189
- package/src/runtime/streaming-output.ts +47 -0
- package/src/runtime/subagent-manager.ts +404 -395
- package/src/runtime/subprocess-tool-registry.ts +67 -67
- package/src/runtime/task-display.ts +38 -38
- package/src/runtime/task-graph-scheduler.ts +122 -122
- package/src/runtime/task-graph.ts +207 -207
- package/src/runtime/task-output-context.ts +177 -177
- package/src/runtime/task-packet.ts +93 -93
- package/src/runtime/task-quality.ts +207 -207
- package/src/runtime/task-runner/capabilities.ts +78 -78
- package/src/runtime/task-runner/live-executor.ts +131 -113
- package/src/runtime/task-runner/progress.ts +119 -119
- package/src/runtime/task-runner/prompt-builder.ts +139 -139
- package/src/runtime/task-runner/prompt-pipeline.ts +64 -64
- package/src/runtime/task-runner/result-utils.ts +14 -14
- package/src/runtime/task-runner/run-projection.ts +103 -103
- package/src/runtime/task-runner/state-helpers.ts +22 -22
- package/src/runtime/task-runner.ts +469 -458
- package/src/runtime/team-runner.ts +693 -945
- package/src/runtime/usage-tracker.ts +71 -0
- package/src/runtime/worker-heartbeat.ts +21 -21
- package/src/runtime/worker-startup.ts +57 -57
- package/src/runtime/workflow-state.ts +187 -187
- package/src/runtime/yield-handler.ts +190 -189
- package/src/schema/config-schema.ts +172 -168
- package/src/schema/team-tool-schema.ts +126 -125
- package/src/schema/validation-types.ts +151 -148
- package/src/skills/discover-skills.ts +67 -67
- package/src/skills/skill-templates.ts +374 -374
- package/src/state/active-run-registry.ts +227 -191
- package/src/state/artifact-store.ts +130 -129
- package/src/state/atomic-write.ts +262 -178
- package/src/state/blob-store.ts +116 -116
- package/src/state/contracts.ts +111 -111
- package/src/state/event-log-rotation.ts +161 -158
- package/src/state/event-log.ts +383 -240
- package/src/state/event-reconstructor.ts +217 -217
- package/src/state/jsonl-writer.ts +82 -82
- package/src/state/locks.ts +146 -148
- package/src/state/mailbox.ts +446 -405
- package/src/state/state-store.ts +364 -351
- package/src/state/task-claims.ts +44 -44
- package/src/state/types.ts +285 -285
- package/src/state/usage.ts +29 -29
- package/src/subagents/async-entry.ts +1 -1
- package/src/subagents/index.ts +3 -3
- package/src/subagents/live/control.ts +1 -1
- package/src/subagents/live/manager.ts +1 -1
- package/src/subagents/live/realtime.ts +1 -1
- package/src/subagents/live/session-runtime.ts +1 -1
- package/src/subagents/manager.ts +1 -1
- package/src/subagents/spawn.ts +1 -1
- package/src/teams/discover-teams.ts +116 -116
- package/src/teams/team-config.ts +27 -27
- package/src/teams/team-serializer.ts +38 -38
- package/src/types/diff.d.ts +18 -18
- package/src/ui/agent-management-overlay.ts +144 -144
- package/src/ui/crew-widget.ts +487 -370
- package/src/ui/dashboard-panes/agents-pane.ts +109 -28
- package/src/ui/dashboard-panes/cancellation-pane.ts +42 -42
- package/src/ui/dashboard-panes/capability-pane.ts +59 -59
- package/src/ui/dashboard-panes/health-pane.ts +30 -30
- package/src/ui/dashboard-panes/mailbox-pane.ts +35 -35
- package/src/ui/dashboard-panes/progress-pane.ts +30 -30
- package/src/ui/dashboard-panes/transcript-pane.ts +10 -10
- package/src/ui/heartbeat-aggregator.ts +63 -63
- package/src/ui/keybinding-map.ts +97 -94
- package/src/ui/live-conversation-overlay.ts +152 -0
- package/src/ui/live-run-sidebar.ts +180 -180
- package/src/ui/mascot.ts +442 -442
- package/src/ui/overlays/agent-picker-overlay.ts +57 -57
- package/src/ui/overlays/confirm-overlay.ts +58 -58
- package/src/ui/overlays/mailbox-compose-overlay.ts +144 -144
- package/src/ui/overlays/mailbox-compose-preview.ts +63 -63
- package/src/ui/overlays/mailbox-detail-overlay.ts +122 -122
- package/src/ui/pi-ui-compat.ts +57 -57
- package/src/ui/powerbar-publisher.ts +221 -197
- package/src/ui/render-scheduler.ts +216 -143
- package/src/ui/run-action-dispatcher.ts +118 -117
- package/src/ui/run-dashboard.ts +526 -464
- package/src/ui/run-event-bus.ts +208 -208
- package/src/ui/run-snapshot-cache.ts +826 -777
- package/src/ui/settings-overlay.ts +721 -0
- package/src/ui/snapshot-types.ts +86 -70
- package/src/ui/theme-adapter.ts +190 -190
- package/src/ui/tool-progress-formatter.ts +89 -0
- package/src/ui/transcript-cache.ts +94 -94
- package/src/ui/transcript-viewer.ts +335 -335
- package/src/utils/conflict-detect.ts +662 -0
- package/src/utils/env-filter.ts +30 -0
- package/src/utils/file-coalescer.ts +86 -86
- package/src/utils/frontmatter.ts +68 -68
- package/src/utils/fs-watch.ts +88 -31
- package/src/utils/gh-protocol.ts +479 -0
- package/src/utils/ids.ts +17 -17
- package/src/utils/incremental-reader.ts +104 -104
- package/src/utils/internal-error.ts +6 -6
- package/src/utils/names.ts +27 -27
- package/src/utils/paths.ts +102 -63
- package/src/utils/redaction.ts +44 -44
- package/src/utils/resolve-shell.ts +34 -0
- package/src/utils/safe-paths.ts +47 -47
- package/src/utils/scan-cache.ts +136 -136
- package/src/utils/sleep.ts +2 -1
- package/src/utils/sse-parser.ts +134 -134
- package/src/utils/task-name-generator.ts +337 -337
- package/src/utils/timings.ts +33 -33
- package/src/utils/visual.ts +243 -198
- package/src/workflows/discover-workflows.ts +139 -139
- package/src/workflows/validate-workflow.ts +40 -40
- package/src/workflows/workflow-config.ts +26 -26
- package/src/workflows/workflow-serializer.ts +32 -32
- package/src/worktree/branch-freshness.ts +45 -45
- package/src/worktree/cleanup.ts +75 -72
- package/src/worktree/worktree-manager.ts +188 -146
- package/teams/default.team.md +12 -12
- package/teams/fast-fix.team.md +11 -11
- package/teams/implementation.team.md +18 -18
- package/teams/parallel-research.team.md +14 -14
- package/teams/research.team.md +11 -11
- package/teams/review.team.md +12 -12
- package/tsconfig.json +19 -19
- package/workflows/default.workflow.md +30 -30
- package/workflows/fast-fix.workflow.md +23 -23
- package/workflows/implementation.workflow.md +43 -43
- package/workflows/parallel-research.workflow.md +46 -46
- package/workflows/research.workflow.md +22 -22
- package/workflows/review.workflow.md +30 -30
- package/skills/task-packet/SKILL.md +0 -28
- package/skills/verify-evidence/SKILL.md +0 -27
|
@@ -1,67 +1,67 @@
|
|
|
1
|
-
export interface SubprocessToolEvent {
|
|
2
|
-
toolName: string;
|
|
3
|
-
toolCallId: string;
|
|
4
|
-
args?: Record<string, unknown>;
|
|
5
|
-
result?: { content: Array<{ type: string; text?: string }>; details?: unknown };
|
|
6
|
-
isError?: boolean;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export interface SubprocessToolHandler<TData = unknown> {
|
|
10
|
-
extractData?: (event: SubprocessToolEvent) => TData | undefined;
|
|
11
|
-
shouldTerminate?: (event: SubprocessToolEvent) => boolean;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface SubprocessToolRegistry {
|
|
15
|
-
register<T>(toolName: string, handler: SubprocessToolHandler<T>): void;
|
|
16
|
-
getHandler(toolName: string): SubprocessToolHandler | undefined;
|
|
17
|
-
hasHandler(toolName: string): boolean;
|
|
18
|
-
getRegisteredTools(): string[];
|
|
19
|
-
extractAll(event: SubprocessToolEvent): Record<string, unknown>;
|
|
20
|
-
/** H3: Clear all registered handlers (for test isolation). */
|
|
21
|
-
clear(): void;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
class SubprocessToolRegistryImpl implements SubprocessToolRegistry {
|
|
25
|
-
private readonly handlers = new Map<string, SubprocessToolHandler>();
|
|
26
|
-
|
|
27
|
-
register<T>(toolName: string, handler: SubprocessToolHandler<T>): void {
|
|
28
|
-
this.handlers.set(toolName, handler as SubprocessToolHandler);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
getHandler(toolName: string): SubprocessToolHandler | undefined {
|
|
32
|
-
return this.handlers.get(toolName);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
hasHandler(toolName: string): boolean {
|
|
36
|
-
return this.handlers.has(toolName);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
getRegisteredTools(): string[] {
|
|
40
|
-
return [...this.handlers.keys()];
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
extractAll(event: SubprocessToolEvent): Record<string, unknown> {
|
|
44
|
-
const extracted: Record<string, unknown> = {};
|
|
45
|
-
for (const [toolName, handler] of this.handlers) {
|
|
46
|
-
if (handler.extractData) {
|
|
47
|
-
const data = handler.extractData(event);
|
|
48
|
-
if (data !== undefined) {
|
|
49
|
-
extracted[toolName] = data;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
return extracted;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** H3: Clear all registered handlers (for test isolation). */
|
|
57
|
-
clear(): void {
|
|
58
|
-
this.handlers.clear();
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export const subprocessToolRegistry: SubprocessToolRegistry = new SubprocessToolRegistryImpl();
|
|
63
|
-
|
|
64
|
-
/** H3: Reset the global singleton registry (for test isolation). */
|
|
65
|
-
export function resetSubprocessToolRegistry(): void {
|
|
66
|
-
subprocessToolRegistry.clear();
|
|
67
|
-
}
|
|
1
|
+
export interface SubprocessToolEvent {
|
|
2
|
+
toolName: string;
|
|
3
|
+
toolCallId: string;
|
|
4
|
+
args?: Record<string, unknown>;
|
|
5
|
+
result?: { content: Array<{ type: string; text?: string }>; details?: unknown };
|
|
6
|
+
isError?: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface SubprocessToolHandler<TData = unknown> {
|
|
10
|
+
extractData?: (event: SubprocessToolEvent) => TData | undefined;
|
|
11
|
+
shouldTerminate?: (event: SubprocessToolEvent) => boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface SubprocessToolRegistry {
|
|
15
|
+
register<T>(toolName: string, handler: SubprocessToolHandler<T>): void;
|
|
16
|
+
getHandler(toolName: string): SubprocessToolHandler | undefined;
|
|
17
|
+
hasHandler(toolName: string): boolean;
|
|
18
|
+
getRegisteredTools(): string[];
|
|
19
|
+
extractAll(event: SubprocessToolEvent): Record<string, unknown>;
|
|
20
|
+
/** H3: Clear all registered handlers (for test isolation). */
|
|
21
|
+
clear(): void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
class SubprocessToolRegistryImpl implements SubprocessToolRegistry {
|
|
25
|
+
private readonly handlers = new Map<string, SubprocessToolHandler>();
|
|
26
|
+
|
|
27
|
+
register<T>(toolName: string, handler: SubprocessToolHandler<T>): void {
|
|
28
|
+
this.handlers.set(toolName, handler as SubprocessToolHandler);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
getHandler(toolName: string): SubprocessToolHandler | undefined {
|
|
32
|
+
return this.handlers.get(toolName);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
hasHandler(toolName: string): boolean {
|
|
36
|
+
return this.handlers.has(toolName);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
getRegisteredTools(): string[] {
|
|
40
|
+
return [...this.handlers.keys()];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
extractAll(event: SubprocessToolEvent): Record<string, unknown> {
|
|
44
|
+
const extracted: Record<string, unknown> = {};
|
|
45
|
+
for (const [toolName, handler] of this.handlers) {
|
|
46
|
+
if (handler.extractData) {
|
|
47
|
+
const data = handler.extractData(event);
|
|
48
|
+
if (data !== undefined) {
|
|
49
|
+
extracted[toolName] = data;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return extracted;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** H3: Clear all registered handlers (for test isolation). */
|
|
57
|
+
clear(): void {
|
|
58
|
+
this.handlers.clear();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export const subprocessToolRegistry: SubprocessToolRegistry = new SubprocessToolRegistryImpl();
|
|
63
|
+
|
|
64
|
+
/** H3: Reset the global singleton registry (for test isolation). */
|
|
65
|
+
export function resetSubprocessToolRegistry(): void {
|
|
66
|
+
subprocessToolRegistry.clear();
|
|
67
|
+
}
|
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
import type { TeamTaskState } from "../state/types.ts";
|
|
2
|
-
import type { CrewAgentRecord, CrewRuntimeKind } from "./crew-agent-runtime.ts";
|
|
3
|
-
import { recordFromTask } from "./crew-agent-records.ts";
|
|
4
|
-
import type { TeamRunManifest } from "../state/types.ts";
|
|
5
|
-
|
|
6
|
-
export function shouldMaterializeAgent(task: TeamTaskState): boolean {
|
|
7
|
-
return task.status !== "queued" && task.status !== "skipped";
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function recordsForMaterializedTasks(manifest: TeamRunManifest, tasks: TeamTaskState[], runtime: CrewRuntimeKind): CrewAgentRecord[] {
|
|
11
|
-
return tasks.filter(shouldMaterializeAgent).map((task) => recordFromTask(manifest, task, runtime));
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function taskById(tasks: TeamTaskState[]): Map<string, TeamTaskState> {
|
|
15
|
-
const map = new Map<string, TeamTaskState>();
|
|
16
|
-
for (const task of tasks) {
|
|
17
|
-
map.set(task.id, task);
|
|
18
|
-
if (task.stepId) map.set(task.stepId, task);
|
|
19
|
-
}
|
|
20
|
-
return map;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function waitingReason(task: TeamTaskState, tasks: TeamTaskState[]): string | undefined {
|
|
24
|
-
if (task.status !== "queued") return undefined;
|
|
25
|
-
const byId = taskById(tasks);
|
|
26
|
-
const waiting = task.dependsOn.map((id) => byId.get(id)?.id ?? id).filter((id) => byId.get(id)?.status !== "completed");
|
|
27
|
-
if (waiting.length === 0) return "ready";
|
|
28
|
-
return `waiting for ${waiting.join(", ")}`;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export function formatTaskGraphLines(tasks: TeamTaskState[]): string[] {
|
|
32
|
-
if (tasks.length === 0) return ["- (none)"];
|
|
33
|
-
return tasks.map((task) => {
|
|
34
|
-
const icon = task.status === "completed" ? "✓" : task.status === "running" ? "⠋" : task.status === "failed" ? "✗" : task.status === "cancelled" || task.status === "skipped" ? "■" : "◦";
|
|
35
|
-
const wait = waitingReason(task, tasks);
|
|
36
|
-
return `- ${icon} ${task.id} [${task.status}] ${task.role}->${task.agent}${wait && wait !== "ready" ? ` (${wait})` : ""}`;
|
|
37
|
-
});
|
|
38
|
-
}
|
|
1
|
+
import type { TeamTaskState } from "../state/types.ts";
|
|
2
|
+
import type { CrewAgentRecord, CrewRuntimeKind } from "./crew-agent-runtime.ts";
|
|
3
|
+
import { recordFromTask } from "./crew-agent-records.ts";
|
|
4
|
+
import type { TeamRunManifest } from "../state/types.ts";
|
|
5
|
+
|
|
6
|
+
export function shouldMaterializeAgent(task: TeamTaskState): boolean {
|
|
7
|
+
return task.status !== "queued" && task.status !== "skipped";
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function recordsForMaterializedTasks(manifest: TeamRunManifest, tasks: TeamTaskState[], runtime: CrewRuntimeKind): CrewAgentRecord[] {
|
|
11
|
+
return tasks.filter(shouldMaterializeAgent).map((task) => recordFromTask(manifest, task, runtime));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function taskById(tasks: TeamTaskState[]): Map<string, TeamTaskState> {
|
|
15
|
+
const map = new Map<string, TeamTaskState>();
|
|
16
|
+
for (const task of tasks) {
|
|
17
|
+
map.set(task.id, task);
|
|
18
|
+
if (task.stepId) map.set(task.stepId, task);
|
|
19
|
+
}
|
|
20
|
+
return map;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function waitingReason(task: TeamTaskState, tasks: TeamTaskState[]): string | undefined {
|
|
24
|
+
if (task.status !== "queued") return undefined;
|
|
25
|
+
const byId = taskById(tasks);
|
|
26
|
+
const waiting = task.dependsOn.map((id) => byId.get(id)?.id ?? id).filter((id) => byId.get(id)?.status !== "completed");
|
|
27
|
+
if (waiting.length === 0) return "ready";
|
|
28
|
+
return `waiting for ${waiting.join(", ")}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function formatTaskGraphLines(tasks: TeamTaskState[]): string[] {
|
|
32
|
+
if (tasks.length === 0) return ["- (none)"];
|
|
33
|
+
return tasks.map((task) => {
|
|
34
|
+
const icon = task.status === "completed" ? "✓" : task.status === "running" ? "⠋" : task.status === "failed" ? "✗" : task.status === "cancelled" || task.status === "skipped" ? "■" : "◦";
|
|
35
|
+
const wait = waitingReason(task, tasks);
|
|
36
|
+
return `- ${icon} ${task.id} [${task.status}] ${task.role}->${task.agent}${wait && wait !== "ready" ? ` (${wait})` : ""}`;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
@@ -1,122 +1,122 @@
|
|
|
1
|
-
import type { TeamTaskState } from "../state/types.ts";
|
|
2
|
-
|
|
3
|
-
export interface TaskGraphSchedulerSnapshot {
|
|
4
|
-
ready: string[];
|
|
5
|
-
blocked: string[];
|
|
6
|
-
running: string[];
|
|
7
|
-
done: string[];
|
|
8
|
-
failed: string[];
|
|
9
|
-
cancelled: string[];
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface TaskGraphIndex {
|
|
13
|
-
doneSteps: Set<string>;
|
|
14
|
-
idMap: Map<string, TeamTaskState>;
|
|
15
|
-
stepToTaskId: Map<string, string>;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function buildTaskGraphIndex(tasks: TeamTaskState[]): TaskGraphIndex {
|
|
19
|
-
return {
|
|
20
|
-
doneSteps: new Set(tasks.filter((task) => task.status === "completed").map((task) => task.stepId).filter((id): id is string => id !== undefined)),
|
|
21
|
-
idMap: new Map(tasks.map((task) => [task.id, task])),
|
|
22
|
-
stepToTaskId: new Map(tasks.map((task) => [task.stepId, task.id]).filter((entry): entry is [string, string] => entry[0] !== undefined)),
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function taskById(tasks: TeamTaskState[]): Map<string, TeamTaskState> {
|
|
27
|
-
return new Map(tasks.map((task) => [task.id, task]));
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function dependencySatisfied(task: TeamTaskState, doneStepIds: Set<string>, idMap: Map<string, TeamTaskState>, stepMap: Map<string, string>): boolean {
|
|
31
|
-
return task.dependsOn.every((dependency) => {
|
|
32
|
-
if (doneStepIds.has(dependency)) return true;
|
|
33
|
-
const taskId = stepMap.get(dependency) ?? dependency;
|
|
34
|
-
return idMap.get(taskId)?.status === "completed";
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function withQueue(task: TeamTaskState, index: TaskGraphIndex): TeamTaskState {
|
|
39
|
-
if (task.status === "queued") {
|
|
40
|
-
const isReady = dependencySatisfied(task, index.doneSteps, index.idMap, index.stepToTaskId);
|
|
41
|
-
return { ...task, graph: task.graph ? { ...task.graph, queue: isReady ? "ready" : "blocked" } : task.graph };
|
|
42
|
-
}
|
|
43
|
-
if (task.status === "running") {
|
|
44
|
-
return { ...task, graph: task.graph ? { ...task.graph, queue: "running" } : task.graph };
|
|
45
|
-
}
|
|
46
|
-
if (task.status === "completed" || task.status === "skipped") {
|
|
47
|
-
return { ...task, graph: task.graph ? { ...task.graph, queue: "done" } : task.graph };
|
|
48
|
-
}
|
|
49
|
-
return { ...task, graph: task.graph ? { ...task.graph, queue: "blocked" } : task.graph };
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function ensureIndex(tasks: TeamTaskState[], index?: TaskGraphIndex): TaskGraphIndex {
|
|
53
|
-
return index ?? buildTaskGraphIndex(tasks);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export function refreshTaskGraphQueues(tasks: TeamTaskState[], index?: TaskGraphIndex): TeamTaskState[] {
|
|
57
|
-
const resolved = ensureIndex(tasks, index);
|
|
58
|
-
return tasks.map((task) => withQueue(task, resolved));
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export function getReadyTasks(tasks: TeamTaskState[], maxCount = 1, index?: TaskGraphIndex): TeamTaskState[] {
|
|
62
|
-
return refreshTaskGraphQueues(tasks, index).filter((task) => task.status === "queued" && task.graph?.queue === "ready").slice(0, Math.max(0, maxCount));
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export function markTaskRunning(tasks: TeamTaskState[], taskId: string, now = new Date(), index?: TaskGraphIndex): TeamTaskState[] {
|
|
66
|
-
const resolved = ensureIndex(tasks, index);
|
|
67
|
-
return refreshTaskGraphQueues(tasks, resolved).map((task) => task.id === taskId ? withQueue({ ...task, status: "running", startedAt: task.startedAt ?? now.toISOString() }, resolved) : task);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export function markTaskDone(tasks: TeamTaskState[], taskId: string, now = new Date(), index?: TaskGraphIndex): TeamTaskState[] {
|
|
71
|
-
const resolved = ensureIndex(tasks, index);
|
|
72
|
-
return refreshTaskGraphQueues(tasks.map((task) => task.id === taskId ? { ...task, status: "completed", finishedAt: task.finishedAt ?? now.toISOString() } : task), resolved);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export function cancelTaskSubtree(tasks: TeamTaskState[], rootTaskId: string, reason = "Cancelled by task graph scheduler.", now = new Date()): TeamTaskState[] {
|
|
76
|
-
const ids = taskById(tasks);
|
|
77
|
-
const toCancel = new Set<string>();
|
|
78
|
-
const stack = [rootTaskId];
|
|
79
|
-
while (stack.length) {
|
|
80
|
-
const current = stack.pop();
|
|
81
|
-
if (!current || toCancel.has(current)) continue;
|
|
82
|
-
toCancel.add(current);
|
|
83
|
-
const task = ids.get(current);
|
|
84
|
-
for (const child of task?.graph?.children ?? []) stack.push(child);
|
|
85
|
-
}
|
|
86
|
-
return refreshTaskGraphQueues(tasks.map((task) => {
|
|
87
|
-
if (!toCancel.has(task.id)) return task;
|
|
88
|
-
if (task.status === "completed") return task;
|
|
89
|
-
return { ...task, status: "cancelled", error: reason, finishedAt: task.finishedAt ?? now.toISOString() };
|
|
90
|
-
}));
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export function failTaskAndBlockChildren(tasks: TeamTaskState[], rootTaskId: string, reason: string, now = new Date()): TeamTaskState[] {
|
|
94
|
-
const ids = taskById(tasks);
|
|
95
|
-
const blocked = new Set<string>();
|
|
96
|
-
const root = ids.get(rootTaskId);
|
|
97
|
-
const stack = [...(root?.graph?.children ?? [])];
|
|
98
|
-
while (stack.length) {
|
|
99
|
-
const current = stack.pop();
|
|
100
|
-
if (!current || blocked.has(current)) continue;
|
|
101
|
-
blocked.add(current);
|
|
102
|
-
const task = ids.get(current);
|
|
103
|
-
for (const child of task?.graph?.children ?? []) stack.push(child);
|
|
104
|
-
}
|
|
105
|
-
return refreshTaskGraphQueues(tasks.map((task) => {
|
|
106
|
-
if (task.id === rootTaskId) return { ...task, status: "failed", error: reason, finishedAt: task.finishedAt ?? now.toISOString() };
|
|
107
|
-
if (blocked.has(task.id) && task.status === "queued") return { ...task, status: "skipped", error: `Blocked by failed task '${rootTaskId}'.`, finishedAt: task.finishedAt ?? now.toISOString() };
|
|
108
|
-
return task;
|
|
109
|
-
}));
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export function taskGraphSnapshot(tasks: TeamTaskState[], index?: TaskGraphIndex): TaskGraphSchedulerSnapshot {
|
|
113
|
-
const refreshed = refreshTaskGraphQueues(tasks, index);
|
|
114
|
-
return {
|
|
115
|
-
ready: refreshed.filter((task) => task.status === "queued" && task.graph?.queue === "ready").map((task) => task.id),
|
|
116
|
-
blocked: refreshed.filter((task) => task.status === "queued" && task.graph?.queue === "blocked").map((task) => task.id),
|
|
117
|
-
running: refreshed.filter((task) => task.status === "running").map((task) => task.id),
|
|
118
|
-
done: refreshed.filter((task) => task.status === "completed" || task.status === "skipped").map((task) => task.id),
|
|
119
|
-
failed: refreshed.filter((task) => task.status === "failed").map((task) => task.id),
|
|
120
|
-
cancelled: refreshed.filter((task) => task.status === "cancelled").map((task) => task.id),
|
|
121
|
-
};
|
|
122
|
-
}
|
|
1
|
+
import type { TeamTaskState } from "../state/types.ts";
|
|
2
|
+
|
|
3
|
+
export interface TaskGraphSchedulerSnapshot {
|
|
4
|
+
ready: string[];
|
|
5
|
+
blocked: string[];
|
|
6
|
+
running: string[];
|
|
7
|
+
done: string[];
|
|
8
|
+
failed: string[];
|
|
9
|
+
cancelled: string[];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface TaskGraphIndex {
|
|
13
|
+
doneSteps: Set<string>;
|
|
14
|
+
idMap: Map<string, TeamTaskState>;
|
|
15
|
+
stepToTaskId: Map<string, string>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function buildTaskGraphIndex(tasks: TeamTaskState[]): TaskGraphIndex {
|
|
19
|
+
return {
|
|
20
|
+
doneSteps: new Set(tasks.filter((task) => task.status === "completed").map((task) => task.stepId).filter((id): id is string => id !== undefined)),
|
|
21
|
+
idMap: new Map(tasks.map((task) => [task.id, task])),
|
|
22
|
+
stepToTaskId: new Map(tasks.map((task) => [task.stepId, task.id]).filter((entry): entry is [string, string] => entry[0] !== undefined)),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function taskById(tasks: TeamTaskState[]): Map<string, TeamTaskState> {
|
|
27
|
+
return new Map(tasks.map((task) => [task.id, task]));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function dependencySatisfied(task: TeamTaskState, doneStepIds: Set<string>, idMap: Map<string, TeamTaskState>, stepMap: Map<string, string>): boolean {
|
|
31
|
+
return task.dependsOn.every((dependency) => {
|
|
32
|
+
if (doneStepIds.has(dependency)) return true;
|
|
33
|
+
const taskId = stepMap.get(dependency) ?? dependency;
|
|
34
|
+
return idMap.get(taskId)?.status === "completed";
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function withQueue(task: TeamTaskState, index: TaskGraphIndex): TeamTaskState {
|
|
39
|
+
if (task.status === "queued") {
|
|
40
|
+
const isReady = dependencySatisfied(task, index.doneSteps, index.idMap, index.stepToTaskId);
|
|
41
|
+
return { ...task, graph: task.graph ? { ...task.graph, queue: isReady ? "ready" : "blocked" } : task.graph };
|
|
42
|
+
}
|
|
43
|
+
if (task.status === "running") {
|
|
44
|
+
return { ...task, graph: task.graph ? { ...task.graph, queue: "running" } : task.graph };
|
|
45
|
+
}
|
|
46
|
+
if (task.status === "completed" || task.status === "skipped") {
|
|
47
|
+
return { ...task, graph: task.graph ? { ...task.graph, queue: "done" } : task.graph };
|
|
48
|
+
}
|
|
49
|
+
return { ...task, graph: task.graph ? { ...task.graph, queue: "blocked" } : task.graph };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function ensureIndex(tasks: TeamTaskState[], index?: TaskGraphIndex): TaskGraphIndex {
|
|
53
|
+
return index ?? buildTaskGraphIndex(tasks);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function refreshTaskGraphQueues(tasks: TeamTaskState[], index?: TaskGraphIndex): TeamTaskState[] {
|
|
57
|
+
const resolved = ensureIndex(tasks, index);
|
|
58
|
+
return tasks.map((task) => withQueue(task, resolved));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function getReadyTasks(tasks: TeamTaskState[], maxCount = 1, index?: TaskGraphIndex): TeamTaskState[] {
|
|
62
|
+
return refreshTaskGraphQueues(tasks, index).filter((task) => task.status === "queued" && task.graph?.queue === "ready").slice(0, Math.max(0, maxCount));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function markTaskRunning(tasks: TeamTaskState[], taskId: string, now = new Date(), index?: TaskGraphIndex): TeamTaskState[] {
|
|
66
|
+
const resolved = ensureIndex(tasks, index);
|
|
67
|
+
return refreshTaskGraphQueues(tasks, resolved).map((task) => task.id === taskId ? withQueue({ ...task, status: "running", startedAt: task.startedAt ?? now.toISOString() }, resolved) : task);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function markTaskDone(tasks: TeamTaskState[], taskId: string, now = new Date(), index?: TaskGraphIndex): TeamTaskState[] {
|
|
71
|
+
const resolved = ensureIndex(tasks, index);
|
|
72
|
+
return refreshTaskGraphQueues(tasks.map((task) => task.id === taskId ? { ...task, status: "completed", finishedAt: task.finishedAt ?? now.toISOString() } : task), resolved);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function cancelTaskSubtree(tasks: TeamTaskState[], rootTaskId: string, reason = "Cancelled by task graph scheduler.", now = new Date()): TeamTaskState[] {
|
|
76
|
+
const ids = taskById(tasks);
|
|
77
|
+
const toCancel = new Set<string>();
|
|
78
|
+
const stack = [rootTaskId];
|
|
79
|
+
while (stack.length) {
|
|
80
|
+
const current = stack.pop();
|
|
81
|
+
if (!current || toCancel.has(current)) continue;
|
|
82
|
+
toCancel.add(current);
|
|
83
|
+
const task = ids.get(current);
|
|
84
|
+
for (const child of task?.graph?.children ?? []) stack.push(child);
|
|
85
|
+
}
|
|
86
|
+
return refreshTaskGraphQueues(tasks.map((task) => {
|
|
87
|
+
if (!toCancel.has(task.id)) return task;
|
|
88
|
+
if (task.status === "completed") return task;
|
|
89
|
+
return { ...task, status: "cancelled", error: reason, finishedAt: task.finishedAt ?? now.toISOString() };
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function failTaskAndBlockChildren(tasks: TeamTaskState[], rootTaskId: string, reason: string, now = new Date()): TeamTaskState[] {
|
|
94
|
+
const ids = taskById(tasks);
|
|
95
|
+
const blocked = new Set<string>();
|
|
96
|
+
const root = ids.get(rootTaskId);
|
|
97
|
+
const stack = [...(root?.graph?.children ?? [])];
|
|
98
|
+
while (stack.length) {
|
|
99
|
+
const current = stack.pop();
|
|
100
|
+
if (!current || blocked.has(current)) continue;
|
|
101
|
+
blocked.add(current);
|
|
102
|
+
const task = ids.get(current);
|
|
103
|
+
for (const child of task?.graph?.children ?? []) stack.push(child);
|
|
104
|
+
}
|
|
105
|
+
return refreshTaskGraphQueues(tasks.map((task) => {
|
|
106
|
+
if (task.id === rootTaskId) return { ...task, status: "failed", error: reason, finishedAt: task.finishedAt ?? now.toISOString() };
|
|
107
|
+
if (blocked.has(task.id) && task.status === "queued") return { ...task, status: "skipped", error: `Blocked by failed task '${rootTaskId}'.`, finishedAt: task.finishedAt ?? now.toISOString() };
|
|
108
|
+
return task;
|
|
109
|
+
}));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function taskGraphSnapshot(tasks: TeamTaskState[], index?: TaskGraphIndex): TaskGraphSchedulerSnapshot {
|
|
113
|
+
const refreshed = refreshTaskGraphQueues(tasks, index);
|
|
114
|
+
return {
|
|
115
|
+
ready: refreshed.filter((task) => task.status === "queued" && task.graph?.queue === "ready").map((task) => task.id),
|
|
116
|
+
blocked: refreshed.filter((task) => task.status === "queued" && task.graph?.queue === "blocked").map((task) => task.id),
|
|
117
|
+
running: refreshed.filter((task) => task.status === "running").map((task) => task.id),
|
|
118
|
+
done: refreshed.filter((task) => task.status === "completed" || task.status === "skipped").map((task) => task.id),
|
|
119
|
+
failed: refreshed.filter((task) => task.status === "failed").map((task) => task.id),
|
|
120
|
+
cancelled: refreshed.filter((task) => task.status === "cancelled").map((task) => task.id),
|
|
121
|
+
};
|
|
122
|
+
}
|