@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
@@ -0,0 +1,101 @@
1
+ import type { AgentWorkspaceActionResult, AgentWorkspaceLocalEditor } from './agent-workspace-types.ts';
2
+ import type { AgentWorkspaceSkillBundleCommandEditorKind } from './agent-workspace-skill-bundle-command-editors.ts';
3
+ import { isAgentWorkspaceSkillBundleCommandEditorKind } from './agent-workspace-skill-bundle-command-editors.ts';
4
+ import { quoteSlashCommandArg } from './slash-command-parser.ts';
5
+
6
+ type AgentWorkspaceFieldReader = (fieldId: string) => string;
7
+
8
+ export type AgentWorkspaceSkillBundleCommandEditorSubmission =
9
+ | {
10
+ readonly kind: 'editor';
11
+ readonly editor: AgentWorkspaceLocalEditor;
12
+ readonly status: string;
13
+ readonly actionResult?: AgentWorkspaceActionResult;
14
+ }
15
+ | {
16
+ readonly kind: 'dispatch';
17
+ readonly command: string;
18
+ readonly status: string;
19
+ readonly actionResult: AgentWorkspaceActionResult;
20
+ };
21
+
22
+ export function isAgentWorkspaceSkillBundleCommandSubmissionKind(kind: string): kind is AgentWorkspaceSkillBundleCommandEditorKind {
23
+ return isAgentWorkspaceSkillBundleCommandEditorKind(kind as AgentWorkspaceSkillBundleCommandEditorKind);
24
+ }
25
+
26
+ function isAffirmative(value: string): boolean {
27
+ return /^(y|yes|true)$/i.test(value.trim());
28
+ }
29
+
30
+ function unconfirmed(editor: AgentWorkspaceLocalEditor, message: string): AgentWorkspaceSkillBundleCommandEditorSubmission {
31
+ return {
32
+ kind: 'editor',
33
+ editor: { ...editor, message },
34
+ status: message,
35
+ };
36
+ }
37
+
38
+ function dispatch(command: string, title: string, detail: string, safety: AgentWorkspaceActionResult['safety']): AgentWorkspaceSkillBundleCommandEditorSubmission {
39
+ return {
40
+ kind: 'dispatch',
41
+ command,
42
+ status: `${title}.`,
43
+ actionResult: { kind: 'dispatched', title, detail, command, safety },
44
+ };
45
+ }
46
+
47
+ export function buildAgentWorkspaceSkillBundleCommandEditorSubmission(
48
+ editor: AgentWorkspaceLocalEditor,
49
+ readField: AgentWorkspaceFieldReader,
50
+ ): AgentWorkspaceSkillBundleCommandEditorSubmission {
51
+ if (editor.kind === 'skill-bundle-search') {
52
+ const query = readField('query').trim();
53
+ const command = query.length > 0 ? `/skills bundle search ${quoteSlashCommandArg(query)}` : '/skills bundle search';
54
+ return dispatch(command, 'Opening skill bundle search', 'The workspace handed a read-only skill bundle search command to the shell-owned command router.', 'read-only');
55
+ }
56
+ if (editor.kind === 'skill-bundle-show') {
57
+ return dispatch(
58
+ `/skills bundle show ${quoteSlashCommandArg(readField('id'))}`,
59
+ 'Opening skill bundle detail',
60
+ 'The workspace handed a read-only skill bundle detail command to the shell-owned command router.',
61
+ 'read-only',
62
+ );
63
+ }
64
+ if (editor.kind === 'skill-bundle-update') {
65
+ if (!isAffirmative(readField('confirm'))) return unconfirmed(editor, 'Skill bundle update not confirmed. Type yes, then press Enter.');
66
+ const parts = ['/skills', 'bundle', 'update', quoteSlashCommandArg(readField('id'))];
67
+ const name = readField('name');
68
+ const description = readField('description');
69
+ const skills = readField('skills');
70
+ if (name.length > 0) parts.push('--name', quoteSlashCommandArg(name));
71
+ if (description.length > 0) parts.push('--description', quoteSlashCommandArg(description));
72
+ if (skills.length > 0) parts.push('--skills', quoteSlashCommandArg(skills));
73
+ return dispatch(parts.join(' '), 'Opening skill bundle update', 'The workspace handed a confirmed skill bundle update command to the shell-owned command router.', 'safe');
74
+ }
75
+ if (editor.kind === 'skill-bundle-enable' || editor.kind === 'skill-bundle-disable' || editor.kind === 'skill-bundle-review') {
76
+ if (!isAffirmative(readField('confirm'))) return unconfirmed(editor, 'Skill bundle action not confirmed. Type yes, then press Enter.');
77
+ const verb = editor.kind.replace('skill-bundle-', '');
78
+ return dispatch(
79
+ `/skills bundle ${verb} ${quoteSlashCommandArg(readField('id'))}`,
80
+ `Opening skill bundle ${verb}`,
81
+ `The workspace handed a confirmed skill bundle ${verb} command to the shell-owned command router.`,
82
+ 'safe',
83
+ );
84
+ }
85
+ if (editor.kind === 'skill-bundle-stale') {
86
+ if (!isAffirmative(readField('confirm'))) return unconfirmed(editor, 'Skill bundle stale action not confirmed. Type yes, then press Enter.');
87
+ return dispatch(
88
+ `/skills bundle stale ${quoteSlashCommandArg(readField('id'))} ${quoteSlashCommandArg(readField('reason'))}`,
89
+ 'Opening skill bundle stale review',
90
+ 'The workspace handed a confirmed skill bundle stale command to the shell-owned command router.',
91
+ 'safe',
92
+ );
93
+ }
94
+ if (!isAffirmative(readField('confirm'))) return unconfirmed(editor, 'Skill bundle delete not confirmed. Type yes, then press Enter.');
95
+ return dispatch(
96
+ `/skills bundle delete ${quoteSlashCommandArg(readField('id'))} --yes`,
97
+ 'Opening skill bundle delete',
98
+ 'The workspace handed a confirmed skill bundle delete command to the shell-owned command router.',
99
+ 'safe',
100
+ );
101
+ }
@@ -0,0 +1,110 @@
1
+ import type { AgentWorkspaceEditorKind, AgentWorkspaceLocalEditor } from './agent-workspace-types.ts';
2
+
3
+ export type AgentWorkspaceSkillBundleCommandEditorKind = Extract<
4
+ AgentWorkspaceEditorKind,
5
+ | 'skill-bundle-search'
6
+ | 'skill-bundle-show'
7
+ | 'skill-bundle-update'
8
+ | 'skill-bundle-enable'
9
+ | 'skill-bundle-disable'
10
+ | 'skill-bundle-review'
11
+ | 'skill-bundle-stale'
12
+ | 'skill-bundle-delete'
13
+ >;
14
+
15
+ export function isAgentWorkspaceSkillBundleCommandEditorKind(kind: AgentWorkspaceEditorKind): kind is AgentWorkspaceSkillBundleCommandEditorKind {
16
+ return kind === 'skill-bundle-search'
17
+ || kind === 'skill-bundle-show'
18
+ || kind === 'skill-bundle-update'
19
+ || kind === 'skill-bundle-enable'
20
+ || kind === 'skill-bundle-disable'
21
+ || kind === 'skill-bundle-review'
22
+ || kind === 'skill-bundle-stale'
23
+ || kind === 'skill-bundle-delete';
24
+ }
25
+
26
+ export function createAgentWorkspaceSkillBundleCommandEditor(kind: AgentWorkspaceSkillBundleCommandEditorKind): AgentWorkspaceLocalEditor {
27
+ if (kind === 'skill-bundle-search') {
28
+ return {
29
+ kind,
30
+ mode: 'create',
31
+ title: 'Search Skill Bundles',
32
+ selectedFieldIndex: 0,
33
+ message: 'Search Agent-local skill bundles by name, description, or member skill.',
34
+ fields: [
35
+ { id: 'query', label: 'Search query', value: '', required: false, multiline: false, hint: 'Optional text query. Blank lists every bundle.' },
36
+ ],
37
+ };
38
+ }
39
+ if (kind === 'skill-bundle-show') {
40
+ return {
41
+ kind,
42
+ mode: 'create',
43
+ title: 'Show Skill Bundle',
44
+ selectedFieldIndex: 0,
45
+ message: 'Show one Agent-local skill bundle with readiness and member skills.',
46
+ fields: [
47
+ { id: 'id', label: 'Bundle id', value: '', required: true, multiline: false, hint: 'Existing local skill bundle id.' },
48
+ ],
49
+ };
50
+ }
51
+ if (kind === 'skill-bundle-update') {
52
+ return {
53
+ kind,
54
+ mode: 'update',
55
+ title: 'Update Skill Bundle',
56
+ selectedFieldIndex: 0,
57
+ message: 'Update one Agent-local skill bundle. Type yes on the final field to confirm.',
58
+ fields: [
59
+ { id: 'id', label: 'Bundle id', value: '', required: true, multiline: false, hint: 'Existing local skill bundle id.' },
60
+ { id: 'name', label: 'Name', value: '', required: false, multiline: false, hint: 'Optional replacement name.' },
61
+ { id: 'description', label: 'Description', value: '', required: false, multiline: false, hint: 'Optional replacement one-line description.' },
62
+ { id: 'skills', label: 'Skill ids', value: '', required: false, multiline: false, hint: 'Optional replacement comma-separated local skill ids.' },
63
+ { id: 'confirm', label: 'Confirm', value: '', required: true, multiline: false, hint: 'Type yes to run /skills bundle update.' },
64
+ ],
65
+ };
66
+ }
67
+ if (kind === 'skill-bundle-stale') {
68
+ return {
69
+ kind,
70
+ mode: 'update',
71
+ title: 'Mark Skill Bundle Stale',
72
+ selectedFieldIndex: 0,
73
+ message: 'Mark one Agent-local skill bundle stale with a review reason. Type yes on the final field to confirm.',
74
+ fields: [
75
+ { id: 'id', label: 'Bundle id', value: '', required: true, multiline: false, hint: 'Existing local skill bundle id.' },
76
+ { id: 'reason', label: 'Reason', value: '', required: true, multiline: true, hint: 'Why this bundle needs review. Ctrl-J inserts a new line.' },
77
+ { id: 'confirm', label: 'Confirm', value: '', required: true, multiline: false, hint: 'Type yes to run /skills bundle stale.' },
78
+ ],
79
+ };
80
+ }
81
+ if (kind === 'skill-bundle-delete') {
82
+ return {
83
+ kind,
84
+ mode: 'delete',
85
+ title: 'Delete Skill Bundle',
86
+ selectedFieldIndex: 0,
87
+ message: 'Delete one Agent-local skill bundle. This does not delete member skills. Type yes to confirm.',
88
+ fields: [
89
+ { id: 'id', label: 'Bundle id', value: '', required: true, multiline: false, hint: 'Existing local skill bundle id.' },
90
+ { id: 'confirm', label: 'Confirm', value: '', required: true, multiline: false, hint: 'Type yes to run /skills bundle delete with --yes.' },
91
+ ],
92
+ };
93
+ }
94
+ const verb = kind === 'skill-bundle-enable'
95
+ ? 'Enable'
96
+ : kind === 'skill-bundle-disable'
97
+ ? 'Disable'
98
+ : 'Review';
99
+ return {
100
+ kind,
101
+ mode: 'update',
102
+ title: `${verb} Skill Bundle`,
103
+ selectedFieldIndex: 0,
104
+ message: `${verb} one Agent-local skill bundle. Type yes on the final field to confirm.`,
105
+ fields: [
106
+ { id: 'id', label: 'Bundle id', value: '', required: true, multiline: false, hint: 'Existing local skill bundle id.' },
107
+ { id: 'confirm', label: 'Confirm', value: '', required: true, multiline: false, hint: `Type yes to run /skills bundle ${verb.toLowerCase()}.` },
108
+ ],
109
+ };
110
+ }
@@ -1,29 +1,39 @@
1
1
  import { basename, sep } from 'node:path';
