@pellux/goodvibes-agent 1.1.7 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (274) hide show
  1. package/CHANGELOG.md +329 -0
  2. package/README.md +46 -30
  3. package/dist/package/{ast-grep-napi.linux-x64-gnu-mkk8xwww.node → ast-grep-napi.linux-x64-gnu-swtppvy9.node} +0 -0
  4. package/dist/package/{ast-grep-napi.linux-x64-musl-ryqtgdv6.node → ast-grep-napi.linux-x64-musl-ttfcdtap.node} +0 -0
  5. package/dist/package/main.js +138903 -91477
  6. package/docs/README.md +14 -7
  7. package/docs/channels-remote-and-api.md +8 -5
  8. package/docs/connected-host.md +14 -12
  9. package/docs/getting-started.md +58 -30
  10. package/docs/knowledge-artifacts-and-multimodal.md +7 -5
  11. package/docs/project-planning.md +2 -2
  12. package/docs/providers-and-routing.md +11 -3
  13. package/docs/tools-and-commands.md +116 -45
  14. package/docs/voice-and-live-tts.md +3 -1
  15. package/package.json +3 -2
  16. package/release/release-notes.md +142 -5
  17. package/release/release-readiness.json +124 -94
  18. package/src/agent/assistant-cockpit.ts +247 -0
  19. package/src/agent/autonomy-schedule-format.ts +96 -0
  20. package/src/agent/autonomy-schedule.ts +514 -0
  21. package/src/agent/channel-delivery-receipts.ts +292 -0
  22. package/src/agent/competitive-feature-inventory.ts +294 -0
  23. package/src/agent/document-registry-types.ts +106 -0
  24. package/src/agent/document-registry.ts +734 -0
  25. package/src/agent/harness-control.ts +2 -2
  26. package/src/agent/memory-prompt.ts +2 -2
  27. package/src/agent/operator-actions.ts +50 -6
  28. package/src/agent/persona-registry.ts +8 -0
  29. package/src/agent/project-context-files.ts +273 -0
  30. package/src/agent/prompt-context-receipts.ts +502 -0
  31. package/src/agent/reminder-schedule-format.ts +16 -2
  32. package/src/agent/research-run-registry.ts +582 -0
  33. package/src/agent/research-source-registry.ts +441 -0
  34. package/src/agent/routine-registry.ts +19 -3
  35. package/src/agent/routine-schedule-format.ts +27 -2
  36. package/src/agent/runtime-profile-starters.ts +7 -0
  37. package/src/agent/runtime-profile.ts +106 -4
  38. package/src/agent/schedule-edit-format.ts +129 -0
  39. package/src/agent/schedule-edit.ts +496 -0
  40. package/src/agent/schedule-next-routes.ts +42 -0
  41. package/src/agent/setup-wizard-artifact-receipts.ts +366 -0
  42. package/src/agent/setup-wizard-checkpoint.ts +140 -0
  43. package/src/agent/setup-wizard.ts +683 -0
  44. package/src/agent/skill-registry-types.ts +102 -0
  45. package/src/agent/skill-registry.ts +81 -107
  46. package/src/agent/vibe-confirmation-routes.ts +62 -0
  47. package/src/agent/vibe-file.ts +285 -0
  48. package/src/cli/agent-knowledge-command.ts +45 -2
  49. package/src/cli/help.ts +3 -0
  50. package/src/cli/profiles-command.ts +25 -11
  51. package/src/config/agent-settings-policy.ts +1 -18
  52. package/src/input/agent-workspace-activation.ts +53 -0
  53. package/src/input/agent-workspace-artifact-browser-editor.ts +494 -0
  54. package/src/input/agent-workspace-artifact-metadata.ts +17 -0
  55. package/src/input/agent-workspace-basic-command-editors.ts +5 -1
  56. package/src/input/agent-workspace-categories.ts +153 -155
  57. package/src/input/agent-workspace-channel-triage.ts +481 -0
  58. package/src/input/agent-workspace-channels.ts +263 -0
  59. package/src/input/agent-workspace-command-editor.ts +152 -0
  60. package/src/input/agent-workspace-context-snapshot.ts +349 -0
  61. package/src/input/agent-workspace-delegation-editor-submission.ts +8 -0
  62. package/src/input/agent-workspace-document-editor.ts +502 -0
  63. package/src/input/agent-workspace-document-ops-editor.ts +523 -0
  64. package/src/input/agent-workspace-host-category.ts +1 -1
  65. package/src/input/agent-workspace-local-library-snapshot.ts +167 -0
  66. package/src/input/agent-workspace-model-compare-editor.ts +376 -0
  67. package/src/input/agent-workspace-model-compare-prompt-submission.ts +552 -0
  68. package/src/input/agent-workspace-model-compare-types.ts +82 -0
  69. package/src/input/agent-workspace-model-compare-utils.ts +35 -0
  70. package/src/input/agent-workspace-onboarding-categories.ts +141 -0
  71. package/src/input/agent-workspace-operations-command-editor-submission.ts +53 -0
  72. package/src/input/agent-workspace-operations-command-editors.ts +22 -0
  73. package/src/input/agent-workspace-research-report-editor.ts +212 -0
  74. package/src/input/agent-workspace-research-run-editor.ts +144 -0
  75. package/src/input/agent-workspace-research-source-editor.ts +167 -0
  76. package/src/input/agent-workspace-review-packet-snapshot.ts +593 -0
  77. package/src/input/agent-workspace-review-packet-utils.ts +265 -0
  78. package/src/input/agent-workspace-settings.ts +313 -30
  79. package/src/input/agent-workspace-setup-checkpoint-action.ts +127 -0
  80. package/src/input/agent-workspace-setup-snapshot.ts +217 -0
  81. package/src/input/agent-workspace-setup.ts +61 -1
  82. package/src/input/agent-workspace-snapshot.ts +184 -149
  83. package/src/input/agent-workspace-types.ts +287 -2
  84. package/src/input/agent-workspace.ts +23 -1
  85. package/src/input/command-registry.ts +9 -2
  86. package/src/input/commands/agent-runtime-profile-runtime.ts +28 -13
  87. package/src/input/commands/channels-runtime.ts +102 -114
  88. package/src/input/commands/delegation-runtime.ts +87 -24
  89. package/src/input/commands/knowledge-browser-flags.ts +12 -0
  90. package/src/input/commands/knowledge.ts +28 -14
  91. package/src/input/commands/operator-actions-runtime.ts +6 -3
  92. package/src/input/commands/schedule-runtime.ts +71 -14
  93. package/src/input/commands/session-content.ts +2 -2
  94. package/src/input/commands/shell-core.ts +2 -0
  95. package/src/input/commands/vibe-runtime.ts +140 -0
  96. package/src/input/commands.ts +2 -0
  97. package/src/input/connected-host-routes.ts +123 -0
  98. package/src/input/settings-modal-types.ts +14 -0
  99. package/src/input/setup-wizard-live-receipts.ts +76 -0
  100. package/src/main.ts +15 -15
  101. package/src/panels/qr-panel.ts +2 -2
  102. package/src/renderer/agent-workspace-context-lines.ts +701 -0
  103. package/src/renderer/agent-workspace.ts +68 -421
  104. package/src/renderer/settings-modal-helpers.ts +12 -0
  105. package/src/renderer/settings-modal.ts +12 -0
  106. package/src/runtime/bootstrap-command-context.ts +11 -1
  107. package/src/runtime/bootstrap-command-parts.ts +14 -3
  108. package/src/runtime/bootstrap-core.ts +39 -1
  109. package/src/runtime/bootstrap-shell.ts +6 -0
  110. package/src/runtime/bootstrap.ts +113 -30
  111. package/src/runtime/connected-host-auth.ts +3 -2
  112. package/src/runtime/execution-ledger.ts +231 -0
  113. package/src/runtime/services.ts +88 -10
  114. package/src/runtime/tool-permission-safety.ts +199 -5
  115. package/src/shell/session-continuity-hints.ts +39 -0
  116. package/src/tools/agent-artifacts-tool.ts +606 -0
  117. package/src/tools/agent-audit-tool.ts +155 -0
  118. package/src/tools/agent-autonomy-schedule-tool.ts +238 -0
  119. package/src/tools/agent-autonomy-tool.ts +140 -0
  120. package/src/tools/agent-channel-send-tool.ts +24 -2
  121. package/src/tools/agent-channels-tool.ts +140 -0
  122. package/src/tools/agent-computer-tool.ts +168 -0
  123. package/src/tools/agent-context-policy.ts +137 -7
  124. package/src/tools/agent-context-tool.ts +143 -0
  125. package/src/tools/agent-delegation-tool.ts +128 -0
  126. package/src/tools/agent-device-tool.ts +240 -0
  127. package/src/tools/agent-documents-tool.ts +684 -0
  128. package/src/tools/agent-execution-tool.ts +230 -0
  129. package/src/tools/agent-harness-agent-orchestration-policy.ts +75 -0
  130. package/src/tools/agent-harness-agent-orchestration.ts +791 -0
  131. package/src/tools/agent-harness-autonomy-intake.ts +785 -0
  132. package/src/tools/agent-harness-autonomy-live-records.ts +742 -0
  133. package/src/tools/agent-harness-autonomy-queue-types.ts +88 -0
  134. package/src/tools/agent-harness-autonomy-queue.ts +571 -0
  135. package/src/tools/agent-harness-autonomy-watcher-read-models.ts +509 -0
  136. package/src/tools/agent-harness-background-processes-types.ts +35 -0
  137. package/src/tools/agent-harness-background-processes.ts +798 -0
  138. package/src/tools/agent-harness-browser-cockpit-route.ts +373 -0
  139. package/src/tools/agent-harness-browser-control.ts +346 -0
  140. package/src/tools/agent-harness-browser-pwa-read-models.ts +622 -0
  141. package/src/tools/agent-harness-channel-metadata.ts +168 -10
  142. package/src/tools/agent-harness-cli-command-policy.ts +110 -0
  143. package/src/tools/agent-harness-command-catalog.ts +4 -2
  144. package/src/tools/agent-harness-command-runner.ts +42 -0
  145. package/src/tools/agent-harness-connected-host-status.ts +7 -4
  146. package/src/tools/agent-harness-delegation-posture.ts +234 -19
  147. package/src/tools/agent-harness-device-live-read-models.ts +366 -0
  148. package/src/tools/agent-harness-document-ops-reviewer-readiness.ts +234 -0
  149. package/src/tools/agent-harness-document-ops-types.ts +72 -0
  150. package/src/tools/agent-harness-document-ops.ts +671 -0
  151. package/src/tools/agent-harness-execution-history.ts +489 -0
  152. package/src/tools/agent-harness-execution-posture.ts +385 -0
  153. package/src/tools/agent-harness-file-recovery.ts +135 -0
  154. package/src/tools/agent-harness-interactive-runtime-records.ts +421 -0
  155. package/src/tools/agent-harness-keybinding-metadata.ts +16 -12
  156. package/src/tools/agent-harness-learning-curator-common.ts +102 -0
  157. package/src/tools/agent-harness-learning-curator-consolidation.ts +295 -0
  158. package/src/tools/agent-harness-learning-curator-proposals.ts +606 -0
  159. package/src/tools/agent-harness-learning-curator-types.ts +151 -0
  160. package/src/tools/agent-harness-learning-curator.ts +417 -0
  161. package/src/tools/agent-harness-local-model-benchmarks.ts +269 -0
  162. package/src/tools/agent-harness-local-model-cookbook.ts +238 -0
  163. package/src/tools/agent-harness-local-model-endpoints.ts +788 -0
  164. package/src/tools/agent-harness-local-model-smoke.ts +277 -0
  165. package/src/tools/agent-harness-local-model-url.ts +78 -0
  166. package/src/tools/agent-harness-media-posture.ts +223 -2
  167. package/src/tools/agent-harness-memory-external-providers.ts +796 -0
  168. package/src/tools/agent-harness-memory-posture.ts +672 -0
  169. package/src/tools/agent-harness-memory-provider-certification.ts +219 -0
  170. package/src/tools/agent-harness-memory-refinement.ts +340 -0
  171. package/src/tools/agent-harness-metadata.ts +100 -168
  172. package/src/tools/agent-harness-mode-catalog.ts +86 -33
  173. package/src/tools/agent-harness-model-catalog.ts +162 -0
  174. package/src/tools/agent-harness-model-provider-health.ts +283 -0
  175. package/src/tools/agent-harness-model-readiness.ts +432 -0
  176. package/src/tools/agent-harness-model-routing-types.ts +327 -0
  177. package/src/tools/agent-harness-model-routing-utils.ts +30 -0
  178. package/src/tools/agent-harness-model-routing.ts +165 -193
  179. package/src/tools/agent-harness-operator-methods.ts +115 -133
  180. package/src/tools/agent-harness-pairing-posture.ts +452 -18
  181. package/src/tools/agent-harness-personal-ops-certification.ts +116 -0
  182. package/src/tools/agent-harness-personal-ops-discovery.ts +533 -0
  183. package/src/tools/agent-harness-personal-ops-intake.ts +385 -0
  184. package/src/tools/agent-harness-personal-ops-lanes.ts +270 -0
  185. package/src/tools/agent-harness-personal-ops-operations.ts +225 -0
  186. package/src/tools/agent-harness-personal-ops-provider-records.ts +358 -0
  187. package/src/tools/agent-harness-personal-ops-provider-task-records.ts +321 -0
  188. package/src/tools/agent-harness-personal-ops-records.ts +684 -0
  189. package/src/tools/agent-harness-personal-ops-runner.ts +637 -0
  190. package/src/tools/agent-harness-personal-ops-types.ts +240 -0
  191. package/src/tools/agent-harness-personal-ops.ts +613 -0
  192. package/src/tools/agent-harness-project-context.ts +144 -0
  193. package/src/tools/agent-harness-prompt-context.ts +589 -0
  194. package/src/tools/agent-harness-provider-account-metadata.ts +2 -2
  195. package/src/tools/agent-harness-release-evidence.ts +9 -7
  196. package/src/tools/agent-harness-release-readiness.ts +9 -7
  197. package/src/tools/agent-harness-remote-read-models.ts +541 -0
  198. package/src/tools/agent-harness-research-briefing.ts +446 -0
  199. package/src/tools/agent-harness-research-live-read-models.ts +500 -0
  200. package/src/tools/agent-harness-research-queue.ts +250 -0
  201. package/src/tools/agent-harness-research-runs.ts +307 -0
  202. package/src/tools/agent-harness-research-workflow.ts +395 -0
  203. package/src/tools/agent-harness-security-posture.ts +2 -2
  204. package/src/tools/agent-harness-service-posture.ts +9 -9
  205. package/src/tools/agent-harness-session-metadata.ts +3 -3
  206. package/src/tools/agent-harness-setup-connected-host.ts +501 -0
  207. package/src/tools/agent-harness-setup-describe.ts +557 -0
  208. package/src/tools/agent-harness-setup-handoffs.ts +502 -0
  209. package/src/tools/agent-harness-setup-model-helpers.ts +102 -0
  210. package/src/tools/agent-harness-setup-plan.ts +253 -0
  211. package/src/tools/agent-harness-setup-posture-types.ts +218 -0
  212. package/src/tools/agent-harness-setup-posture-utils.ts +173 -0
  213. package/src/tools/agent-harness-setup-posture.ts +449 -221
  214. package/src/tools/agent-harness-setup-smoke.ts +533 -0
  215. package/src/tools/agent-harness-sudo-posture.ts +114 -0
  216. package/src/tools/agent-harness-tool-schema.ts +142 -7
  217. package/src/tools/agent-harness-tool-types.ts +83 -0
  218. package/src/tools/agent-harness-tool-utils.ts +43 -0
  219. package/src/tools/agent-harness-tool.ts +319 -370
  220. package/src/tools/agent-harness-ui-surface-metadata.ts +76 -69
  221. package/src/tools/agent-harness-ui-surface-types.ts +46 -0
  222. package/src/tools/agent-harness-vibe-health.ts +105 -0
  223. package/src/tools/agent-harness-workspace-action-runner.ts +149 -0
  224. package/src/tools/agent-harness-workspace-actions.ts +114 -8
  225. package/src/tools/agent-harness-workspace-editor-execution.ts +214 -0
  226. package/src/tools/agent-harness-workspace-editor-runner.ts +755 -0
  227. package/src/tools/agent-host-tool.ts +159 -0
  228. package/src/tools/agent-knowledge-ingest-tool.ts +34 -1
  229. package/src/tools/agent-learning-consolidation-core.ts +327 -0
  230. package/src/tools/agent-learning-consolidation-tool.ts +758 -0
  231. package/src/tools/agent-memory-tool.ts +253 -0
  232. package/src/tools/agent-model-compare-export.ts +315 -0
  233. package/src/tools/agent-model-compare-handoff.ts +592 -0
  234. package/src/tools/agent-model-compare-judgment.ts +633 -0
  235. package/src/tools/agent-model-compare-run.ts +735 -0
  236. package/src/tools/agent-model-compare-tool.ts +698 -0
  237. package/src/tools/agent-model-compare-types.ts +191 -0
  238. package/src/tools/agent-model-compare-utils.ts +93 -0
  239. package/src/tools/agent-models-tool.ts +208 -0
  240. package/src/tools/agent-operator-action-tool.ts +1 -1
  241. package/src/tools/agent-operator-method-tool.ts +643 -0
  242. package/src/tools/agent-personal-ops-tool.ts +197 -0
  243. package/src/tools/agent-policy-explanation.ts +415 -0
  244. package/src/tools/agent-research-report-tool.ts +608 -0
  245. package/src/tools/agent-research-runner.ts +367 -0
  246. package/src/tools/agent-research-runs-tool.ts +434 -0
  247. package/src/tools/agent-research-sources-tool.ts +443 -0
  248. package/src/tools/agent-research-tool.ts +515 -0
  249. package/src/tools/agent-review-packet-presets-core.ts +757 -0
  250. package/src/tools/agent-review-packet-presets-tool.ts +466 -0
  251. package/src/tools/agent-review-packet-share-tool.ts +305 -0
  252. package/src/tools/agent-route-planner-candidates-setup.ts +411 -0
  253. package/src/tools/agent-route-planner-candidates-surfaces.ts +432 -0
  254. package/src/tools/agent-route-planner-candidates-work.ts +251 -0
  255. package/src/tools/agent-route-planner-helpers.ts +667 -0
  256. package/src/tools/agent-route-planner.ts +185 -0
  257. package/src/tools/agent-route-tool.ts +105 -0
  258. package/src/tools/agent-schedule-edit-tool.ts +210 -0
  259. package/src/tools/agent-schedule-tool.ts +282 -0
  260. package/src/tools/agent-security-tool.ts +145 -0
  261. package/src/tools/agent-sessions-tool.ts +122 -0
  262. package/src/tools/agent-settings-import-tool.ts +104 -0
  263. package/src/tools/agent-settings-tool.ts +176 -0
  264. package/src/tools/agent-setup-tool.ts +226 -0
  265. package/src/tools/agent-support-tool.ts +122 -0
  266. package/src/tools/agent-terminal-process-tools.ts +167 -0
  267. package/src/tools/agent-tool-policy-guard-types.ts +77 -0
  268. package/src/tools/agent-tool-policy-guard.ts +106 -85
  269. package/src/tools/agent-vibe-tool.ts +297 -0
  270. package/src/tools/agent-work-plan-tool.ts +265 -6
  271. package/src/tools/agent-workspace-tool.ts +305 -0
  272. package/src/tools/artifact-archive.ts +169 -0
  273. package/src/tools/tool-definition-compaction.ts +36 -0
  274. package/src/version.ts +1 -1
