@pellux/goodvibes-agent 1.1.7 → 1.3.0

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.
Files changed (274) hide show
  1. package/CHANGELOG.md +329 -0
  2. package/README.md +46 -30
  3. package/dist/package/{ast-grep-napi.linux-x64-gnu-mkk8xwww.node → ast-grep-napi.linux-x64-gnu-swtppvy9.node} +0 -0
  4. package/dist/package/{ast-grep-napi.linux-x64-musl-ryqtgdv6.node → ast-grep-napi.linux-x64-musl-ttfcdtap.node} +0 -0
  5. package/dist/package/main.js +138903 -91477
  6. package/docs/README.md +14 -7
  7. package/docs/channels-remote-and-api.md +8 -5
  8. package/docs/connected-host.md +14 -12
  9. package/docs/getting-started.md +58 -30
  10. package/docs/knowledge-artifacts-and-multimodal.md +7 -5
  11. package/docs/project-planning.md +2 -2
  12. package/docs/providers-and-routing.md +11 -3
  13. package/docs/tools-and-commands.md +116 -45
  14. package/docs/voice-and-live-tts.md +3 -1
  15. package/package.json +3 -2
  16. package/release/release-notes.md +142 -5
  17. package/release/release-readiness.json +124 -94
  18. package/src/agent/assistant-cockpit.ts +247 -0
  19. package/src/agent/autonomy-schedule-format.ts +96 -0
  20. package/src/agent/autonomy-schedule.ts +514 -0
  21. package/src/agent/channel-delivery-receipts.ts +292 -0
  22. package/src/agent/competitive-feature-inventory.ts +294 -0
  23. package/src/agent/document-registry-types.ts +106 -0
  24. package/src/agent/document-registry.ts +734 -0
  25. package/src/agent/harness-control.ts +2 -2
  26. package/src/agent/memory-prompt.ts +2 -2
  27. package/src/agent/operator-actions.ts +50 -6
  28. package/src/agent/persona-registry.ts +8 -0
  29. package/src/agent/project-context-files.ts +273 -0
  30. package/src/agent/prompt-context-receipts.ts +502 -0
  31. package/src/agent/reminder-schedule-format.ts +16 -2
  32. package/src/agent/research-run-registry.ts +582 -0
  33. package/src/agent/research-source-registry.ts +441 -0
  34. package/src/agent/routine-registry.ts +19 -3
  35. package/src/agent/routine-schedule-format.ts +27 -2
  36. package/src/agent/runtime-profile-starters.ts +7 -0
  37. package/src/agent/runtime-profile.ts +106 -4
  38. package/src/agent/schedule-edit-format.ts +129 -0
  39. package/src/agent/schedule-edit.ts +496 -0
  40. package/src/agent/schedule-next-routes.ts +42 -0
  41. package/src/agent/setup-wizard-artifact-receipts.ts +366 -0
  42. package/src/agent/setup-wizard-checkpoint.ts +140 -0
  43. package/src/agent/setup-wizard.ts +683 -0
  44. package/src/agent/skill-registry-types.ts +102 -0
  45. package/src/agent/skill-registry.ts +81 -107
  46. package/src/agent/vibe-confirmation-routes.ts +62 -0
  47. package/src/agent/vibe-file.ts +285 -0
  48. package/src/cli/agent-knowledge-command.ts +45 -2
  49. package/src/cli/help.ts +3 -0
  50. package/src/cli/profiles-command.ts +25 -11
  51. package/src/config/agent-settings-policy.ts +1 -18
  52. package/src/input/agent-workspace-activation.ts +53 -0
  53. package/src/input/agent-workspace-artifact-browser-editor.ts +494 -0
  54. package/src/input/agent-workspace-artifact-metadata.ts +17 -0
  55. package/src/input/agent-workspace-basic-command-editors.ts +5 -1
  56. package/src/input/agent-workspace-categories.ts +153 -155
  57. package/src/input/agent-workspace-channel-triage.ts +481 -0
  58. package/src/input/agent-workspace-channels.ts +263 -0
  59. package/src/input/agent-workspace-command-editor.ts +152 -0
  60. package/src/input/agent-workspace-context-snapshot.ts +349 -0
  61. package/src/input/agent-workspace-delegation-editor-submission.ts +8 -0
  62. package/src/input/agent-workspace-document-editor.ts +502 -0
  63. package/src/input/agent-workspace-document-ops-editor.ts +523 -0
  64. package/src/input/agent-workspace-host-category.ts +1 -1
  65. package/src/input/agent-workspace-local-library-snapshot.ts +167 -0
  66. package/src/input/agent-workspace-model-compare-editor.ts +376 -0
  67. package/src/input/agent-workspace-model-compare-prompt-submission.ts +552 -0
  68. package/src/input/agent-workspace-model-compare-types.ts +82 -0
  69. package/src/input/agent-workspace-model-compare-utils.ts +35 -0
  70. package/src/input/agent-workspace-onboarding-categories.ts +141 -0
  71. package/src/input/agent-workspace-operations-command-editor-submission.ts +53 -0
  72. package/src/input/agent-workspace-operations-command-editors.ts +22 -0
  73. package/src/input/agent-workspace-research-report-editor.ts +212 -0
  74. package/src/input/agent-workspace-research-run-editor.ts +144 -0
  75. package/src/input/agent-workspace-research-source-editor.ts +167 -0
  76. package/src/input/agent-workspace-review-packet-snapshot.ts +593 -0
  77. package/src/input/agent-workspace-review-packet-utils.ts +265 -0
  78. package/src/input/agent-workspace-settings.ts +313 -30
  79. package/src/input/agent-workspace-setup-checkpoint-action.ts +127 -0
  80. package/src/input/agent-workspace-setup-snapshot.ts +217 -0
  81. package/src/input/agent-workspace-setup.ts +61 -1
  82. package/src/input/agent-workspace-snapshot.ts +184 -149
  83. package/src/input/agent-workspace-types.ts +287 -2
  84. package/src/input/agent-workspace.ts +23 -1
  85. package/src/input/command-registry.ts +9 -2
  86. package/src/input/commands/agent-runtime-profile-runtime.ts +28 -13
  87. package/src/input/commands/channels-runtime.ts +102 -114
  88. package/src/input/commands/delegation-runtime.ts +87 -24
  89. package/src/input/commands/knowledge-browser-flags.ts +12 -0
  90. package/src/input/commands/knowledge.ts +28 -14
  91. package/src/input/commands/operator-actions-runtime.ts +6 -3
  92. package/src/input/commands/schedule-runtime.ts +71 -14
  93. package/src/input/commands/session-content.ts +2 -2
  94. package/src/input/commands/shell-core.ts +2 -0
  95. package/src/input/commands/vibe-runtime.ts +140 -0
  96. package/src/input/commands.ts +2 -0
  97. package/src/input/connected-host-routes.ts +123 -0
  98. package/src/input/settings-modal-types.ts +14 -0
  99. package/src/input/setup-wizard-live-receipts.ts +76 -0
  100. package/src/main.ts +15 -15
  101. package/src/panels/qr-panel.ts +2 -2
  102. package/src/renderer/agent-workspace-context-lines.ts +701 -0
  103. package/src/renderer/agent-workspace.ts +68 -421
  104. package/src/renderer/settings-modal-helpers.ts +12 -0
  105. package/src/renderer/settings-modal.ts +12 -0
  106. package/src/runtime/bootstrap-command-context.ts +11 -1
  107. package/src/runtime/bootstrap-command-parts.ts +14 -3
  108. package/src/runtime/bootstrap-core.ts +39 -1
  109. package/src/runtime/bootstrap-shell.ts +6 -0
  110. package/src/runtime/bootstrap.ts +113 -30
  111. package/src/runtime/connected-host-auth.ts +3 -2
  112. package/src/runtime/execution-ledger.ts +231 -0
  113. package/src/runtime/services.ts +88 -10
  114. package/src/runtime/tool-permission-safety.ts +199 -5
  115. package/src/shell/session-continuity-hints.ts +39 -0
  116. package/src/tools/agent-artifacts-tool.ts +606 -0
  117. package/src/tools/agent-audit-tool.ts +155 -0
  118. package/src/tools/agent-autonomy-schedule-tool.ts +238 -0
  119. package/src/tools/agent-autonomy-tool.ts +140 -0
  120. package/src/tools/agent-channel-send-tool.ts +24 -2
  121. package/src/tools/agent-channels-tool.ts +140 -0
  122. package/src/tools/agent-computer-tool.ts +168 -0
  123. package/src/tools/agent-context-policy.ts +137 -7
  124. package/src/tools/agent-context-tool.ts +143 -0
  125. package/src/tools/agent-delegation-tool.ts +128 -0
  126. package/src/tools/agent-device-tool.ts +240 -0
  127. package/src/tools/agent-documents-tool.ts +684 -0
  128. package/src/tools/agent-execution-tool.ts +230 -0
  129. package/src/tools/agent-harness-agent-orchestration-policy.ts +75 -0
  130. package/src/tools/agent-harness-agent-orchestration.ts +791 -0
  131. package/src/tools/agent-harness-autonomy-intake.ts +785 -0
  132. package/src/tools/agent-harness-autonomy-live-records.ts +742 -0
  133. package/src/tools/agent-harness-autonomy-queue-types.ts +88 -0
  134. package/src/tools/agent-harness-autonomy-queue.ts +571 -0
  135. package/src/tools/agent-harness-autonomy-watcher-read-models.ts +509 -0
  136. package/src/tools/agent-harness-background-processes-types.ts +35 -0
  137. package/src/tools/agent-harness-background-processes.ts +798 -0
  138. package/src/tools/agent-harness-browser-cockpit-route.ts +373 -0
  139. package/src/tools/agent-harness-browser-control.ts +346 -0
  140. package/src/tools/agent-harness-browser-pwa-read-models.ts +622 -0
  141. package/src/tools/agent-harness-channel-metadata.ts +168 -10
  142. package/src/tools/agent-harness-cli-command-policy.ts +110 -0
  143. package/src/tools/agent-harness-command-catalog.ts +4 -2
  144. package/src/tools/agent-harness-command-runner.ts +42 -0
  145. package/src/tools/agent-harness-connected-host-status.ts +7 -4
  146. package/src/tools/agent-harness-delegation-posture.ts +234 -19
  147. package/src/tools/agent-harness-device-live-read-models.ts +366 -0
  148. package/src/tools/agent-harness-document-ops-reviewer-readiness.ts +234 -0
  149. package/src/tools/agent-harness-document-ops-types.ts +72 -0
  150. package/src/tools/agent-harness-document-ops.ts +671 -0
  151. package/src/tools/agent-harness-execution-history.ts +489 -0
  152. package/src/tools/agent-harness-execution-posture.ts +385 -0
  153. package/src/tools/agent-harness-file-recovery.ts +135 -0
  154. package/src/tools/agent-harness-interactive-runtime-records.ts +421 -0
  155. package/src/tools/agent-harness-keybinding-metadata.ts +16 -12
  156. package/src/tools/agent-harness-learning-curator-common.ts +102 -0
  157. package/src/tools/agent-harness-learning-curator-consolidation.ts +295 -0
  158. package/src/tools/agent-harness-learning-curator-proposals.ts +606 -0
  159. package/src/tools/agent-harness-learning-curator-types.ts +151 -0
  160. package/src/tools/agent-harness-learning-curator.ts +417 -0
  161. package/src/tools/agent-harness-local-model-benchmarks.ts +269 -0
  162. package/src/tools/agent-harness-local-model-cookbook.ts +238 -0
  163. package/src/tools/agent-harness-local-model-endpoints.ts +788 -0
  164. package/src/tools/agent-harness-local-model-smoke.ts +277 -0
  165. package/src/tools/agent-harness-local-model-url.ts +78 -0
  166. package/src/tools/agent-harness-media-posture.ts +223 -2
  167. package/src/tools/agent-harness-memory-external-providers.ts +796 -0
  168. package/src/tools/agent-harness-memory-posture.ts +672 -0
  169. package/src/tools/agent-harness-memory-provider-certification.ts +219 -0
  170. package/src/tools/agent-harness-memory-refinement.ts +340 -0
  171. package/src/tools/agent-harness-metadata.ts +100 -168
  172. package/src/tools/agent-harness-mode-catalog.ts +86 -33
  173. package/src/tools/agent-harness-model-catalog.ts +162 -0
  174. package/src/tools/agent-harness-model-provider-health.ts +283 -0
  175. package/src/tools/agent-harness-model-readiness.ts +432 -0
  176. package/src/tools/agent-harness-model-routing-types.ts +327 -0
  177. package/src/tools/agent-harness-model-routing-utils.ts +30 -0
  178. package/src/tools/agent-harness-model-routing.ts +165 -193
  179. package/src/tools/agent-harness-operator-methods.ts +115 -133
  180. package/src/tools/agent-harness-pairing-posture.ts +452 -18
  181. package/src/tools/agent-harness-personal-ops-certification.ts +116 -0
  182. package/src/tools/agent-harness-personal-ops-discovery.ts +533 -0
  183. package/src/tools/agent-harness-personal-ops-intake.ts +385 -0
  184. package/src/tools/agent-harness-personal-ops-lanes.ts +270 -0
  185. package/src/tools/agent-harness-personal-ops-operations.ts +225 -0
  186. package/src/tools/agent-harness-personal-ops-provider-records.ts +358 -0
  187. package/src/tools/agent-harness-personal-ops-provider-task-records.ts +321 -0
  188. package/src/tools/agent-harness-personal-ops-records.ts +684 -0
  189. package/src/tools/agent-harness-personal-ops-runner.ts +637 -0
  190. package/src/tools/agent-harness-personal-ops-types.ts +240 -0
  191. package/src/tools/agent-harness-personal-ops.ts +613 -0
  192. package/src/tools/agent-harness-project-context.ts +144 -0
  193. package/src/tools/agent-harness-prompt-context.ts +589 -0
  194. package/src/tools/agent-harness-provider-account-metadata.ts +2 -2
  195. package/src/tools/agent-harness-release-evidence.ts +9 -7
  196. package/src/tools/agent-harness-release-readiness.ts +9 -7
  197. package/src/tools/agent-harness-remote-read-models.ts +541 -0
  198. package/src/tools/agent-harness-research-briefing.ts +446 -0
  199. package/src/tools/agent-harness-research-live-read-models.ts +500 -0
  200. package/src/tools/agent-harness-research-queue.ts +250 -0
  201. package/src/tools/agent-harness-research-runs.ts +307 -0
  202. package/src/tools/agent-harness-research-workflow.ts +395 -0
  203. package/src/tools/agent-harness-security-posture.ts +2 -2
  204. package/src/tools/agent-harness-service-posture.ts +9 -9
  205. package/src/tools/agent-harness-session-metadata.ts +3 -3
  206. package/src/tools/agent-harness-setup-connected-host.ts +501 -0
  207. package/src/tools/agent-harness-setup-describe.ts +557 -0
  208. package/src/tools/agent-harness-setup-handoffs.ts +502 -0
  209. package/src/tools/agent-harness-setup-model-helpers.ts +102 -0
  210. package/src/tools/agent-harness-setup-plan.ts +253 -0
  211. package/src/tools/agent-harness-setup-posture-types.ts +218 -0
  212. package/src/tools/agent-harness-setup-posture-utils.ts +173 -0
  213. package/src/tools/agent-harness-setup-posture.ts +449 -221
  214. package/src/tools/agent-harness-setup-smoke.ts +533 -0
  215. package/src/tools/agent-harness-sudo-posture.ts +114 -0
  216. package/src/tools/agent-harness-tool-schema.ts +142 -7
  217. package/src/tools/agent-harness-tool-types.ts +83 -0
  218. package/src/tools/agent-harness-tool-utils.ts +43 -0
  219. package/src/tools/agent-harness-tool.ts +319 -370
  220. package/src/tools/agent-harness-ui-surface-metadata.ts +76 -69
  221. package/src/tools/agent-harness-ui-surface-types.ts +46 -0
  222. package/src/tools/agent-harness-vibe-health.ts +105 -0
  223. package/src/tools/agent-harness-workspace-action-runner.ts +149 -0
  224. package/src/tools/agent-harness-workspace-actions.ts +114 -8
  225. package/src/tools/agent-harness-workspace-editor-execution.ts +214 -0
  226. package/src/tools/agent-harness-workspace-editor-runner.ts +755 -0
  227. package/src/tools/agent-host-tool.ts +159 -0
  228. package/src/tools/agent-knowledge-ingest-tool.ts +34 -1
  229. package/src/tools/agent-learning-consolidation-core.ts +327 -0
  230. package/src/tools/agent-learning-consolidation-tool.ts +758 -0
  231. package/src/tools/agent-memory-tool.ts +253 -0
  232. package/src/tools/agent-model-compare-export.ts +315 -0
  233. package/src/tools/agent-model-compare-handoff.ts +592 -0
  234. package/src/tools/agent-model-compare-judgment.ts +633 -0
  235. package/src/tools/agent-model-compare-run.ts +735 -0
  236. package/src/tools/agent-model-compare-tool.ts +698 -0
  237. package/src/tools/agent-model-compare-types.ts +191 -0
  238. package/src/tools/agent-model-compare-utils.ts +93 -0
  239. package/src/tools/agent-models-tool.ts +208 -0
  240. package/src/tools/agent-operator-action-tool.ts +1 -1
  241. package/src/tools/agent-operator-method-tool.ts +643 -0
  242. package/src/tools/agent-personal-ops-tool.ts +197 -0
  243. package/src/tools/agent-policy-explanation.ts +415 -0
  244. package/src/tools/agent-research-report-tool.ts +608 -0
  245. package/src/tools/agent-research-runner.ts +367 -0
  246. package/src/tools/agent-research-runs-tool.ts +434 -0
  247. package/src/tools/agent-research-sources-tool.ts +443 -0
  248. package/src/tools/agent-research-tool.ts +515 -0
  249. package/src/tools/agent-review-packet-presets-core.ts +757 -0
  250. package/src/tools/agent-review-packet-presets-tool.ts +466 -0
  251. package/src/tools/agent-review-packet-share-tool.ts +305 -0
  252. package/src/tools/agent-route-planner-candidates-setup.ts +411 -0
  253. package/src/tools/agent-route-planner-candidates-surfaces.ts +432 -0
  254. package/src/tools/agent-route-planner-candidates-work.ts +251 -0
  255. package/src/tools/agent-route-planner-helpers.ts +667 -0
  256. package/src/tools/agent-route-planner.ts +185 -0
  257. package/src/tools/agent-route-tool.ts +105 -0
  258. package/src/tools/agent-schedule-edit-tool.ts +210 -0
  259. package/src/tools/agent-schedule-tool.ts +282 -0
  260. package/src/tools/agent-security-tool.ts +145 -0
  261. package/src/tools/agent-sessions-tool.ts +122 -0
  262. package/src/tools/agent-settings-import-tool.ts +104 -0
  263. package/src/tools/agent-settings-tool.ts +176 -0
  264. package/src/tools/agent-setup-tool.ts +226 -0
  265. package/src/tools/agent-support-tool.ts +122 -0
  266. package/src/tools/agent-terminal-process-tools.ts +167 -0
  267. package/src/tools/agent-tool-policy-guard-types.ts +77 -0
  268. package/src/tools/agent-tool-policy-guard.ts +106 -85
  269. package/src/tools/agent-vibe-tool.ts +297 -0
  270. package/src/tools/agent-work-plan-tool.ts +265 -6
  271. package/src/tools/agent-workspace-tool.ts +305 -0
  272. package/src/tools/artifact-archive.ts +169 -0
  273. package/src/tools/tool-definition-compaction.ts +36 -0
  274. package/src/version.ts +1 -1
