@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,588 @@
1
+ import type { CommandContext } from '../input/command-registry.ts';
2
+ import { buildAgentWorkspaceRuntimeSnapshot } from '../input/agent-workspace-snapshot.ts';
3
+ import { previewHarnessText } from './agent-harness-text.ts';
4
+ import type { UiAutomationSnapshot, UiTasksSnapshot } from '../runtime/ui-read-models.ts';
5
+ import type { AutonomyQueueLiveRecord, AutonomyQueueRecordControl, AutonomyQueueRecordOutput, SnapshotReader } from './agent-harness-autonomy-queue-types.ts';
6
+ function readSnapshot<TSnapshot>(readModel: SnapshotReader<TSnapshot> | undefined): TSnapshot | null {
7
+ if (!readModel) return null;
8
+ try {
9
+ return readModel.getSnapshot();
10
+ } catch {
11
+ return null;
12
+ }
13
+ }
14
+
15
+ function formatEpochMs(value: number | undefined): string | undefined {
16
+ if (typeof value !== 'number' || !Number.isFinite(value)) return undefined;
17
+ return new Date(value).toISOString();
18
+ }
19
+
20
+ function formatTimeFragment(label: string, value: number | undefined): string {
21
+ const formatted = formatEpochMs(value);
22
+ return formatted ? `${label} ${formatted}` : '';
23
+ }
24
+
25
+ const SENSITIVE_TEXT_PATTERNS: readonly [RegExp, string][] = [
26
+ [/("?\b(?:api[-_]?key|apikey|token|secret|password|passwd|credential|authorization)\b"?\s*:\s*)("[^"]*"|'[^']*'|[^\s,}]+)/gi, '$1"<redacted>"'],
27
+ [/\b([A-Z0-9_]*(?:API[_-]?KEY|TOKEN|SECRET|PASSWORD|PASSWD|CREDENTIAL|AUTHORIZATION|BEARER)[A-Z0-9_]*)=("[^"]*"|'[^']*'|[^\s]+)/gi, '$1=<redacted>'],
28
+ [/(\b(?:token|secret|password|passwd|api[-_]?key|apikey|authorization|credential)\s*[:=]\s*)("[^"]*"|'[^']*'|[^\s,}]+)/gi, '$1<redacted>'],
29
+ [/(Authorization:\s*Bearer\s+)[A-Za-z0-9._~+/=-]+/gi, '$1<redacted>'],
30
+ [/(\s--(?:token|password|secret|api-key|api_key)\s+)("[^"]*"|'[^']*'|[^\s]+)/gi, '$1<redacted>'],
31
+ ];
32
+
33
+ function redactHarnessOutputText(value: string): string {
34
+ return SENSITIVE_TEXT_PATTERNS.reduce((text, [pattern, replacement]) => text.replace(pattern, replacement), value);
35
+ }
36
+
37
+ function compactUnknown(value: unknown): string {
38
+ if (value === undefined || value === null) return '';
39
+ if (typeof value === 'string') return redactHarnessOutputText(value.replace(/\s+/g, ' ').trim());
40
+ if (typeof value === 'number' || typeof value === 'boolean') return redactHarnessOutputText(String(value));
41
+ try {
42
+ return redactHarnessOutputText(JSON.stringify(value).replace(/\s+/g, ' ').trim());
43
+ } catch {
44
+ return '';
45
+ }
46
+ }
47
+
48
+ function formatIntervalMs(value: number): string {
49
+ if (!Number.isFinite(value) || value <= 0) return `${value}ms`;
50
+ const units: ReadonlyArray<readonly [number, string]> = [
51
+ [86_400_000, 'd'],
52
+ [3_600_000, 'h'],
53
+ [60_000, 'm'],
54
+ [1_000, 's'],
55
+ ];
56
+ for (const [size, suffix] of units) {
57
+ if (value >= size && value % size === 0) return `${value / size}${suffix}`;
58
+ }
59
+ return `${value}ms`;
60
+ }
61
+
62
+ function summarizeSchedule(schedule: UiAutomationSnapshot['jobs'][number]['schedule']): string {
63
+ if (schedule.kind === 'cron') {
64
+ return [
65
+ `cron ${schedule.expression}`,
66
+ schedule.timezone ? `timezone ${schedule.timezone}` : '',
67
+ schedule.staggerMs !== undefined ? `stagger ${schedule.staggerMs}ms` : '',
68
+ ].filter(Boolean).join(', ');
69
+ }
70
+ if (schedule.kind === 'every') return `every ${formatIntervalMs(schedule.intervalMs)}`;
71
+ return `at ${formatEpochMs(schedule.at) ?? schedule.at}`;
72
+ }
73
+
74
+ function quoteRouteValue(value: string): string {
75
+ return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
76
+ }
77
+
78
+ function operatorMethodRoute(methodId: string, input: Record<string, string>): string {
79
+ const payload = JSON.stringify(input);
80
+ return `agent_operator_method methodId:"${quoteRouteValue(methodId)}" input:${payload} confirm:true explicitUserRequest:"..."`;
81
+ }
82
+
83
+ function availableControl(
84
+ id: string,
85
+ label: string,
86
+ effect: AutonomyQueueRecordControl['effect'],
87
+ modelRoute: string,
88
+ ): AutonomyQueueRecordControl {
89
+ return {
90
+ id,
91
+ label,
92
+ state: 'available',
93
+ effect,
94
+ confirmationRequired: effect === 'confirmed-effect',
95
+ modelRoute,
96
+ };
97
+ }
98
+
99
+ function unavailableControl(id: string, label: string, reason: string): AutonomyQueueRecordControl {
100
+ return {
101
+ id,
102
+ label,
103
+ state: 'unavailable',
104
+ effect: 'confirmed-effect',
105
+ confirmationRequired: true,
106
+ reason,
107
+ };
108
+ }
109
+
110
+ export function controlAvailable(record: AutonomyQueueLiveRecord, id: string): boolean {
111
+ return record.controls?.some((control) => control.id === id && control.state === 'available') === true;
112
+ }
113
+
114
+ function availableControlRoute(record: AutonomyQueueLiveRecord, id: string): string | undefined {
115
+ return record.controls?.find((control) => control.id === id && control.state === 'available')?.modelRoute;
116
+ }
117
+
118
+ export function firstAvailableControlRoute(records: readonly AutonomyQueueLiveRecord[], id: string): string | undefined {
119
+ for (const record of records) {
120
+ const route = availableControlRoute(record, id);
121
+ if (route) return route;
122
+ }
123
+ return undefined;
124
+ }
125
+
126
+ function taskOutputDescriptor(task: UiTasksSnapshot['tasks'][number]): AutonomyQueueRecordOutput {
127
+ const route = `/tasks output ${task.id}`;
128
+ const resultPreview = task.result !== undefined ? compactUnknown(task.result) : '';
129
+ if (resultPreview.length > 0) {
130
+ return {
131
+ status: 'preview',
132
+ route,
133
+ source: 'runtime-task-result',
134
+ preview: previewHarnessText(resultPreview, 240),
135
+ policy: 'Bounded preview from the connected-host task read model; secret-looking text is redacted. Use the route for the full host-owned output view when available.',
136
+ };
137
+ }
138
+ const errorPreview = task.error ? compactUnknown(task.error) : '';
139
+ if (errorPreview.length > 0) {
140
+ return {
141
+ status: 'preview',
142
+ route,
143
+ source: 'runtime-task-error',
144
+ preview: previewHarnessText(errorPreview, 240),
145
+ policy: 'Bounded error preview from the connected-host task read model; secret-looking text is redacted. Use the route for the full host-owned output view when available.',
146
+ };
147
+ }
148
+ return {
149
+ status: 'route-only',
150
+ route,
151
+ source: 'not-published',
152
+ policy: 'The connected host has not published task result/error text in the task read model. Use the route for host-owned output if that host exposes it.',
153
+ };
154
+ }
155
+
156
+ function taskDiagnostics(task: UiTasksSnapshot['tasks'][number]): readonly string[] {
157
+ const retry = task.retryPolicy
158
+ ? `retry attempt ${task.retryPolicy.currentAttempt}/${task.retryPolicy.maxAttempts} backoff ${task.retryPolicy.backoff} delay ${task.retryPolicy.delayMs}ms categories ${task.retryPolicy.retryOn.join(',')}`
159
+ : '';
160
+ return [
161
+ retry,
162
+ task.retryAt ? `retry eligible ${formatEpochMs(task.retryAt)}` : '',
163
+ task.exitCode !== undefined ? `exit code ${task.exitCode}` : '',
164
+ task.parentTaskId ? `parent ${task.parentTaskId}` : '',
165
+ task.childTaskIds.length > 0 ? `children ${task.childTaskIds.join(',')}` : '',
166
+ task.correlationId ? `correlation ${task.correlationId}` : '',
167
+ task.turnId ? `turn ${task.turnId}` : '',
168
+ task.error ? `error ${compactUnknown(task.error)}` : '',
169
+ task.result !== undefined ? `result ${compactUnknown(task.result)}` : '',
170
+ `output route /tasks output ${task.id}`,
171
+ ].filter((value): value is string => value.length > 0);
172
+ }
173
+
174
+ function automationRunDiagnostics(run: UiAutomationSnapshot['runs'][number]): readonly string[] {
175
+ const telemetry = run.telemetry;
176
+ const usage = telemetry?.usage;
177
+ const usageSummary = usage
178
+ ? [
179
+ `telemetry usage input ${usage.inputTokens}`,
180
+ `output ${usage.outputTokens}`,
181
+ `cache-read ${usage.cacheReadTokens}`,
182
+ `cache-write ${usage.cacheWriteTokens}`,
183
+ usage.reasoningTokens !== undefined ? `reasoning ${usage.reasoningTokens}` : '',
184
+ ].filter(Boolean).join(' ')
185
+ : '';
186
+ const callSummary = telemetry
187
+ ? [
188
+ telemetry.llmCallCount !== undefined ? `llm ${telemetry.llmCallCount}` : '',
189
+ telemetry.toolCallCount !== undefined ? `tool ${telemetry.toolCallCount}` : '',
190
+ telemetry.turnCount !== undefined ? `turns ${telemetry.turnCount}` : '',
191
+ telemetry.reasoningSummaryPresent !== undefined ? `reasoning-summary ${telemetry.reasoningSummaryPresent ? 'yes' : 'no'}` : '',
192
+ ].filter(Boolean).join(' ')
193
+ : '';
194
+ const route = run.route
195
+ ? [
196
+ `route ${run.route.id}`,
197
+ run.route.surfaceKind,
198
+ run.route.kind,
199
+ run.route.title,
200
+ ].filter(Boolean).join(' ')
201
+ : '';
202
+ const deliveries = (run.deliveryAttempts ?? []).slice(-3).map((delivery) => [
203
+ `delivery ${delivery.id}`,
204
+ delivery.status,
205
+ delivery.responseId ? `response ${delivery.responseId}` : '',
206
+ delivery.endedAt ? `ended ${formatEpochMs(delivery.endedAt)}` : '',
207
+ ].filter(Boolean).join(' '));
208
+ return [
209
+ run.continuationMode ? `continuation ${run.continuationMode}` : '',
210
+ run.executionIntent ? `intent ${compactUnknown(run.executionIntent)}` : '',
211
+ telemetry?.source ? `telemetry source ${telemetry.source}` : '',
212
+ telemetry?.modelId ? `telemetry model ${telemetry.modelId}` : '',
213
+ telemetry?.providerId ? `telemetry provider ${telemetry.providerId}` : '',
214
+ usageSummary,
215
+ callSummary ? `telemetry calls ${callSummary}` : '',
216
+ route,
217
+ ...deliveries,
218
+ run.result !== undefined ? `result ${compactUnknown(run.result)}` : '',
219
+ run.cancelledReason ? `cancelled ${run.cancelledReason}` : '',
220
+ ].filter((value): value is string => value.length > 0);
221
+ }
222
+
223
+ function scheduleEditRoute(job: UiAutomationSnapshot['jobs'][number]): string {
224
+ const schedule = job.schedule;
225
+ const value = schedule.kind === 'cron'
226
+ ? schedule.expression
227
+ : schedule.kind === 'every'
228
+ ? formatIntervalMs(schedule.intervalMs)
229
+ : formatEpochMs(schedule.at) ?? String(schedule.at);
230
+ const timezone = schedule.kind === 'cron' && schedule.timezone
231
+ ? ` timezone:"${quoteRouteValue(schedule.timezone)}"`
232
+ : '';
233
+ return `schedule action:"edit" scheduleId:"${quoteRouteValue(job.id)}" scheduleKind:"${schedule.kind}" scheduleValue:"${quoteRouteValue(value)}"${timezone} confirm:true explicitUserRequest:"..."`;
234
+ }
235
+
236
+ function taskStatusRank(status: UiTasksSnapshot['tasks'][number]['status']): number {
237
+ if (status === 'running') return 0;
238
+ if (status === 'queued') return 1;
239
+ if (status === 'blocked') return 2;
240
+ if (status === 'failed') return 3;
241
+ if (status === 'completed') return 4;
242
+ return 5;
243
+ }
244
+
245
+ export function taskLiveRecords(context: CommandContext): readonly AutonomyQueueLiveRecord[] {
246
+ const snapshot = readSnapshot(context.platform.readModels?.tasks);
247
+ const tasks = [...(snapshot?.tasks ?? [])].sort((left, right) => {
248
+ const rankDelta = taskStatusRank(left.status) - taskStatusRank(right.status);
249
+ if (rankDelta !== 0) return rankDelta;
250
+ const leftTime = left.endedAt ?? left.startedAt ?? left.queuedAt;
251
+ const rightTime = right.endedAt ?? right.startedAt ?? right.queuedAt;
252
+ return rightTime - leftTime || left.title.localeCompare(right.title);
253
+ });
254
+ return tasks.slice(0, 20).map((task) => {
255
+ const active = task.status === 'queued' || task.status === 'running' || task.status === 'blocked';
256
+ const canCancel = task.cancellable && active;
257
+ const canRetry = task.status === 'failed' || task.status === 'cancelled';
258
+ const cancelRoute = operatorMethodRoute('tasks.cancel', { taskId: task.id });
259
+ const retryRoute = operatorMethodRoute('tasks.retry', { taskId: task.id });
260
+ const retry = task.retryPolicy
261
+ ? `attempt ${task.retryPolicy.currentAttempt}/${task.retryPolicy.maxAttempts}`
262
+ : '';
263
+ const summary = [
264
+ `${task.status} ${task.kind}`,
265
+ `owner ${task.owner}`,
266
+ task.cancellable ? 'host-cancellable' : 'not cancellable',
267
+ formatTimeFragment('queued', task.queuedAt),
268
+ formatTimeFragment('started', task.startedAt),
269
+ formatTimeFragment('ended', task.endedAt),
270
+ retry,
271
+ task.retryAt ? `retry ${formatEpochMs(task.retryAt)}` : '',
272
+ task.error ? `error ${compactUnknown(task.error)}` : '',
273
+ task.result !== undefined ? `result ${compactUnknown(task.result)}` : compactUnknown(task.description),
274
+ ].filter(Boolean).join(' | ');
275
+ const output = taskOutputDescriptor(task);
276
+ return {
277
+ id: task.id,
278
+ label: task.title,
279
+ status: task.status,
280
+ phase: task.kind,
281
+ updatedAt: formatEpochMs(task.endedAt ?? task.startedAt ?? task.queuedAt),
282
+ summary,
283
+ inspectRoute: `/tasks show ${task.id}`,
284
+ ...(canCancel ? { cancelRoute } : {}),
285
+ nextSteps: [
286
+ `/tasks show ${task.id}`,
287
+ `/tasks output ${task.id}`,
288
+ ...(canCancel ? [cancelRoute] : []),
289
+ ...(canRetry ? [retryRoute] : []),
290
+ 'Use /workplan for Agent-owned visible task changes; host task mutation requires exact confirmed daemon methods.',
291
+ ],
292
+ sourceIds: [
293
+ task.parentTaskId,
294
+ ...task.childTaskIds,
295
+ task.correlationId,
296
+ task.turnId,
297
+ ].filter((value): value is string => typeof value === 'string' && value.length > 0),
298
+ ...(task.error ? { logTail: [compactUnknown(task.error)] } : {}),
299
+ output,
300
+ diagnostics: taskDiagnostics(task),
301
+ controls: [
302
+ availableControl('inspect', 'Inspect task', 'read-only', `/tasks show ${task.id}`),
303
+ availableControl('output', 'Show output', 'read-only', `/tasks output ${task.id}`),
304
+ canCancel
305
+ ? availableControl('cancel', 'Cancel task', 'confirmed-effect', cancelRoute)
306
+ : unavailableControl('cancel', 'Cancel task', task.cancellable ? `Task is ${task.status}; cancel is only useful before terminal completion.` : 'Task owner did not mark this task cancellable.'),
307
+ canRetry
308
+ ? availableControl('retry', 'Retry task', 'confirmed-effect', retryRoute)
309
+ : unavailableControl('retry', 'Retry task', `Task is ${task.status}; retry is only offered for failed or cancelled tasks.`),
310
+ ],
311
+ };
312
+ });
313
+ }
314
+
315
+ export function approvalLiveRecords(context: CommandContext): readonly AutonomyQueueLiveRecord[] {
316
+ const snapshot = readSnapshot(context.platform.readModels?.controlPlane);
317
+ const statusRank = new Map([
318
+ ['pending', 0],
319
+ ['claimed', 1],
320
+ ['denied', 2],
321
+ ['cancelled', 3],
322
+ ['expired', 4],
323
+ ['approved', 5],
324
+ ]);
325
+ return [...(snapshot?.approvals ?? [])]
326
+ .sort((left, right) => {
327
+ const rankDelta = (statusRank.get(left.status) ?? 99) - (statusRank.get(right.status) ?? 99);
328
+ if (rankDelta !== 0) return rankDelta;
329
+ return right.updatedAt - left.updatedAt || left.id.localeCompare(right.id);
330
+ })
331
+ .slice(0, 20)
332
+ .map((approval) => {
333
+ const active = approval.status === 'pending' || approval.status === 'claimed';
334
+ const label = `${approval.request.tool}: ${approval.request.analysis.summary}`;
335
+ const approveRoute = `agent_operator_action action:"approvals.approve" approvalId:"${approval.id}" confirm:true explicitUserRequest:"..."`;
336
+ const denyRoute = `agent_operator_action action:"approvals.deny" approvalId:"${approval.id}" confirm:true explicitUserRequest:"..."`;
337
+ const cancelRoute = `agent_operator_action action:"approvals.cancel" approvalId:"${approval.id}" confirm:true explicitUserRequest:"..."`;
338
+ return {
339
+ id: approval.id,
340
+ label,
341
+ status: approval.status,
342
+ phase: approval.request.analysis.riskLevel,
343
+ updatedAt: formatEpochMs(approval.updatedAt),
344
+ summary: [
345
+ `${approval.request.category}/${approval.request.analysis.riskLevel}`,
346
+ approval.request.analysis.classification,
347
+ `call ${approval.callId}`,
348
+ approval.sessionId ? `session ${approval.sessionId}` : '',
349
+ approval.routeId ? `route ${approval.routeId}` : '',
350
+ approval.claimedBy ? `claimed by ${approval.claimedBy}` : '',
351
+ approval.resolvedBy ? `resolved by ${approval.resolvedBy}` : '',
352
+ compactUnknown(approval.request.args),
353
+ ].filter(Boolean).join(' | '),
354
+ inspectRoute: '/approval matrix',
355
+ ...(active ? {
356
+ cancelRoute,
357
+ } : {}),
358
+ nextSteps: active ? [
359
+ approveRoute,
360
+ denyRoute,
361
+ cancelRoute,
362
+ ] : [`/approval matrix`],
363
+ sourceIds: [
364
+ approval.callId,
365
+ approval.sessionId,
366
+ approval.routeId,
367
+ ...approval.audit.map((entry) => entry.id),
368
+ ].filter((value): value is string => typeof value === 'string' && value.length > 0),
369
+ logTail: approval.audit.slice(-3).map((entry) => [
370
+ entry.action,
371
+ entry.actor,
372
+ formatEpochMs(entry.createdAt),
373
+ entry.note,
374
+ ].filter(Boolean).join(' ')),
375
+ controls: [
376
+ availableControl('inspect', 'Inspect approval matrix', 'read-only', '/approval matrix'),
377
+ active
378
+ ? availableControl('approve', 'Approve approval', 'confirmed-effect', approveRoute)
379
+ : unavailableControl('approve', 'Approve approval', `Approval is ${approval.status}; only pending or claimed approvals can be approved.`),
380
+ active
381
+ ? availableControl('deny', 'Deny approval', 'confirmed-effect', denyRoute)
382
+ : unavailableControl('deny', 'Deny approval', `Approval is ${approval.status}; only pending or claimed approvals can be denied.`),
383
+ active
384
+ ? availableControl('cancel', 'Cancel approval', 'confirmed-effect', cancelRoute)
385
+ : unavailableControl('cancel', 'Cancel approval', `Approval is ${approval.status}; only pending or claimed approvals can be cancelled.`),
386
+ ],
387
+ };
388
+ });
389
+ }
390
+
391
+ export function automationRunLiveRecords(context: CommandContext): readonly AutonomyQueueLiveRecord[] {
392
+ const snapshot = readSnapshot(context.platform.readModels?.automation);
393
+ return [...(snapshot?.runs ?? [])]
394
+ .sort((left, right) => {
395
+ const activeDelta = Number(right.status === 'queued' || right.status === 'running') - Number(left.status === 'queued' || left.status === 'running');
396
+ if (activeDelta !== 0) return activeDelta;
397
+ return right.queuedAt - left.queuedAt || left.id.localeCompare(right.id);
398
+ })
399
+ .slice(0, 20)
400
+ .map((run) => {
401
+ const active = run.status === 'queued' || run.status === 'running';
402
+ const failed = run.status === 'failed';
403
+ const cancelRoute = `agent_operator_action action:"automation.runs.cancel" runId:"${run.id}" confirm:true explicitUserRequest:"..."`;
404
+ const retryRoute = `agent_operator_action action:"automation.runs.retry" runId:"${run.id}" confirm:true explicitUserRequest:"..."`;
405
+ const timing = [
406
+ formatTimeFragment('queued', run.queuedAt),
407
+ formatTimeFragment('started', run.startedAt),
408
+ formatTimeFragment('ended', run.endedAt),
409
+ run.durationMs !== undefined ? `duration ${run.durationMs}ms` : '',
410
+ ].filter(Boolean).join(', ');
411
+ return {
412
+ id: run.id,
413
+ label: `${run.jobId} -> ${run.target.kind}`,
414
+ status: run.status,
415
+ phase: run.scheduleKind ?? run.triggeredBy.kind,
416
+ updatedAt: formatEpochMs(run.updatedAt),
417
+ summary: [
418
+ `job ${run.jobId}`,
419
+ `target ${run.target.kind}`,
420
+ `attempt ${run.attempt}`,
421
+ run.agentId ? `agent ${run.agentId}` : '',
422
+ run.sessionId ? `session ${run.sessionId}` : '',
423
+ run.routeId ? `route ${run.routeId}` : '',
424
+ run.modelId ? `model ${run.modelId}` : '',
425
+ run.providerId ? `provider ${run.providerId}` : '',
426
+ timing,
427
+ run.error ? `error ${run.error}` : '',
428
+ run.result !== undefined ? `result ${compactUnknown(run.result)}` : '',
429
+ ].filter(Boolean).join(' | '),
430
+ inspectRoute: 'workspace action:"action" actionId:"schedule-list"',
431
+ ...(active ? {
432
+ cancelRoute,
433
+ } : {}),
434
+ nextSteps: [
435
+ ...(active ? [cancelRoute] : []),
436
+ ...(failed ? [retryRoute] : []),
437
+ `workspace action:"action" actionId:"schedule-list"`,
438
+ ],
439
+ sourceIds: [
440
+ run.jobId,
441
+ run.agentId,
442
+ run.sessionId,
443
+ run.routeId,
444
+ run.triggeredBy.id,
445
+ ...run.deliveryIds,
446
+ ].filter((value): value is string => typeof value === 'string' && value.length > 0),
447
+ logTail: [
448
+ run.error,
449
+ run.cancelledReason,
450
+ ].filter((value): value is string => typeof value === 'string' && value.length > 0),
451
+ diagnostics: automationRunDiagnostics(run),
452
+ controls: [
453
+ availableControl('inspect', 'Inspect schedule list', 'read-only', 'workspace action:"action" actionId:"schedule-list"'),
454
+ active
455
+ ? availableControl('cancel', 'Cancel automation run', 'confirmed-effect', cancelRoute)
456
+ : unavailableControl('cancel', 'Cancel automation run', `Run is ${run.status}; cancel is only offered for queued or running runs.`),
457
+ failed
458
+ ? availableControl('retry', 'Retry automation run', 'confirmed-effect', retryRoute)
459
+ : unavailableControl('retry', 'Retry automation run', `Run is ${run.status}; retry is only offered for failed runs.`),
460
+ ],
461
+ };
462
+ });
463
+ }
464
+
465
+ export function scheduleLiveRecords(context: CommandContext): readonly AutonomyQueueLiveRecord[] {
466
+ const snapshot = readSnapshot(context.platform.readModels?.automation);
467
+ return [...(snapshot?.jobs ?? [])]
468
+ .sort((left, right) => {
469
+ const errorDelta = Number(right.status === 'error') - Number(left.status === 'error');
470
+ if (errorDelta !== 0) return errorDelta;
471
+ return (right.nextRunAt ?? 0) - (left.nextRunAt ?? 0) || left.name.localeCompare(right.name);
472
+ })
473
+ .slice(0, 20)
474
+ .map((job) => {
475
+ const enabled = job.enabled && job.status === 'enabled';
476
+ const paused = job.status === 'paused' || !job.enabled;
477
+ const toggleRoute = enabled
478
+ ? `schedule action:"pause" scheduleId:"${job.id}" confirm:true explicitUserRequest:"..."`
479
+ : `schedule action:"resume" scheduleId:"${job.id}" confirm:true explicitUserRequest:"..."`;
480
+ const runRoute = `schedule action:"run" scheduleId:"${job.id}" confirm:true explicitUserRequest:"..."`;
481
+ const editRoute = scheduleEditRoute(job);
482
+ const deleteRoute = `schedule action:"delete" scheduleId:"${job.id}" confirm:true explicitUserRequest:"..."`;
483
+ return {
484
+ id: job.id,
485
+ label: job.name,
486
+ status: job.status,
487
+ phase: job.schedule.kind,
488
+ updatedAt: formatEpochMs(job.updatedAt),
489
+ summary: [
490
+ enabled ? 'enabled' : paused ? 'paused' : job.status,
491
+ summarizeSchedule(job.schedule),
492
+ `runs ${job.runCount}`,
493
+ `success ${job.successCount}`,
494
+ `failed ${job.failureCount}`,
495
+ formatTimeFragment('next', job.nextRunAt),
496
+ formatTimeFragment('last', job.lastRunAt),
497
+ job.lastRunId ? `last run ${job.lastRunId}` : '',
498
+ job.description ?? '',
499
+ job.pausedReason ? `paused ${job.pausedReason}` : '',
500
+ ].filter(Boolean).join(' | '),
501
+ inspectRoute: '/schedule list',
502
+ ...(enabled ? { cancelRoute: toggleRoute } : {}),
503
+ ...(enabled ? { pauseRoute: toggleRoute } : { resumeRoute: toggleRoute }),
504
+ nextSteps: [
505
+ runRoute,
506
+ editRoute,
507
+ toggleRoute,
508
+ deleteRoute,
509
+ `workspace action:"action" actionId:"schedule-list"`,
510
+ ],
511
+ sourceIds: [
512
+ job.source.id,
513
+ job.lastRunId,
514
+ ...job.labels,
515
+ ].filter((value): value is string => typeof value === 'string' && value.length > 0),
516
+ ...(job.pausedReason || job.status === 'error' ? {
517
+ logTail: [job.pausedReason ?? `Schedule status ${job.status}`],
518
+ } : {}),
519
+ controls: [
520
+ availableControl('inspect', 'Inspect schedules', 'read-only', '/schedule list'),
521
+ availableControl('run', 'Run schedule now', 'confirmed-effect', runRoute),
522
+ availableControl('edit', 'Edit schedule', 'confirmed-effect', editRoute),
523
+ availableControl(enabled ? 'pause' : 'resume', enabled ? 'Pause schedule' : 'Resume schedule', 'confirmed-effect', toggleRoute),
524
+ availableControl(enabled ? 'disable' : 'enable', enabled ? 'Disable schedule' : 'Enable schedule', 'confirmed-effect', toggleRoute),
525
+ availableControl('delete', 'Delete schedule', 'confirmed-effect', deleteRoute),
526
+ ],
527
+ };
528
+ });
529
+ }
530
+
531
+ export function researchRunLiveRecords(snapshot: ReturnType<typeof buildAgentWorkspaceRuntimeSnapshot>): readonly AutonomyQueueLiveRecord[] {
532
+ return snapshot.researchRuns.map((run) => {
533
+ const terminal = run.status === 'cancelled' || run.status === 'completed' || run.status === 'failed';
534
+ const canPause = run.status === 'running' || run.status === 'blocked';
535
+ const canResume = run.status === 'paused' || run.status === 'planned' || run.status === 'blocked';
536
+ const inspectRoute = `research action:"run" runId="${run.id}"`;
537
+ const cancelRoute = `research action:"cancel" id="${run.id}" note="..." confirm:true explicitUserRequest:"..."`;
538
+ const checkpointRoute = `research action:"checkpoint" id="${run.id}" note="..." progress:${run.progress} confirm:true explicitUserRequest:"..."`;
539
+ const pauseRoute = `research action:"pause" id="${run.id}" note="..." confirm:true explicitUserRequest:"..."`;
540
+ const resumeRoute = `research action:"resume" id="${run.id}" note="..." confirm:true explicitUserRequest:"..."`;
541
+ const availableNextRoutes = [
542
+ checkpointRoute,
543
+ ...(canPause ? [pauseRoute] : []),
544
+ ...(canResume ? [resumeRoute] : []),
545
+ cancelRoute,
546
+ ];
547
+ return {
548
+ id: run.id,
549
+ label: run.title,
550
+ status: run.status,
551
+ phase: run.phase,
552
+ progress: run.progress,
553
+ updatedAt: run.updatedAt,
554
+ summary: [
555
+ `${run.status}/${run.phase} ${run.progress}%`,
556
+ `${run.checkpointCount} checkpoint(s)`,
557
+ `${run.sourceIds.length} source(s)`,
558
+ run.reportArtifactId ? `report ${run.reportArtifactId}` : '',
559
+ run.note ?? '',
560
+ ].filter(Boolean).join(' | '),
561
+ inspectRoute,
562
+ ...(terminal ? {} : {
563
+ cancelRoute,
564
+ checkpointRoute,
565
+ ...(canPause ? { pauseRoute } : {}),
566
+ ...(canResume ? { resumeRoute } : {}),
567
+ }),
568
+ nextSteps: terminal ? run.nextSteps : [...run.nextSteps, ...availableNextRoutes],
569
+ sourceIds: run.sourceIds,
570
+ logTail: run.logTail,
571
+ controls: [
572
+ availableControl('inspect', 'Inspect research run', 'read-only', inspectRoute),
573
+ terminal
574
+ ? unavailableControl('checkpoint', 'Checkpoint research run', `Research run is ${run.status}; checkpoint is only offered before terminal completion.`)
575
+ : availableControl('checkpoint', 'Checkpoint research run', 'confirmed-effect', checkpointRoute),
576
+ canPause
577
+ ? availableControl('pause', 'Pause research run', 'confirmed-effect', pauseRoute)
578
+ : unavailableControl('pause', 'Pause research run', terminal ? `Research run is ${run.status}; pause is only offered before terminal completion.` : `Research run is ${run.status}; pause is offered for running or blocked runs.`),
579
+ canResume
580
+ ? availableControl('resume', 'Resume research run', 'confirmed-effect', resumeRoute)
581
+ : unavailableControl('resume', 'Resume research run', terminal ? `Research run is ${run.status}; resume is only offered before terminal completion.` : `Research run is ${run.status}; resume is offered for planned, paused, or blocked runs.`),
582
+ terminal
583
+ ? unavailableControl('cancel', 'Cancel research run', `Research run is ${run.status}; cancel is only offered before terminal completion.`)
584
+ : availableControl('cancel', 'Cancel research run', 'confirmed-effect', cancelRoute),
585
+ ],
586
+ };
587
+ });
588
+ }
@@ -0,0 +1,88 @@
1
+ export type AutonomyQueueStatus = 'ready' | 'active' | 'needs-setup' | 'attention' | 'blocked';
2
+
3
+ export interface AgentHarnessAutonomyQueueArgs {
4
+ readonly queueItemId?: unknown;
5
+ readonly target?: unknown;
6
+ readonly query?: unknown;
7
+ readonly includeParameters?: unknown;
8
+ readonly limit?: unknown;
9
+ }
10
+
11
+ export interface OperatorContractMethod {
12
+ readonly id: string;
13
+ readonly title?: string;
14
+ readonly description?: string;
15
+ readonly category?: string;
16
+ readonly http?: {
17
+ readonly method?: string;
18
+ readonly path?: string;
19
+ };
20
+ }
21
+
22
+ export interface AutonomyQueueItem {
23
+ readonly id: string;
24
+ readonly label: string;
25
+ readonly status: AutonomyQueueStatus;
26
+ readonly owner: 'agent' | 'connected-host' | 'agent-and-connected-host';
27
+ readonly kind: 'work-plan' | 'research-run' | 'host-task' | 'approval' | 'automation-run' | 'schedule' | 'reminder' | 'routine-schedule' | 'delegated-agent' | 'delivery';
28
+ readonly visible: true;
29
+ readonly cancellable: boolean;
30
+ readonly count: number;
31
+ readonly current: string;
32
+ readonly next: string;
33
+ readonly inspectRoute: string;
34
+ readonly modelRoute: string;
35
+ readonly cancelRoute?: string;
36
+ readonly createRoute?: string;
37
+ readonly batchCreateRoute?: string;
38
+ readonly methodIds?: readonly string[];
39
+ readonly liveRecords?: readonly AutonomyQueueLiveRecord[];
40
+ }
41
+
42
+ export interface AutonomyQueueLiveRecord {
43
+ readonly id: string;
44
+ readonly label: string;
45
+ readonly status: string;
46
+ readonly phase?: string;
47
+ readonly progress?: number;
48
+ readonly updatedAt?: string;
49
+ readonly summary: string;
50
+ readonly inspectRoute: string;
51
+ readonly cancelRoute?: string;
52
+ readonly checkpointRoute?: string;
53
+ readonly pauseRoute?: string;
54
+ readonly resumeRoute?: string;
55
+ readonly nextSteps?: readonly string[];
56
+ readonly sourceIds?: readonly string[];
57
+ readonly logTail?: readonly string[];
58
+ readonly output?: AutonomyQueueRecordOutput;
59
+ readonly diagnostics?: readonly string[];
60
+ readonly controls?: readonly AutonomyQueueRecordControl[];
61
+ }
62
+
63
+ export interface AutonomyQueueRecordOutput {
64
+ readonly status: 'preview' | 'route-only';
65
+ readonly route: string;
66
+ readonly source: 'runtime-task-result' | 'runtime-task-error' | 'not-published';
67
+ readonly preview?: string;
68
+ readonly policy: string;
69
+ }
70
+
71
+ export interface AutonomyQueueRecordControl {
72
+ readonly id: string;
73
+ readonly label: string;
74
+ readonly state: 'available' | 'unavailable';
75
+ readonly effect: 'read-only' | 'confirmed-effect';
76
+ readonly confirmationRequired: boolean;
77
+ readonly modelRoute?: string;
78
+ readonly reason?: string;
79
+ }
80
+
81
+ export type SnapshotReader<TSnapshot> = {
82
+ readonly getSnapshot: () => TSnapshot;
83
+ };
84
+
85
+ export type AutonomyQueueResolution =
86
+ | { readonly status: 'found'; readonly item: Record<string, unknown> }
87
+ | { readonly status: 'ambiguous'; readonly input: string; readonly candidates: readonly Record<string, unknown>[] }
88
+ | { readonly status: 'missing_lookup'; readonly usage: string };