@pellux/goodvibes-agent 1.1.6 → 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 (256) hide show
  1. package/CHANGELOG.md +176 -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 +132662 -91399
  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 +43 -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 +287 -0
  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 +267 -10
  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 +110 -89
  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/tools/tool-execution-safety.ts +41 -0
  256. package/src/version.ts +1 -1
@@ -0,0 +1,732 @@
1
+ import type { ArtifactDescriptor } from '@pellux/goodvibes-sdk/platform/artifacts';
2
+ import type { CommandContext } from '../input/command-registry.ts';
3
+ import { buildAgentWorkspaceRuntimeSnapshot } from '../input/agent-workspace-snapshot.ts';
4
+ import { previewHarnessText } from './agent-harness-text.ts';
5
+ import { hasMethod } from './agent-harness-personal-ops-discovery.ts';
6
+ import { redactedPersonalOpsText } from './agent-harness-personal-ops-runner.ts';
7
+ import type { PersonalOpsConnectorSignal, PersonalOpsConnectorTool, PersonalOpsLane, PersonalOpsLaneId, PersonalOpsLiveRecord, PersonalOpsRecordFreshness, PersonalOpsStatus, PersonalOpsWorkflow, PersonalOpsWorkflowStatus } from './agent-harness-personal-ops-types.ts';
8
+
9
+ export function laneStatusRank(status: PersonalOpsStatus): number {
10
+ if (status === 'ready') return 4;
11
+ if (status === 'partial') return 3;
12
+ if (status === 'needs-setup') return 2;
13
+ return 1;
14
+ }
15
+
16
+ export function searchText(lane: PersonalOpsLane): string {
17
+ return [
18
+ lane.id,
19
+ lane.label,
20
+ lane.status,
21
+ lane.outcome,
22
+ lane.current,
23
+ lane.next,
24
+ lane.userRoute,
25
+ lane.modelRoute,
26
+ lane.signals.join('\n'),
27
+ lane.connectorSignals?.flatMap((signal) => [
28
+ signal.id,
29
+ signal.label,
30
+ signal.status,
31
+ signal.summary,
32
+ signal.modelRoute,
33
+ String(signal.toolCount),
34
+ signal.capabilityTags.join('\n'),
35
+ signal.readTools?.map((tool) => `${tool.name} ${tool.description ?? ''} ${tool.capability}`).join('\n') ?? '',
36
+ signal.writeTools?.map((tool) => `${tool.name} ${tool.description ?? ''} ${tool.capability}`).join('\n') ?? '',
37
+ ]).join('\n') ?? '',
38
+ lane.workflows?.flatMap((workflow) => [
39
+ workflow.id,
40
+ workflow.label,
41
+ workflow.status,
42
+ workflow.summary,
43
+ workflow.next,
44
+ workflow.modelRoute,
45
+ workflow.inspectRoutes.join('\n'),
46
+ workflow.prerequisites.join('\n'),
47
+ workflow.runBoundary,
48
+ ]).join('\n') ?? '',
49
+ lane.liveRecords?.flatMap((record) => [
50
+ record.id,
51
+ record.label,
52
+ record.status,
53
+ record.summary,
54
+ record.userRoute,
55
+ record.modelRoute,
56
+ record.tags?.join('\n') ?? '',
57
+ record.freshness ? [
58
+ record.freshness.status,
59
+ record.freshness.source,
60
+ record.freshness.sourceTool ?? '',
61
+ record.freshness.refreshRoute ?? '',
62
+ record.freshness.policy,
63
+ ].join('\n') : '',
64
+ ]).join('\n') ?? '',
65
+ ].join('\n').toLowerCase();
66
+ }
67
+
68
+ export function describeLiveRecord(record: PersonalOpsLiveRecord, includeParameters: boolean): Record<string, unknown> {
69
+ return {
70
+ id: record.id,
71
+ label: record.label,
72
+ status: record.status,
73
+ summary: previewHarnessText(record.summary, includeParameters ? 180 : 96),
74
+ userRoute: previewHarnessText(record.userRoute, includeParameters ? 140 : 96),
75
+ modelRoute: previewHarnessText(record.modelRoute, includeParameters ? 140 : 96),
76
+ ...(record.tags && record.tags.length > 0 ? { tags: record.tags.slice(0, includeParameters ? 12 : 4) } : {}),
77
+ ...(includeParameters && record.effect ? { effect: record.effect } : {}),
78
+ ...(includeParameters && record.capability ? { capability: record.capability } : {}),
79
+ ...(includeParameters && record.qualifiedName ? { qualifiedName: record.qualifiedName } : {}),
80
+ ...(includeParameters && record.requiredFields ? { requiredFields: record.requiredFields } : {}),
81
+ ...(includeParameters && record.optionalFields ? { optionalFields: record.optionalFields.slice(0, 12) } : {}),
82
+ ...(includeParameters && record.sampleInput ? { sampleInput: record.sampleInput } : {}),
83
+ ...(includeParameters && typeof record.confirmationRequired === 'boolean' ? { confirmationRequired: record.confirmationRequired } : {}),
84
+ ...(includeParameters && record.artifactId ? { artifactId: record.artifactId } : {}),
85
+ ...(includeParameters && typeof record.reviewRecordCount === 'number' ? { reviewRecordCount: record.reviewRecordCount } : {}),
86
+ ...(includeParameters && record.reviewLabels && record.reviewLabels.length > 0 ? { reviewLabels: record.reviewLabels } : {}),
87
+ ...(includeParameters && record.sourceTool ? { sourceTool: record.sourceTool } : {}),
88
+ ...(includeParameters && record.freshness ? { freshness: record.freshness } : {}),
89
+ ...(includeParameters && record.followUpRoutes && record.followUpRoutes.length > 0 ? { followUpRoutes: record.followUpRoutes } : {}),
90
+ };
91
+ }
92
+
93
+ export function describeConnectorSignal(signal: PersonalOpsConnectorSignal, includeParameters: boolean): Record<string, unknown> {
94
+ return {
95
+ id: signal.id,
96
+ kind: signal.kind,
97
+ label: signal.label,
98
+ status: signal.status,
99
+ summary: previewHarnessText(signal.summary, includeParameters ? 180 : 96),
100
+ modelRoute: previewHarnessText(signal.modelRoute, includeParameters ? 140 : 96),
101
+ toolCount: signal.toolCount,
102
+ ...(signal.capabilityTags.length > 0 ? { capabilityTags: signal.capabilityTags } : {}),
103
+ ...(includeParameters && signal.readTools && signal.readTools.length > 0 ? { readTools: signal.readTools } : {}),
104
+ ...(includeParameters && signal.writeTools && signal.writeTools.length > 0 ? { writeTools: signal.writeTools } : {}),
105
+ };
106
+ }
107
+
108
+ export function describeWorkflow(workflow: PersonalOpsWorkflow, includeParameters: boolean): Record<string, unknown> {
109
+ return {
110
+ id: workflow.id,
111
+ label: workflow.label,
112
+ status: workflow.status,
113
+ summary: previewHarnessText(workflow.summary, includeParameters ? 180 : 96),
114
+ next: previewHarnessText(workflow.next, includeParameters ? 180 : 96),
115
+ modelRoute: previewHarnessText(workflow.modelRoute, 96),
116
+ ...(includeParameters ? {
117
+ inspectRoutes: workflow.inspectRoutes,
118
+ prerequisites: workflow.prerequisites,
119
+ runBoundary: workflow.runBoundary,
120
+ } : {}),
121
+ };
122
+ }
123
+
124
+ export function describeLane(lane: PersonalOpsLane, includeParameters: boolean): Record<string, unknown> {
125
+ return {
126
+ id: lane.id,
127
+ label: lane.label,
128
+ status: lane.status,
129
+ outcome: lane.outcome,
130
+ current: lane.current,
131
+ next: lane.next,
132
+ userRoute: previewHarnessText(lane.userRoute, 96),
133
+ modelRoute: previewHarnessText(lane.modelRoute, 96),
134
+ signals: lane.signals,
135
+ ...(lane.connectorSignals && lane.connectorSignals.length > 0 ? { connectorSignals: lane.connectorSignals.slice(0, includeParameters ? 8 : 3).map((signal) => describeConnectorSignal(signal, includeParameters)) } : {}),
136
+ ...(lane.workflows && lane.workflows.length > 0 ? { workflows: lane.workflows.slice(0, includeParameters ? 8 : 3).map((workflow) => describeWorkflow(workflow, includeParameters)) } : {}),
137
+ ...(lane.liveRecords && lane.liveRecords.length > 0 ? { liveRecords: lane.liveRecords.slice(0, includeParameters ? 8 : 3).map((record) => describeLiveRecord(record, includeParameters)) } : {}),
138
+ ...(includeParameters ? {
139
+ routes: {
140
+ user: lane.userRoute,
141
+ model: lane.modelRoute,
142
+ },
143
+ methodIds: lane.methodIds ?? [],
144
+ safety: 'Writes, sends, schedules, and operator calls require explicit user request and confirmation through the owning tool.',
145
+ } : {}),
146
+ };
147
+ }
148
+
149
+ export function localRecord(domain: 'note' | 'routine', item: ReturnType<typeof buildAgentWorkspaceRuntimeSnapshot>['localNotes'][number]): PersonalOpsLiveRecord {
150
+ return {
151
+ id: item.id,
152
+ label: item.name,
153
+ status: item.reviewState,
154
+ summary: item.description,
155
+ userRoute: domain === 'note' ? 'Agent Workspace -> Notes' : 'Agent Workspace -> Routines',
156
+ modelRoute: `agent_local_registry domain:"${domain}" action:"get" id:"${item.id}"`,
157
+ tags: item.tags,
158
+ };
159
+ }
160
+
161
+ export function routineReceiptRecord(receipt: ReturnType<typeof buildAgentWorkspaceRuntimeSnapshot>['latestRoutineScheduleReceipt']): PersonalOpsLiveRecord | null {
162
+ if (!receipt) return null;
163
+ return {
164
+ id: receipt.id,
165
+ label: receipt.scheduleName,
166
+ status: receipt.status,
167
+ summary: `${receipt.routineName} -> ${receipt.scheduleKind} ${receipt.scheduleValue}`,
168
+ userRoute: 'Agent Workspace -> Personal Ops -> Routine schedule receipts',
169
+ modelRoute: 'autonomy action:"item" queueItemId:"routine-schedule-promotions"',
170
+ };
171
+ }
172
+
173
+ export function channelRecords(snapshot: ReturnType<typeof buildAgentWorkspaceRuntimeSnapshot>): readonly PersonalOpsLiveRecord[] {
174
+ return snapshot.channels.map((channel) => ({
175
+ id: channel.id,
176
+ label: channel.label,
177
+ status: channel.setupState,
178
+ summary: `${channel.delivery}; ${channel.riskLabel}. ${channel.nextStep}`,
179
+ userRoute: 'Agent Workspace -> Channels',
180
+ modelRoute: `channels action:"channel" channelId:"${channel.id}"`,
181
+ tags: [channel.risk, channel.delivery],
182
+ }));
183
+ }
184
+
185
+ export function personalOpsReadRunRoute(laneId: PersonalOpsLaneId, recordId: string): string {
186
+ return `personal_ops action:"read" laneId:"${laneId}" recordId:"${recordId}" fields:{...} confirm:true explicitUserRequest:"..."`;
187
+ }
188
+
189
+ export function connectorReadFreshness(signal: PersonalOpsConnectorSignal, tool: PersonalOpsConnectorTool, laneId: PersonalOpsLaneId): PersonalOpsRecordFreshness | undefined {
190
+ if (tool.effect !== 'read-only') return undefined;
191
+ const recordId = tool.qualifiedName ?? `${signal.id}:${tool.name}`;
192
+ return {
193
+ status: signal.status === 'ready' ? 'fresh-provider-route-ready' : 'connector-attention',
194
+ source: 'connector-read',
195
+ ...(tool.qualifiedName ? { sourceTool: tool.qualifiedName } : {}),
196
+ ...(signal.status === 'ready' ? { refreshRoute: personalOpsReadRunRoute(laneId, recordId) } : {}),
197
+ ...(tool.requiredFields ? { requiredFields: tool.requiredFields } : {}),
198
+ ...(tool.sampleInput ? { sampleInput: tool.sampleInput } : {}),
199
+ policy: signal.status === 'ready'
200
+ ? 'Reads fresh provider data only through the confirmed Personal Ops read route; provider mutations stay on separate confirmed-effect routes.'
201
+ : 'Repair connector connection, trust, or schema freshness before reading provider data.',
202
+ };
203
+ }
204
+
205
+ export function connectorRecords(signals: readonly PersonalOpsConnectorSignal[], laneLabel: string, laneId: PersonalOpsLaneId): readonly PersonalOpsLiveRecord[] {
206
+ return signals.flatMap((signal) => {
207
+ const summaryRecord: PersonalOpsLiveRecord = {
208
+ id: signal.id,
209
+ label: `${laneLabel} connector: ${signal.label}`,
210
+ status: signal.status,
211
+ summary: [
212
+ signal.summary,
213
+ signal.capabilityTags.length > 0 ? `capabilities ${signal.capabilityTags.join(', ')}` : '',
214
+ ].filter(Boolean).join('; '),
215
+ userRoute: 'Agent Workspace -> Tools & MCP',
216
+ modelRoute: signal.modelRoute,
217
+ tags: ['connector', signal.kind, ...signal.capabilityTags],
218
+ };
219
+ const operationTools = [...(signal.readTools ?? []), ...(signal.writeTools ?? [])];
220
+ const operationRecords: PersonalOpsLiveRecord[] = operationTools
221
+ .slice(0, 8)
222
+ .map((tool) => {
223
+ const freshness = connectorReadFreshness(signal, tool, laneId);
224
+ return {
225
+ id: tool.qualifiedName ?? `${signal.id}:${tool.name}`,
226
+ label: `${laneLabel} ${tool.effect === 'read-only' ? 'read' : 'confirmed action'}: ${tool.name}`,
227
+ status: signal.status,
228
+ summary: [
229
+ `${tool.effect === 'read-only' ? 'Read-only' : 'Write-like'} ${tool.capability} MCP route.`,
230
+ tool.requiredFields && tool.requiredFields.length > 0 ? `required fields ${tool.requiredFields.join(', ')}` : 'schema fields unknown until inspected',
231
+ tool.description ?? '',
232
+ ].filter(Boolean).join(' '),
233
+ userRoute: 'Agent Workspace -> Tools & MCP -> Tool schema',
234
+ modelRoute: tool.schemaRoute ?? signal.modelRoute,
235
+ tags: ['connector-operation', signal.kind, tool.capability, tool.effect],
236
+ effect: tool.effect,
237
+ capability: tool.capability,
238
+ ...(tool.qualifiedName ? { qualifiedName: tool.qualifiedName } : {}),
239
+ ...(tool.requiredFields ? { requiredFields: tool.requiredFields } : {}),
240
+ ...(tool.optionalFields ? { optionalFields: tool.optionalFields } : {}),
241
+ ...(tool.sampleInput ? { sampleInput: tool.sampleInput } : {}),
242
+ confirmationRequired: tool.effect === 'confirmed-effect',
243
+ ...(freshness ? { freshness } : {}),
244
+ };
245
+ });
246
+ return [summaryRecord, ...operationRecords];
247
+ });
248
+ }
249
+
250
+ export function artifactMetadata(artifact: ArtifactDescriptor): Readonly<Record<string, unknown>> {
251
+ return artifact.metadata && typeof artifact.metadata === 'object' && !Array.isArray(artifact.metadata)
252
+ ? artifact.metadata
253
+ : {};
254
+ }
255
+
256
+ export function artifactMetadataString(artifact: ArtifactDescriptor, key: string): string {
257
+ const value = artifactMetadata(artifact)[key];
258
+ return typeof value === 'string' ? value.trim() : '';
259
+ }
260
+
261
+ export function artifactMetadataNumber(artifact: ArtifactDescriptor, key: string): number | null {
262
+ const value = artifactMetadata(artifact)[key];
263
+ if (typeof value === 'number' && Number.isFinite(value)) return value;
264
+ if (typeof value === 'string' && value.trim()) {
265
+ const parsed = Number(value);
266
+ if (Number.isFinite(parsed)) return parsed;
267
+ }
268
+ return null;
269
+ }
270
+
271
+ export function artifactMetadataStringArray(artifact: ArtifactDescriptor, key: string): readonly string[] {
272
+ const value = artifactMetadata(artifact)[key];
273
+ if (Array.isArray(value)) {
274
+ return value
275
+ .filter((entry): entry is string => typeof entry === 'string' && entry.trim().length > 0)
276
+ .map((entry) => previewHarnessText(redactedPersonalOpsText(entry.trim()), 120));
277
+ }
278
+ if (typeof value === 'string' && value.trim()) return [previewHarnessText(redactedPersonalOpsText(value.trim()), 120)];
279
+ return [];
280
+ }
281
+
282
+ export function safeRecordIdPart(value: string): string {
283
+ return value
284
+ .toLowerCase()
285
+ .replace(/[^a-z0-9._-]+/g, '-')
286
+ .replace(/^-+|-+$/g, '')
287
+ .slice(0, 80) || 'item';
288
+ }
289
+
290
+ export function savedReviewArtifacts(context: CommandContext, laneId: 'inbox' | 'calendar'): readonly ArtifactDescriptor[] {
291
+ const store = context.platform.artifactStore;
292
+ if (!store?.list) return [];
293
+ try {
294
+ return store.list(100)
295
+ .filter((artifact) => artifactMetadataString(artifact, 'purpose') === 'personal-ops-review-cards')
296
+ .filter((artifact) => artifactMetadataString(artifact, 'laneId') === laneId)
297
+ .sort((left, right) => {
298
+ const leftCreated = typeof left.createdAt === 'number' ? left.createdAt : 0;
299
+ const rightCreated = typeof right.createdAt === 'number' ? right.createdAt : 0;
300
+ return rightCreated - leftCreated;
301
+ })
302
+ .slice(0, 5);
303
+ } catch {
304
+ return [];
305
+ }
306
+ }
307
+
308
+ export function matchingReadTool(
309
+ connectors: readonly PersonalOpsConnectorSignal[],
310
+ sourceTool: string,
311
+ ): { readonly signal: PersonalOpsConnectorSignal; readonly tool: PersonalOpsConnectorTool } | null {
312
+ if (!sourceTool) return null;
313
+ for (const signal of connectors) {
314
+ const tool = (signal.readTools ?? []).find((entry) => entry.qualifiedName === sourceTool || entry.name === sourceTool);
315
+ if (tool) return { signal, tool };
316
+ }
317
+ return null;
318
+ }
319
+
320
+ export function savedReviewFreshness(options: {
321
+ readonly laneId: 'inbox' | 'calendar';
322
+ readonly createdAt: string;
323
+ readonly sourceTool: string;
324
+ readonly connectors: readonly PersonalOpsConnectorSignal[];
325
+ }): PersonalOpsRecordFreshness {
326
+ const match = matchingReadTool(options.connectors, options.sourceTool);
327
+ if (!options.sourceTool) {
328
+ return {
329
+ status: 'source-tool-missing',
330
+ source: 'saved-review-artifact',
331
+ ...(options.createdAt ? { lastReviewedAt: options.createdAt } : {}),
332
+ policy: 'This saved review artifact did not preserve a connector source tool, so Agent can only reopen the redacted artifact and cannot offer a precise refresh route.',
333
+ };
334
+ }
335
+ if (!match) {
336
+ return {
337
+ status: 'provider-contract-missing',
338
+ source: 'saved-review-artifact',
339
+ sourceTool: options.sourceTool,
340
+ ...(options.createdAt ? { lastReviewedAt: options.createdAt } : {}),
341
+ policy: 'The saved review names a source tool, but the current runtime does not expose a matching read-only connector route. Reconnect or repair the provider before refreshing.',
342
+ };
343
+ }
344
+ return {
345
+ status: match.signal.status === 'ready' ? 'saved-review-refreshable' : 'connector-attention',
346
+ source: 'saved-review-artifact',
347
+ sourceTool: options.sourceTool,
348
+ ...(options.createdAt ? { lastReviewedAt: options.createdAt } : {}),
349
+ ...(match.signal.status === 'ready' ? { refreshRoute: personalOpsReadRunRoute(options.laneId, options.sourceTool) } : {}),
350
+ ...(match.tool.requiredFields ? { requiredFields: match.tool.requiredFields } : {}),
351
+ ...(match.tool.sampleInput ? { sampleInput: match.tool.sampleInput } : {}),
352
+ policy: match.signal.status === 'ready'
353
+ ? 'Saved review data is stale by default. Refresh requires the user to supply current connector fields and confirm the read; saved artifacts do not store raw prior input values.'
354
+ : 'A matching connector route exists, but it needs connection, trust, or schema freshness repair before refreshing saved review data.',
355
+ };
356
+ }
357
+
358
+ export function refreshableSavedRecordCount(records: readonly PersonalOpsLiveRecord[]): number {
359
+ return records.filter((record) => record.freshness?.status === 'saved-review-refreshable').length;
360
+ }
361
+
362
+ export function savedReviewQueueRecords(
363
+ context: CommandContext,
364
+ laneId: 'inbox' | 'calendar',
365
+ connectors: readonly PersonalOpsConnectorSignal[],
366
+ ): readonly PersonalOpsLiveRecord[] {
367
+ return savedReviewArtifacts(context, laneId)
368
+ .flatMap((artifact) => {
369
+ const reviewLabels = artifactMetadataStringArray(artifact, 'reviewLabels').slice(0, 5);
370
+ const reviewRecordIds = artifactMetadataStringArray(artifact, 'reviewRecordIds').slice(0, reviewLabels.length);
371
+ const sourceTool = artifactMetadataString(artifact, 'sourceTool') || artifactMetadataString(artifact, 'sourceRecordId');
372
+ const createdAt = typeof artifact.createdAt === 'number' && Number.isFinite(artifact.createdAt)
373
+ ? new Date(artifact.createdAt).toISOString()
374
+ : '';
375
+ const freshness = savedReviewFreshness({ laneId, createdAt, sourceTool, connectors });
376
+ return reviewLabels.map((label, index): PersonalOpsLiveRecord => {
377
+ const recordId = reviewRecordIds[index] || label || `${index + 1}`;
378
+ const artifactRoute = `agent_artifacts show artifactId:"${artifact.id}" includeContent:true`;
379
+ const calendar = laneId === 'calendar';
380
+ return {
381
+ id: `${calendar ? 'review-event' : 'review-thread'}:${artifact.id}:${safeRecordIdPart(recordId)}`,
382
+ label: `${calendar ? 'Saved event' : 'Saved thread'}: ${label}`,
383
+ status: calendar ? 'ready-for-reminder' : 'ready-for-draft',
384
+ summary: [
385
+ `Derived from saved redacted ${calendar ? 'calendar' : 'inbox'} review artifact ${artifact.id}.`,
386
+ sourceTool ? `Source ${sourceTool}.` : '',
387
+ createdAt ? `Saved ${createdAt}.` : '',
388
+ calendar
389
+ ? 'Inspect the artifact before creating reminders or proposing calendar edits.'
390
+ : 'Inspect the artifact before drafting; sending remains a separate confirmed connector action.',
391
+ ].filter(Boolean).join(' '),
392
+ userRoute: calendar
393
+ ? 'Agent Workspace -> Personal Ops -> Calendar review queue'
394
+ : 'Agent Workspace -> Personal Ops -> Inbox review queue',
395
+ modelRoute: artifactRoute,
396
+ tags: [
397
+ 'saved-review',
398
+ 'artifact',
399
+ calendar ? 'calendar-event' : 'inbox-thread',
400
+ calendar ? 'reminder-ready' : 'draft-ready',
401
+ ],
402
+ effect: 'read-only',
403
+ capability: calendar ? 'calendar-event-review' : 'inbox-thread-review',
404
+ confirmationRequired: false,
405
+ artifactId: artifact.id,
406
+ reviewRecordCount: 1,
407
+ reviewLabels: [label],
408
+ ...(sourceTool ? { sourceTool } : {}),
409
+ freshness,
410
+ followUpRoutes: calendar
411
+ ? [
412
+ ...(freshness.refreshRoute ? [{
413
+ id: 'refresh-saved-event',
414
+ label: 'Refresh saved event from provider',
415
+ effect: 'read-only' as const,
416
+ modelRoute: freshness.refreshRoute,
417
+ requiresConfirmation: true,
418
+ policy: 'Refresh reads current provider data only after the user supplies required fields and confirms the bounded read.',
419
+ }] : []),
420
+ {
421
+ id: 'create-reminder-from-event',
422
+ label: 'Create reminder from saved event',
423
+ effect: 'confirmed-effect',
424
+ modelRoute: 'schedule action:"remind" message:"..." at:"..." confirm:true explicitUserRequest:"..."',
425
+ requiresConfirmation: true,
426
+ policy: 'Create one reminder only after the user reviews the saved event and confirms exact timing.',
427
+ },
428
+ {
429
+ id: 'calendar-edit-boundary',
430
+ label: 'Inspect calendar edit route',
431
+ effect: 'confirmed-effect',
432
+ modelRoute: 'personal_ops action:"intake" query:"edit saved calendar event" includeParameters:true',
433
+ requiresConfirmation: true,
434
+ policy: 'Calendar edits, RSVP, reschedule, and deletes require a separate inspected connector route and explicit confirmation.',
435
+ },
436
+ ]
437
+ : [
438
+ ...(freshness.refreshRoute ? [{
439
+ id: 'refresh-saved-thread',
440
+ label: 'Refresh saved thread from provider',
441
+ effect: 'read-only' as const,
442
+ modelRoute: freshness.refreshRoute,
443
+ requiresConfirmation: true,
444
+ policy: 'Refresh reads current provider data only after the user supplies required fields and confirms the bounded read.',
445
+ }] : []),
446
+ {
447
+ id: 'draft-local-reply',
448
+ label: 'Draft local reply from saved thread',
449
+ effect: 'read-only',
450
+ modelRoute: artifactRoute,
451
+ requiresConfirmation: false,
452
+ policy: 'Drafting stays local in the Agent transcript and does not send, label, archive, move, or delete provider records.',
453
+ },
454
+ {
455
+ id: 'send-reviewed-reply-boundary',
456
+ label: 'Inspect send route for reviewed reply',
457
+ effect: 'confirmed-effect',
458
+ modelRoute: 'personal_ops action:"intake" query:"send reviewed reply from saved inbox review" includeParameters:true',
459
+ requiresConfirmation: true,
460
+ policy: 'Send only after a write-like inbox connector route is inspected and the user confirms exact recipients and body.',
461
+ },
462
+ ],
463
+ };
464
+ });
465
+ })
466
+ .slice(0, 10);
467
+ }
468
+
469
+ export function savedReviewArtifactRecords(
470
+ context: CommandContext,
471
+ laneId: 'inbox' | 'calendar',
472
+ connectors: readonly PersonalOpsConnectorSignal[],
473
+ ): readonly PersonalOpsLiveRecord[] {
474
+ return savedReviewArtifacts(context, laneId).map((artifact) => {
475
+ const reviewRecordCount = artifactMetadataNumber(artifact, 'reviewRecordCount') ?? 0;
476
+ const reviewLabels = artifactMetadataStringArray(artifact, 'reviewLabels').slice(0, 5);
477
+ const sourceTool = artifactMetadataString(artifact, 'sourceTool') || artifactMetadataString(artifact, 'sourceRecordId');
478
+ const createdAt = typeof artifact.createdAt === 'number' && Number.isFinite(artifact.createdAt)
479
+ ? new Date(artifact.createdAt).toISOString()
480
+ : '';
481
+ const freshness = savedReviewFreshness({ laneId, createdAt, sourceTool, connectors });
482
+ const countText = reviewRecordCount > 0
483
+ ? `${reviewRecordCount} normalized review card${reviewRecordCount === 1 ? '' : 's'}`
484
+ : 'normalized review cards';
485
+ return {
486
+ id: `review-artifact:${artifact.id}`,
487
+ label: `${laneId === 'calendar' ? 'Saved agenda review' : 'Saved inbox review'}: ${artifact.filename ?? artifact.id}`,
488
+ status: 'ready',
489
+ summary: [
490
+ `${countText} saved for later review.`,
491
+ reviewLabels.length > 0 ? `Items ${reviewLabels.slice(0, 3).join('; ')}.` : '',
492
+ sourceTool ? `Source ${sourceTool}.` : '',
493
+ createdAt ? `Saved ${createdAt}.` : '',
494
+ 'Use the artifact route to reopen redacted cards before summary, draft, or promotion work.',
495
+ ].filter(Boolean).join(' '),
496
+ userRoute: 'Agent Workspace -> Artifacts -> Browse artifacts',
497
+ modelRoute: `agent_artifacts show artifactId:"${artifact.id}" includeContent:true`,
498
+ tags: ['saved-review', 'artifact', laneId === 'calendar' ? 'calendar-read' : 'inbox-read'],
499
+ effect: 'read-only',
500
+ capability: laneId === 'calendar' ? 'calendar-review-artifact' : 'inbox-review-artifact',
501
+ confirmationRequired: false,
502
+ artifactId: artifact.id,
503
+ reviewRecordCount,
504
+ ...(reviewLabels.length > 0 ? { reviewLabels } : {}),
505
+ ...(sourceTool ? { sourceTool } : {}),
506
+ freshness,
507
+ };
508
+ });
509
+ }
510
+
511
+ export function taskOperationRecords(methodIds: readonly string[]): readonly PersonalOpsLiveRecord[] {
512
+ const records: PersonalOpsLiveRecord[] = [
513
+ {
514
+ id: 'workplan-list',
515
+ label: 'Review visible work plan',
516
+ status: 'ready',
517
+ summary: 'Read Agent-owned work-plan items before starting or switching multi-step work.',
518
+ userRoute: 'Agent Workspace -> Work -> Review work plan',
519
+ modelRoute: 'agent_work_plan action:"list"',
520
+ tags: ['work-plan', 'task-read'],
521
+ effect: 'read-only',
522
+ capability: 'task-read',
523
+ },
524
+ {
525
+ id: 'workplan-add',
526
+ label: 'Add visible work item',
527
+ status: 'ready',
528
+ summary: 'Create one local Agent work-plan item instead of hiding task state in chat.',
529
+ userRoute: 'Agent Workspace -> Personal Ops -> Add work item',
530
+ modelRoute: 'agent_work_plan action:"create" title:"..."',
531
+ tags: ['work-plan', 'task-write'],
532
+ effect: 'confirmed-effect',
533
+ capability: 'task-write',
534
+ requiredFields: ['title'],
535
+ optionalFields: ['detail', 'priority', 'status'],
536
+ confirmationRequired: false,
537
+ },
538
+ {
539
+ id: 'workplan-status',
540
+ label: 'Update work item status',
541
+ status: 'ready',
542
+ summary: 'Move one visible work item through pending, active, blocked, done, failed, or cancelled state.',
543
+ userRoute: 'Agent Workspace -> Work -> Update work item status',
544
+ modelRoute: 'agent_work_plan action:"set_status" id:"..." status:"..."',
545
+ tags: ['work-plan', 'task-write'],
546
+ effect: 'confirmed-effect',
547
+ capability: 'task-write',
548
+ requiredFields: ['id', 'status'],
549
+ confirmationRequired: false,
550
+ },
551
+ ];
552
+ if (hasMethod(methodIds, 'tasks.list')) {
553
+ records.push({
554
+ id: 'host-tasks-list',
555
+ label: 'List connected-host tasks',
556
+ status: 'ready',
557
+ summary: 'Inspect connected-host task state without creating, retrying, or mutating host tasks.',
558
+ userRoute: 'Agent Workspace -> Work -> Host tasks',
559
+ modelRoute: 'workspace action:"action" actionId:"tasks-list"',
560
+ tags: ['host-task', 'task-read'],
561
+ effect: 'read-only',
562
+ capability: 'host-task-read',
563
+ });
564
+ }
565
+ if (hasMethod(methodIds, 'tasks.get') || hasMethod(methodIds, 'tasks.status')) {
566
+ records.push({
567
+ id: 'host-task-inspect',
568
+ label: 'Inspect connected-host task',
569
+ status: 'ready',
570
+ summary: 'Inspect one exact connected-host task id and output before considering controls.',
571
+ userRoute: 'Agent Workspace -> Work -> Inspect host task',
572
+ modelRoute: 'workspace action:"action" actionId:"task-show"',
573
+ tags: ['host-task', 'task-read'],
574
+ effect: 'read-only',
575
+ capability: 'host-task-read',
576
+ requiredFields: ['taskId'],
577
+ });
578
+ }
579
+ if (hasMethod(methodIds, 'tasks.cancel')) {
580
+ records.push({
581
+ id: 'host-task-cancel',
582
+ label: 'Cancel connected-host task',
583
+ status: 'ready',
584
+ summary: 'Cancel one exact connected-host task id only when the user authorizes it.',
585
+ userRoute: 'Agent Workspace -> Work -> Host task controls',
586
+ modelRoute: 'agent_operator_method methodId:"tasks.cancel" input:{"taskId":"..."} confirm:true explicitUserRequest:"..."',
587
+ tags: ['host-task', 'task-write'],
588
+ effect: 'confirmed-effect',
589
+ capability: 'host-task-control',
590
+ requiredFields: ['taskId'],
591
+ confirmationRequired: true,
592
+ });
593
+ }
594
+ if (hasMethod(methodIds, 'tasks.retry')) {
595
+ records.push({
596
+ id: 'host-task-retry',
597
+ label: 'Retry connected-host task',
598
+ status: 'ready',
599
+ summary: 'Retry one failed or cancelled connected-host task id only after inspection.',
600
+ userRoute: 'Agent Workspace -> Work -> Host task controls',
601
+ modelRoute: 'agent_operator_method methodId:"tasks.retry" input:{"taskId":"..."} confirm:true explicitUserRequest:"..."',
602
+ tags: ['host-task', 'task-write'],
603
+ effect: 'confirmed-effect',
604
+ capability: 'host-task-control',
605
+ requiredFields: ['taskId'],
606
+ confirmationRequired: true,
607
+ });
608
+ }
609
+ return records;
610
+ }
611
+
612
+ export function reminderOperationRecords(methodIds: readonly string[], deliveryConfigured: boolean): readonly PersonalOpsLiveRecord[] {
613
+ const records: PersonalOpsLiveRecord[] = [
614
+ {
615
+ id: 'reminder-create',
616
+ label: 'Create confirmed reminder',
617
+ status: hasMethod(methodIds, 'schedules.create') ? deliveryConfigured ? 'ready' : 'attention' : 'needs-setup',
618
+ summary: deliveryConfigured
619
+ ? 'Create one connected reminder schedule with real timing and a visible delivery path.'
620
+ : 'Create one reminder only after confirming timing and delivery scope; no configured delivery target was detected.',
621
+ userRoute: 'Agent Workspace -> Personal Ops -> Create reminder',
622
+ modelRoute: 'schedule action:"remind" message:"..." scheduleKind:"..." scheduleValue:"..." confirm:true explicitUserRequest:"..."',
623
+ tags: ['reminder', 'schedule-write'],
624
+ effect: 'confirmed-effect',
625
+ capability: 'reminder-create',
626
+ requiredFields: ['title', 'scheduleKind', 'scheduleValue'],
627
+ optionalFields: ['deliveryTargetId', 'timezone', 'message'],
628
+ confirmationRequired: true,
629
+ },
630
+ {
631
+ id: 'autonomous-schedule-create',
632
+ label: 'Create autonomous schedule',
633
+ status: hasMethod(methodIds, 'schedules.create') ? 'ready' : 'needs-setup',
634
+ summary: 'Create one visible autonomous schedule only when task, cadence, success criteria, and user request provenance are explicit.',
635
+ userRoute: 'Agent Workspace -> Automation -> Create schedule',
636
+ modelRoute: 'schedule action:"create" task:"..." successCriteria:"..." scheduleKind:"..." scheduleValue:"..." confirm:true explicitUserRequest:"..."',
637
+ tags: ['autonomy', 'schedule-write'],
638
+ effect: 'confirmed-effect',
639
+ capability: 'schedule-create',
640
+ requiredFields: ['task', 'successCriteria', 'scheduleKind', 'scheduleValue'],
641
+ confirmationRequired: true,
642
+ },
643
+ ];
644
+ if (hasMethod(methodIds, 'schedules.list')) {
645
+ records.push({
646
+ id: 'schedule-list',
647
+ label: 'List connected schedules',
648
+ status: 'ready',
649
+ summary: 'Inspect configured schedules and history before running or mutating one.',
650
+ userRoute: 'Agent Workspace -> Automation -> Schedules',
651
+ modelRoute: 'workspace action:"action" actionId:"schedule-list"',
652
+ tags: ['schedule', 'schedule-read'],
653
+ effect: 'read-only',
654
+ capability: 'schedule-read',
655
+ });
656
+ records.push({
657
+ id: 'schedule-edit',
658
+ label: 'Edit connected schedule',
659
+ status: 'ready',
660
+ summary: 'Preview and edit one exact connected schedule id with before/after diff context.',
661
+ userRoute: 'Agent Workspace -> Automation -> Edit schedule',
662
+ modelRoute: 'schedule action:"edit" scheduleId:"..." confirm:true explicitUserRequest:"..."',
663
+ tags: ['schedule', 'schedule-write'],
664
+ effect: 'confirmed-effect',
665
+ capability: 'schedule-control',
666
+ requiredFields: ['scheduleId'],
667
+ optionalFields: ['name', 'scheduleKind', 'scheduleValue', 'prompt'],
668
+ confirmationRequired: true,
669
+ });
670
+ }
671
+ if (hasMethod(methodIds, 'schedules.run')) {
672
+ records.push({
673
+ id: 'schedule-run-now',
674
+ label: 'Run schedule now',
675
+ status: 'ready',
676
+ summary: 'Run one exact connected schedule id now after the user confirms.',
677
+ userRoute: 'Agent Workspace -> Automation -> Run job now',
678
+ modelRoute: 'schedule action:"run" scheduleId:"..." confirm:true explicitUserRequest:"..."',
679
+ tags: ['schedule', 'schedule-write'],
680
+ effect: 'confirmed-effect',
681
+ capability: 'schedule-control',
682
+ requiredFields: ['scheduleId'],
683
+ confirmationRequired: true,
684
+ });
685
+ }
686
+ if (hasMethod(methodIds, 'schedules.disable')) {
687
+ records.push({
688
+ id: 'schedule-pause',
689
+ label: 'Pause connected schedule',
690
+ status: 'ready',
691
+ summary: 'Disable one exact connected schedule id after reviewing current state.',
692
+ userRoute: 'Agent Workspace -> Automation -> Schedule controls',
693
+ modelRoute: 'schedule action:"pause" scheduleId:"..." confirm:true explicitUserRequest:"..."',
694
+ tags: ['schedule', 'schedule-write'],
695
+ effect: 'confirmed-effect',
696
+ capability: 'schedule-control',
697
+ requiredFields: ['scheduleId'],
698
+ confirmationRequired: true,
699
+ });
700
+ }
701
+ if (hasMethod(methodIds, 'schedules.enable')) {
702
+ records.push({
703
+ id: 'schedule-resume',
704
+ label: 'Resume connected schedule',
705
+ status: 'ready',
706
+ summary: 'Enable one exact connected schedule id after reviewing current state.',
707
+ userRoute: 'Agent Workspace -> Automation -> Schedule controls',
708
+ modelRoute: 'schedule action:"resume" scheduleId:"..." confirm:true explicitUserRequest:"..."',
709
+ tags: ['schedule', 'schedule-write'],
710
+ effect: 'confirmed-effect',
711
+ capability: 'schedule-control',
712
+ requiredFields: ['scheduleId'],
713
+ confirmationRequired: true,
714
+ });
715
+ }
716
+ if (hasMethod(methodIds, 'schedules.delete')) {
717
+ records.push({
718
+ id: 'schedule-delete',
719
+ label: 'Delete connected schedule',
720
+ status: 'ready',
721
+ summary: 'Delete one exact connected schedule id only after explicit user confirmation.',
722
+ userRoute: 'Agent Workspace -> Automation -> Schedule controls',
723
+ modelRoute: 'schedule action:"delete" scheduleId:"..." confirm:true explicitUserRequest:"..."',
724
+ tags: ['schedule', 'schedule-write'],
725
+ effect: 'confirmed-effect',
726
+ capability: 'schedule-control',
727
+ requiredFields: ['scheduleId'],
728
+ confirmationRequired: true,
729
+ });
730
+ }
731
+ return records;
732
+ }