@@ -0,0 +1,791 @@
1
+ import type { ToolRegistry } from '@pellux/goodvibes-sdk/platform/tools';
2
+ import type { ArtifactDescriptor } from '@pellux/goodvibes-sdk/platform/artifacts';
3
+ import type { CommandContext } from '../input/command-registry.ts';
4
+ import type { WorkPlanItem } from '../work-plans/work-plan-store.ts';
5
+ import { AGENT_TEMPLATES, AGENT_TOOL_MODES, agentOrchestrationDecisionCards } from './agent-harness-agent-orchestration-policy.ts';
6
+ import { remoteReadModelSnapshot, type RemoteCaptureOutcomeRecord, type RemoteWorkspaceEvidenceRecord } from './agent-harness-remote-read-models.ts';
7
+ import { previewHarnessText } from './agent-harness-text.ts';
8
+
9
+ interface AgentHarnessAgentOrchestrationArgs {
10
+ readonly agentId?: unknown;
11
+ readonly target?: unknown;
12
+ readonly query?: unknown;
13
+ readonly includeParameters?: unknown;
14
+ readonly limit?: unknown;
15
+ }
16
+
17
+ type AgentLookupSource = 'agentId' | 'target' | 'query';
18
+ type AgentRecordView = Record<string, unknown>;
19
+ type ManagedPlanStatus = 'ready' | 'active' | 'attention' | 'needs-setup';
20
+
21
+ interface RemoteRuntimeSnapshot {
22
+ readonly pools: readonly Record<string, unknown>[];
23
+ readonly contracts: readonly Record<string, unknown>[];
24
+ readonly artifacts: readonly Record<string, unknown>[];
25
+ readonly outcomes: readonly RemoteCaptureOutcomeRecord[];
26
+ readonly workspaces: readonly RemoteWorkspaceEvidenceRecord[];
27
+ readonly sourceCounts: Readonly<Record<string, number>>;
28
+ }
29
+
30
+ export type AgentOrchestrationResolution =
31
+ | { readonly status: 'found'; readonly agent: Record<string, unknown> }
32
+ | { readonly status: 'ambiguous'; readonly input: string; readonly candidates: readonly Record<string, unknown>[] }
33
+ | { readonly status: 'missing_lookup'; readonly usage: string };
34
+
35
+ const REMOTE_ARTIFACT_RECEIPT_PURPOSES = new Set([
36
+ 'remote-runner-artifact-receipt',
37
+ 'remote-runner-closeout-receipt',
38
+ 'remote-runner-export-receipt',
39
+ 'agent-remote-runner-artifact-receipt',
40
+ 'agent-remote-runner-closeout-receipt',
41
+ 'connected-host-remote-runner-artifact-receipt',
42
+ 'connected-host-remote-runner-closeout-receipt',
43
+ ]);
44
+
45
+ function readString(value: unknown): string {
46
+ return typeof value === 'string' ? value.trim() : '';
47
+ }
48
+
49
+ function readObject(value: unknown): Record<string, unknown> {
50
+ return value && typeof value === 'object' ? value as Record<string, unknown> : {};
51
+ }
52
+
53
+ function artifactMetadata(record: Record<string, unknown>): Record<string, unknown> {
54
+ return readObject(record.metadata);
55
+ }
56
+
57
+ function metadataString(record: Record<string, unknown>, key: string): string {
58
+ return readString(artifactMetadata(record)[key]);
59
+ }
60
+
61
+ function recordOrMetadataString(record: Record<string, unknown>, key: string): string {
62
+ return readString(record[key]) || metadataString(record, key);
63
+ }
64
+
65
+ function recordOrMetadataNumber(record: Record<string, unknown>, key: string): number {
66
+ const value = record[key] ?? artifactMetadata(record)[key];
67
+ return typeof value === 'number' && Number.isFinite(value) ? value : 0;
68
+ }
69
+
70
+ function artifactPurpose(record: Record<string, unknown>): string {
71
+ return metadataString(record, 'purpose');
72
+ }
73
+
74
+ function isRemoteArtifactReceipt(record: Record<string, unknown>): boolean {
75
+ return REMOTE_ARTIFACT_RECEIPT_PURPOSES.has(artifactPurpose(record));
76
+ }
77
+
78
+ function readLimit(value: unknown, fallback: number): number {
79
+ const parsed = typeof value === 'string' && value.trim() ? Number(value) : value;
80
+ if (typeof parsed !== 'number' || !Number.isFinite(parsed)) return fallback;
81
+ return Math.max(1, Math.min(500, Math.trunc(parsed)));
82
+ }
83
+
84
+ function lookupFromArgs(args: AgentHarnessAgentOrchestrationArgs): { readonly source: AgentLookupSource; readonly input: string } | null {
85
+ const agentId = readString(args.agentId);
86
+ if (agentId) return { source: 'agentId', input: agentId };
87
+ const target = readString(args.target);
88
+ if (target) return { source: 'target', input: target };
89
+ const query = readString(args.query);
90
+ return query ? { source: 'query', input: query } : null;
91
+ }
92
+
93
+ function exportAgents(context: CommandContext): readonly AgentRecordView[] | null {
94
+ const agentManager = context.ops.agentManager;
95
+ if (!agentManager) return null;
96
+ try {
97
+ return agentManager.exportState().map((record) => record as unknown as AgentRecordView);
98
+ } catch {
99
+ return [];
100
+ }
101
+ }
102
+
103
+ function remoteContracts(context: CommandContext): readonly Record<string, unknown>[] {
104
+ try {
105
+ return context.ops.remoteRuntime?.listContracts().map((record) => record as unknown as Record<string, unknown>) ?? [];
106
+ } catch {
107
+ return [];
108
+ }
109
+ }
110
+
111
+ function remotePools(context: CommandContext): readonly Record<string, unknown>[] {
112
+ try {
113
+ return context.ops.remoteRuntime?.listPools().map((record) => record as unknown as Record<string, unknown>) ?? [];
114
+ } catch {
115
+ return [];
116
+ }
117
+ }
118
+
119
+ function remoteRuntimeArtifacts(context: CommandContext): readonly Record<string, unknown>[] {
120
+ try {
121
+ return context.ops.remoteRuntime?.listArtifacts().map((record) => record as unknown as Record<string, unknown>) ?? [];
122
+ } catch {
123
+ return [];
124
+ }
125
+ }
126
+
127
+ function artifactCreatedAt(artifact: ArtifactDescriptor): number {
128
+ return typeof artifact.createdAt === 'number' && Number.isFinite(artifact.createdAt) ? artifact.createdAt : 0;
129
+ }
130
+
131
+ function remoteReceiptArtifacts(context: CommandContext): readonly Record<string, unknown>[] {
132
+ const store = context.platform.artifactStore;
133
+ if (!store?.list) return [];
134
+ try {
135
+ return store.list(100)
136
+ .filter((artifact) => isRemoteArtifactReceipt(artifact as unknown as Record<string, unknown>))
137
+ .filter((artifact) => remoteRunnerId(artifact as unknown as Record<string, unknown>))
138
+ .sort((left, right) => artifactCreatedAt(right) - artifactCreatedAt(left))
139
+ .slice(0, 20)
140
+ .map((artifact) => artifact as unknown as Record<string, unknown>);
141
+ } catch {
142
+ return [];
143
+ }
144
+ }
145
+
146
+ function remoteArtifacts(context: CommandContext): readonly Record<string, unknown>[] {
147
+ const runtimeArtifacts = remoteRuntimeArtifacts(context);
148
+ const seen = new Set(runtimeArtifacts.map((artifact) => readString(artifact.id)).filter(Boolean));
149
+ const receiptArtifacts = remoteReceiptArtifacts(context).filter((artifact) => {
150
+ const id = readString(artifact.id);
151
+ return !id || !seen.has(id);
152
+ });
153
+ return [...runtimeArtifacts, ...receiptArtifacts];
154
+ }
155
+
156
+ function remoteRuntimeSnapshot(context: CommandContext): RemoteRuntimeSnapshot {
157
+ const readModels = remoteReadModelSnapshot(context);
158
+ return {
159
+ pools: remotePools(context),
160
+ contracts: remoteContracts(context),
161
+ artifacts: remoteArtifacts(context),
162
+ outcomes: readModels.outcomes,
163
+ workspaces: readModels.workspaces,
164
+ sourceCounts: readModels.sourceCounts,
165
+ };
166
+ }
167
+
168
+ function agentToolRegistered(toolRegistry: ToolRegistry): boolean {
169
+ return toolRegistry.getToolDefinitions().some((tool) => tool.name === 'agent');
170
+ }
171
+
172
+ function remoteToolRegistered(toolRegistry: ToolRegistry): boolean {
173
+ return toolRegistry.getToolDefinitions().some((tool) => tool.name === 'remote');
174
+ }
175
+
176
+ function agentId(record: AgentRecordView): string {
177
+ return readString(record.id);
178
+ }
179
+
180
+ function agentStatus(record: AgentRecordView): string {
181
+ return readString(record.status) || 'unknown';
182
+ }
183
+
184
+ function agentSearchText(record: AgentRecordView): string {
185
+ return [
186
+ record.id,
187
+ record.task,
188
+ record.template,
189
+ record.status,
190
+ record.progress,
191
+ record.model,
192
+ record.provider,
193
+ Array.isArray(record.tools) ? record.tools.join('\n') : '',
194
+ record.context,
195
+ ].map((value) => typeof value === 'string' ? value : String(value ?? '')).join('\n').toLowerCase();
196
+ }
197
+
198
+ function statusCounts(records: readonly AgentRecordView[]): Record<string, number> {
199
+ const counts: Record<string, number> = {
200
+ pending: 0,
201
+ running: 0,
202
+ completed: 0,
203
+ failed: 0,
204
+ cancelled: 0,
205
+ unknown: 0,
206
+ };
207
+ for (const record of records) {
208
+ const status = agentStatus(record);
209
+ counts[status] = (counts[status] ?? 0) + 1;
210
+ }
211
+ return counts;
212
+ }
213
+
214
+ function routeForAgent(mode: string, id: string): string {
215
+ return `agent { mode: "${mode}", agentId: "${id}" }`;
216
+ }
217
+
218
+ function remoteRunnerId(record: Record<string, unknown>): string {
219
+ return recordOrMetadataString(record, 'runnerId')
220
+ || recordOrMetadataString(record, 'agentId')
221
+ || recordOrMetadataString(record, 'linkedAgentId')
222
+ || recordOrMetadataString(record, 'runner');
223
+ }
224
+
225
+ function transportState(contract: Record<string, unknown>): string {
226
+ const transport = contract.transport;
227
+ return transport && typeof transport === 'object' ? readString((transport as Record<string, unknown>).state) || 'unknown' : 'unknown';
228
+ }
229
+
230
+ function capabilityCeiling(contract: Record<string, unknown>): Record<string, unknown> {
231
+ const ceiling = contract.capabilityCeiling;
232
+ return ceiling && typeof ceiling === 'object' ? ceiling as Record<string, unknown> : {};
233
+ }
234
+
235
+ function stringArray(value: unknown): readonly string[] {
236
+ return Array.isArray(value) ? value.filter((entry): entry is string => typeof entry === 'string' && entry.trim().length > 0) : [];
237
+ }
238
+
239
+ function contractSummary(contract: Record<string, unknown>, includeParameters: boolean): Record<string, unknown> {
240
+ const ceiling = capabilityCeiling(contract);
241
+ return {
242
+ id: readString(contract.id),
243
+ runnerId: remoteRunnerId(contract),
244
+ poolId: readString(contract.poolId) || null,
245
+ label: previewHarnessText(readString(contract.label) || remoteRunnerId(contract), includeParameters ? 120 : 72),
246
+ sourceTransport: readString(contract.sourceTransport) || 'unknown',
247
+ trustClass: readString(contract.trustClass) || 'unknown',
248
+ template: readString(contract.template) || 'general',
249
+ transportState: transportState(contract),
250
+ allowedTools: stringArray(ceiling.allowedTools).slice(0, includeParameters ? 20 : 8),
251
+ capabilityCeilingTools: stringArray(ceiling.capabilityCeilingTools).slice(0, includeParameters ? 20 : 8),
252
+ executionProtocol: readString(ceiling.executionProtocol) || 'unknown',
253
+ reviewMode: readString(ceiling.reviewMode) || 'unknown',
254
+ communicationLane: readString(ceiling.communicationLane) || 'unknown',
255
+ orchestrationDepth: typeof ceiling.orchestrationDepth === 'number' ? ceiling.orchestrationDepth : null,
256
+ requiredEvidence: stringArray(ceiling.requiredEvidence).slice(0, includeParameters ? 12 : 5),
257
+ successCriteria: stringArray(ceiling.successCriteria).slice(0, includeParameters ? 12 : 5),
258
+ writeScope: stringArray(ceiling.writeScope).slice(0, includeParameters ? 12 : 5),
259
+ };
260
+ }
261
+
262
+ function artifactSummary(artifact: Record<string, unknown>, includeParameters: boolean): Record<string, unknown> {
263
+ const metadata = artifactMetadata(artifact);
264
+ const task = readObject(artifact.task);
265
+ const evidence = readObject(artifact.evidence);
266
+ const receipt = isRemoteArtifactReceipt(artifact);
267
+ const id = readString(artifact.id);
268
+ const status = readString(task.status)
269
+ || metadataString(artifact, 'status')
270
+ || metadataString(artifact, 'outcome')
271
+ || 'unknown';
272
+ const taskText = readString(task.task)
273
+ || metadataString(artifact, 'task')
274
+ || metadataString(artifact, 'title');
275
+ const summary = readString(task.summary)
276
+ || metadataString(artifact, 'summary')
277
+ || metadataString(artifact, 'description');
278
+ const sourceArtifactId = metadataString(artifact, 'sourceArtifactId')
279
+ || metadataString(artifact, 'remoteArtifactId')
280
+ || metadataString(artifact, 'exportArtifactId');
281
+ return {
282
+ id,
283
+ runnerId: remoteRunnerId(artifact),
284
+ status,
285
+ task: previewHarnessText(taskText, includeParameters ? 160 : 72),
286
+ summary: previewHarnessText(summary, includeParameters ? 220 : 96),
287
+ toolCallCount: typeof evidence.toolCallCount === 'number' ? evidence.toolCallCount : recordOrMetadataNumber(artifact, 'toolCallCount'),
288
+ messageCount: typeof evidence.messageCount === 'number' ? evidence.messageCount : recordOrMetadataNumber(artifact, 'messageCount'),
289
+ errorCount: typeof evidence.errorCount === 'number' ? evidence.errorCount : recordOrMetadataNumber(artifact, 'errorCount'),
290
+ hasKnowledgeInjections: Boolean(evidence.hasKnowledgeInjections ?? metadata.hasKnowledgeInjections),
291
+ modelRoute: artifactReviewRoute(artifact),
292
+ ...(receipt ? {
293
+ receipt: true,
294
+ purpose: artifactPurpose(artifact),
295
+ sourceArtifactId: sourceArtifactId || null,
296
+ redaction: metadataString(artifact, 'redaction') || metadataString(artifact, 'redactionPolicy') || 'metadata-only',
297
+ } : {}),
298
+ };
299
+ }
300
+
301
+ function artifactReviewRoute(artifact: Record<string, unknown>): string {
302
+ const id = readString(artifact.id);
303
+ return isRemoteArtifactReceipt(artifact)
304
+ ? `agent_artifacts show artifactId:"${id}" includeContent:false`
305
+ : `remote { mode: "review", artifactId: "${id}" }`;
306
+ }
307
+
308
+ function agentRoutes(id: string): Record<string, string> {
309
+ return {
310
+ inspect: routeForAgent('get', id),
311
+ status: routeForAgent('status', id),
312
+ budget: routeForAgent('budget', id),
313
+ plan: routeForAgent('plan', id),
314
+ wait: routeForAgent('wait', id),
315
+ message: routeForAgent('message', id),
316
+ cancel: routeForAgent('cancel', id),
317
+ };
318
+ }
319
+
320
+ function contractByRunnerId(contracts: readonly Record<string, unknown>[]): Map<string, Record<string, unknown>> {
321
+ const entries: Array<readonly [string, Record<string, unknown>]> = [];
322
+ for (const contract of contracts) {
323
+ const id = remoteRunnerId(contract);
324
+ if (id) entries.push([id, contract]);
325
+ }
326
+ return new Map(entries);
327
+ }
328
+
329
+ function artifactsByRunnerId(artifacts: readonly Record<string, unknown>[]): Map<string, readonly Record<string, unknown>[]> {
330
+ const grouped = new Map<string, Record<string, unknown>[]>();
331
+ for (const artifact of artifacts) {
332
+ const id = remoteRunnerId(artifact);
333
+ if (!id) continue;
334
+ const entries = grouped.get(id) ?? [];
335
+ entries.push(artifact);
336
+ grouped.set(id, entries);
337
+ }
338
+ return grouped;
339
+ }
340
+
341
+ function outcomesByRunnerId(outcomes: readonly RemoteCaptureOutcomeRecord[]): Map<string, readonly RemoteCaptureOutcomeRecord[]> {
342
+ const grouped = new Map<string, RemoteCaptureOutcomeRecord[]>();
343
+ for (const outcome of outcomes) {
344
+ const entries = grouped.get(outcome.runnerId) ?? [];
345
+ entries.push(outcome);
346
+ grouped.set(outcome.runnerId, entries);
347
+ }
348
+ return grouped;
349
+ }
350
+
351
+ function workspacesByRunnerId(workspaces: readonly RemoteWorkspaceEvidenceRecord[]): Map<string, readonly RemoteWorkspaceEvidenceRecord[]> {
352
+ const grouped = new Map<string, RemoteWorkspaceEvidenceRecord[]>();
353
+ for (const workspace of workspaces) {
354
+ const entries = grouped.get(workspace.runnerId) ?? [];
355
+ entries.push(workspace);
356
+ grouped.set(workspace.runnerId, entries);
357
+ }
358
+ return grouped;
359
+ }
360
+
361
+ function workPlanItems(context: CommandContext): readonly WorkPlanItem[] {
362
+ try {
363
+ return context.workspace.workPlanStore?.listItems() ?? [];
364
+ } catch {
365
+ return [];
366
+ }
367
+ }
368
+
369
+ function workPlanItemsByAgentId(items: readonly WorkPlanItem[]): Map<string, readonly WorkPlanItem[]> {
370
+ const grouped = new Map<string, WorkPlanItem[]>();
371
+ for (const item of items) {
372
+ const id = item.linked?.agentId;
373
+ if (!id) continue;
374
+ const entries = grouped.get(id) ?? [];
375
+ entries.push(item);
376
+ grouped.set(id, entries);
377
+ }
378
+ return grouped;
379
+ }
380
+
381
+ function dispatchReceiptLines(item: WorkPlanItem): readonly string[] {
382
+ return readString(item.notes)
383
+ .split('\n')
384
+ .map((line) => line.trim())
385
+ .filter((line) => line.includes('Agent dispatch receipt'));
386
+ }
387
+
388
+ function workPlanCloseoutItem(item: WorkPlanItem, includeParameters: boolean): Record<string, unknown> {
389
+ const receipts = dispatchReceiptLines(item);
390
+ return {
391
+ itemId: item.id,
392
+ title: previewHarnessText(item.title, includeParameters ? 160 : 72),
393
+ status: item.status,
394
+ owner: item.owner ?? null,
395
+ source: item.source ?? null,
396
+ dispatchReceiptCount: receipts.length,
397
+ latestDispatchReceipt: receipts.at(-1) ? previewHarnessText(receipts.at(-1)!, includeParameters ? 260 : 120) : null,
398
+ routes: {
399
+ inspect: `agent_work_plan action:"get" id:"${item.id}"`,
400
+ markDone: `agent_work_plan action:"set_status" id:"${item.id}" status:"done"`,
401
+ markBlocked: `agent_work_plan action:"set_status" id:"${item.id}" status:"blocked"`,
402
+ },
403
+ };
404
+ }
405
+
406
+ function closeoutReviewRoutes(id: string, items: readonly WorkPlanItem[], artifacts: readonly Record<string, unknown>[], outcomes: readonly RemoteCaptureOutcomeRecord[] = [], workspaces: readonly RemoteWorkspaceEvidenceRecord[] = []): readonly string[] {
407
+ return [
408
+ routeForAgent('get', id),
409
+ ...items.map((item) => `agent_work_plan action:"get" id:"${item.id}"`),
410
+ ...artifacts.map((artifact) => artifactReviewRoute(artifact)),
411
+ ...outcomes.map((outcome) => outcome.modelRoute),
412
+ ...workspaces.map((workspace) => workspace.modelRoute),
413
+ ];
414
+ }
415
+
416
+ function closeoutStatus(status: string, items: readonly WorkPlanItem[], artifacts: readonly Record<string, unknown>[], outcomes: readonly RemoteCaptureOutcomeRecord[] = []): string {
417
+ if (['pending', 'running'].includes(status)) return 'pending-work';
418
+ if (status === 'failed') return 'attention';
419
+ if (items.some((item) => item.status === 'blocked' || item.status === 'failed')) return 'attention';
420
+ if (artifacts.length > 0 || outcomes.length > 0) return 'evidence-ready';
421
+ if (items.length > 0) return 'needs-artifact-evidence';
422
+ return 'unlinked';
423
+ }
424
+
425
+ function closeoutCard(id: string, status: string, items: readonly WorkPlanItem[], artifacts: readonly Record<string, unknown>[], outcomes: readonly RemoteCaptureOutcomeRecord[], workspaces: readonly RemoteWorkspaceEvidenceRecord[], includeParameters: boolean): Record<string, unknown> {
426
+ const hasReadModelEvidence = outcomes.length > 0 || workspaces.length > 0;
427
+ return {
428
+ status: closeoutStatus(status, items, artifacts, outcomes),
429
+ workPlanItemCount: items.length,
430
+ dispatchReceiptCount: items.reduce((count, item) => count + dispatchReceiptLines(item).length, 0),
431
+ remoteArtifactCount: artifacts.length,
432
+ remoteReceiptCount: artifacts.filter((artifact) => isRemoteArtifactReceipt(artifact)).length,
433
+ remoteOutcomeCount: outcomes.length,
434
+ workspaceEvidenceCount: workspaces.length,
435
+ autoAttachReason: artifacts.length > 0
436
+ ? 'remote artifact or durable receipt runnerId matched the visible agent id'
437
+ : hasReadModelEvidence
438
+ ? 'daemon/SDK remote read-model runnerId matched the visible agent id'
439
+ : null,
440
+ workPlanItems: items.slice(0, includeParameters ? 8 : 3).map((item) => workPlanCloseoutItem(item, includeParameters)),
441
+ autoAttachedRemoteArtifacts: artifacts.slice(0, includeParameters ? 8 : 3).map((artifact) => artifactSummary(artifact, includeParameters)),
442
+ liveRemoteOutcomes: outcomes.slice(0, includeParameters ? 8 : 3),
443
+ workspaceEvidence: workspaces.slice(0, includeParameters ? 8 : 3),
444
+ reviewRoutes: closeoutReviewRoutes(id, items, artifacts, outcomes, workspaces).slice(0, includeParameters ? 24 : 8),
445
+ updateRoutes: items.slice(0, includeParameters ? 8 : 3).flatMap((item) => [
446
+ `agent_work_plan action:"set_status" id:"${item.id}" status:"done"`,
447
+ `agent_work_plan action:"set_status" id:"${item.id}" status:"blocked"`,
448
+ ]),
449
+ policy: 'Closeout is read-only here; status changes stay on agent_work_plan and artifact review stays on first-class routes.',
450
+ };
451
+ }
452
+
453
+ function managedPlanItem(
454
+ record: AgentRecordView,
455
+ contract: Record<string, unknown> | undefined,
456
+ artifacts: readonly Record<string, unknown>[],
457
+ outcomes: readonly RemoteCaptureOutcomeRecord[],
458
+ workspaces: readonly RemoteWorkspaceEvidenceRecord[],
459
+ linkedWorkItems: readonly WorkPlanItem[],
460
+ includeParameters: boolean,
461
+ ): Record<string, unknown> {
462
+ const id = agentId(record);
463
+ const status = agentStatus(record);
464
+ const task = readString(record.task);
465
+ const progress = readString(record.progress);
466
+ const hasRemoteContract = Boolean(contract);
467
+ const hasLiveRemoteEvidence = hasRemoteContract || outcomes.length > 0 || workspaces.length > 0;
468
+ const running = ['pending', 'running'].includes(status);
469
+ const failed = status === 'failed';
470
+ const hasOutcomeEvidence = artifacts.length > 0 || outcomes.length > 0;
471
+ return {
472
+ planItemId: `agent:${id}`,
473
+ agentId: id,
474
+ lane: hasLiveRemoteEvidence ? 'remote-runner' : 'visible-agent',
475
+ milestoneId: running ? 'visible-agent-work' : 'review-and-closeout',
476
+ status,
477
+ title: previewHarnessText(task || id, includeParameters ? 160 : 72),
478
+ progress: progress ? previewHarnessText(progress, includeParameters ? 180 : 72) : null,
479
+ template: readString(record.template) || 'general',
480
+ toolCallCount: typeof record.toolCallCount === 'number' ? record.toolCallCount : 0,
481
+ routes: agentRoutes(id),
482
+ workPlanLinks: linkedWorkItems.slice(0, includeParameters ? 8 : 3).map((item) => workPlanCloseoutItem(item, includeParameters)),
483
+ remoteContract: contract ? contractSummary(contract, includeParameters) : null,
484
+ artifactTrail: artifacts.slice(0, includeParameters ? 8 : 3).map((artifact) => artifactSummary(artifact, includeParameters)),
485
+ liveOutcomeTrail: outcomes.slice(0, includeParameters ? 8 : 3),
486
+ workspaceEvidence: workspaces.slice(0, includeParameters ? 8 : 3),
487
+ closeout: closeoutCard(id, status, linkedWorkItems, artifacts, outcomes, workspaces, includeParameters),
488
+ reviewGate: {
489
+ status: failed ? 'attention' : running ? 'pending-work' : hasOutcomeEvidence ? 'artifact-ready' : workspaces.length > 0 ? 'workspace-evidence-ready' : linkedWorkItems.length > 0 ? 'needs-artifact-evidence' : 'needs-link',
490
+ requiredEvidence: [
491
+ ...(contract ? stringArray(capabilityCeiling(contract).requiredEvidence).slice(0, includeParameters ? 12 : 5) : []),
492
+ ...(workspaces.length > 0 ? ['workspace/worktree isolation evidence'] : []),
493
+ ...(outcomes.length > 0 ? ['live remote capture/export outcome evidence'] : []),
494
+ ],
495
+ modelRoutes: closeoutReviewRoutes(id, linkedWorkItems, artifacts, outcomes, workspaces).slice(0, includeParameters ? 24 : 8),
496
+ },
497
+ nextAction: failed
498
+ ? 'Inspect the failed agent, then decide whether to message, retry through a new visible task, or cancel related work.'
499
+ : running
500
+ ? 'Use wait/status for progress, message for guidance, or cancel if the work no longer helps the user.'
501
+ : hasOutcomeEvidence
502
+ ? 'Review the artifact trail before closing the plan.'
503
+ : workspaces.length > 0
504
+ ? 'Confirm the workspace isolation evidence, then attach outcome evidence before closing the plan.'
505
+ : 'Capture or attach outcome evidence before treating this work as complete.',
506
+ };
507
+ }
508
+
509
+ function managedPlanStatus(records: readonly AgentRecordView[], agentToolAvailable: boolean): ManagedPlanStatus {
510
+ if (records.some((record) => agentStatus(record) === 'failed')) return 'attention';
511
+ if (records.some((record) => ['pending', 'running'].includes(agentStatus(record)))) return 'active';
512
+ if (records.length > 0 || agentToolAvailable) return 'ready';
513
+ return 'needs-setup';
514
+ }
515
+
516
+ function managedExecutionPlan(
517
+ records: readonly AgentRecordView[],
518
+ context: CommandContext,
519
+ toolRegistry: ToolRegistry,
520
+ remoteSnapshot: RemoteRuntimeSnapshot,
521
+ includeParameters: boolean,
522
+ ): Record<string, unknown> {
523
+ const agentToolAvailable = agentToolRegistered(toolRegistry);
524
+ const remoteToolAvailable = remoteToolRegistered(toolRegistry);
525
+ const { pools, contracts, artifacts, outcomes, workspaces, sourceCounts } = remoteSnapshot;
526
+ const contractsByRunner = contractByRunnerId(contracts);
527
+ const artifactsByRunner = artifactsByRunnerId(artifacts);
528
+ const outcomesByRunner = outcomesByRunnerId(outcomes);
529
+ const workspacesByRunner = workspacesByRunnerId(workspaces);
530
+ const workPlanByAgent = workPlanItemsByAgentId(workPlanItems(context));
531
+ const items = records.map((record) => {
532
+ const id = agentId(record);
533
+ return managedPlanItem(
534
+ record,
535
+ contractsByRunner.get(id),
536
+ artifactsByRunner.get(id) ?? [],
537
+ outcomesByRunner.get(id) ?? [],
538
+ workspacesByRunner.get(id) ?? [],
539
+ workPlanByAgent.get(id) ?? [],
540
+ includeParameters,
541
+ );
542
+ });
543
+ const status = managedPlanStatus(records, agentToolAvailable);
544
+ const running = records.filter((record) => ['pending', 'running'].includes(agentStatus(record))).length;
545
+ const failed = records.filter((record) => agentStatus(record) === 'failed').length;
546
+ const completed = records.filter((record) => agentStatus(record) === 'completed').length;
547
+ const remoteStatus = contracts.length > 0 || artifacts.length > 0 || outcomes.length > 0 || workspaces.length > 0 ? 'ready' : context.ops.remoteRuntime ? 'ready' : 'needs-setup';
548
+ const linkedWorkPlanItemCount = Array.from(workPlanByAgent.values()).reduce((count, entries) => count + entries.length, 0);
549
+ const dispatchReceiptCount = Array.from(workPlanByAgent.values()).reduce(
550
+ (count, entries) => count + entries.reduce((entryCount, item) => entryCount + dispatchReceiptLines(item).length, 0),
551
+ 0,
552
+ );
553
+ return {
554
+ planId: 'visible-managed-execution',
555
+ status,
556
+ summary: `${records.length} visible agent${records.length === 1 ? '' : 's'}, ${running} active, ${failed} attention, ${artifacts.length} remote artifact${artifacts.length === 1 ? '' : 's'}, ${outcomes.length} live remote outcome${outcomes.length === 1 ? '' : 's'}, ${workspaces.length} workspace evidence record${workspaces.length === 1 ? '' : 's'}, ${dispatchReceiptCount} dispatch receipt${dispatchReceiptCount === 1 ? '' : 's'}.`,
557
+ milestones: [
558
+ {
559
+ id: 'intake-and-lane-selection',
560
+ label: 'Intake and lane selection',
561
+ status: 'ready',
562
+ purpose: 'Choose serial chat, one visible agent, batch agents, delegated review, or remote inspection based on user outcome.',
563
+ routes: ['delegation action:"status"', 'execution action:"status"', 'agent_harness mode:"agent_orchestration"', 'agent_work_plan action:"dispatch_agents" ids:["..."] confirm:true explicitUserRequest:"..."'],
564
+ },
565
+ {
566
+ id: 'visible-agent-work',
567
+ label: 'Visible agent work',
568
+ status: running > 0 ? 'active' : failed > 0 ? 'attention' : agentToolAvailable ? 'ready' : 'needs-setup',
569
+ count: records.length,
570
+ active: running,
571
+ completed,
572
+ failed,
573
+ cancellableRoutes: records.filter((record) => ['pending', 'running'].includes(agentStatus(record))).map((record) => routeForAgent('cancel', agentId(record))).slice(0, 12),
574
+ },
575
+ {
576
+ id: 'remote-runner-evidence',
577
+ label: 'Remote runner evidence',
578
+ status: remoteStatus,
579
+ pools: pools.length,
580
+ contracts: contracts.length,
581
+ artifacts: artifacts.length,
582
+ readModelOutcomes: outcomes.length,
583
+ workspaceEvidence: workspaces.length,
584
+ routes: {
585
+ pools: remoteToolAvailable ? 'remote { mode: "pools", view: "summary" }' : 'delegation action:"route" delegationRouteId:"remote-runner-inspection"',
586
+ contracts: remoteToolAvailable ? 'remote { mode: "contracts", view: "summary" }' : 'delegation action:"route" delegationRouteId:"remote-runner-inspection"',
587
+ artifacts: remoteToolAvailable ? 'remote { mode: "artifacts", view: "summary" }' : 'delegation action:"route" delegationRouteId:"remote-runner-inspection"',
588
+ },
589
+ },
590
+ {
591
+ id: 'review-and-closeout',
592
+ label: 'Review and closeout',
593
+ status: failed > 0 ? 'attention' : running > 0 ? 'active' : records.length > 0 ? 'ready' : 'needs-setup',
594
+ linkedWorkPlanItems: linkedWorkPlanItemCount,
595
+ dispatchReceipts: dispatchReceiptCount,
596
+ autoAttachedRemoteArtifacts: artifacts.length,
597
+ liveRemoteOutcomes: outcomes.length,
598
+ workspaceEvidence: workspaces.length,
599
+ requiredEvidence: ['changed files or artifact', 'test or verification output', 'agent status', 'workspace isolation evidence when remote runners are used', 'recovery route when writes happened'],
600
+ routes: ['agent_harness mode:"agent_orchestration"', 'execution action:"history"', 'execution action:"recovery"', 'delegation action:"status"', 'agent_work_plan action:"list"'],
601
+ },
602
+ ],
603
+ workItems: items,
604
+ remoteEvidence: {
605
+ status: remoteStatus,
606
+ pools: pools.slice(0, includeParameters ? 8 : 3).map((pool) => ({
607
+ id: readString(pool.id),
608
+ label: readString(pool.label) || readString(pool.id),
609
+ runnerIds: stringArray(pool.runnerIds).slice(0, includeParameters ? 12 : 5),
610
+ })),
611
+ contracts: contracts.slice(0, includeParameters ? 8 : 3).map((contract) => contractSummary(contract, includeParameters)),
612
+ artifacts: artifacts.slice(0, includeParameters ? 8 : 3).map((artifact) => artifactSummary(artifact, includeParameters)),
613
+ liveOutcomes: outcomes.slice(0, includeParameters ? 8 : 3),
614
+ workspaceEvidence: workspaces.slice(0, includeParameters ? 8 : 3),
615
+ sourceCounts,
616
+ policy: 'Remote runner evidence is read-only here; creating pools, assigning runners, importing artifacts, accepting workspace isolation, or spawning agents stays on confirmed first-class routes.',
617
+ },
618
+ modelAccess: {
619
+ spawn: 'agent { mode: "spawn" }',
620
+ batchSpawn: 'agent { mode: "batch-spawn" }',
621
+ listAgents: 'agent { mode: "list" }',
622
+ remoteContracts: remoteToolAvailable ? 'remote { mode: "contracts", view: "summary" }' : 'delegation action:"route" delegationRouteId:"remote-runner-inspection"',
623
+ remoteArtifacts: remoteToolAvailable ? 'remote { mode: "artifacts", view: "summary" }' : 'delegation action:"route" delegationRouteId:"remote-runner-inspection"',
624
+ remoteReadModelOutcomes: 'agent_harness mode:"agent_orchestration" includeParameters:true',
625
+ },
626
+ policy: 'Managed execution plans are read-only summaries. Parallel work must remain visible, cancellable, attached to evidence, and justified by user outcome.',
627
+ };
628
+ }
629
+
630
+ function describeAgent(
631
+ record: AgentRecordView,
632
+ includeParameters: boolean,
633
+ contract?: Record<string, unknown>,
634
+ artifacts: readonly Record<string, unknown>[] = [],
635
+ outcomes: readonly RemoteCaptureOutcomeRecord[] = [],
636
+ workspaces: readonly RemoteWorkspaceEvidenceRecord[] = [],
637
+ linkedWorkItems: readonly WorkPlanItem[] = [],
638
+ ): Record<string, unknown> {
639
+ const id = agentId(record);
640
+ const task = readString(record.task);
641
+ const progress = readString(record.progress);
642
+ const context = readString(record.context);
643
+ return {
644
+ agentId: id,
645
+ status: agentStatus(record),
646
+ template: readString(record.template) || 'general',
647
+ task: previewHarnessText(task, includeParameters ? 240 : 96),
648
+ progress: progress ? previewHarnessText(progress, includeParameters ? 180 : 72) : null,
649
+ toolCallCount: typeof record.toolCallCount === 'number' ? record.toolCallCount : 0,
650
+ modelRoute: 'agent { mode: "get" }',
651
+ userRoute: 'Agent Workspace -> Work -> Autonomy queue',
652
+ routes: agentRoutes(id),
653
+ managedPlanCard: managedPlanItem(record, contract, artifacts, outcomes, workspaces, linkedWorkItems, includeParameters),
654
+ ...(readString(record.model) ? { model: readString(record.model) } : {}),
655
+ ...(readString(record.provider) ? { provider: readString(record.provider) } : {}),
656
+ ...(includeParameters ? {
657
+ tools: Array.isArray(record.tools) ? record.tools.filter((tool): tool is string => typeof tool === 'string') : [],
658
+ context: context ? previewHarnessText(context, 500) : null,
659
+ startedAt: typeof record.startedAt === 'number' ? record.startedAt : null,
660
+ completedAt: typeof record.completedAt === 'number' ? record.completedAt : null,
661
+ usage: record.usage && typeof record.usage === 'object' ? record.usage : null,
662
+ } : {}),
663
+ };
664
+ }
665
+
666
+ export function agentOrchestrationCatalogStatus(context: CommandContext, toolRegistry: ToolRegistry): Record<string, unknown> {
667
+ const records = exportAgents(context);
668
+ const counts = statusCounts(records ?? []);
669
+ const toolRegistered = agentToolRegistered(toolRegistry);
670
+ return {
671
+ modes: ['agent_orchestration', 'agent_orchestration_agent'],
672
+ status: !records ? 'unavailable' : counts.running > 0 || counts.pending > 0 ? 'attention' : toolRegistered ? 'ready' : 'needs-setup',
673
+ toolRegistered,
674
+ agents: records?.length ?? 0,
675
+ running: counts.running,
676
+ pending: counts.pending,
677
+ failed: counts.failed,
678
+ cancellable: (records ?? []).filter((record) => ['pending', 'running'].includes(agentStatus(record))).length,
679
+ readOnly: true,
680
+ };
681
+ }
682
+
683
+ export function agentOrchestrationSummary(context: CommandContext, toolRegistry: ToolRegistry, args: AgentHarnessAgentOrchestrationArgs): Record<string, unknown> {
684
+ const records = exportAgents(context);
685
+ const toolRegistered = agentToolRegistered(toolRegistry);
686
+ if (!records) {
687
+ return {
688
+ status: 'unavailable',
689
+ reason: 'Visible Agent orchestration requires an Agent manager in the runtime.',
690
+ modes: ['agent_orchestration', 'agent_orchestration_agent'],
691
+ toolRegistered,
692
+ policy: 'Read-only orchestration posture. Actual spawn/message/wait/cancel remains on the first-class agent tool.',
693
+ };
694
+ }
695
+ const counts = statusCounts(records);
696
+ const query = readString(args.query).toLowerCase();
697
+ const includeParameters = args.includeParameters === true;
698
+ const filtered = records
699
+ .filter((record) => !query || agentSearchText(record).includes(query))
700
+ .slice(0, readLimit(args.limit, 100));
701
+ const remoteSnapshot = remoteRuntimeSnapshot(context);
702
+ const contracts = contractByRunnerId(remoteSnapshot.contracts);
703
+ const artifacts = artifactsByRunnerId(remoteSnapshot.artifacts);
704
+ const outcomes = outcomesByRunnerId(remoteSnapshot.outcomes);
705
+ const workspaces = workspacesByRunnerId(remoteSnapshot.workspaces);
706
+ const workPlanByAgent = workPlanItemsByAgentId(workPlanItems(context));
707
+ return {
708
+ status: counts.running > 0 || counts.pending > 0 ? 'attention' : toolRegistered ? 'ready' : 'needs-setup',
709
+ summary: {
710
+ agents: records.length,
711
+ running: counts.running,
712
+ pending: counts.pending,
713
+ completed: counts.completed,
714
+ failed: counts.failed,
715
+ cancelled: counts.cancelled,
716
+ cancellable: records.filter((record) => ['pending', 'running'].includes(agentStatus(record))).length,
717
+ toolRegistered,
718
+ serialDefault: true,
719
+ managedPlanStatus: managedPlanStatus(records, toolRegistered),
720
+ },
721
+ managedExecutionPlan: managedExecutionPlan(records, context, toolRegistry, remoteSnapshot, includeParameters),
722
+ agents: filtered.map((record) => {
723
+ const id = agentId(record);
724
+ return describeAgent(record, includeParameters, contracts.get(id), artifacts.get(id) ?? [], outcomes.get(id) ?? [], workspaces.get(id) ?? [], workPlanByAgent.get(id) ?? []);
725
+ }),
726
+ returned: filtered.length,
727
+ total: records.length,
728
+ decisionCards: agentOrchestrationDecisionCards(toolRegistered),
729
+ modes: [...AGENT_TOOL_MODES],
730
+ templates: [...AGENT_TEMPLATES],
731
+ modelAccess: {
732
+ list: 'agent { mode: "list" }',
733
+ templates: 'agent { mode: "templates" }',
734
+ spawn: 'agent { mode: "spawn" }',
735
+ batchSpawn: 'agent { mode: "batch-spawn" }',
736
+ inspect: 'agent { mode: "get" }',
737
+ cancel: 'agent { mode: "cancel" }',
738
+ harness: 'agent_harness mode:"agent_orchestration"',
739
+ },
740
+ policy: 'Read-only orchestration posture. Agent work must be visible, statused, cancellable, and tied to the user request; hidden fanout is blocked.',
741
+ };
742
+ }
743
+
744
+ export function describeAgentOrchestrationAgent(context: CommandContext, args: AgentHarnessAgentOrchestrationArgs): AgentOrchestrationResolution {
745
+ const lookup = lookupFromArgs(args);
746
+ if (!lookup) {
747
+ return {
748
+ status: 'missing_lookup',
749
+ usage: 'agent_orchestration_agent requires agentId, target, or query. Use mode:"agent_orchestration" to inspect visible agents.',
750
+ };
751
+ }
752
+ const records = exportAgents(context);
753
+ if (!records) {
754
+ return {
755
+ status: 'missing_lookup',
756
+ usage: 'Visible Agent orchestration requires an Agent manager in the runtime.',
757
+ };
758
+ }
759
+ const exact = records.find((record) => agentId(record) === lookup.input);
760
+ const remoteSnapshot = remoteRuntimeSnapshot(context);
761
+ const contracts = contractByRunnerId(remoteSnapshot.contracts);
762
+ const artifacts = artifactsByRunnerId(remoteSnapshot.artifacts);
763
+ const outcomes = outcomesByRunnerId(remoteSnapshot.outcomes);
764
+ const workspaces = workspacesByRunnerId(remoteSnapshot.workspaces);
765
+ const workPlanByAgent = workPlanItemsByAgentId(workPlanItems(context));
766
+ if (exact) {
767
+ const id = agentId(exact);
768
+ return { status: 'found', agent: describeAgent(exact, args.includeParameters !== false, contracts.get(id), artifacts.get(id) ?? [], outcomes.get(id) ?? [], workspaces.get(id) ?? [], workPlanByAgent.get(id) ?? []) };
769
+ }
770
+ const normalized = lookup.input.toLowerCase();
771
+ const matches = records.filter((record) => agentSearchText(record).includes(normalized));
772
+ if (matches.length === 1) {
773
+ const record = matches[0]!;
774
+ const id = agentId(record);
775
+ return { status: 'found', agent: describeAgent(record, args.includeParameters !== false, contracts.get(id), artifacts.get(id) ?? [], outcomes.get(id) ?? [], workspaces.get(id) ?? [], workPlanByAgent.get(id) ?? []) };
776
+ }
777
+ if (matches.length > 1) {
778
+ return {
779
+ status: 'ambiguous',
780
+ input: lookup.input,
781
+ candidates: matches.slice(0, 8).map((record) => {
782
+ const id = agentId(record);
783
+ return describeAgent(record, false, contracts.get(id), artifacts.get(id) ?? [], outcomes.get(id) ?? [], workspaces.get(id) ?? [], workPlanByAgent.get(id) ?? []);
784
+ }),
785
+ };
786
+ }
787
+ return {
788
+ status: 'missing_lookup',
789
+ usage: `Unknown visible agent ${lookup.input}. Use mode:"agent_orchestration" to inspect visible agents.`,
790
+ };
791
+ }