2
2
  import type { MemoryRecord } from '@pellux/goodvibes-sdk/platform/state';
3
3
  import type { CommandContext } from './command-registry.ts';
4
+ import { AgentNoteRegistry, type AgentNoteRecord } from '../agent/note-registry.ts';
4
5
  import { AgentPersonaRegistry, type AgentPersonaRecord } from '../agent/persona-registry.ts';
5
- import { AgentRoutineRegistry, type AgentRoutineRecord } from '../agent/routine-registry.ts';
6
- import { AgentSkillRegistry, type AgentSkillBundleRecord, type AgentSkillRecord } from '../agent/skill-registry.ts';
6
+ import { formatAgentRecordOrigin } from '../agent/record-labels.ts';
7
+ import { AgentRoutineRegistry, evaluateAgentRoutineReadiness, type AgentRoutineRecord } from '../agent/routine-registry.ts';
8
+ import {
9
+ AgentSkillRegistry,
10
+ evaluateAgentSkillBundleReadiness,
11
+ evaluateAgentSkillReadiness,
12
+ formatAgentSkillRequirement,
13
+ type AgentSkillBundleRecord,
14
+ type AgentSkillRecord,
15
+ } from '../agent/skill-registry.ts';
7
16
  import { summarizeAgentBehaviorDiscovery } from '../agent/behavior-discovery-summary.ts';
