@pellux/goodvibes-agent 0.1.116 → 1.0.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 (285) hide show
  1. package/CHANGELOG.md +48 -661
  2. package/README.md +64 -57
  3. package/bin/goodvibes-agent.ts +16 -2
  4. package/dist/package/main.js +199180 -192185
  5. package/docs/README.md +15 -8
  6. package/docs/channels-remote-and-api.md +50 -0
  7. package/docs/connected-host.md +59 -0
  8. package/docs/getting-started.md +61 -50
  9. package/docs/knowledge-artifacts-and-multimodal.md +91 -0
  10. package/docs/project-planning.md +79 -0
  11. package/docs/providers-and-routing.md +46 -0
  12. package/docs/release-and-publishing.md +48 -11
  13. package/docs/tools-and-commands.md +123 -0
  14. package/docs/voice-and-live-tts.md +51 -0
  15. package/package.json +3 -6
  16. package/src/agent/behavior-discovery-summary.ts +1 -3
  17. package/src/agent/channel-delivery.ts +201 -0
  18. package/src/agent/media-generation.ts +159 -0
  19. package/src/agent/memory-prompt.ts +0 -1
  20. package/src/agent/note-registry.ts +329 -0
  21. package/src/agent/operator-actions.ts +343 -0
  22. package/src/agent/persona-discovery.ts +1 -3
  23. package/src/agent/persona-registry.ts +19 -16
  24. package/src/agent/record-labels.ts +107 -0
  25. package/src/agent/reminder-schedule-format.ts +33 -24
  26. package/src/agent/reminder-schedule.ts +27 -26
  27. package/src/agent/routine-registry.ts +54 -14
  28. package/src/agent/routine-schedule-args.ts +2 -1
  29. package/src/agent/routine-schedule-format.ts +77 -53
  30. package/src/agent/routine-schedule-promotion.ts +35 -33
  31. package/src/agent/routine-schedule-receipts.ts +29 -27
  32. package/src/agent/runtime-profile-starters.ts +5 -5
  33. package/src/agent/runtime-profile.ts +91 -12
  34. package/src/agent/skill-registry.ts +210 -32
  35. package/src/cli/agent-knowledge-args.ts +5 -1
  36. package/src/cli/agent-knowledge-command.ts +40 -34
  37. package/src/cli/agent-knowledge-format.ts +80 -67
  38. package/src/cli/agent-knowledge-methods.ts +1 -1
  39. package/src/cli/agent-knowledge-runtime.ts +32 -26
  40. package/src/cli/bundle-command.ts +14 -9
  41. package/src/cli/config-overrides.ts +37 -36
  42. package/src/cli/entrypoint.ts +16 -7
  43. package/src/cli/external-runtime.ts +10 -4
  44. package/src/cli/help.ts +54 -29
  45. package/src/cli/local-library-command.ts +203 -83
  46. package/src/cli/management-commands.ts +105 -68
  47. package/src/cli/management.ts +55 -74
  48. package/src/cli/memory-command.ts +66 -32
  49. package/src/cli/parser.ts +37 -3
  50. package/src/cli/profiles-command.ts +166 -31
  51. package/src/cli/provider-auth-routes.ts +2 -1
  52. package/src/cli/routines-command.ts +176 -40
  53. package/src/cli/service-posture.ts +16 -16
  54. package/src/cli/status.ts +56 -135
  55. package/src/core/conversation-message-snapshot.ts +131 -0
  56. package/src/input/agent-workspace-access-command-editor-submission.ts +149 -0
  57. package/src/input/agent-workspace-access-command-editors.ts +170 -0
  58. package/src/input/agent-workspace-activation.ts +35 -8
  59. package/src/input/agent-workspace-basic-command-editor-submission.ts +351 -94
  60. package/src/input/agent-workspace-basic-command-editors.ts +502 -9
  61. package/src/input/agent-workspace-categories.ts +423 -51
  62. package/src/input/agent-workspace-channel-command-editor-submission.ts +83 -0
  63. package/src/input/agent-workspace-channel-command-editors.ts +65 -0
  64. package/src/input/agent-workspace-channels.ts +35 -2
  65. package/src/input/agent-workspace-command-editor.ts +41 -3
  66. package/src/input/agent-workspace-config-reader.ts +16 -0
  67. package/src/input/agent-workspace-delegation-editor-submission.ts +55 -0
  68. package/src/input/agent-workspace-editors.ts +166 -1
  69. package/src/input/agent-workspace-knowledge-command-editor-submission.ts +132 -0
  70. package/src/input/agent-workspace-knowledge-command-editors.ts +110 -0
  71. package/src/input/agent-workspace-knowledge-query-editor.ts +1 -1
  72. package/src/input/agent-workspace-learned-behavior.ts +67 -0
  73. package/src/input/agent-workspace-library-command-editor-submission.ts +50 -0
  74. package/src/input/agent-workspace-library-command-editors.ts +35 -0
  75. package/src/input/agent-workspace-local-operations.ts +218 -0
  76. package/src/input/agent-workspace-local-selection.ts +75 -0
  77. package/src/input/agent-workspace-mcp-command-editor-submission.ts +95 -0
  78. package/src/input/agent-workspace-media-command-editor-submission.ts +62 -0
  79. package/src/input/agent-workspace-media-command-editors.ts +27 -0
  80. package/src/input/agent-workspace-memory-command-editor-submission.ts +232 -0
  81. package/src/input/agent-workspace-memory-command-editors.ts +180 -0
  82. package/src/input/agent-workspace-memory-editor.ts +2 -2
  83. package/src/input/agent-workspace-navigation.ts +81 -0
  84. package/src/input/agent-workspace-notify-editor-submission.ts +121 -0
  85. package/src/input/agent-workspace-operations-command-editor-submission.ts +208 -0
  86. package/src/input/agent-workspace-operations-command-editors.ts +196 -0
  87. package/src/input/agent-workspace-panel-route.ts +43 -0
  88. package/src/input/agent-workspace-provider-command-editor-submission.ts +155 -0
  89. package/src/input/agent-workspace-provider-command-editors.ts +93 -0
  90. package/src/input/agent-workspace-reminder-schedule-editor.ts +1 -1
  91. package/src/input/agent-workspace-requirements.ts +11 -0
  92. package/src/input/agent-workspace-routine-schedule-editor.ts +2 -2
  93. package/src/input/agent-workspace-search.ts +169 -0
  94. package/src/input/agent-workspace-secret-editor-submission.ts +153 -0
  95. package/src/input/agent-workspace-session-command-editor-submission.ts +199 -0
  96. package/src/input/agent-workspace-session-command-editors.ts +249 -0
  97. package/src/input/agent-workspace-setup.ts +37 -16
  98. package/src/input/agent-workspace-skill-bundle-command-editor-submission.ts +101 -0
  99. package/src/input/agent-workspace-skill-bundle-command-editors.ts +110 -0
  100. package/src/input/agent-workspace-snapshot.ts +162 -21
  101. package/src/input/agent-workspace-task-command-editor-submission.ts +61 -0
  102. package/src/input/agent-workspace-task-command-editors.ts +47 -0
  103. package/src/input/agent-workspace-token.ts +18 -2
  104. package/src/input/agent-workspace-types.ts +212 -4
  105. package/src/input/agent-workspace-voice-media.ts +4 -7
  106. package/src/input/agent-workspace-web-research-editor.ts +104 -0
  107. package/src/input/agent-workspace-workplan-editor-submission.ts +153 -0
  108. package/src/input/agent-workspace.ts +178 -240
  109. package/src/input/command-registry.ts +5 -2
  110. package/src/input/commands/agent-runtime-profile-runtime.ts +126 -37
  111. package/src/input/commands/agent-skills-runtime.ts +149 -72
  112. package/src/input/commands/agent-workspace-runtime.ts +23 -6
  113. package/src/input/commands/brief-runtime.ts +55 -25
  114. package/src/input/commands/channels-runtime.ts +147 -33
  115. package/src/input/commands/compat-runtime.ts +32 -0
  116. package/src/input/commands/delegation-runtime.ts +29 -23
  117. package/src/input/commands/experience-runtime.ts +6 -4
  118. package/src/input/commands/guidance-runtime.ts +4 -4
  119. package/src/input/commands/health-runtime.ts +149 -126
  120. package/src/input/commands/knowledge.ts +82 -60
  121. package/src/input/commands/local-provider-runtime.ts +43 -21
  122. package/src/input/commands/local-runtime.ts +138 -16
  123. package/src/input/commands/local-setup-review.ts +10 -20
  124. package/src/input/commands/mcp-runtime.ts +63 -46
  125. package/src/input/commands/notify-runtime.ts +38 -9
  126. package/src/input/commands/operator-actions-runtime.ts +138 -0
  127. package/src/input/commands/operator-runtime.ts +6 -76
  128. package/src/input/commands/personas-runtime.ts +46 -31
  129. package/src/input/commands/planning-runtime.ts +1 -1
  130. package/src/input/commands/platform-access-runtime.ts +35 -98
  131. package/src/input/commands/product-runtime.ts +2 -2
  132. package/src/input/commands/provider-accounts-runtime.ts +60 -39
  133. package/src/input/commands/qrcode-runtime.ts +50 -9
  134. package/src/input/commands/recall-bundle.ts +11 -11
  135. package/src/input/commands/recall-capture.ts +13 -11
  136. package/src/input/commands/recall-query.ts +29 -21
  137. package/src/input/commands/recall-review.ts +2 -1
  138. package/src/input/commands/routines-runtime.ts +99 -45
  139. package/src/input/commands/runtime-services.ts +1 -14
  140. package/src/input/commands/schedule-runtime.ts +33 -20
  141. package/src/input/commands/security-runtime.ts +6 -11
  142. package/src/input/commands/session-content.ts +80 -78
  143. package/src/input/commands/session-workflow.ts +134 -104
  144. package/src/input/commands/session.ts +3 -174
  145. package/src/input/commands/shell-core.ts +38 -17
  146. package/src/input/commands/subscription-runtime.ts +54 -185
  147. package/src/input/commands/support-bundle-runtime.ts +53 -0
  148. package/src/input/commands/tasks-runtime.ts +21 -21
  149. package/src/input/commands/work-plan-runtime.ts +33 -8
  150. package/src/input/commands.ts +6 -2
  151. package/src/input/feed-context-factory.ts +2 -2
  152. package/src/input/file-picker.ts +3 -2
  153. package/src/input/handler-command-route.ts +4 -7
  154. package/src/input/handler-content-actions.ts +89 -26
  155. package/src/input/handler-feed-routes.ts +19 -12
  156. package/src/input/handler-feed.ts +6 -5
  157. package/src/input/handler-interactions.ts +9 -36
  158. package/src/input/handler-modal-stack.ts +3 -3
  159. package/src/input/handler-onboarding.ts +52 -91
  160. package/src/input/handler-shortcuts.ts +16 -7
  161. package/src/input/handler.ts +50 -23
  162. package/src/input/input-history.ts +5 -6
  163. package/src/input/keybindings.ts +27 -16
  164. package/src/input/mcp-workspace.ts +90 -26
  165. package/src/input/onboarding/handler-onboarding-routes.ts +3 -1
  166. package/src/input/onboarding/onboarding-wizard-apply.ts +62 -0
  167. package/src/input/onboarding/onboarding-wizard-constants.ts +1 -0
  168. package/src/input/onboarding/onboarding-wizard-helpers.ts +1 -1
  169. package/src/input/onboarding/onboarding-wizard-operator-steps.ts +223 -55
  170. package/src/input/onboarding/onboarding-wizard-steps.ts +59 -35
  171. package/src/input/onboarding/onboarding-wizard-types.ts +4 -1
  172. package/src/input/onboarding/onboarding-wizard.ts +87 -2
  173. package/src/input/profile-picker-modal.ts +31 -12
  174. package/src/input/session-picker-modal.ts +21 -4
  175. package/src/input/settings-modal-agent-policy.ts +6 -6
  176. package/src/input/settings-modal-behavior.ts +0 -3
  177. package/src/input/settings-modal-subscriptions.ts +3 -3
  178. package/src/input/settings-modal-types.ts +2 -13
  179. package/src/input/settings-modal.ts +20 -66
  180. package/src/input/submission-intent.ts +0 -1
  181. package/src/input/submission-router.ts +3 -3
  182. package/src/main.ts +18 -10
  183. package/src/panels/approval-panel.ts +8 -8
  184. package/src/panels/automation-control-panel.ts +4 -4
  185. package/src/panels/base-panel.ts +1 -1
  186. package/src/panels/builtin/agent.ts +1 -1
  187. package/src/panels/builtin/operations.ts +3 -12
  188. package/src/panels/builtin/session.ts +32 -24
  189. package/src/panels/builtin/shared.ts +7 -7
  190. package/src/panels/cost-tracker-panel.ts +1 -1
  191. package/src/panels/docs-panel.ts +5 -3
  192. package/src/panels/index.ts +0 -1
  193. package/src/panels/knowledge-panel.ts +6 -5
  194. package/src/panels/memory-panel.ts +7 -6
  195. package/src/panels/panel-list-panel.ts +36 -80
  196. package/src/panels/project-planning-panel.ts +19 -12
  197. package/src/panels/provider-account-snapshot.ts +51 -25
  198. package/src/panels/provider-accounts-panel.ts +33 -18
  199. package/src/panels/provider-health-domains.ts +48 -7
  200. package/src/panels/provider-health-panel.ts +5 -4
  201. package/src/panels/qr-panel.ts +44 -20
  202. package/src/panels/schedule-panel.ts +9 -17
  203. package/src/panels/security-panel.ts +8 -8
  204. package/src/panels/session-browser-panel.ts +10 -10
  205. package/src/panels/subscription-panel.ts +6 -6
  206. package/src/panels/system-messages-panel.ts +3 -3
  207. package/src/panels/tasks-panel.ts +21 -14
  208. package/src/panels/tool-inspector-panel.ts +19 -12
  209. package/src/panels/work-plan-panel.ts +5 -5
  210. package/src/planning/project-planning-coordinator.ts +3 -3
  211. package/src/provider-auth-route-display.ts +9 -0
  212. package/src/renderer/agent-workspace-style.ts +34 -0
  213. package/src/renderer/agent-workspace.ts +254 -57
  214. package/src/renderer/autocomplete-overlay.ts +25 -6
  215. package/src/renderer/block-actions.ts +1 -3
  216. package/src/renderer/bookmark-modal.ts +19 -4
  217. package/src/renderer/buffer.ts +4 -2
  218. package/src/renderer/context-inspector.ts +50 -13
  219. package/src/renderer/diff.ts +1 -1
  220. package/src/renderer/file-picker-overlay.ts +19 -6
  221. package/src/renderer/help-overlay.ts +112 -34
  222. package/src/renderer/history-search-overlay.ts +19 -4
  223. package/src/renderer/live-tail-modal.ts +27 -5
  224. package/src/renderer/mcp-workspace.ts +176 -43
  225. package/src/renderer/model-picker-overlay.ts +58 -3
  226. package/src/renderer/model-workspace.ts +104 -22
  227. package/src/renderer/onboarding/onboarding-wizard.ts +20 -4
  228. package/src/renderer/process-modal.ts +27 -6
  229. package/src/renderer/profile-picker-modal.ts +21 -5
  230. package/src/renderer/search-overlay.ts +25 -5
  231. package/src/renderer/selection-modal-overlay.ts +46 -14
  232. package/src/renderer/session-picker-modal.ts +18 -1
  233. package/src/renderer/settings-modal-helpers.ts +2 -40
  234. package/src/renderer/settings-modal.ts +88 -55
  235. package/src/renderer/system-message.ts +1 -1
  236. package/src/renderer/tool-call.ts +20 -11
  237. package/src/runtime/agent-runtime-events.ts +129 -0
  238. package/src/runtime/bootstrap-command-context.ts +7 -1
  239. package/src/runtime/bootstrap-command-parts.ts +11 -8
  240. package/src/runtime/bootstrap-core.ts +23 -65
  241. package/src/runtime/bootstrap-hook-bridge.ts +7 -18
  242. package/src/runtime/bootstrap-shell.ts +46 -8
  243. package/src/runtime/bootstrap.ts +36 -46
  244. package/src/runtime/connected-host-auth.ts +47 -0
  245. package/src/runtime/diagnostics/panels/index.ts +2 -2
  246. package/src/runtime/diagnostics/panels/panel-resources.ts +1 -1
  247. package/src/runtime/diagnostics/panels/policy.ts +7 -7
  248. package/src/runtime/index.ts +2 -5
  249. package/src/runtime/onboarding/apply-file-helpers.ts +66 -0
  250. package/src/runtime/onboarding/apply.ts +288 -74
  251. package/src/runtime/onboarding/derivation.ts +10 -13
  252. package/src/runtime/onboarding/snapshot.ts +2 -17
  253. package/src/runtime/onboarding/types.ts +34 -20
  254. package/src/runtime/onboarding/verify.ts +105 -4
  255. package/src/runtime/operator-token-cleanup.ts +3 -3
  256. package/src/runtime/services.ts +95 -11
  257. package/src/runtime/store/selectors/index.ts +3 -3
  258. package/src/runtime/store/state.ts +1 -4
  259. package/src/runtime/surface-feature-flags.ts +41 -6
  260. package/src/runtime/ui-read-models.ts +3 -4
  261. package/src/runtime/ui-services.ts +6 -6
  262. package/src/shell/blocking-input.ts +2 -1
  263. package/src/shell/service-settings-sync.ts +7 -7
  264. package/src/shell/ui-openers.ts +17 -38
  265. package/src/tools/agent-analysis-registry-policy.ts +0 -1
  266. package/src/tools/agent-channel-send-tool.ts +133 -0
  267. package/src/tools/agent-context-policy.ts +1 -1
  268. package/src/tools/agent-knowledge-ingest-tool.ts +405 -0
  269. package/src/tools/agent-knowledge-tool.ts +170 -0
  270. package/src/tools/agent-local-registry-tool.ts +279 -73
  271. package/src/tools/agent-media-generate-tool.ts +133 -0
  272. package/src/tools/agent-notify-tool.ts +143 -0
  273. package/src/tools/agent-operator-action-tool.ts +137 -0
  274. package/src/tools/agent-operator-briefing-tool.ts +217 -0
  275. package/src/tools/agent-reminder-schedule-tool.ts +237 -0
  276. package/src/tools/agent-tool-policy-guard.ts +13 -15
  277. package/src/tools/agent-work-plan-tool.ts +256 -0
  278. package/src/version.ts +1 -1
  279. package/docs/connected-services.md +0 -51
  280. package/src/cli/package-verification.ts +0 -274
  281. package/src/input/commands/policy-dispatch.ts +0 -339
  282. package/src/input/commands/policy.ts +0 -17
  283. package/src/panels/panel-picker.ts +0 -105
  284. package/src/panels/policy-panel.ts +0 -308
  285. package/src/renderer/panel-picker-overlay.ts +0 -202
