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