8
17
  import { isPromptActiveMemory } from '../agent/memory-prompt.ts';
9
- import { getAgentRuntimeProfilesRoot, listAgentRuntimeProfiles, listAgentRuntimeProfileTemplates } from '../agent/runtime-profile.ts';
18
+ import { getAgentRuntimeProfilesRoot, listAgentRuntimeProfiles, listAgentRuntimeProfileTemplates, readAgentRuntimeProfileSelection } from '../agent/runtime-profile.ts';
19
+ import { RoutineScheduleReceiptStore } from '../agent/routine-schedule-receipts.ts';
20
+ import { GOODVIBES_AGENT_PAIRING_SURFACE } from '../config/surface.ts';
21
+ import { connectedHostOperatorTokenFingerprint, readConnectedHostOperatorToken, type ConnectedHostOperatorToken } from '../runtime/connected-host-auth.ts';
10
22
  import { buildAgentWorkspaceChannels } from './agent-workspace-channels.ts';
23
+ import { getAgentWorkspaceConfigReader } from './agent-workspace-config-reader.ts';
11
24
  import { buildAgentWorkspaceSetupChecklist } from './agent-workspace-setup.ts';
12
25
  import { buildAgentWorkspaceVoiceMediaReadiness, type AgentWorkspaceVoiceMediaProviderDescriptor } from './agent-workspace-voice-media.ts';