@@ -1,6 +1,7 @@
1
1
  import type { CommandContext } from '../command-registry.ts';
2
2
  import type { MemoryApi } from '@pellux/goodvibes-sdk/platform/knowledge';
3
3
  import type { MemorySearchFilter } from '@pellux/goodvibes-sdk/platform/state';
4
+ import { formatAgentRecordReference, formatAgentRecordReferences } from '../../agent/record-labels.ts';
4
5
  import { VALID_CLASSES, VALID_SCOPES, isValidClass, isValidScope } from './recall-shared.ts';
5
6
  import { requireYesFlag, stripYesFlag } from './confirmation.ts';
6
7
 
@@ -8,7 +9,7 @@ export function getMemoryApi(context: CommandContext): MemoryApi | null {
8
9
  const memoryApi = context.clients?.agentKnowledgeApi?.memory;
9
10
  if (!memoryApi) {
10
11
  context.print('[memory] Agent Memory API is not available in this runtime.');
11
- context.print('[memory] Refusing to use default Knowledge/Wiki or non-Agent knowledge fallback.');
12
+ context.print('[memory] Refusing to use default knowledge or non-Agent knowledge fallback.');
12
13
  return null;
13
14
  }
14
15
  return memoryApi;
@@ -29,7 +30,7 @@ export function handleRecallSearch(args: string[], context: CommandContext): voi
29
30
  const cls = args[clsIdx + 1];
30
31
  if (isValidClass(cls)) filter.cls = cls;
31
32
  else {
32
- context.print(`[memory] Unknown class "${cls}". Valid: ${VALID_CLASSES.join(', ')}`);
33
+ context.print(`[memory] Unknown class "${cls}". Valid values ${VALID_CLASSES.join(', ')}.`);
33
34
  return;
34
35
  }
35
36
  }
