@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,5 +1,14 @@
1
- import { AgentSkillRegistry, type AgentSkillBundleRecord, type AgentSkillRecord } from '../../agent/skill-registry.ts';
1
+ import {
2
+ AgentSkillRegistry,
3
+ buildAgentSkillRequirements,
4
+ evaluateAgentSkillBundleReadiness,
5
+ evaluateAgentSkillReadiness,
6
+ formatAgentSkillRequirement,
7
+ type AgentSkillBundleRecord,
8
+ type AgentSkillRecord,
9
+ } from '../../agent/skill-registry.ts';
2
10
  import { discoverSkills, type SkillRecord } from '../../agent/skill-discovery.ts';
11
+ import { formatAgentRecordOrigin, formatAgentRecordReviewState } from '../../agent/record-labels.ts';
3
12
  import type { CommandContext, CommandRegistry } from '../command-registry.ts';
4
13
  import { requireShellPaths } from './runtime-services.ts';
5
14
 
@@ -50,35 +59,56 @@ function requiredFlag(flags: ReadonlyMap<string, string>, key: string): string {
50
59
  return value;
51
60
  }
52
61
 
62
+ function formatSkillReceipt(title: string, record: { readonly id: string; readonly name: string }, extra: readonly string[] = []): string {
63
+ return [
64
+ `${title} ${record.id}`,
65
+ ` id ${record.id}`,
66
+ ` name ${record.name}`,
67
+ ...extra,
68
+ ].join('\n');
69
+ }
70
+
53
71
  function summarizeSkill(skill: AgentSkillRecord): string {
54
72
  const enabled = skill.enabled ? 'enabled' : 'disabled';
55
- const tags = skill.tags.length > 0 ? ` tags=${skill.tags.join(',')}` : '';
56
- return ` ${skill.id} ${enabled} ${skill.reviewState} ${skill.name} - ${skill.description}${tags}`;
73
+ const tags = skill.tags.length > 0 ? ` tags ${skill.tags.join(', ')}` : '';
74
+ const readiness = evaluateAgentSkillReadiness(skill);
75
+ const review = formatAgentRecordReviewState(skill.reviewState);
76
+ const ready = readiness.ready ? 'ready' : `needs ${readiness.missing.map(formatAgentSkillRequirement).join(',')}`;
77
+ return ` ${skill.id} ${enabled} ${review} ${ready} ${skill.name} - ${skill.description}${tags}`;
57
78
  }
58
79
 