@@ -0,0 +1,489 @@
1
+ import type { CommandContext } from '../input/command-registry.ts';
2
+ import type { AgentExecutionRecord, AgentExecutionRouteKind, AgentExecutionStatus } from '../runtime/execution-ledger.ts';
3
+ import { fileRecoveryCatalogStatus } from './agent-harness-file-recovery.ts';
4
+ import { previewHarnessText } from './agent-harness-text.ts';
5
+
6
+ export interface AgentHarnessExecutionHistoryArgs {
7
+ readonly executionRecordId?: unknown;
8
+ readonly recordId?: unknown;
9
+ readonly target?: unknown;
10
+ readonly query?: unknown;
11
+ readonly includeParameters?: unknown;
12
+ readonly limit?: unknown;
13
+ }
14
+
15
+ type ExecutionHistoryLookupSource = 'executionRecordId' | 'recordId' | 'target' | 'query';
16
+
17
+ type ExecutionHistoryResolution =
18
+ | { readonly status: 'found'; readonly record: Record<string, unknown> }
19
+ | { readonly status: 'ambiguous'; readonly input: string; readonly candidates: readonly Record<string, unknown>[] }
20
+ | { readonly status: 'missing_lookup'; readonly usage: string };
21
+
22
+ type ActivityCardStatus = AgentExecutionStatus | 'mixed';
23
+ type VerificationStatus = 'passed' | 'failed' | 'running' | 'cancelled' | 'not_recorded';
24
+
25
+ const VERIFICATION_PATTERN = /\b(?:bun\s+test|npm\s+(?:run\s+)?test|pnpm\s+(?:run\s+)?test|yarn\s+test|pytest|vitest|jest|mocha|cargo\s+test|go\s+test|go\s+vet|tsc|typecheck|lint|eslint|prettier|ruff|mypy|cargo\s+check|make\s+test|build|verify|check)\b/i;
26
+ const RESULT_VERIFICATION_PATTERN = /\b(?:pass|passed|fail|failed|test|tests|spec|specs|suite|suites)\b/i;
27
+
28
+ function readString(value: unknown): string {
29
+ return typeof value === 'string' ? value.trim() : '';
30
+ }
31
+
32
+ function readLimit(value: unknown, fallback: number): number {
33
+ const parsed = typeof value === 'string' && value.trim() ? Number(value) : value;
34
+ if (typeof parsed !== 'number' || !Number.isFinite(parsed)) return fallback;
35
+ return Math.max(1, Math.min(500, Math.trunc(parsed)));
36
+ }
37
+
38
+ function iso(value: number | undefined): string | null {
39
+ return typeof value === 'number' && Number.isFinite(value) ? new Date(value).toISOString() : null;
40
+ }
41
+
42
+ function lookupFromArgs(args: AgentHarnessExecutionHistoryArgs): { readonly source: ExecutionHistoryLookupSource; readonly input: string } | null {
43
+ const executionRecordId = readString(args.executionRecordId);
44
+ if (executionRecordId) return { source: 'executionRecordId', input: executionRecordId };
45
+ const recordId = readString(args.recordId);
46
+ if (recordId) return { source: 'recordId', input: recordId };
47
+ const target = readString(args.target);
48
+ if (target) return { source: 'target', input: target };
49
+ const query = readString(args.query);
50
+ return query ? { source: 'query', input: query } : null;
51
+ }
52
+
53
+ function records(context: CommandContext): readonly AgentExecutionRecord[] {
54
+ return context.ops.executionLedger?.getSnapshot().records ?? [];
55
+ }
56
+
57
+ function recordSearchText(record: AgentExecutionRecord): string {
58
+ return [
59
+ record.id,
60
+ record.callId,
61
+ record.turnId,
62
+ record.tool,
63
+ record.routeKind,
64
+ record.status,
65
+ record.phase,
66
+ record.argsPreview,
67
+ record.commandPreview ?? '',
68
+ record.targetPreview ?? '',
69
+ record.resultSummary?.preview ?? '',
70
+ record.error ?? '',
71
+ record.cancelReason ?? '',
72
+ ].join('\n').toLowerCase();
73
+ }
74
+
75
+ function isRecoverableRoute(record: AgentExecutionRecord): boolean {
76
+ if (record.routeKind === 'write') return true;
77
+ const tool = record.tool.toLowerCase();
78
+ return tool.includes('write') || tool.includes('edit') || tool.includes('patch') || tool.includes('delete');
79
+ }
80
+
81
+ function toolInspectorAvailable(context: CommandContext): boolean {
82
+ return Boolean(context.workspace.panelManager?.getRegisteredTypes().some((panel) => panel.id === 'tools'));
83
+ }
84
+
85
+ function supervisionRoutes(context: CommandContext, record: AgentExecutionRecord): readonly Record<string, unknown>[] {
86
+ const routes: Record<string, unknown>[] = [];
87
+ if (toolInspectorAvailable(context)) {
88
+ routes.push({
89
+ id: 'tool-inspector',
90
+ label: 'Tool Call Inspector',
91
+ modelRoute: 'workspace action:"open_panel" panelId:"tools"',
92
+ requiresConfirmation: true,
93
+ });
94
+ }
95
+ if (record.routeKind === 'shell') {
96
+ if (typeof context.openProcessModal === 'function') {
97
+ routes.push({
98
+ id: 'process-monitor',
99
+ label: 'Runtime Activity Monitor',
100
+ modelRoute: 'workspace action:"open" surfaceId:"process-monitor"',
101
+ requiresConfirmation: true,
102
+ });
103
+ }
104
+ if (typeof context.openLiveTail === 'function') {
105
+ routes.push({
106
+ id: 'live-tail',
107
+ label: 'Live Process Output',
108
+ modelRoute: 'workspace action:"open" surfaceId:"live-tail"',
109
+ requiresConfirmation: true,
110
+ });
111
+ }
112
+ }
113
+ return routes;
114
+ }
115
+
116
+ function routeForRecord(record: AgentExecutionRecord): string {
117
+ return `execution action:"record" id:"${record.id}"`;
118
+ }
119
+
120
+ function uniqueStrings(values: readonly string[], limit = 8): readonly string[] {
121
+ return Array.from(new Set(values.filter((value) => value.trim()))).slice(0, limit);
122
+ }
123
+
124
+ function dedupeRoutes(routes: readonly Record<string, unknown>[]): readonly Record<string, unknown>[] {
125
+ const seen = new Set<string>();
126
+ const unique: Record<string, unknown>[] = [];
127
+ for (const route of routes) {
128
+ const id = typeof route.id === 'string' && route.id.trim() ? route.id : JSON.stringify(route);
129
+ if (seen.has(id)) continue;
130
+ seen.add(id);
131
+ unique.push(route);
132
+ }
133
+ return unique;
134
+ }
135
+
136
+ function routeKindSummary(records: readonly AgentExecutionRecord[]): Record<AgentExecutionRouteKind, number> {
137
+ return {
138
+ read: records.filter((record) => record.routeKind === 'read').length,
139
+ write: records.filter((record) => record.routeKind === 'write').length,
140
+ shell: records.filter((record) => record.routeKind === 'shell').length,
141
+ network: records.filter((record) => record.routeKind === 'network').length,
142
+ browser: records.filter((record) => record.routeKind === 'browser').length,
143
+ delegation: records.filter((record) => record.routeKind === 'delegation').length,
144
+ other: records.filter((record) => record.routeKind === 'other').length,
145
+ };
146
+ }
147
+
148
+ function statusSummary(records: readonly AgentExecutionRecord[]): Record<AgentExecutionStatus, number> {
149
+ return {
150
+ running: records.filter((record) => record.status === 'running').length,
151
+ succeeded: records.filter((record) => record.status === 'succeeded').length,
152
+ failed: records.filter((record) => record.status === 'failed').length,
153
+ cancelled: records.filter((record) => record.status === 'cancelled').length,
154
+ };
155
+ }
156
+
157
+ function orderedByReceivedAt(records: readonly AgentExecutionRecord[]): readonly AgentExecutionRecord[] {
158
+ return [...records].sort((left, right) => left.receivedAt - right.receivedAt);
159
+ }
160
+
161
+ function latestByUpdatedAt(records: readonly AgentExecutionRecord[]): AgentExecutionRecord {
162
+ return [...records].sort((left, right) => right.updatedAt - left.updatedAt)[0]!;
163
+ }
164
+
165
+ function cardStatus(records: readonly AgentExecutionRecord[]): ActivityCardStatus {
166
+ if (records.some((record) => record.status === 'running')) return 'running';
167
+ if (records.some((record) => record.status === 'failed')) return 'failed';
168
+ if (records.some((record) => record.status === 'cancelled')) return 'cancelled';
169
+ if (records.every((record) => record.status === 'succeeded')) return 'succeeded';
170
+ return 'mixed';
171
+ }
172
+
173
+ function titleForRecord(record: AgentExecutionRecord, includeParameters: boolean): string {
174
+ const subject = record.commandPreview ?? record.targetPreview ?? record.tool;
175
+ const preview = previewHarnessText(subject, includeParameters ? 96 : 64);
176
+ if (record.routeKind === 'shell') return `Shell: ${preview}`;
177
+ if (record.routeKind === 'write') return `File change: ${preview}`;
178
+ if (record.routeKind === 'read') return `Read: ${preview}`;
179
+ if (record.routeKind === 'network') return `Web: ${preview}`;
180
+ if (record.routeKind === 'browser') return `Browser: ${preview}`;
181
+ if (record.routeKind === 'delegation') return `Delegation: ${preview}`;
182
+ return `Tool: ${preview}`;
183
+ }
184
+
185
+ function titleRecord(records: readonly AgentExecutionRecord[]): AgentExecutionRecord {
186
+ const failed = records.find((record) => record.status === 'failed');
187
+ if (failed) return failed;
188
+ const runningShell = records.find((record) => record.status === 'running' && record.routeKind === 'shell');
189
+ if (runningShell) return runningShell;
190
+ const verification = records.find((record) => looksLikeVerificationRecord(record));
191
+ if (verification) return verification;
192
+ return latestByUpdatedAt(records);
193
+ }
194
+
195
+ function looksLikeVerificationRecord(record: AgentExecutionRecord): boolean {
196
+ const text = [
197
+ record.tool,
198
+ record.commandPreview ?? '',
199
+ record.targetPreview ?? '',
200
+ record.resultSummary?.preview ?? '',
201
+ ].join('\n');
202
+ return record.routeKind === 'shell'
203
+ ? VERIFICATION_PATTERN.test(text) || RESULT_VERIFICATION_PATTERN.test(record.resultSummary?.preview ?? '')
204
+ : VERIFICATION_PATTERN.test(record.tool);
205
+ }
206
+
207
+ function verificationLabel(record: AgentExecutionRecord, includeParameters: boolean): string {
208
+ return previewHarnessText(record.commandPreview ?? record.targetPreview ?? record.tool, includeParameters ? 120 : 72);
209
+ }
210
+
211
+ function verificationStatus(records: readonly AgentExecutionRecord[]): VerificationStatus {
212
+ if (records.length === 0) return 'not_recorded';
213
+ if (records.some((record) => record.status === 'failed')) return 'failed';
214
+ if (records.some((record) => record.status === 'running')) return 'running';
215
+ if (records.some((record) => record.status === 'cancelled')) return 'cancelled';
216
+ return 'passed';
217
+ }
218
+
219
+ function verificationSummary(records: readonly AgentExecutionRecord[], includeParameters: boolean): Record<string, unknown> {
220
+ const verificationRecords = records.filter((record) => looksLikeVerificationRecord(record));
221
+ const status = verificationStatus(verificationRecords);
222
+ return {
223
+ status,
224
+ evidence: verificationRecords.slice(0, 5).map((record) => ({
225
+ executionRecordId: record.id,
226
+ label: verificationLabel(record, includeParameters),
227
+ status: record.status,
228
+ ...(record.resultSummary?.preview ? { outputPreview: previewHarnessText(record.resultSummary.preview, includeParameters ? 180 : 96) } : {}),
229
+ modelRoute: routeForRecord(record),
230
+ })),
231
+ nextAction: status === 'not_recorded'
232
+ ? 'No verification command is recorded in this activity card.'
233
+ : status === 'failed'
234
+ ? 'Inspect the failed verification record before continuing.'
235
+ : status === 'running'
236
+ ? 'Use the process monitor or live-tail route when available.'
237
+ : status === 'cancelled'
238
+ ? 'Inspect the cancelled verification record before retrying.'
239
+ : 'Verification evidence is recorded for this activity card.',
240
+ };
241
+ }
242
+
243
+ function recoverableRecordIds(context: CommandContext, records: readonly AgentExecutionRecord[]): readonly string[] {
244
+ const undoDepth = fileRecoveryCatalogStatus(context).undoDepth as number | undefined;
245
+ if (!undoDepth || undoDepth < 1) return [];
246
+ return records.filter(isRecoverableRoute).map((record) => record.id);
247
+ }
248
+
249
+ function processOutputAttachment(context: CommandContext, records: readonly AgentExecutionRecord[], includeParameters: boolean): Record<string, unknown> | null {
250
+ const shellRecords = records.filter((record) => record.routeKind === 'shell');
251
+ if (shellRecords.length === 0) return null;
252
+ const liveRoutes = dedupeRoutes(shellRecords.flatMap((record) => supervisionRoutes(context, record)))
253
+ .filter((route) => route.id === 'process-monitor' || route.id === 'live-tail');
254
+ const evidence = shellRecords
255
+ .filter((record) => record.resultSummary?.preview)
256
+ .slice(0, 5)
257
+ .map((record) => ({
258
+ executionRecordId: record.id,
259
+ status: record.status,
260
+ outputPreview: previewHarnessText(record.resultSummary?.preview ?? '', includeParameters ? 180 : 96),
261
+ modelRoute: routeForRecord(record),
262
+ }));
263
+ return {
264
+ status: evidence.length > 0 ? 'bounded-summary-attached' : 'live-route-only',
265
+ shellRecords: shellRecords.length,
266
+ evidence,
267
+ liveRoutes,
268
+ policy: 'Cards attach only bounded redacted summaries; use live process routes for visible output instead of raw hidden log capture.',
269
+ };
270
+ }
271
+
272
+ function activityOutcome(status: ActivityCardStatus, records: readonly AgentExecutionRecord[], verification: Record<string, unknown>): string {
273
+ const failed = records.filter((record) => record.status === 'failed').length;
274
+ const running = records.filter((record) => record.status === 'running').length;
275
+ const cancelled = records.filter((record) => record.status === 'cancelled').length;
276
+ const count = `${records.length} record${records.length === 1 ? '' : 's'}`;
277
+ if (status === 'failed') return `Needs attention: ${failed} of ${count} failed.`;
278
+ if (status === 'running') return `Still running: ${running} of ${count} in progress.`;
279
+ if (status === 'cancelled') return `Cancelled: ${cancelled} of ${count} cancelled.`;
280
+ if (verification.status === 'passed') return `Succeeded with verification evidence across ${count}.`;
281
+ if (status === 'succeeded') return `Succeeded: ${count} completed.`;
282
+ return `Mixed outcome across ${count}.`;
283
+ }
284
+
285
+ function activityNextAction(status: ActivityCardStatus, verification: Record<string, unknown>, recoverableIds: readonly string[]): string {
286
+ if (status === 'failed') return recoverableIds.length > 0
287
+ ? 'Inspect the first failure, then use file recovery if an edit needs rollback.'
288
+ : 'Inspect the first failure record before retrying.';
289
+ if (status === 'running') return 'Open the process monitor or live-tail route when available.';
290
+ if (status === 'cancelled') return 'Inspect the cancelled record before deciding whether to retry.';
291
+ if (verification.status === 'not_recorded') return 'Run or inspect verification if the change needs proof.';
292
+ return 'No recovery action is needed from this card.';
293
+ }
294
+
295
+ function activityCard(context: CommandContext, cardRecords: readonly AgentExecutionRecord[], includeParameters: boolean, idPrefix = 'turn'): Record<string, unknown> {
296
+ const ordered = orderedByReceivedAt(cardRecords);
297
+ const latest = latestByUpdatedAt(cardRecords);
298
+ const firstReceived = ordered[0]!;
299
+ const firstFailure = ordered.find((record) => record.status === 'failed');
300
+ const recoverableIds = recoverableRecordIds(context, ordered);
301
+ const supervision = dedupeRoutes(ordered.flatMap((record) => supervisionRoutes(context, record)));
302
+ const verification = verificationSummary(ordered, includeParameters);
303
+ const status = cardStatus(ordered);
304
+ const completedAt = ordered.every((record) => typeof record.completedAt === 'number')
305
+ ? Math.max(...ordered.map((record) => record.completedAt ?? record.updatedAt))
306
+ : null;
307
+ const processOutput = processOutputAttachment(context, ordered, includeParameters);
308
+ const recordIds = ordered.map((record) => record.id);
309
+ return {
310
+ activityCardId: idPrefix === 'record' ? `record:${latest.id}` : `turn:${latest.turnId || latest.id}`,
311
+ turnId: latest.turnId,
312
+ title: titleForRecord(titleRecord(ordered), includeParameters),
313
+ status,
314
+ outcome: activityOutcome(status, ordered, verification),
315
+ records: ordered.length,
316
+ recordIds: recordIds.slice(0, 20),
317
+ ...(recordIds.length > 20 ? { recordIdOverflow: recordIds.length - 20 } : {}),
318
+ tools: uniqueStrings(ordered.map((record) => record.tool)),
319
+ routeKinds: routeKindSummary(ordered),
320
+ startedAt: iso(firstReceived.receivedAt),
321
+ updatedAt: iso(latest.updatedAt),
322
+ ...(completedAt ? { completedAt: iso(completedAt) } : {}),
323
+ ...(typeof completedAt === 'number' ? { durationMs: Math.max(0, completedAt - firstReceived.receivedAt) } : {}),
324
+ verification,
325
+ ...(processOutput ? { processOutput } : {}),
326
+ routes: {
327
+ inspectLatest: routeForRecord(latest),
328
+ ...(firstFailure ? { inspectFirstFailure: routeForRecord(firstFailure) } : {}),
329
+ ...(recoverableIds.length > 0 ? { fileRecovery: 'execution action:"recovery"' } : {}),
330
+ supervision,
331
+ },
332
+ nextAction: activityNextAction(status, verification, recoverableIds),
333
+ };
334
+ }
335
+
336
+ function activityCards(context: CommandContext, records: readonly AgentExecutionRecord[], includeParameters: boolean): readonly Record<string, unknown>[] {
337
+ const groups = new Map<string, AgentExecutionRecord[]>();
338
+ for (const record of records) {
339
+ const key = record.turnId ? `turn:${record.turnId}` : `record:${record.id}`;
340
+ const group = groups.get(key) ?? [];
341
+ group.push(record);
342
+ groups.set(key, group);
343
+ }
344
+ return Array.from(groups.values())
345
+ .sort((left, right) => latestByUpdatedAt(right).updatedAt - latestByUpdatedAt(left).updatedAt)
346
+ .map((group) => activityCard(context, group, includeParameters));
347
+ }
348
+
349
+ function activityCardCount(records: readonly AgentExecutionRecord[]): number {
350
+ return new Set(records.map((record) => record.turnId ? `turn:${record.turnId}` : `record:${record.id}`)).size;
351
+ }
352
+
353
+ function describeRecord(
354
+ context: CommandContext,
355
+ record: AgentExecutionRecord,
356
+ includeParameters: boolean,
357
+ lookup?: Record<string, unknown>,
358
+ ): Record<string, unknown> {
359
+ const recoverable = isRecoverableRoute(record) && (fileRecoveryCatalogStatus(context).undoDepth as number | undefined ?? 0) > 0;
360
+ return {
361
+ executionRecordId: record.id,
362
+ callId: record.callId,
363
+ turnId: record.turnId,
364
+ tool: record.tool,
365
+ routeKind: record.routeKind,
366
+ status: record.status,
367
+ phase: record.phase,
368
+ receivedAt: iso(record.receivedAt),
369
+ updatedAt: iso(record.updatedAt),
370
+ ...(record.completedAt ? { completedAt: iso(record.completedAt) } : {}),
371
+ ...(typeof record.durationMs === 'number' ? { durationMs: record.durationMs } : {}),
372
+ ...(typeof record.permissionApproved === 'boolean' ? { permissionApproved: record.permissionApproved } : {}),
373
+ ...(record.commandPreview ? { commandPreview: previewHarnessText(record.commandPreview, includeParameters ? 180 : 96) } : {}),
374
+ ...(record.targetPreview ? { targetPreview: previewHarnessText(record.targetPreview, includeParameters ? 180 : 96) } : {}),
375
+ argsPreview: previewHarnessText(record.argsPreview, includeParameters ? 360 : 120),
376
+ ...(record.resultSummary ? {
377
+ resultSummary: {
378
+ kind: record.resultSummary.kind,
379
+ byteSize: record.resultSummary.byteSize,
380
+ ...(record.resultSummary.preview ? { preview: previewHarnessText(record.resultSummary.preview, includeParameters ? 220 : 96) } : {}),
381
+ },
382
+ } : {}),
383
+ ...(record.error ? { error: previewHarnessText(record.error, includeParameters ? 220 : 96) } : {}),
384
+ ...(record.cancelReason ? { cancelReason: previewHarnessText(record.cancelReason, includeParameters ? 220 : 96) } : {}),
385
+ userCard: activityCard(context, [record], includeParameters, 'record'),
386
+ supervisionRoutes: supervisionRoutes(context, record),
387
+ ...(recoverable ? { recoveryRoute: 'execution action:"recovery"' } : {}),
388
+ modelRoute: routeForRecord(record),
389
+ ...(lookup ? { lookup } : {}),
390
+ ...(includeParameters ? {
391
+ argsKeys: record.argsKeys,
392
+ policy: {
393
+ effect: 'read-only',
394
+ values: 'Execution history stores bounded, redacted args and result summaries only; raw file bytes, binary bodies, and secret-looking argument keys are not exposed.',
395
+ mutation: 'Follow-up UI routing and file recovery remain confirmation-gated through workspace open routes, execution recovery inspection, or run_file_recovery.',
396
+ },
397
+ modelAccess: {
398
+ inspectHistory: 'execution action:"history"',
399
+ inspectRecord: routeForRecord(record),
400
+ toolInspector: 'workspace action:"open_panel" panelId:"tools" confirm:true explicitUserRequest:"..."',
401
+ fileRecovery: 'execution action:"recovery"',
402
+ },
403
+ } : {}),
404
+ };
405
+ }
406
+
407
+ function candidate(record: AgentExecutionRecord): Record<string, unknown> {
408
+ return {
409
+ executionRecordId: record.id,
410
+ tool: record.tool,
411
+ routeKind: record.routeKind,
412
+ status: record.status,
413
+ modelRoute: routeForRecord(record),
414
+ };
415
+ }
416
+
417
+ export function executionHistoryCatalogStatus(context: CommandContext): Record<string, unknown> {
418
+ const ledger = context.ops.executionLedger;
419
+ if (!ledger) {
420
+ return {
421
+ modes: ['execution_history', 'execution_history_item'],
422
+ status: 'unavailable',
423
+ readOnly: true,
424
+ };
425
+ }
426
+ const snapshot = ledger.getSnapshot();
427
+ return {
428
+ modes: ['execution_history', 'execution_history_item'],
429
+ status: 'available',
430
+ records: snapshot.total,
431
+ running: snapshot.running,
432
+ failed: snapshot.failed,
433
+ readOnly: true,
434
+ };
435
+ }
436
+
437
+ export function executionHistorySummary(context: CommandContext, args: AgentHarnessExecutionHistoryArgs): Record<string, unknown> {
438
+ const all = records(context);
439
+ const query = readString(args.query).toLowerCase();
440
+ const includeParameters = args.includeParameters === true;
441
+ const filtered = all
442
+ .filter((record) => !query || recordSearchText(record).includes(query))
443
+ .slice(0, readLimit(args.limit, 100));
444
+ const cards = activityCards(context, filtered, includeParameters);
445
+ return {
446
+ status: context.ops.executionLedger ? 'available' : 'unavailable',
447
+ summary: {
448
+ records: all.length,
449
+ activityCards: activityCardCount(all),
450
+ ...statusSummary(all),
451
+ routeKinds: routeKindSummary(all),
452
+ },
453
+ activityCards: cards,
454
+ returnedActivityCards: cards.length,
455
+ records: filtered.map((record) => describeRecord(context, record, includeParameters)),
456
+ returned: filtered.length,
457
+ total: all.length,
458
+ policy: 'Read-only local execution history. Activity cards group bounded redacted records into user-facing outcomes; UI routing and recovery remain separate confirmation-gated modes.',
459
+ };
460
+ }
461
+
462
+ export function describeExecutionHistoryItem(context: CommandContext, args: AgentHarnessExecutionHistoryArgs): ExecutionHistoryResolution {
463
+ const lookup = lookupFromArgs(args);
464
+ if (!lookup) {
465
+ return {
466
+ status: 'missing_lookup',
467
+ usage: 'execution action:"record" requires executionRecordId, recordId, target, or query. Use execution action:"history" to inspect recent record ids.',
468
+ };
469
+ }
470
+ const all = records(context);
471
+ const normalized = lookup.input.toLowerCase();
472
+ const exact = all.find((record) => record.id === lookup.input || record.callId === lookup.input);
473
+ if (exact) return { status: 'found', record: describeRecord(context, exact, true, { ...lookup, resolvedBy: 'id' }) };
474
+ const insensitive = all.find((record) => record.id.toLowerCase() === normalized || record.callId.toLowerCase() === normalized);
475
+ if (insensitive) return { status: 'found', record: describeRecord(context, insensitive, true, { ...lookup, resolvedBy: 'case-insensitive-id' }) };
476
+ const searched = all.filter((record) => recordSearchText(record).includes(normalized));
477
+ if (searched.length === 1) return { status: 'found', record: describeRecord(context, searched[0]!, true, { ...lookup, resolvedBy: 'search' }) };
478
+ if (searched.length > 1) {
479
+ return {
480
+ status: 'ambiguous',
481
+ input: lookup.input,
482
+ candidates: searched.slice(0, 8).map(candidate),
483
+ };
484
+ }
485
+ return {
486
+ status: 'missing_lookup',
487
+ usage: `Unknown execution history record ${lookup.input}. Use execution action:"history" to inspect recent record ids.`,
488
+ };
489
+ }