@@ -39,7 +40,7 @@ export function handleRecallSearch(args: string[], context: CommandContext): voi
39
40
  const scope = args[scopeIdx + 1];
40
41
  if (isValidScope(scope)) filter.scope = scope;
41
42
  else {
42
- context.print(`[memory] Unknown scope "${scope}". Valid: ${VALID_SCOPES.join(', ')}`);
43
+ context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES.join(', ')}.`);
43
44
  return;
44
45
  }
45
46
  }
@@ -63,7 +64,7 @@ export function handleRecallSearch(args: string[], context: CommandContext): voi
63
64
  return;
64
65
  }
65
66
 
66
- context.print(`[memory] ${results.length} ${semantic ? 'semantic ' : ''}record(s):`);
67
+ context.print(`[memory] ${results.length} ${semantic ? 'semantic ' : ''}record(s)`);
67
68
  for (const record of results) {
68
69
  const semanticEntry = semanticResults.find((entry) => entry.record.id === record.id);
69
70
  const ts = new Date(record.createdAt).toISOString().slice(0, 16).replace('T', ' ');
@@ -72,7 +73,7 @@ export function handleRecallSearch(args: string[], context: CommandContext): voi
72
73
  context.print(` ${record.id} [${record.cls}]${tagStr} ${ts}${scoreStr}`);
73
74
  context.print(` ${record.summary}`);
74
75
  if (record.provenance.length) {
75
- context.print(` via: ${record.provenance.map((entry) => `${entry.kind}:${entry.ref}`).join(', ')}`);
76
+ context.print(` origin ${formatAgentRecordReferences(record.provenance)}`);
76
77
  }
77
78
  }
78
79
  }
@@ -124,29 +125,28 @@ export function handleRecallGet(args: string[], context: CommandContext): void {
124
125
  }
125
126
  const record = memory.get(id);
126
127
  if (!record) {
127
- context.print(`[memory] Record not found: ${id}`);
128
+ context.print(`[memory] Record not found ${id}`);
128
129
  return;
129
130
  }
130
131
  const ts = new Date(record.createdAt).toISOString().slice(0, 19).replace('T', ' ');
131
132
  context.print(`[memory] ${record.id}`);
132
- context.print(` Scope: ${record.scope}`);
133
- context.print(` Class: ${record.cls}`);
134
- context.print(` Summary: ${record.summary}`);
135
- if (record.detail) context.print(` Detail: ${record.detail}`);
136
- if (record.tags.length) context.print(` Tags: ${record.tags.join(', ')}`);
137
- context.print(` Created: ${ts}`);
133
+ context.print(` scope ${record.scope}`);
134
+ context.print(` class ${record.cls}`);
135
+ context.print(` summary ${record.summary}`);
136
+ if (record.detail) context.print(` detail ${record.detail}`);
137
+ if (record.tags.length) context.print(` tags ${record.tags.join(', ')}`);
138
+ context.print(` created ${ts}`);
138
139
 
139
140
  if (record.provenance.length) {
140
- context.print(' Provenance:');
141
+ context.print(' origin');
141
142
  for (const provenance of record.provenance) {
142
- const label = provenance.label ? ` (${provenance.label})` : '';
143
- context.print(` ${provenance.kind}: ${provenance.ref}${label}`);
143
+ context.print(` ${formatAgentRecordReference(provenance)}`);
144
144
  }
145
145
  }
146
146
 
147
147
  const links = memory.linksFor(id);
148
148
  if (links.length) {
149
- context.print(' Links:');
149
+ context.print(' links');
150
150
  for (const link of links) {
151
151
  const dir = link.fromId === id ? '->' : '<-';
152
152
  const other = link.fromId === id ? link.toId : link.fromId;
@@ -175,7 +175,12 @@ export async function handleRecallLink(args: string[], context: CommandContext):
175
175
  context.print('[memory] Link failed — check that both IDs exist.');
176
176
  return;
177
177
  }
178
- context.print(`[memory] Linked: ${fromId} -> ${toId} [${relation}]`);
178
+ context.print([
179
+ '[memory] Linked',
180
+ ` from ${fromId}`,
181
+ ` to ${toId}`,
182
+ ` relation ${relation}`,
183
+ ].join('\n'));
179
184
  }
180
185
 
181
186
  export function handleRecallRemove(args: string[], context: CommandContext): void {
@@ -195,10 +200,13 @@ export function handleRecallRemove(args: string[], context: CommandContext): voi
195
200
  }
196
201
  const removed = memory.delete(id);
197
202
  if (!removed) {
198
- context.print(`[memory] Record not found: ${id}`);
203
+ context.print(`[memory] Record not found ${id}`);
199
204
  return;
200
205
  }
201
- context.print(`[memory] Deleted: ${id}`);
206
+ context.print([
207
+ '[memory] Deleted',
208
+ ` id ${id}`,
209
+ ].join('\n'));
202
210
  }
203
211
 
204
212
  export function handleRecallList(args: string[], context: CommandContext): void {
@@ -213,7 +221,7 @@ export function handleRecallList(args: string[], context: CommandContext): void
213
221
  if (scopeIdx !== -1 && args[scopeIdx + 1]) {
214
222
  const scope = args[scopeIdx + 1];
215
223
  if (!isValidScope(scope)) {
216
- context.print(`[memory] Unknown scope "${scope}". Valid: ${VALID_SCOPES.join(', ')}`);
224
+ context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES.join(', ')}.`);
217
225
  return;