59
- function summarizeBundle(bundle: AgentSkillBundleRecord): string {
80
+ function summarizeBundle(bundle: AgentSkillBundleRecord, skills: readonly AgentSkillRecord[]): string {
60
81
  const enabled = bundle.enabled ? 'enabled' : 'disabled';
61
- return ` ${bundle.id} ${enabled} ${bundle.reviewState} ${bundle.name} - ${bundle.description} skills=${bundle.skillIds.join(',')}`;
82
+ const readiness = evaluateAgentSkillBundleReadiness(bundle, skills);
83
+ const review = formatAgentRecordReviewState(bundle.reviewState);
84
+ const missing = [
85
+ ...readiness.missingRequirements.map(formatAgentSkillRequirement),
86
+ ...readiness.missingSkillIds.map((skillId) => `skill ${skillId}`),
87
+ ];
88
+ const ready = readiness.ready ? 'ready' : `needs ${missing.join(',')}`;
89
+ return ` ${bundle.id} ${enabled} ${review} ${ready} ${bundle.name} - ${bundle.description} skills ${bundle.skillIds.join(', ')}`;
62
90
  }
63
91
 
64
- function renderList(title: string, registry: AgentSkillRegistry, skills: readonly AgentSkillRecord[]): string {
92
+ function renderList(title: string, registry: AgentSkillRegistry, skills: readonly AgentSkillRecord[], emptyMessage?: string): string {
65
93
  const snapshot = registry.snapshot();
66
94
  if (skills.length === 0) {
67
- return `${title}\n No local Agent skills yet. Create one with /agent-skills create --name <name> --description <summary> --procedure <steps>.`;
95
+ return emptyMessage
96
+ ? `${title}\n ${emptyMessage}`
97
+ : `${title}\n No Agent-local skills yet. Create one with /skills create --name <name> --description <summary> --procedure <steps>.`;
68
98
  }
69
99
  return [
70
100
  `${title} (${skills.length})`,
71
- ` store: ${snapshot.path}`,
72
- ` enabled: ${snapshot.enabledSkills.length}`,
101
+ ` store ${snapshot.path}`,
102
+ ` enabled ${snapshot.enabledSkills.length}`,
73
103
  ...skills.map(summarizeSkill),
74
104
  ].join('\n');
75
105
  }
76
106
 
77
107
  function summarizeDiscoveredSkill(skill: SkillRecord): string {
78
108
  const description = skill.description ? ` - ${skill.description}` : '';
79
- const dependencies = skill.dependencies.length > 0 ? ` deps=${skill.dependencies.join(',')}` : '';
80
- const includes = skill.includes.length > 0 ? ` includes=${skill.includes.join(',')}` : '';
81
- return ` ${skill.name} ${skill.origin}${description}${dependencies}${includes}\n path: ${skill.path}`;
109
+ const dependencies = skill.dependencies.length > 0 ? ` deps ${skill.dependencies.join(', ')}` : '';
110
+ const includes = skill.includes.length > 0 ? ` includes ${skill.includes.join(', ')}` : '';
111
+ return ` ${skill.name} ${skill.origin}${description}${dependencies}${includes}\n path ${skill.path}`;
82
112
  }
83
113
 
84
114
  function renderDiscoveredSkills(skills: readonly SkillRecord[]): string {
@@ -93,7 +123,7 @@ function renderDiscoveredSkills(skills: readonly SkillRecord[]): string {
93
123
  `Discovered Agent skill files (${skills.length})`,
94
124
  ...skills.map(summarizeDiscoveredSkill),
95
125
  '',
96
- 'Import one with: /agent-skills import-discovered <name> --yes',
126
+ 'Import one with: /skills import-discovered <name> --yes',
97
127
  ].join('\n');
98
128
  }
99
129
 
@@ -120,27 +150,35 @@ function frontmatterList(skill: SkillRecord, key: string): readonly string[] {
120
150
  return splitList(value);
121
151
  }
122
152
 
153
+ function frontmatterAnyList(skill: SkillRecord, keys: readonly string[]): readonly string[] {
154
+ for (const key of keys) {
155
+ const values = frontmatterList(skill, key);
156
+ if (values.length > 0) return values;
157
+ }
158
+ return [];
159
+ }
160
+
123
161
  async function importDiscoveredSkill(args: readonly string[], ctx: CommandContext, skillRegistry: AgentSkillRegistry): Promise<void> {
124
162
  const parsed = parseSkillArgs(args);
125
163
  const name = parsed.rest.join(' ').trim();
126
164
  if (!name) {
127
- ctx.print('Usage: /agent-skills import-discovered <name> [--enabled] --yes');
165
+ ctx.print('Usage: /skills import-discovered <name> [--enabled] --yes');
128
166
  return;
129
167
  }
130
168
  const discovered = findDiscoveredSkill(await discoverSkills(requireShellPaths(ctx)), name);
131
169
  if (!discovered) {
132
- ctx.print(`Unknown discovered Agent skill: ${name}\nRun /agent-skills discover to inspect available skill files.`);
170
+ ctx.print(`Unknown discovered Agent skill ${name}\nRun /skills discover to inspect available skill files.`);
133
171
  return;
134
172
  }
135
173
  if (!parsed.yes) {
136
174
  ctx.print([
137
175
  'Agent skill import preview',
138
- ` name: ${discovered.name}`,
139
- ` origin: ${discovered.origin}`,
140
- ` path: ${discovered.path}`,
141
- ` description: ${discovered.description || '(none)'}`,
142
- ` procedure characters: ${discovered.body.length}`,
143
- ' next: rerun with --yes to import into the Agent-local skill registry',
176
+ ` name ${discovered.name}`,
177
+ ` origin ${discovered.origin}`,
178
+ ` path ${discovered.path}`,
179
+ ` description ${discovered.description || '(none)'}`,
180
+ ` procedure characters ${discovered.body.length}`,
181
+ ' next rerun with --yes to import into the Agent-local skill registry',
144
182
  ].join('\n'));
145
183
  return;
146
184
  }
@@ -150,35 +188,44 @@ async function importDiscoveredSkill(args: readonly string[], ctx: CommandContex
150
188
  procedure: discovered.body,
151
189
  triggers: frontmatterList(discovered, 'triggers'),
152
190
  tags: frontmatterList(discovered, 'tags'),
191
+ requirements: buildAgentSkillRequirements({
192
+ env: frontmatterAnyList(discovered, ['requiresEnv', 'requires-env', 'requires_env']),
193
+ commands: frontmatterAnyList(discovered, ['requiresCommands', 'requires-commands', 'requires_commands', 'commands']),
194
+ }),
153
195
  enabled: parsed.flags.get('enabled') === 'true',
154
196
  source: 'imported',
155
- provenance: `discovered:${discovered.origin}:${discovered.path}`,
197
+ provenance: `Imported file (${discovered.origin}): ${discovered.path}`,
156
198
  });
157
- ctx.print(`Imported Agent skill ${skill.id}: ${skill.name}`);
199
+ ctx.print(formatSkillReceipt('Imported Agent skill', skill, [` enabled ${skill.enabled ? 'yes' : 'no'}`]));
158
200
  }
159
201
 
160
- function renderBundleList(title: string, registry: AgentSkillRegistry, bundles: readonly AgentSkillBundleRecord[]): string {
202
+ function renderBundleList(title: string, registry: AgentSkillRegistry, bundles: readonly AgentSkillBundleRecord[], emptyMessage?: string): string {
161
203
  const snapshot = registry.snapshot();
162
204
  if (bundles.length === 0) {
163
- return `${title}\n No local Agent skill bundles yet. Create one with /agent-skills bundle create --name <name> --description <summary> --skills <id,id>.`;
205
+ return emptyMessage
206
+ ? `${title}\n ${emptyMessage}`
207
+ : `${title}\n No Agent-local skill bundles yet. Create one with /skills bundle create --name <name> --description <summary> --skills <id,id>.`;
164
208
  }
165
209
  return [
166
210
  `${title} (${bundles.length})`,
167
- ` store: ${snapshot.path}`,
211
+ ` store ${snapshot.path}`,
168
212
  ` enabled bundles: ${snapshot.enabledBundles.length}`,
169
213
  ` active skills: ${snapshot.activeSkills.length}`,
170
- ...bundles.map(summarizeBundle),
214
+ ...bundles.map((bundle) => summarizeBundle(bundle, snapshot.skills)),
171
215
  ].join('\n');
172
216
  }
173
217
 
174
218
  function renderSkill(skill: AgentSkillRecord): string {
219
+ const readiness = evaluateAgentSkillReadiness(skill);
175
220
  return [
176
221
  `Skill ${skill.name}`,
177
- ` id: ${skill.id}`,
222
+ ` id ${skill.id}`,
178
223
  ` enabled: ${skill.enabled ? 'yes' : 'no'}`,
179
- ` review: ${skill.reviewState}`,
180
- ` source: ${skill.source}`,
181
- ` provenance: ${skill.provenance}`,
224
+ ` readiness: ${readiness.ready ? 'ready' : 'needs setup'}`,
225
+ ` requirements: ${skill.requirements.map(formatAgentSkillRequirement).join(', ') || '(none)'}`,
226
+ readiness.missing.length > 0 ? ` missing: ${readiness.missing.map(formatAgentSkillRequirement).join(', ')}` : '',
227
+ ` review: ${formatAgentRecordReviewState(skill.reviewState)}`,
228
+ ` origin: ${formatAgentRecordOrigin(skill.source, skill.provenance)}`,
182
229
  ` tags: ${skill.tags.join(', ') || '(none)'}`,
183
230
  ` triggers: ${skill.triggers.join(', ') || '(manual)'}`,
184
231
  ` created: ${skill.createdAt}`,
@@ -195,13 +242,19 @@ function renderBundle(bundle: AgentSkillBundleRecord, registry: AgentSkillRegist
195
242
  const skills = bundle.skillIds
196
243
  .map((skillId) => registry.get(skillId))
197
244
  .filter((skill): skill is AgentSkillRecord => skill !== null);
245
+ const readiness = evaluateAgentSkillBundleReadiness(bundle, registry.snapshot().skills);
246
+ const missing = [
247
+ ...readiness.missingRequirements.map(formatAgentSkillRequirement),
248
+ ...readiness.missingSkillIds.map((skillId) => `skill ${skillId}`),
249
+ ];
198
250
  return [
199
251
  `Skill Bundle ${bundle.name}`,
200
- ` id: ${bundle.id}`,
252
+ ` id ${bundle.id}`,
201
253
  ` enabled: ${bundle.enabled ? 'yes' : 'no'}`,
202
- ` review: ${bundle.reviewState}`,
203
- ` source: ${bundle.source}`,
204
- ` provenance: ${bundle.provenance}`,
254
+ ` readiness: ${readiness.ready ? 'ready' : 'needs setup'}`,
255
+ missing.length > 0 ? ` missing: ${missing.join(', ')}` : '',
256
+ ` review: ${formatAgentRecordReviewState(bundle.reviewState)}`,
257
+ ` origin: ${formatAgentRecordOrigin(bundle.source, bundle.provenance)}`,
205
258
  ` skills: ${bundle.skillIds.join(', ')}`,
206
259
  ` created: ${bundle.createdAt}`,
207
260
  ` updated: ${bundle.updatedAt}`,
@@ -214,7 +267,10 @@ function renderBundle(bundle: AgentSkillBundleRecord, registry: AgentSkillRegist
214
267
  }
215
268
 
216
269
  function printError(ctx: CommandContext, error: unknown): void {
217
- ctx.print(`Error: ${error instanceof Error ? error.message : String(error)}`);
270
+ ctx.print([
271
+ 'Error',
272
+ ` message ${error instanceof Error ? error.message : String(error)}`,
273
+ ].join('\n'));
218
274
  }
219
275
 
220
276
  function runBundleCommand(args: readonly string[], ctx: CommandContext, skillRegistry: AgentSkillRegistry): void {
@@ -228,6 +284,12 @@ function runBundleCommand(args: readonly string[], ctx: CommandContext, skillReg
228
284
  ctx.print(renderBundleList('Enabled Agent Skill Bundles', skillRegistry, snapshot.enabledBundles));
229
285
  return;
230
286
  }
287
+ if (sub === 'attention' || sub === 'needs-setup') {
288
+ const snapshot = skillRegistry.snapshot();
289
+ const bundles = snapshot.bundles.filter((bundle) => !evaluateAgentSkillBundleReadiness(bundle, snapshot.skills).ready);
290
+ ctx.print(renderBundleList('Agent Skill Bundles needing setup', skillRegistry, bundles, 'No Agent-local skill bundles need setup.'));
291
+ return;
292
+ }
231
293
  if (sub === 'search') {
232
294
  const query = args.slice(1).join(' ').trim();
233
295
  ctx.print(renderBundleList(query ? `Agent Skill Bundles matching "${query}"` : 'Agent Skill Bundles', skillRegistry, skillRegistry.searchBundles(query)));
@@ -236,11 +298,11 @@ function runBundleCommand(args: readonly string[], ctx: CommandContext, skillReg
236
298
  if (sub === 'show') {
237
299
  const id = args[1];
238
300
  if (!id) {
239
- ctx.print('Usage: /agent-skills bundle show <id>');
301
+ ctx.print('Usage: /skills bundle show <id>');
240
302
  return;
241
303
  }
242
304
  const bundle = skillRegistry.getBundle(id);
243
- ctx.print(bundle ? renderBundle(bundle, skillRegistry) : `Unknown Agent skill bundle: ${id}`);
305
+ ctx.print(bundle ? renderBundle(bundle, skillRegistry) : `Unknown Agent skill bundle ${id}`);
244
306
  return;
245
307
  }
246
308
  if (sub === 'create') {
@@ -251,15 +313,15 @@ function runBundleCommand(args: readonly string[], ctx: CommandContext, skillReg
251
313
  skillIds: splitList(requiredFlag(parsed.flags, 'skills')),
252
314
  enabled: parsed.flags.get('enabled') === 'true',
253
315
  source: 'user',
254
- provenance: 'slash-command',
316
+ provenance: 'Command',
255
317
  });
256
- ctx.print(`Created Agent skill bundle ${bundle.id}: ${bundle.name}`);
318
+ ctx.print(formatSkillReceipt('Created Agent skill bundle', bundle));
257
319
  return;
258
320
  }
259
321
  if (sub === 'update') {
260
322
  const id = args[1];
261
323
  if (!id) {
262
- ctx.print('Usage: /agent-skills bundle update <id> [--name ...] [--description ...] [--skills id,id]');
324
+ ctx.print('Usage: /skills bundle update <id> [--name ...] [--description ...] [--skills id,id]');
263
325
  return;
264
326
  }
265
327
  const parsed = parseSkillArgs(args.slice(2));
@@ -267,46 +329,46 @@ function runBundleCommand(args: readonly string[], ctx: CommandContext, skillReg
267
329
  name: parsed.flags.get('name'),
268
330
  description: parsed.flags.get('description'),
269
331
  skillIds: parsed.flags.has('skills') ? splitList(parsed.flags.get('skills')) : undefined,
270
- provenance: 'slash-command',
332
+ provenance: 'Command',
271
333
  });
272
- ctx.print(`Updated Agent skill bundle ${updated.id}: ${updated.name}`);
334
+ ctx.print(formatSkillReceipt('Updated Agent skill bundle', updated));
273
335
  return;
274
336
  }
275
337
  if (sub === 'enable' || sub === 'disable') {
276
338
  const id = args[1];
277
339
  if (!id) {
278
- ctx.print(`Usage: /agent-skills bundle ${sub} <id>`);
340
+ ctx.print(`Usage: /skills bundle ${sub} <id>`);
279
341
  return;
280
342
  }
281
343
  const bundle = skillRegistry.setBundleEnabled(id, sub === 'enable');
282
- ctx.print(`${sub === 'enable' ? 'Enabled' : 'Disabled'} Agent skill bundle ${bundle.id}: ${bundle.name}`);
344
+ ctx.print(formatSkillReceipt(`${sub === 'enable' ? 'Enabled' : 'Disabled'} Agent skill bundle`, bundle));
283
345
  return;
284
346
  }
285
347
  if (sub === 'review') {
286
348
  const id = args[1];
287
349
  if (!id) {
288
- ctx.print('Usage: /agent-skills bundle review <id>');
350
+ ctx.print('Usage: /skills bundle review <id>');
289
351
  return;
290
352
  }
291
353
  const bundle = skillRegistry.markBundleReviewed(id);
292
- ctx.print(`Reviewed Agent skill bundle ${bundle.id}.`);
354
+ ctx.print(formatSkillReceipt('Reviewed Agent skill bundle', bundle));
293
355
  return;
294
356
  }
295
357
  if (sub === 'stale') {
296
358
  const id = args[1];
297
359
  if (!id) {
298
- ctx.print('Usage: /agent-skills bundle stale <id> <reason...>');
360
+ ctx.print('Usage: /skills bundle stale <id> <reason...>');
299
361
  return;
300
362
  }
301
363
  const bundle = skillRegistry.markBundleStale(id, args.slice(2).join(' '));
302
- ctx.print(`Marked Agent skill bundle ${bundle.id} stale.`);
364
+ ctx.print(formatSkillReceipt('Marked Agent skill bundle stale', bundle));
303
365
  return;
304
366
  }
305
367
  if (sub === 'delete' || sub === 'remove') {
306
368
  const parsed = parseSkillArgs(args.slice(1));
307
369
  const id = parsed.rest[0];
308
370
  if (!id) {
309
- ctx.print('Usage: /agent-skills bundle delete <id> --yes');
371
+ ctx.print('Usage: /skills bundle delete <id> --yes');
310
372
  return;
311
373
  }
312
374
  if (!parsed.yes) {
@@ -314,10 +376,10 @@ function runBundleCommand(args: readonly string[], ctx: CommandContext, skillReg
314
376
  return;
315
377
  }
316
378
  const removed = skillRegistry.deleteBundle(id);
317
- ctx.print(`Deleted Agent skill bundle ${removed.id}: ${removed.name}`);
379
+ ctx.print(formatSkillReceipt('Deleted Agent skill bundle', removed));
318
380
  return;
319
381
  }
320
- ctx.print('Usage: /agent-skills bundle [list|enabled|search|show|create|update|enable|disable|review|stale|delete]');
382
+ ctx.print('Usage: /skills bundle [list|enabled|attention|search|show|create|update|enable|disable|review|stale|delete]');
321
383
  }
322
384
 
323
385
  export async function runAgentSkillsRuntimeCommand(args: readonly string[], ctx: CommandContext): Promise<void> {
@@ -349,6 +411,11 @@ export async function runAgentSkillsRuntimeCommand(args: readonly string[], ctx:
349
411
  ctx.print(renderList('Enabled Agent Skills', skillRegistry, snapshot.enabledSkills));
350
412
  return;
351
413
  }
414
+ if (sub === 'attention' || sub === 'needs-setup') {
415
+ const skills = skillRegistry.list().filter((skill) => !evaluateAgentSkillReadiness(skill).ready);
416
+ ctx.print(renderList('Agent Skills needing setup', skillRegistry, skills, 'No Agent-local skills need setup.'));
417
+ return;
418
+ }
352
419
  if (sub === 'search') {
353
420
  const query = args.slice(1).join(' ').trim();
354
421
  ctx.print(renderList(query ? `Agent Skills matching "${query}"` : 'Agent Skills', skillRegistry, skillRegistry.search(query)));
@@ -357,11 +424,11 @@ export async function runAgentSkillsRuntimeCommand(args: readonly string[], ctx:
357
424
  if (sub === 'show') {
358
425
  const id = args[1];
359
426
  if (!id) {
360
- ctx.print('Usage: /agent-skills show <id>');
427
+ ctx.print('Usage: /skills show <id>');
361
428
  return;
362
429
  }
363
430
  const skill = skillRegistry.get(id);
364
- ctx.print(skill ? renderSkill(skill) : `Unknown Agent skill: ${id}`);
431
+ ctx.print(skill ? renderSkill(skill) : `Unknown Agent skill ${id}`);
365
432
  return;
366
433
  }
367
434
  if (sub === 'create') {
@@ -373,17 +440,21 @@ export async function runAgentSkillsRuntimeCommand(args: readonly string[], ctx:
373
440
  procedure,
374
441
  triggers: splitList(parsed.flags.get('triggers')),
375
442
  tags: splitList(parsed.flags.get('tags')),
443
+ requirements: buildAgentSkillRequirements({
444
+ env: splitList(parsed.flags.get('requires-env')),
445
+ commands: splitList(parsed.flags.get('requires-command') ?? parsed.flags.get('requires-commands')),
446
+ }),
376
447
  enabled: parsed.flags.get('enabled') === 'true',
377
448
  source: 'user',
378
- provenance: 'slash-command',
449
+ provenance: 'Command',
379
450
  });
380
- ctx.print(`Created Agent skill ${skill.id}: ${skill.name}`);
451
+ ctx.print(formatSkillReceipt('Created Agent skill', skill));
381
452
  return;
382
453
  }
383
454
  if (sub === 'update') {
384
455
  const id = args[1];
385
456
  if (!id) {
386
- ctx.print('Usage: /agent-skills update <id> [--name ...] [--description ...] [--procedure ...]');
457
+ ctx.print('Usage: /skills update <id> [--name ...] [--description ...] [--procedure ...]');
387
458
  return;
388
459
  }
389
460
  const parsed = parseSkillArgs(args.slice(2));
@@ -393,46 +464,52 @@ export async function runAgentSkillsRuntimeCommand(args: readonly string[], ctx:
393
464
  procedure: parsed.flags.get('procedure'),
394
465
  triggers: parsed.flags.has('triggers') ? splitList(parsed.flags.get('triggers')) : undefined,
395
466
  tags: parsed.flags.has('tags') ? splitList(parsed.flags.get('tags')) : undefined,
396
- provenance: 'slash-command',
467
+ requirements: parsed.flags.has('requires-env') || parsed.flags.has('requires-command') || parsed.flags.has('requires-commands')
468
+ ? buildAgentSkillRequirements({
469
+ env: splitList(parsed.flags.get('requires-env')),
470
+ commands: splitList(parsed.flags.get('requires-command') ?? parsed.flags.get('requires-commands')),
471
+ })
472
+ : undefined,
473
+ provenance: 'Command',
397
474
  });
398
- ctx.print(`Updated Agent skill ${updated.id}: ${updated.name}`);
475
+ ctx.print(formatSkillReceipt('Updated Agent skill', updated));
399
476
  return;
400
477
  }
401
478
  if (sub === 'enable' || sub === 'disable') {
402
479
  const id = args[1];
403
480
  if (!id) {
404
- ctx.print(`Usage: /agent-skills ${sub} <id>`);
481
+ ctx.print(`Usage: /skills ${sub} <id>`);
405
482
  return;
406
483
  }
407
484
  const skill = skillRegistry.setEnabled(id, sub === 'enable');
408
- ctx.print(`${sub === 'enable' ? 'Enabled' : 'Disabled'} Agent skill ${skill.id}: ${skill.name}`);
485
+ ctx.print(formatSkillReceipt(`${sub === 'enable' ? 'Enabled' : 'Disabled'} Agent skill`, skill));
409
486
  return;
410
487
  }
411
488
  if (sub === 'review') {
412
489
  const id = args[1];
413
490
  if (!id) {
414
- ctx.print('Usage: /agent-skills review <id>');
491
+ ctx.print('Usage: /skills review <id>');
415
492
  return;
416
493
  }
417
494
  const skill = skillRegistry.markReviewed(id);
418
- ctx.print(`Reviewed Agent skill ${skill.id}.`);
495
+ ctx.print(formatSkillReceipt('Reviewed Agent skill', skill));
419
496
  return;
420
497
  }
421
498
  if (sub === 'stale') {
422
499
  const id = args[1];
423
500
  if (!id) {
424
- ctx.print('Usage: /agent-skills stale <id> <reason...>');
501
+ ctx.print('Usage: /skills stale <id> <reason...>');
425
502
  return;
426
503
  }
427
504
  const skill = skillRegistry.markStale(id, args.slice(2).join(' '));
428
- ctx.print(`Marked Agent skill ${skill.id} stale.`);
505
+ ctx.print(formatSkillReceipt('Marked Agent skill stale', skill));
429
506
  return;
430
507
  }
431
508
  if (sub === 'delete' || sub === 'remove') {
432
509
  const parsed = parseSkillArgs(args.slice(1));
433
510
  const id = parsed.rest[0];
434
511
  if (!id) {
435
- ctx.print('Usage: /agent-skills delete <id> --yes');
512
+ ctx.print('Usage: /skills delete <id> --yes');
436
513
  return;
437
514
  }
438
515
  if (!parsed.yes) {
@@ -440,10 +517,10 @@ export async function runAgentSkillsRuntimeCommand(args: readonly string[], ctx:
440
517
  return;
441
518
  }
442
519
  const removed = skillRegistry.deleteSkill(id);
443
- ctx.print(`Deleted Agent skill ${removed.id}: ${removed.name}`);
520
+ ctx.print(formatSkillReceipt('Deleted Agent skill', removed));
444
521
  return;
445
522
  }
446
- ctx.print('Usage: /agent-skills [list|enabled|discover|import-discovered|search|show|create|update|enable|disable|review|stale|delete|bundle]');
523
+ ctx.print('Usage: /skills [list|enabled|attention|discover|import-discovered|search|show|create|update|enable|disable|review|stale|delete|bundle]');
447
524
  } catch (error) {
448
525
  printError(ctx, error);
449
526
  }
@@ -451,10 +528,10 @@ export async function runAgentSkillsRuntimeCommand(args: readonly string[], ctx:
451
528
 
452
529
  export function registerAgentSkillsRuntimeCommands(registry: CommandRegistry): void {
453
530
  registry.register({
454
- name: 'agent-skills',
455
- aliases: ['askills', 'local-skills', 'skills', 'skill'],
456
- description: 'Manage local GoodVibes Agent skills',
457
- usage: '[list|enabled|discover|import-discovered <name> --yes|search <query>|show <id>|create --name <name> --description <summary> --procedure <steps>|update <id> [--name ...] [--description ...] [--procedure ...]|enable <id>|disable <id>|review <id>|stale <id> <reason...>|delete <id> --yes|bundle ...]',
531
+ name: 'skills',
532
+ aliases: ['skill', 'agent-skills', 'askills', 'local-skills'],
533
+ description: 'Manage Agent-local skills',
534
+ usage: '[list|enabled|attention|discover|import-discovered <name> --yes|search <query>|show <id>|create --name <name> --description <summary> --procedure <steps> [--requires-env A,B] [--requires-command gh,jq]|update <id> [--name ...] [--description ...] [--procedure ...]|enable <id>|disable <id>|review <id>|stale <id> <reason...>|delete <id> --yes|bundle ...]',
458
535
  handler: runAgentSkillsRuntimeCommand,
459
536
  });
460
537
  }
@@ -1,17 +1,34 @@
1
- import type { CommandRegistry } from '../command-registry.ts';
1
+ import type { CommandContext, CommandRegistry } from '../command-registry.ts';
2
+ import { AGENT_WORKSPACE_CATEGORY_IDS } from '../agent-workspace-types.ts';
3
+
4
+ const AGENT_WORKSPACE_ARGS_HINT = `${AGENT_WORKSPACE_CATEGORY_IDS.join('|')}|connected-host`;
2
5
 
3
6
  export function registerAgentWorkspaceRuntimeCommands(registry: CommandRegistry): void {
7
+ function openAgentWorkspace(ctx: CommandContext, categoryId: string | undefined): void {
8
+ if (!ctx.openAgentWorkspace) {
9
+ ctx.print('Agent operator workspace is not available in this runtime.');
10
+ return;
11
+ }
12
+ ctx.openAgentWorkspace(categoryId);
13
+ }
14
+
4
15
  registry.register({
5
16
  name: 'agent',
6
17
  aliases: ['home', 'operator'],
7
18
  description: 'Open the GoodVibes Agent operator workspace',
19
+ usage: '[category]',
20
+ argsHint: AGENT_WORKSPACE_ARGS_HINT,
21
+ handler(args, ctx) {
22
+ openAgentWorkspace(ctx, args[0]);
23
+ },
24
+ });
25
+ registry.register({
26
+ name: 'notes',
27
+ aliases: ['scratchpad'],
28
+ description: 'Open Agent-local scratchpad notes in the operator workspace',
8
29
  usage: '',
9
30
  handler(_args, ctx) {
10
- if (!ctx.openAgentWorkspace) {
11
- ctx.print('Agent operator workspace is not available in this runtime.');
12
- return;
13
- }
14
- ctx.openAgentWorkspace();
31
+ openAgentWorkspace(ctx, 'notes');
15
32
  },
16
33
  });
17
34
  }
@@ -34,8 +34,12 @@ function plural(count: number, singular: string, pluralWord = `${singular}s`): s
34
34
  return `${count} ${count === 1 ? singular : pluralWord}`;
35
35
  }
36
36
 
37
+ function countSetupGaps(items: readonly { readonly missingRequirementCount?: number }[]): number {
38
+ return items.filter((item) => (item.missingRequirementCount ?? 0) > 0).length;
39
+ }
40
+
37
41
  function formatWorkPlanLine(total: number, counts: StatusCounts): string {
38
- if (total === 0) return ' work plan: empty';
42
+ if (total === 0) return ' work plan empty';
39
43
  const active = counts.pending + counts.in_progress + counts.blocked;
40
44
  return [
41
45
  ` work plan: ${plural(total, 'item')}`,
@@ -48,8 +52,8 @@ function formatWorkPlanLine(total: number, counts: StatusCounts): string {
48
52
  }
49
53
 
50
54
  function formatWarnings(warnings: readonly string[]): readonly string[] {
51
- if (warnings.length === 0) return [' warnings: none'];
52
- return [' warnings:', ...warnings.slice(0, 4).map((warning) => ` - ${warning}`)];
55
+ if (warnings.length === 0) return [' warnings none'];
56
+ return [' warnings', ...warnings.slice(0, 4).map((warning) => ` - ${warning}`)];
53
57
  }
54
58
 
55
59
  export function formatAgentOperatorBriefing(ctx: CommandContext): string {
@@ -62,48 +66,74 @@ export function formatAgentOperatorBriefing(ctx: CommandContext): string {
62
66
  const setupBlocked = countReady(snapshot.setupChecklist, 'blocked');
63
67
  const readyChannels = snapshot.channels.filter((channel) => channel.ready).length;
64
68
  const enabledChannels = snapshot.channels.filter((channel) => channel.enabled).length;
69
+ const channelSetupGaps = snapshot.channels.filter((channel) => channel.enabled && !channel.ready).length;
70
+ const skillSetupGaps = countSetupGaps(snapshot.localSkills);
71
+ const skillBundleSetupGaps = countSetupGaps(snapshot.localSkillBundles);
72
+ const routineSetupGaps = countSetupGaps(snapshot.localRoutines);
73
+ const voiceSetupNeedsReview = snapshot.voiceSurfaceEnabled && snapshot.voiceMediaReadiness.selectedTtsProviderStatus !== 'ready';
74
+ const mediaSetupNeedsReview = snapshot.mediaProviderCount > 0 && snapshot.voiceMediaReadiness.readyMediaProviderCount === 0;
75
+ const hasLocalSkillBehavior = snapshot.localSkillCount > 0 || snapshot.localSkillBundleCount > 0;
65
76
 
66
77
  const nextActions = [
67
78
  snapshot.provider === 'unknown' || snapshot.model === 'unknown'
68
- ? 'Choose the assistant model with /model.'
79
+ ? 'Choose the assistant model from Agent Workspace -> Home -> Choose model.'
69
80
  : '',
70
81
  snapshot.localMemoryCount === 0
71
- ? 'Store durable non-secret facts with /memory add or the Agent workspace memory form.'
82
+ ? 'Store durable non-secret facts from Agent Workspace -> Memory -> Add memory.'
72
83
  : snapshot.localMemoryReviewQueueCount > 0
73
- ? `Review ${plural(snapshot.localMemoryReviewQueueCount, 'memory record')} with /memory queue.`
74
- : '',
75
- snapshot.localSkillCount === 0 && snapshot.localSkillBundleCount === 0
76
- ? 'Create reusable procedures with /agent-skills create or import reviewed skill files.'
77
- : snapshot.activeSkillCount === 0
78
- ? 'Enable reviewed skills or bundles with /agent-skills enabled and /agent-skills bundle enabled.'
84
+ ? `Review ${plural(snapshot.localMemoryReviewQueueCount, 'memory record')} from Agent Workspace -> Memory -> Review queue.`
79
85
  : '',
86
+ !hasLocalSkillBehavior
87
+ ? 'Create reusable procedures from Agent Workspace -> Skills or import reviewed skill files.'
88
+ : '',
89
+ skillSetupGaps > 0
90
+ ? `Resolve ${plural(skillSetupGaps, 'skill')} with setup gaps from Agent Workspace -> Skills.`
91
+ : '',
92
+ skillBundleSetupGaps > 0
93
+ ? `Resolve ${plural(skillBundleSetupGaps, 'skill bundle')} with setup gaps from Agent Workspace -> Skills.`
94
+ : '',
95
+ hasLocalSkillBehavior && skillSetupGaps === 0 && skillBundleSetupGaps === 0 && snapshot.activeSkillCount === 0
96
+ ? 'Enable reviewed skills or bundles from Agent Workspace -> Skills.'
97
+ : '',
80
98
  snapshot.localRoutineCount === 0
81
- ? 'Create repeatable workflows with /routines create; promote schedules only with explicit confirmation.'
82
- : snapshot.enabledRoutineCount === 0
83
- ? 'Enable reviewed routines with /routines enable.'
99
+ ? 'Create repeatable workflows from Agent Workspace -> Routines; promote schedules only with explicit confirmation.'
100
+ : routineSetupGaps > 0
101
+ ? `Resolve ${plural(routineSetupGaps, 'routine')} with setup gaps from Agent Workspace -> Routines.`
102
+ : snapshot.enabledRoutineCount === 0
103
+ ? 'Enable reviewed routines from Agent Workspace -> Routines.'
84
104
  : '',
85
- 'Use /knowledge status, /knowledge search, and explicit ingest forms for Agent Knowledge only.',
86
- 'Use /delegate only for explicit build, fix, implementation, or review handoff to GoodVibes TUI.',
105
+ channelSetupGaps > 0
106
+ ? `Review ${plural(channelSetupGaps, 'enabled channel')} needing setup from Agent Workspace -> Channels.`
107
+ : '',
108
+ voiceSetupNeedsReview
109
+ ? 'Review voice setup from Agent Workspace -> Voice & Media before relying on spoken replies.'
110
+ : '',
111
+ mediaSetupNeedsReview
112
+ ? 'Review media provider setup from Agent Workspace -> Voice & Media before relying on image or media workflows.'
113
+ : '',
114
+ 'Use Agent Workspace -> Knowledge for Agent Knowledge status, search, and explicit ingest forms.',
115
+ 'Use Agent Workspace -> Build Delegation only for explicit build, fix, implementation, or review handoff to GoodVibes TUI.',
87
116
  ].filter((line): line is string => line.length > 0);
88
117
 
89
118
  return [
90
119
  'Agent Briefing',
91
120
  ` chat route: ${snapshot.provider} / ${snapshot.modelDisplayName}`,
92
- ` session: ${snapshot.sessionId}`,
93
- ` profile: ${snapshot.activeRuntimeProfile}`,
94
- ` policy: ${snapshot.executionPolicy}; WRFC ${snapshot.wrfcPolicy}`,
95
- ` knowledge: ${snapshot.knowledgeRoute} (${snapshot.knowledgeIsolation}; no fallback)`,
121
+ ` session ${snapshot.sessionId}`,
122
+ ` profile ${snapshot.activeRuntimeProfile}`,
123
+ ` policy ${snapshot.executionPolicy}; delegated review ${snapshot.delegatedReviewPolicy}`,
124
+ ` knowledge ${snapshot.knowledgeRoute} (${snapshot.knowledgeIsolation}; no fallback)`,
96
125
  '',
97
126
  'Readiness',
98
- ` setup: ${setupReady}/${snapshot.setupChecklist.length} ready; ${setupRecommended} recommended; ${setupBlocked} blocked`,
127
+ ` setup ${setupReady}/${snapshot.setupChecklist.length} ready; ${setupRecommended} recommended; ${setupBlocked} blocked`,
99
128
  ` local memory: ${plural(snapshot.localMemoryCount, 'record')}; prompt-active ${snapshot.localMemoryPromptActiveCount}; review queue ${snapshot.localMemoryReviewQueueCount}`,
129
+ ` scratchpad notes: ${plural(snapshot.localNoteCount, 'note')}; review queue ${snapshot.localNoteReviewQueueCount}`,
100
130
  ` personas: ${plural(snapshot.localPersonaCount, 'persona')}; active ${snapshot.activePersonaName}`,
101
- ` skills: ${snapshot.enabledSkillCount}/${snapshot.localSkillCount} enabled; bundles ${snapshot.enabledSkillBundleCount}/${snapshot.localSkillBundleCount}; active ${snapshot.activeSkillCount}`,
102
- ` routines: ${snapshot.enabledRoutineCount}/${snapshot.localRoutineCount} enabled`,
103
- ` channels: ${readyChannels}/${snapshot.channels.length} ready; ${enabledChannels} enabled`,
131
+ ` skills: ${snapshot.enabledSkillCount}/${snapshot.localSkillCount} enabled; bundles ${snapshot.enabledSkillBundleCount}/${snapshot.localSkillBundleCount}; active ${snapshot.activeSkillCount}; setup gaps ${skillSetupGaps} skill, ${skillBundleSetupGaps} bundle`,
132
+ ` routines: ${snapshot.enabledRoutineCount}/${snapshot.localRoutineCount} enabled; setup gaps ${routineSetupGaps}`,
133
+ ` channels: ${readyChannels}/${snapshot.channels.length} ready; ${enabledChannels} enabled; setup gaps ${channelSetupGaps}`,
104
134
  ` voice/media: ${snapshot.voiceProviderCount} voice, ${snapshot.mediaProviderCount} media; browser tools ${snapshot.voiceMediaReadiness.browserToolState}`,
105
135
  formatWorkPlanLine(workPlan.total, workPlan.counts),
106
- ` schedules: ${enabledJobs}/${jobs.length} visible jobs enabled`,
136
+ ` schedules ${enabledJobs}/${jobs.length} visible jobs enabled`,
107
137
  '',
108
138
  'Next Actions',
109
139
  ...nextActions.map((line) => ` - ${line}`),