13
26
  import type {
14
27
  AgentWorkspaceLocalLibraryItem,
28
+ AgentWorkspaceRoutineScheduleReceiptSummary,
15
29
  AgentWorkspaceRuntimeProfileItem,
16
30
  AgentWorkspaceRuntimeSnapshot,
17
31
  AgentWorkspaceRuntimeStarterTemplateItem,
18
32
  } from './agent-workspace-types.ts';
19
33
 
20
- type AgentWorkspaceConfigReader = {
21
- get(key: string): unknown;
22
- };
23
-
24
34
  function readConfigString(context: CommandContext, key: string, fallback: string): string {
25
35
  try {
26
- const configManager = context.platform?.configManager as unknown as AgentWorkspaceConfigReader | undefined;
36
+ const configManager = getAgentWorkspaceConfigReader(context);
27
37
  const value = configManager?.get(key);
28
38
  return typeof value === 'string' && value.trim().length > 0 ? value.trim() : fallback;
29
39
  } catch {
@@ -33,7 +43,7 @@ function readConfigString(context: CommandContext, key: string, fallback: string
33
43
 
34
44
  function readConfigNumber(context: CommandContext, key: string, fallback: number): number {
35
45
  try {
36
- const configManager = context.platform?.configManager as unknown as AgentWorkspaceConfigReader | undefined;
46
+ const configManager = getAgentWorkspaceConfigReader(context);
37
47
  const value = configManager?.get(key);
38
48
  const numberValue = typeof value === 'number' ? value : Number(value);
39
49
  return Number.isFinite(numberValue) ? numberValue : fallback;
@@ -44,7 +54,7 @@ function readConfigNumber(context: CommandContext, key: string, fallback: number
44
54
 
45
55
  function readConfigBoolean(context: CommandContext, key: string, fallback: boolean): boolean {
46
56
  try {
47
- const configManager = context.platform?.configManager as unknown as AgentWorkspaceConfigReader | undefined;
57
+ const configManager = getAgentWorkspaceConfigReader(context);
48
58
  const value = configManager?.get(key);
49
59
  if (typeof value === 'boolean') return value;
50
60
  if (typeof value === 'string') {
@@ -63,13 +73,19 @@ function inferActiveRuntimeProfile(homeDirectory: string): string {
63
73
  return homeDirectory.includes(marker) ? basename(homeDirectory) : '(default home)';
64
74
  }
65
75
 
76
+ function inferRuntimeProfileBaseHome(homeDirectory: string): string {
77
+ const marker = `${sep}.goodvibes${sep}agent${sep}profile-homes${sep}`;
78
+ const markerIndex = homeDirectory.indexOf(marker);
79
+ return markerIndex >= 0 ? homeDirectory.slice(0, markerIndex) : homeDirectory;
80
+ }
81
+
66
82
  function summarizePersonaItem(persona: AgentPersonaRecord, activePersonaId: string | null): AgentWorkspaceLocalLibraryItem {
67
83
  return {
68
84
  id: persona.id,
69
85
  name: persona.name,
70
86
  description: persona.description,
71
87
  reviewState: persona.reviewState,
72
- source: persona.source,
88
+ source: formatAgentRecordOrigin(persona.source, persona.provenance),
73
89
  tags: persona.tags,
74
90
  triggers: persona.triggers,
75
91
  active: persona.id === activePersonaId,
@@ -77,45 +93,76 @@ function summarizePersonaItem(persona: AgentPersonaRecord, activePersonaId: stri
77
93
  }
78
94
 
79
95
  function summarizeSkillItem(skill: AgentSkillRecord): AgentWorkspaceLocalLibraryItem {
96
+ const readiness = evaluateAgentSkillReadiness(skill);
80
97
  return {
81
98
  id: skill.id,
82
99
  name: skill.name,
83
100
  description: skill.description,
84
101
  reviewState: skill.reviewState,
85
- source: skill.source,
102
+ source: formatAgentRecordOrigin(skill.source, skill.provenance),
86
103
  tags: skill.tags,
87
104
  triggers: skill.triggers,
88
105
  enabled: skill.enabled,
106
+ requirementCount: skill.requirements.length,
107
+ missingRequirementCount: readiness.missing.length,
108
+ missingRequirements: readiness.missing.map(formatAgentSkillRequirement),
89
109
  };
90
110
  }
91
111
 
92
- function summarizeSkillBundleItem(bundle: AgentSkillBundleRecord): AgentWorkspaceLocalLibraryItem {
112
+ function summarizeSkillBundleItem(bundle: AgentSkillBundleRecord, skills: readonly AgentSkillRecord[]): AgentWorkspaceLocalLibraryItem {
113
+ const readiness = evaluateAgentSkillBundleReadiness(bundle, skills);
114
+ const missing = [
115
+ ...readiness.missingRequirements.map(formatAgentSkillRequirement),
116
+ ...readiness.missingSkillIds.map((skillId) => `skill:${skillId}`),
117
+ ];
93
118
  return {
94
119
  id: bundle.id,
95
120
  name: bundle.name,
96
121
  description: `${bundle.description} Skills: ${bundle.skillIds.join(', ')}`,
97
122
  reviewState: bundle.reviewState,
98
- source: bundle.source,
123
+ source: formatAgentRecordOrigin(bundle.source, bundle.provenance),
99
124
  tags: bundle.skillIds,
100
125
  triggers: [],
101
126
  enabled: bundle.enabled,
127
+ requirementCount: readiness.includedSkills.reduce((total, skill) => total + skill.requirements.length, 0) + readiness.missingSkillIds.length,
128
+ missingRequirementCount: missing.length,
129
+ missingRequirements: missing,
102
130
  };
103
131
  }
104
132
 
105
133
  function summarizeRoutineItem(routine: AgentRoutineRecord): AgentWorkspaceLocalLibraryItem {
134
+ const readiness = evaluateAgentRoutineReadiness(routine);
106
135
  return {
107
136
  id: routine.id,
108
137
  name: routine.name,
109
138
  description: routine.description,
110
139
  reviewState: routine.reviewState,
111
- source: routine.source,
140
+ source: formatAgentRecordOrigin(routine.source, routine.provenance),
112
141
  tags: routine.tags,
113
142
  triggers: routine.triggers,
114
143
  enabled: routine.enabled,
144
+ requirementCount: routine.requirements.length,
145
+ missingRequirementCount: readiness.missing.length,
146
+ missingRequirements: readiness.missing.map(formatAgentSkillRequirement),
115
147
  startCount: routine.startCount,
116
148
  };
117
149
  }
118
150
 
151
+ function summarizeRoutineScheduleReceipt(
152
+ receipt: ReturnType<RoutineScheduleReceiptStore['snapshot']>['receipts'][number],
153
+ ): AgentWorkspaceRoutineScheduleReceiptSummary {
154
+ return {
155
+ id: receipt.id,
156
+ status: receipt.status,
157
+ routineId: receipt.routineId,
158
+ routineName: receipt.routineName,
159
+ scheduleName: receipt.scheduleName,
160
+ scheduleKind: receipt.scheduleKind,
161
+ scheduleValue: receipt.scheduleValue,
162
+ createdAt: receipt.createdAt,
163
+ };
164
+ }
165
+
119
166
  function summarizeMemoryItem(record: MemoryRecord): AgentWorkspaceLocalLibraryItem {
120
167
  const detail = record.detail?.trim();
121
168
  return {
@@ -123,7 +170,7 @@ function summarizeMemoryItem(record: MemoryRecord): AgentWorkspaceLocalLibraryIt
123
170
  name: record.summary,
124
171
  description: detail && detail.length > 0 ? detail : `${record.scope}/${record.cls}`,
125
172
  reviewState: record.reviewState,
126
- source: 'agent-memory',
173
+ source: 'Agent memory',
127
174
  tags: record.tags,
128
175
  triggers: [],
129
176
  scope: record.scope,
@@ -132,6 +179,22 @@ function summarizeMemoryItem(record: MemoryRecord): AgentWorkspaceLocalLibraryIt
132
179
  };
133
180
  }
134
181
 
182
+ function summarizeNoteItem(note: AgentNoteRecord): AgentWorkspaceLocalLibraryItem {
183
+ const preview = note.body.replace(/\s+/g, ' ').trim();
184
+ const description = note.sourceUrl
185
+ ? `${preview.slice(0, 160)}${preview.length > 160 ? '...' : ''} Origin URL ${note.sourceUrl}`
186
+ : preview;
187
+ return {
188
+ id: note.id,
189
+ name: note.title,
190
+ description,
191
+ reviewState: note.reviewState,
192
+ source: formatAgentRecordOrigin(note.source, note.provenance),
193
+ tags: note.tags,
194
+ triggers: [],
195
+ };
196
+ }
197
+
135
198
  function summarizeRuntimeProfile(profile: ReturnType<typeof listAgentRuntimeProfiles>[number]): AgentWorkspaceRuntimeProfileItem {
136
199
  return {
137
200
  id: profile.id,
@@ -202,6 +265,20 @@ export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): Age
202
265
  return { count: 0, activeName: '(unavailable)', items: [] };
203
266
  }
204
267
  })();
268
+ const noteSnapshot = (() => {
269
+ try {
270
+ const shellPaths = context.workspace?.shellPaths;
271
+ if (!shellPaths) return { count: 0, reviewQueueCount: 0, items: [] };
272
+ const snapshot = AgentNoteRegistry.fromShellPaths(shellPaths).snapshot();
273
+ return {
274
+ count: snapshot.notes.length,
275
+ reviewQueueCount: snapshot.reviewQueue.length,
276
+ items: snapshot.notes.map(summarizeNoteItem),
277
+ };
278
+ } catch {
279
+ return { count: 0, reviewQueueCount: 0, items: [] };
280
+ }
281
+ })();
205
282
  const skillSnapshot = (() => {
206
283
  try {
207
284
  const shellPaths = context.workspace?.shellPaths;
@@ -214,7 +291,7 @@ export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): Age
214
291
  bundleCount: snapshot.bundles.length,
215
292
  enabledBundleCount: snapshot.enabledBundles.length,
216
293
  items: snapshot.skills.map(summarizeSkillItem),
217
- bundleItems: snapshot.bundles.map(summarizeSkillBundleItem),
294
+ bundleItems: snapshot.bundles.map((bundle) => summarizeSkillBundleItem(bundle, snapshot.skills)),
218
295
  };
219
296
  } catch {
220
297
  return { count: 0, enabled: 0, active: 0, bundleCount: 0, enabledBundleCount: 0, items: [], bundleItems: [] };
@@ -234,21 +311,44 @@ export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): Age
234
311
  return { count: 0, enabled: 0, items: [] };
235
312
  }
236
313
  })();
314
+ const routineScheduleReceipts = (() => {
315
+ try {
316
+ const shellPaths = context.workspace?.shellPaths;
317
+ if (!shellPaths) return { count: 0, successful: 0, failed: 0, latest: null };
318
+ const receipts = RoutineScheduleReceiptStore.fromShellPaths(shellPaths).snapshot().receipts;
319
+ return {
320
+ count: receipts.length,
321
+ successful: receipts.filter((receipt) => receipt.status === 'created').length,
322
+ failed: receipts.filter((receipt) => receipt.status === 'failed').length,
323
+ latest: receipts[0] ? summarizeRoutineScheduleReceipt(receipts[0]) : null,
324
+ };
325
+ } catch {
326
+ return { count: 0, successful: 0, failed: 0, latest: null };
327
+ }
328
+ })();
237
329
  const discoveredBehavior = summarizeAgentBehaviorDiscovery(context.workspace?.shellPaths);
330
+ const profileBaseHome = inferRuntimeProfileBaseHome(context.workspace?.shellPaths?.homeDirectory ?? '');
238
331
  const runtimeProfiles = (() => {
239
332
  try {
240
- return listAgentRuntimeProfiles(context.workspace?.shellPaths?.homeDirectory ?? '');
333
+ return listAgentRuntimeProfiles(profileBaseHome);
241
334
  } catch {
242
335
  return [];
243
336
  }
244
337
  })();
245
338
  const runtimeStarterTemplates = (() => {
246
339
  try {
247
- return listAgentRuntimeProfileTemplates(context.workspace?.shellPaths?.homeDirectory ?? '');
340
+ return listAgentRuntimeProfileTemplates(profileBaseHome);
248
341
  } catch {
249
342
  return [];
250
343
  }
251
344
  })();
345
+ const selectedRuntimeProfile = (() => {
346
+ try {
347
+ return readAgentRuntimeProfileSelection(profileBaseHome);
348
+ } catch {
349
+ return null;
350
+ }
351
+ })();
252
352
  const voiceProviders = (() => {
253
353
  try {
254
354
  return context.platform?.voiceProviderRegistry?.list?.() ?? [];
@@ -299,6 +399,32 @@ export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): Age
299
399
  const ttsLlmProvider = readConfigString(context, 'tts.llmProvider', '');
300
400
  const ttsLlmModel = readConfigString(context, 'tts.llmModel', '');
301
401
  const runtimeBaseUrl = `http://${host}:${port}`;
402
+ const companionAccess = (() => {
403
+ const homeDirectory = context.workspace?.shellPaths?.homeDirectory ?? '';
404
+ const tokenRecord: ConnectedHostOperatorToken = homeDirectory.length > 0
405
+ ? readConnectedHostOperatorToken(homeDirectory)
406
+ : { path: '(Agent home unavailable)', present: false, token: null };
407
+ const tokenFingerprint = tokenRecord.token ? connectedHostOperatorTokenFingerprint(tokenRecord.token) : null;
408
+ const pairingReady = Boolean(tokenRecord.token);
409
+ const nextStep = tokenRecord.error
410
+ ? 'Repair the connected-host operator token file through the owning GoodVibes host, then rerun /pair.'
411
+ : pairingReady
412
+ ? 'Use /pair to scan the QR code. Manual token display stays hidden unless /pair --show-token --yes is used.'
413
+ : 'Pair or provision connected-host access through the owning GoodVibes host, then rerun /pair.';
414
+ return {
415
+ surface: GOODVIBES_AGENT_PAIRING_SURFACE,
416
+ hostUrl: runtimeBaseUrl,
417
+ tokenPath: tokenRecord.path,
418
+ tokenPresent: tokenRecord.present,
419
+ tokenReadable: Boolean(tokenRecord.token),
420
+ tokenFingerprint,
421
+ tokenError: tokenRecord.error ?? null,
422
+ pairingReady,
423
+ qrCommand: '/pair',
424
+ manualTokenCommand: '/pair --show-token --yes',
425
+ nextStep,
426
+ } as const;
427
+ })();
302
428
  const channels = buildAgentWorkspaceChannels(context);
303
429
  const voiceMediaReadiness = buildAgentWorkspaceVoiceMediaReadiness({
304
430
  context,
@@ -312,12 +438,16 @@ export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): Age
312
438
  sessionMemoryCount,
313
439
  localMemoryCount: memorySnapshot.count,
314
440
  localMemoryReviewQueueCount: memorySnapshot.reviewQueueCount,
441
+ localNoteCount: noteSnapshot.count,
442
+ localNoteReviewQueueCount: noteSnapshot.reviewQueueCount,
315
443
  routineCount: routineSnapshot.count,
316
444
  enabledRoutineCount: routineSnapshot.enabled,
445
+ missingRoutineRequirementCount: routineSnapshot.items.reduce((total, item) => total + (item.missingRequirementCount ?? 0), 0),
317
446
  skillCount: skillSnapshot.count,
318
447
  enabledSkillCount: skillSnapshot.enabled,
319
448
  skillBundleCount: skillSnapshot.bundleCount,
320
449
  enabledSkillBundleCount: skillSnapshot.enabledBundleCount,
450
+ missingSkillRequirementCount: skillSnapshot.items.reduce((total, item) => total + (item.missingRequirementCount ?? 0), 0),
321
451
  activePersonaName: personaSnapshot.activeName,
322
452
  discoveredPersonas: discoveredBehavior.personas,
323
453
  discoveredSkills: discoveredBehavior.skills,
@@ -343,9 +473,16 @@ export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): Age
343
473
  localMemoryReviewQueueCount: memorySnapshot.reviewQueueCount,
344
474
  localMemoryPromptActiveCount: memorySnapshot.promptActiveCount,
345
475
  localMemories: memorySnapshot.items,
476
+ localNoteCount: noteSnapshot.count,
477
+ localNoteReviewQueueCount: noteSnapshot.reviewQueueCount,
478
+ localNotes: noteSnapshot.items,
346
479
  localRoutineCount: routineSnapshot.count,
347
480
  enabledRoutineCount: routineSnapshot.enabled,
348
481
  localRoutines: routineSnapshot.items,
482
+ routineScheduleReceiptCount: routineScheduleReceipts.count,
483
+ successfulRoutineScheduleReceiptCount: routineScheduleReceipts.successful,
484
+ failedRoutineScheduleReceiptCount: routineScheduleReceipts.failed,
485
+ latestRoutineScheduleReceipt: routineScheduleReceipts.latest,
349
486
  localSkillCount: skillSnapshot.count,
350
487
  enabledSkillCount: skillSnapshot.enabled,
351
488
  localSkillBundleCount: skillSnapshot.bundleCount,
@@ -360,7 +497,8 @@ export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): Age
360
497
  knowledgeRoute: '/api/goodvibes-agent/knowledge',
361
498
  knowledgeIsolation: 'agent-only',
362
499
  executionPolicy: 'serial-proactive',
363
- wrfcPolicy: 'explicit-build-delegation-only',
500
+ delegatedReviewPolicy: 'explicit-build-delegation-only',
501
+ companionAccess,
364
502
  channels,
365
503
  voiceProviderCount: voiceProviders.length,
366
504
  voiceStreamingProviderCount: voiceProviders.filter((entry) => entry.capabilities.includes('tts-stream')).length,
@@ -381,9 +519,12 @@ export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): Age
381
519
  browserToolExposureEnabled: readConfigBoolean(context, 'web.enabled', false),
382
520
  browserToolPublicBaseUrl: readConfigString(context, 'web.publicBaseUrl', '(not configured)'),
383
521
  activeRuntimeProfile: inferActiveRuntimeProfile(context.workspace?.shellPaths?.homeDirectory ?? ''),
522
+ selectedRuntimeProfile: selectedRuntimeProfile?.id ?? null,
523
+ selectedRuntimeProfileExists: selectedRuntimeProfile?.exists ?? false,
524
+ selectedRuntimeProfileSelectedAt: selectedRuntimeProfile?.selectedAt ?? null,
384
525
  runtimeProfileCount: runtimeProfiles.length,
385
526
  runtimeProfiles: runtimeProfiles.map(summarizeRuntimeProfile),
386
- runtimeProfileRoot: getAgentRuntimeProfilesRoot(context.workspace?.shellPaths?.homeDirectory ?? ''),
527
+ runtimeProfileRoot: getAgentRuntimeProfilesRoot(profileBaseHome),
387
528
  runtimeStarterTemplateCount: runtimeStarterTemplates.length,
388
529
  localStarterTemplateCount: runtimeStarterTemplates.filter((template) => template.source === 'local').length,
389
530
  runtimeStarterTemplates: runtimeStarterTemplates.map(summarizeStarterTemplate),
@@ -0,0 +1,61 @@
1
+ import type { AgentWorkspaceActionResult, AgentWorkspaceEditorKind, AgentWorkspaceLocalEditor } from './agent-workspace-types.ts';
2
+ import type { AgentWorkspaceTaskCommandEditorKind } from './agent-workspace-task-command-editors.ts';
3
+ import { isAgentWorkspaceTaskCommandEditorKind } from './agent-workspace-task-command-editors.ts';
4
+ import { quoteSlashCommandArg } from './slash-command-parser.ts';
5
+
6
+ type AgentWorkspaceFieldReader = (fieldId: string) => string;
7
+
8
+ export type AgentWorkspaceTaskCommandEditorSubmission =
9
+ | {
10
+ readonly kind: 'editor';
11
+ readonly editor: AgentWorkspaceLocalEditor;
12
+ readonly status: string;
13
+ readonly actionResult?: AgentWorkspaceActionResult;
14
+ }
15
+ | {
16
+ readonly kind: 'dispatch';
17
+ readonly command: string;
18
+ readonly status: string;
19
+ readonly actionResult: AgentWorkspaceActionResult;
20
+ };
21
+
22
+ export function isAgentWorkspaceTaskCommandSubmissionKind(kind: AgentWorkspaceEditorKind): kind is AgentWorkspaceTaskCommandEditorKind {
23
+ return isAgentWorkspaceTaskCommandEditorKind(kind);
24
+ }
25
+
26
+ export function buildAgentWorkspaceTaskCommandEditorSubmission(
27
+ editor: AgentWorkspaceLocalEditor,
28
+ readField: AgentWorkspaceFieldReader,
29
+ ): AgentWorkspaceTaskCommandEditorSubmission {
30
+ if (editor.kind === 'task-list-filter') {
31
+ const filter = readField('filter');
32
+ const command = filter.length > 0 ? `/tasks list ${quoteSlashCommandArg(filter)}` : '/tasks list';
33
+ return {
34
+ kind: 'dispatch',
35
+ command,
36
+ status: 'Opening filtered task list.',
37
+ actionResult: {
38
+ kind: 'dispatched',
39
+ title: 'Opening filtered task list',
40
+ detail: 'The workspace handed read-only connected-host task listing to the shell-owned command router.',
41
+ command,
42
+ safety: 'read-only',
43
+ },
44
+ };
45
+ }
46
+ const subcommand = editor.kind === 'task-output' ? 'output' : 'show';
47
+ const command = `/tasks ${subcommand} ${quoteSlashCommandArg(readField('taskId'))}`;
48
+ const title = editor.kind === 'task-output' ? 'Opening task output' : 'Opening task inspection';
49
+ return {
50
+ kind: 'dispatch',
51
+ command,
52
+ status: `${title}.`,
53
+ actionResult: {
54
+ kind: 'dispatched',
55
+ title,
56
+ detail: 'The workspace handed read-only connected-host task inspection to the shell-owned command router.',
57
+ command,
58
+ safety: 'read-only',
59
+ },
60
+ };
61
+ }