218
226
  }
219
227
  filter.scope = scope;
@@ -232,7 +240,7 @@ export function handleRecallList(args: string[], context: CommandContext): void
232
240
  }
233
241
 
234
242
  for (const [clsName, group] of Object.entries(grouped)) {
235
- context.print(`\n[memory] ${clsName.toUpperCase()} (${group.length}):`);
243
+ context.print(`\n[memory] ${clsName.toUpperCase()} (${group.length})`);
236
244
  for (const record of group) {
237
245
  const tagStr = record.tags.length ? ` [${record.tags.join(', ')}]` : '';
238
246
  context.print(` ${record.id} [${record.scope}]${tagStr} ${record.summary}`);
@@ -1,4 +1,5 @@
1
1
  import type { CommandContext } from '../command-registry.ts';
2
+ import { formatAgentRecordReviewState } from '../../agent/record-labels.ts';
2
3
  import { VALID_REVIEW_STATES, VALID_SCOPES, isValidReviewState, isValidScope } from './recall-shared.ts';
3
4
  import { getMemoryApi } from './recall-query.ts';
4
5
  import { requireYesFlag, stripYesFlag } from './confirmation.ts';
@@ -17,7 +18,7 @@ export function handleRecallQueue(args: string[], context: CommandContext): void
17
18
  context.print(`[memory] Review queue (${queue.length}):`);
18
19
  for (const record of queue) {
19
20
  const reason = record.staleReason ? ` — ${record.staleReason}` : '';
20
- context.print(` ${record.id} [${record.scope}/${record.cls}] ${record.reviewState} ${record.confidence}% ${record.summary}${reason}`);
21
+ context.print(` ${record.id} [${record.scope}/${record.cls}] ${formatAgentRecordReviewState(record.reviewState)} ${record.confidence}% ${record.summary}${reason}`);
21
22
  }
22
23
  }
23
24
 
@@ -1,9 +1,11 @@
1
1
  import { discoverRoutines, type DiscoveredRoutineRecord } from '../../agent/routine-discovery.ts';
2
- import { AgentRoutineRegistry, type AgentRoutineRecord } from '../../agent/routine-registry.ts';
2
+ import { AgentRoutineRegistry, evaluateAgentRoutineReadiness, type AgentRoutineRecord } from '../../agent/routine-registry.ts';
3
+ import { formatAgentRecordOrigin, formatAgentRecordReviewState } from '../../agent/record-labels.ts';
4
+ import { buildAgentSkillRequirements, formatAgentSkillRequirement } from '../../agent/skill-registry.ts';
3
5
  import {
4
6
  buildRoutineSchedulePreview,
5
- promoteRoutineToDaemonSchedule,
6
- resolveAgentDaemonConnection,
7
+ promoteRoutineToConnectedSchedule,
8
+ resolveAgentConnectedHostConnection,
7
9
  } from '../../agent/routine-schedule-promotion.ts';
8
10
  import { parseRoutineSchedulePromotionArgs } from '../../agent/routine-schedule-args.ts';
9
11
  import {
@@ -72,39 +74,57 @@ function requiredFlag(flags: ReadonlyMap<string, string>, key: string): string {
72
74
  return value;
73
75
  }
74
76
 
77
+ function formatRoutineReceipt(title: string, routine: Pick<AgentRoutineRecord, 'id' | 'name'>, extra: readonly string[] = []): string {
78
+ const enabled = extra.some((line) => line.trim() === 'enabled yes');
79
+ return [
80
+ `${title} ${routine.id}: ${routine.name}${enabled ? ' (enabled)' : ''}`,
81
+ ` id ${routine.id}`,
82
+ ` name ${routine.name}`,
83
+ ...extra,
84
+ ].join('\n');
85
+ }
86
+
75
87
  function summarizeRoutine(routine: AgentRoutineRecord): string {
76
88
  const enabled = routine.enabled ? 'enabled' : 'disabled';
77
- const tags = routine.tags.length > 0 ? ` tags=${routine.tags.join(',')}` : '';
78
- return ` ${routine.id} ${enabled} ${routine.reviewState} starts=${routine.startCount} ${routine.name} - ${routine.description}${tags}`;
89
+ const tags = routine.tags.length > 0 ? ` tags ${routine.tags.join(', ')}` : '';
90
+ const readiness = evaluateAgentRoutineReadiness(routine);
91
+ const review = formatAgentRecordReviewState(routine.reviewState);
92
+ const ready = readiness.ready ? 'ready' : `needs ${readiness.missing.map(formatAgentSkillRequirement).join(',')}`;
93
+ return ` ${routine.id} ${enabled} ${review} ${ready} starts ${routine.startCount} ${routine.name} - ${routine.description}${tags}`;
79
94
  }
80
95
 
81
- function renderList(title: string, registry: AgentRoutineRegistry, routines: readonly AgentRoutineRecord[]): string {
96
+ function renderList(title: string, registry: AgentRoutineRegistry, routines: readonly AgentRoutineRecord[], emptyMessage?: string): string {
82
97
  const snapshot = registry.snapshot();
83
98
  if (routines.length === 0) {
84
- return `${title}\n No local Agent routines yet. Create one with /routines create --name <name> --description <summary> --steps <steps>.`;
99
+ return emptyMessage
100
+ ? `${title}\n ${emptyMessage}`
101
+ : `${title}\n No local Agent routines yet.\n No Agent-local routines yet. Create one with /routines create --name <name> --description <summary> --steps <steps>.`;
85
102
  }
86
103
  return [
87
104
  `${title} (${routines.length})`,
88
- ` store: ${snapshot.path}`,
89
- ` enabled: ${snapshot.enabledRoutines.length}`,
105
+ ` store ${snapshot.path}`,
106
+ ` enabled ${snapshot.enabledRoutines.length}`,
90
107
  ...routines.map(summarizeRoutine),
91
108
  ].join('\n');
92
109
  }
93
110
 
94
111
  function renderRoutine(routine: AgentRoutineRecord): string {
112
+ const readiness = evaluateAgentRoutineReadiness(routine);
95
113
  return [
96
114
  `Routine ${routine.name}`,
97
- ` id: ${routine.id}`,
98
- ` enabled: ${routine.enabled ? 'yes' : 'no'}`,
99
- ` review: ${routine.reviewState}`,
100
- ` source: ${routine.source}`,
101
- ` provenance: ${routine.provenance}`,
115
+ ` id ${routine.id}`,
116
+ ` enabled ${routine.enabled ? 'yes' : 'no'}`,
117
+ ` readiness: ${readiness.ready ? 'ready' : 'needs setup'}`,
118
+ ` requirements ${routine.requirements.map(formatAgentSkillRequirement).join(', ') || '(none)'}`,
119
+ readiness.missing.length > 0 ? ` missing: ${readiness.missing.map(formatAgentSkillRequirement).join(', ')}` : '',
120
+ ` review ${formatAgentRecordReviewState(routine.reviewState)}`,
121
+ ` origin ${formatAgentRecordOrigin(routine.source, routine.provenance)}`,
102
122
  ` tags: ${routine.tags.join(', ') || '(none)'}`,
103
123
  ` triggers: ${routine.triggers.join(', ') || '(manual)'}`,
104
- ` started: ${routine.startCount}${routine.lastStartedAt ? `; last ${routine.lastStartedAt}` : ''}`,
105
- ` created: ${routine.createdAt}`,
106
- ` updated: ${routine.updatedAt}`,
107
- routine.staleReason ? ` stale reason: ${routine.staleReason}` : '',
124
+ ` started ${routine.startCount}${routine.lastStartedAt ? `; last ${routine.lastStartedAt}` : ''}`,
125
+ ` created ${routine.createdAt}`,
126
+ ` updated ${routine.updatedAt}`,
127
+ routine.staleReason ? ` stale reason ${routine.staleReason}` : '',
108
128
  '',
109
129
  routine.description,
110
130
  '',
@@ -114,7 +134,7 @@ function renderRoutine(routine: AgentRoutineRecord): string {
114
134
 
115
135
  function summarizeDiscoveredRoutine(routine: DiscoveredRoutineRecord): string {
116
136
  const description = routine.description ? ` - ${routine.description}` : '';
117
- return ` ${routine.name} ${routine.origin}${description}\n path: ${routine.path}`;
137
+ return ` ${routine.name} ${routine.origin}${description}\n path ${routine.path}`;
118
138
  }
119
139
 
120
140
  function renderDiscoveredRoutines(routines: readonly DiscoveredRoutineRecord[]): string {
@@ -151,8 +171,19 @@ function frontmatterList(routine: DiscoveredRoutineRecord, key: string): readonl
151
171
  return splitList(value);
152
172
  }
153
173
 
174
+ function frontmatterAnyList(routine: DiscoveredRoutineRecord, keys: readonly string[]): readonly string[] {
175
+ for (const key of keys) {
176
+ const values = frontmatterList(routine, key);
177
+ if (values.length > 0) return values;
178
+ }
179
+ return [];
180
+ }
181
+
154
182
  function printError(ctx: CommandContext, error: unknown): void {
155
- ctx.print(`Error: ${error instanceof Error ? error.message : String(error)}`);
183
+ ctx.print([
184
+ 'Error',
185
+ ` message ${error instanceof Error ? error.message : String(error)}`,
186
+ ].join('\n'));
156
187
  }
157
188
 
158
189
  async function importDiscoveredRoutine(args: readonly string[], ctx: CommandContext, routineRegistry: AgentRoutineRegistry): Promise<void> {
@@ -164,18 +195,18 @@ async function importDiscoveredRoutine(args: readonly string[], ctx: CommandCont
164
195
  }
165
196
  const discovered = findDiscoveredRoutine(await discoverRoutines(requireShellPaths(ctx)), name);
166
197
  if (!discovered) {
167
- ctx.print(`Unknown discovered Agent routine: ${name}\nRun /routines discover to inspect available routine files.`);
198
+ ctx.print(`Unknown discovered Agent routine ${name}\nRun /routines discover to inspect available routine files.`);
168
199
  return;
169
200
  }
170
201
  if (!parsed.yes) {
171
202
  ctx.print([
172
203
  'Agent routine import preview',
173
- ` name: ${discovered.name}`,
174
- ` origin: ${discovered.origin}`,
175
- ` path: ${discovered.path}`,
176
- ` description: ${discovered.description || '(none)'}`,
177
- ` steps characters: ${discovered.steps.length}`,
178
- ' next: rerun with --yes to import into the Agent-local routine registry',
204
+ ` name ${discovered.name}`,
205
+ ` origin ${discovered.origin}`,
206
+ ` path ${discovered.path}`,
207
+ ` description ${discovered.description || '(none)'}`,
208
+ ` steps characters ${discovered.steps.length}`,
209
+ ' next rerun with --yes to import into the Agent-local routine registry',
179
210
  ].join('\n'));
180
211
  return;
181
212
  }
@@ -185,11 +216,15 @@ async function importDiscoveredRoutine(args: readonly string[], ctx: CommandCont
185
216
  steps: discovered.steps,
186
217
  tags: frontmatterList(discovered, 'tags'),
187
218
  triggers: frontmatterList(discovered, 'triggers'),
219
+ requirements: buildAgentSkillRequirements({
220
+ env: frontmatterAnyList(discovered, ['requiresEnv', 'requires-env', 'requires_env']),
221
+ commands: frontmatterAnyList(discovered, ['requiresCommands', 'requires-commands', 'requires_commands', 'commands']),
222
+ }),
188
223
  enabled: parsed.flags.get('enabled') === 'true',
189
224
  source: 'imported',
190
225
  provenance: `discovered:${discovered.origin}:${discovered.path}`,
191
226
  });
192
- ctx.print(`Imported Agent routine ${routine.id}: ${routine.name}${routine.enabled ? ' (enabled)' : ''}`);
227
+ ctx.print(formatRoutineReceipt('Imported Agent routine', routine, [` enabled ${routine.enabled ? 'yes' : 'no'}`]));
193
228
  }
194
229
 
195
230
  async function promoteRoutine(args: readonly string[], routineRegistry: AgentRoutineRegistry, ctx: CommandContext): Promise<void> {
@@ -212,8 +247,8 @@ async function promoteRoutine(args: readonly string[], routineRegistry: AgentRou
212
247
  return;
213
248
  }
214
249
  const shellPaths = requireShellPaths(ctx);
215
- const connection = resolveAgentDaemonConnection(ctx.platform.configManager, shellPaths.homeDirectory);
216
- const result = await promoteRoutineToDaemonSchedule(connection, preview);
250
+ const connection = resolveAgentConnectedHostConnection(ctx.platform.configManager, shellPaths.homeDirectory);
251
+ const result = await promoteRoutineToConnectedSchedule(connection, preview);
217
252
  const receipt = receiptStoreFromContext(ctx).append(connection, preview, result);
218
253
  ctx.print(result.ok ? `${formatRoutineScheduleSuccess(result)}\n receipt: ${receipt.id}` : `${formatRoutineScheduleFailure(result)}\n receipt: ${receipt.id}`);
219
254
  }
@@ -231,6 +266,11 @@ export async function runRoutinesRuntimeCommand(args: readonly string[], ctx: Co
231
266
  ctx.print(renderList('Enabled Agent Routines', routineRegistry, snapshot.enabledRoutines));
232
267
  return;
233
268
  }
269
+ if (sub === 'attention' || sub === 'needs-setup') {
270
+ const routines = routineRegistry.list().filter((routine) => !evaluateAgentRoutineReadiness(routine).ready);
271
+ ctx.print(renderList('Agent Routines needing setup', routineRegistry, routines, 'No Agent-local routines need setup.'));
272
+ return;
273
+ }
234
274
  if (sub === 'discover' || sub === 'discovered') {
235
275
  ctx.print(renderDiscoveredRoutines(await discoverRoutines(requireShellPaths(ctx))));
236
276
  return;
@@ -260,7 +300,7 @@ export async function runRoutinesRuntimeCommand(args: readonly string[], ctx: Co
260
300
  }
261
301
  if (sub === 'reconcile' || sub === 'sync' || sub === 'status') {
262
302
  const shellPaths = requireShellPaths(ctx);
263
- const connection = resolveAgentDaemonConnection(ctx.platform.configManager, shellPaths.homeDirectory);
303
+ const connection = resolveAgentConnectedHostConnection(ctx.platform.configManager, shellPaths.homeDirectory);
264
304
  const result = await reconcileRoutineScheduleReceipts(connection, receiptStoreFromContext(ctx).snapshot());
265
305
  ctx.print(formatRoutineScheduleCorrelation(result));
266
306
  return;
@@ -272,7 +312,7 @@ export async function runRoutinesRuntimeCommand(args: readonly string[], ctx: Co
272
312
  return;
273
313
  }
274
314
  const receipt = receiptStoreFromContext(ctx).get(id);
275
- ctx.print(receipt ? formatRoutineScheduleReceipt(receipt) : `Unknown routine schedule receipt: ${id}`);
315
+ ctx.print(receipt ? formatRoutineScheduleReceipt(receipt) : `Unknown routine schedule receipt ${id}`);
276
316
  return;
277
317
  }
278
318
  if (sub === 'create') {
@@ -284,11 +324,15 @@ export async function runRoutinesRuntimeCommand(args: readonly string[], ctx: Co
284
324
  steps,
285
325
  triggers: splitList(parsed.flags.get('triggers')),
286
326
  tags: splitList(parsed.flags.get('tags')),
327
+ requirements: buildAgentSkillRequirements({
328
+ env: splitList(parsed.flags.get('requires-env')),
329
+ commands: splitList(parsed.flags.get('requires-command') ?? parsed.flags.get('requires-commands')),
330
+ }),
287
331
  enabled: parsed.flags.get('enabled') === 'true',
288
332
  source: 'user',
289
- provenance: 'slash-command',
333
+ provenance: 'Command',
290
334
  });
291
- ctx.print(`Created Agent routine ${routine.id}: ${routine.name}`);
335
+ ctx.print(formatRoutineReceipt('Created Agent routine', routine));
292
336
  return;
293
337
  }
294
338
  if (sub === 'update') {
@@ -304,9 +348,15 @@ export async function runRoutinesRuntimeCommand(args: readonly string[], ctx: Co
304
348
  steps: parsed.flags.get('steps'),
305
349
  triggers: parsed.flags.has('triggers') ? splitList(parsed.flags.get('triggers')) : undefined,
306
350
  tags: parsed.flags.has('tags') ? splitList(parsed.flags.get('tags')) : undefined,
307
- provenance: 'slash-command',
351
+ requirements: parsed.flags.has('requires-env') || parsed.flags.has('requires-command') || parsed.flags.has('requires-commands')
352
+ ? buildAgentSkillRequirements({
353
+ env: splitList(parsed.flags.get('requires-env')),
354
+ commands: splitList(parsed.flags.get('requires-command') ?? parsed.flags.get('requires-commands')),
355
+ })
356
+ : undefined,
357
+ provenance: 'Command',
308
358
  });
309
- ctx.print(`Updated Agent routine ${updated.id}: ${updated.name}`);
359
+ ctx.print(formatRoutineReceipt('Updated Agent routine', updated));
310
360
  return;
311
361
  }
312
362
  if (sub === 'enable' || sub === 'disable') {
@@ -316,7 +366,7 @@ export async function runRoutinesRuntimeCommand(args: readonly string[], ctx: Co
316
366
  return;
317
367
  }
318
368
  const routine = routineRegistry.setEnabled(id, sub === 'enable');
319
- ctx.print(`${sub === 'enable' ? 'Enabled' : 'Disabled'} Agent routine ${routine.id}: ${routine.name}`);
369
+ ctx.print(formatRoutineReceipt(`${sub === 'enable' ? 'Enabled' : 'Disabled'} Agent routine`, routine));
320
370
  return;
321
371
  }
322
372
  if (sub === 'start' || sub === 'run') {
@@ -326,9 +376,13 @@ export async function runRoutinesRuntimeCommand(args: readonly string[], ctx: Co
326
376
  return;
327
377
  }
328
378
  const routine = routineRegistry.markStarted(id);
379
+ const readiness = evaluateAgentRoutineReadiness(routine);
329
380
  ctx.print([
330
- `Started Agent routine ${routine.id}: ${routine.name}`,
331
- ' policy: same main conversation; no hidden job, runtime mutation, or external side effect was started',
381
+ `Started Agent routine ${routine.id}`,
382
+ ` id ${routine.id}`,
383
+ ` name ${routine.name}`,
384
+ ` readiness: ${readiness.ready ? 'ready' : `needs setup (${readiness.missing.map(formatAgentSkillRequirement).join(', ')})`}`,
385
+ ' policy same main conversation; no hidden job, runtime mutation, or external side effect was started',
332
386
  '',
333
387
  routine.steps,
334
388
  ].join('\n'));
@@ -341,7 +395,7 @@ export async function runRoutinesRuntimeCommand(args: readonly string[], ctx: Co
341
395
  return;
342
396
  }
343
397
  const routine = routineRegistry.markReviewed(id);
344
- ctx.print(`Reviewed Agent routine ${routine.id}.`);
398
+ ctx.print(formatRoutineReceipt('Reviewed Agent routine', routine));
345
399
  return;
346
400
  }
347
401
  if (sub === 'stale') {
@@ -351,7 +405,7 @@ export async function runRoutinesRuntimeCommand(args: readonly string[], ctx: Co
351
405
  return;
352
406
  }
353
407
  const routine = routineRegistry.markStale(id, args.slice(2).join(' '));
354
- ctx.print(`Marked Agent routine ${routine.id} stale.`);
408
+ ctx.print(formatRoutineReceipt('Marked Agent routine stale', routine));
355
409
  return;
356
410
  }
357
411
  if (sub === 'promote' || sub === 'schedule' || sub === 'promote-schedule') {
@@ -370,10 +424,10 @@ export async function runRoutinesRuntimeCommand(args: readonly string[], ctx: Co
370
424
  return;
371
425
  }
372
426
  const removed = routineRegistry.deleteRoutine(id);
373
- ctx.print(`Deleted Agent routine ${removed.id}: ${removed.name}`);
427
+ ctx.print(formatRoutineReceipt('Deleted Agent routine', removed));
374
428
  return;
375
429
  }
376
- ctx.print('Usage: /routines [list|enabled|discover|import-discovered|search|show|receipts|reconcile|receipt|create|update|enable|disable|start|review|stale|promote|delete]');
430
+ ctx.print('Usage: /routines [list|enabled|attention|discover|import-discovered|search|show|receipts|reconcile|receipt|create|update|enable|disable|start|review|stale|promote|delete]');
377
431
  } catch (error) {
378
432
  printError(ctx, error);
379
433
  }
@@ -383,8 +437,8 @@ export function registerRoutinesRuntimeCommands(registry: CommandRegistry): void
383
437
  registry.register({
384
438
  name: 'routines',
385
439
  aliases: ['routine'],
386
- description: 'Manage local GoodVibes Agent routines',
387
- usage: '[list|enabled|discover|import-discovered <name> --yes|search <query>|show <id>|receipts|reconcile|receipt <id>|create --name <name> --description <summary> --steps <steps>|update <id> [--name ...] [--description ...] [--steps ...]|enable <id>|disable <id>|start <id>|review <id>|stale <id> <reason...>|promote <id> --cron <expr> [--delivery-channel slack] --yes|delete <id> --yes]',
440
+ description: 'Manage Agent-local routines',
441
+ usage: '[list|enabled|attention|discover|import-discovered <name> --yes|search <query>|show <id>|receipts|reconcile|receipt <id>|create --name <name> --description <summary> --steps <steps> [--requires-env A,B] [--requires-command gh,jq]|update <id> [--name ...] [--description ...] [--steps ...]|enable <id>|disable <id>|start <id>|review <id>|stale <id> <reason...>|promote <id> --cron <expr> [--delivery-channel slack] --yes|delete <id> --yes]',
388
442
  handler: runRoutinesRuntimeCommand,
389
443
  });
390
444
  }
@@ -22,7 +22,6 @@ import { GOODVIBES_AGENT_SURFACE_ROOT } from '../../config/surface.ts';
22
22
  import type { ProviderApi } from '@pellux/goodvibes-sdk/platform/providers';
23
23
  import type {
24
24
  ShellAgentManagerService,
25
- ShellAcpManagerService,
26
25
  ShellAutomationManagerService,
27
26
  ShellAutomationManagerRuntimeService,
28
27
  ShellModeManagerService,
@@ -32,7 +31,7 @@ import type {
32
31
 
33
32
  function requireContextValue<T>(value: T | null | undefined, name: string): T {
34
33
  if (value == null) {
35
- throw new Error(`commandContext.${name} is required but was not wired at bootstrap`);
34
+ throw new Error(`commandContext.${name} is unavailable in this Agent runtime`);
36
35
  }
37
36
  return value;
38
37
  }
@@ -274,10 +273,6 @@ export function requireAgentManager(context: CommandContext): ShellAgentManagerS
274
273
  return requireContextValue(context.ops.agentManager, 'ops.agentManager') as ShellAgentManagerService;
275
274
  }
276
275
 
277
- export function requireAcpManager(context: CommandContext): ShellAcpManagerService {
278
- return requireContextValue(context.ops.acpManager, 'ops.acpManager') as ShellAcpManagerService;
279
- }
280
-
281
276
  export function requireModeManager(context: CommandContext): ShellModeManagerService {
282
277
  return requireContextValue(context.ops.modeManager, 'ops.modeManager') as ShellModeManagerService;
283
278
  }
@@ -285,11 +280,3 @@ export function requireModeManager(context: CommandContext): ShellModeManagerSer
285
280
  export function requireAutomationManager(context: CommandContext): ShellAutomationManagerRuntimeService {
286
281
  return requireContextValue(context.ops.automationManager, 'ops.automationManager') as ShellAutomationManagerRuntimeService;
287
282
  }
288
-
289
- export function requireSandboxSessionRegistry(context: CommandContext) {
290
- return requireContextValue(context.workspace.sandboxSessionRegistry, 'workspace.sandboxSessionRegistry');
291
- }
292
-
293
- export function requireWorktreeRegistry(context: CommandContext) {
294
- return requireContextValue(context.workspace.worktreeRegistry, 'workspace.worktreeRegistry');
295
- }
@@ -8,7 +8,7 @@ import {
8
8
  buildReminderSchedulePreview,
9
9
  createReminderSchedule,
10
10
  parseReminderScheduleArgs,
11
- resolveReminderDaemonConnection,
11
+ resolveReminderConnectedHostConnection,
12
12
  } from '../../agent/reminder-schedule.ts';
13
13
  import {
14
14
  formatReminderScheduleFailure,
@@ -18,8 +18,8 @@ import {
18
18
  import { AgentRoutineRegistry } from '../../agent/routine-registry.ts';
19
19
  import {
20
20
  buildRoutineSchedulePreview,
21
- promoteRoutineToDaemonSchedule,
22
- resolveAgentDaemonConnection,
21
+ promoteRoutineToConnectedSchedule,
22
+ resolveAgentConnectedHostConnection,
23
23
  } from '../../agent/routine-schedule-promotion.ts';
24
24
  import { parseRoutineSchedulePromotionArgs } from '../../agent/routine-schedule-args.ts';
25
25
  import {
@@ -36,6 +36,7 @@ import {
36
36
  } from '../../agent/routine-schedule-receipts.ts';
37
37
  import type { CommandContext } from '../command-registry.ts';
38
38
  import { requireShellPaths } from './runtime-services.ts';
39
+ import { executeConfirmedOperatorAction } from './operator-actions-runtime.ts';
39
40
 
40
41
  function formatSchedule(schedule: AutomationScheduleDefinition): string {
41
42
  switch (schedule.kind) {
@@ -64,10 +65,11 @@ function formatPrompt(job: AutomationJob): string {
64
65
  function printReadOnlyScheduleBoundary(print: (text: string) => void, requestedAction: string): void {
65
66
  print([
66
67
  'GoodVibes Agent local schedule commands are read-only in this runtime.',
67
- ` requested: ${requestedAction}`,
68
- ' policy: no local Agent automation jobs, scheduled spawns, or immediate automation runs',
69
- ' use: /schedule list',
70
- ' schedule route: use /schedule promote-routine <routine> --cron <expr> --yes to create a connected schedule explicitly',
68
+ ` requested ${requestedAction}`,
69
+ ' policy no hidden local Agent automation jobs or immediate automation runs',
70
+ ' use /schedule list',
71
+ ' connected run route /automation schedule run <schedule-id> --yes',
72
+ ' schedule route use /schedule promote-routine <routine> --cron <expr> --yes to create a connected schedule explicitly',
71
73
  ].join('\n'));
72
74
  }
73
75
 
@@ -83,7 +85,7 @@ async function promoteRoutineSchedule(args: readonly string[], ctx: CommandConte
83
85
  const shellPaths = requireShellPaths(ctx);
84
86
  const routine = AgentRoutineRegistry.fromShellPaths(shellPaths).get(parsed.routineId ?? '');
85
87
  if (!routine) {
86
- ctx.print(`Unknown Agent routine: ${parsed.routineId ?? ''}`);
88
+ ctx.print(`Unknown Agent routine ${parsed.routineId ?? ''}`);
87
89
  return;
88
90
  }
89
91
  const preview = buildRoutineSchedulePreview(routine, parsed);
@@ -91,8 +93,8 @@ async function promoteRoutineSchedule(args: readonly string[], ctx: CommandConte
91
93
  ctx.print(formatRoutineSchedulePreview(preview));
92
94
  return;
93
95
  }
94
- const connection = resolveAgentDaemonConnection(ctx.platform.configManager, shellPaths.homeDirectory);
95
- const result = await promoteRoutineToDaemonSchedule(connection, preview);
96
+ const connection = resolveAgentConnectedHostConnection(ctx.platform.configManager, shellPaths.homeDirectory);
97
+ const result = await promoteRoutineToConnectedSchedule(connection, preview);
96
98
  const receipt = RoutineScheduleReceiptStore.fromShellPaths(shellPaths).append(connection, preview, result);
97
99
  ctx.print(result.ok ? `${formatRoutineScheduleSuccess(result)}\n receipt: ${receipt.id}` : `${formatRoutineScheduleFailure(result)}\n receipt: ${receipt.id}`);
98
100
  }
@@ -112,7 +114,7 @@ async function createReminder(args: readonly string[], ctx: CommandContext): Pro
112
114
  return;
113
115
  }
114
116
  const shellPaths = requireShellPaths(ctx);
115
- const connection = resolveReminderDaemonConnection(ctx.platform.configManager, shellPaths.homeDirectory);
117
+ const connection = resolveReminderConnectedHostConnection(ctx.platform.configManager, shellPaths.homeDirectory);
116
118
  const result = await createReminderSchedule(connection, preview);
117
119
  ctx.print(result.ok ? formatReminderScheduleSuccess(result) : formatReminderScheduleFailure(result));
118
120
  }
@@ -121,7 +123,7 @@ export function registerScheduleRuntimeCommands(registry: CommandRegistry): void
121
123
  registry.register({
122
124
  name: 'schedule',
123
125
  aliases: ['sched'],
124
- description: 'Inspect schedules, create confirmed reminders, and explicitly promote local Agent routines to connected schedules',
126
+ description: 'Inspect schedules, create confirmed reminders, and explicitly promote Agent-local routines to connected schedules',
125
127
  usage: 'list | remind --at <iso> --message <text> --yes | receipts | reconcile | receipt <id> | promote-routine <routine-id> --cron <expr> [--delivery-channel slack] --yes',
126
128
  argsHint: 'list | remind --at <iso> --message <text> --yes | receipts | reconcile | receipt <id> | promote-routine <routine-id> --cron <expr> [--delivery-channel slack] --yes',
127
129
  async handler(args, ctx) {
@@ -144,7 +146,7 @@ export function registerScheduleRuntimeCommands(registry: CommandRegistry): void
144
146
 
145
147
  if (sub === 'reconcile' || sub === 'sync' || sub === 'status') {
146
148
  const shellPaths = requireShellPaths(ctx);
147
- const connection = resolveAgentDaemonConnection(ctx.platform.configManager, shellPaths.homeDirectory);
149
+ const connection = resolveAgentConnectedHostConnection(ctx.platform.configManager, shellPaths.homeDirectory);
148
150
  const result = await reconcileRoutineScheduleReceipts(connection, RoutineScheduleReceiptStore.fromShellPaths(shellPaths).snapshot());
149
151
  ctx.print(formatRoutineScheduleCorrelation(result));
150
152
  return;
@@ -157,7 +159,7 @@ export function registerScheduleRuntimeCommands(registry: CommandRegistry): void
157
159
  return;
158
160
  }
159
161
  const receipt = RoutineScheduleReceiptStore.fromShellPaths(requireShellPaths(ctx)).get(id);
160
- ctx.print(receipt ? formatRoutineScheduleReceipt(receipt) : `Unknown routine schedule receipt: ${id}`);
162
+ ctx.print(receipt ? formatRoutineScheduleReceipt(receipt) : `Unknown routine schedule receipt ${id}`);
161
163
  return;
162
164
  }
163
165
 
@@ -176,20 +178,30 @@ export function registerScheduleRuntimeCommands(registry: CommandRegistry): void
176
178
  );
177
179
  return;
178
180
  }
179
- const lines = ['Automation jobs:', ''];
181
+ const lines = ['Automation jobs', ''];
180
182
  for (const job of jobs) {
181
183
  const status = job.enabled ? '● enabled ' : '○ paused ';
182
184
  const next = formatNextRun(job.nextRunAt);
183
185
  const last = job.lastRunAt ? new Date(job.lastRunAt).toLocaleString() : 'never';
184
- lines.push(` ${job.id.slice(0, 12)} ${status} runs:${job.runCount} next:${next} last:${last}`);
185
- lines.push(` name: ${job.name} schedule: ${formatSchedule(job.schedule)}`);
186
- lines.push(` prompt: ${formatPrompt(job)}`);
186
+ lines.push(` ${job.id.slice(0, 12)} ${status} runs ${job.runCount} next ${next} last ${last}`);
187
+ lines.push(` name ${job.name} schedule ${formatSchedule(job.schedule)}`);
188
+ lines.push(` prompt ${formatPrompt(job)}`);
187
189
  }
188
190
  ctx.print(lines.join('\n'));
189
191
  return;
190
192
  }
191
193
 
192
- if (sub === 'add' || sub === 'remove' || sub === 'enable' || sub === 'disable' || sub === 'run') {
194
+ if (sub === 'run') {
195
+ const scheduleId = args[1] ?? '';
196
+ if (!scheduleId) {
197
+ ctx.print('Usage: /schedule run <schedule-id> --yes');
198
+ return;
199
+ }
200
+ await executeConfirmedOperatorAction(ctx, 'schedules.run', 'scheduleId', scheduleId, args.slice(2), '/schedule run <schedule-id> --yes');
201
+ return;
202
+ }
203
+
204
+ if (sub === 'add' || sub === 'remove' || sub === 'enable' || sub === 'disable') {
193
205
  printReadOnlyScheduleBoundary(ctx.print, `/schedule ${args.join(' ')}`.trim());
194
206
  return;
195
207
  }
@@ -200,9 +212,10 @@ export function registerScheduleRuntimeCommands(registry: CommandRegistry): void
200
212
  + ' /schedule receipts\n'
201
213
  + ' /schedule reconcile\n'
202
214
  + ' /schedule receipt <receipt-id>\n'
215
+ + ' /schedule run <schedule-id> --yes\n'
203
216
  + ' /schedule remind (--cron <expr>|--every <interval>|--at <iso-time>) (--message <text>|<text...>) [--delivery-channel <channel>|--delivery-route <route>|--delivery-webhook <url>] --yes\n'
204
217
  + ' /schedule promote-routine <routine-id> (--cron <expr>|--every <interval>|--at <iso-time>) [--delivery-channel <channel>|--delivery-route <route>|--delivery-webhook <url>] --yes\n'
205
- + ' Local schedule mutations and runs remain blocked.'
218
+ + ' Local schedule mutations remain blocked; schedule run is a confirmed connected-host action.'
206
219
  );
207
220
  },
208
221
  });