@pellux/goodvibes-agent 0.1.117 → 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 (253) hide show
  1. package/CHANGELOG.md +13 -4
  2. package/README.md +35 -14
  3. package/bin/goodvibes-agent.ts +16 -2
  4. package/dist/package/main.js +176073 -170980
  5. package/docs/README.md +11 -5
  6. package/docs/channels-remote-and-api.md +50 -0
  7. package/docs/connected-host.md +3 -3
  8. package/docs/getting-started.md +29 -15
  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 +44 -9
  13. package/docs/tools-and-commands.md +123 -0
  14. package/docs/voice-and-live-tts.md +51 -0
  15. package/package.json +2 -5
  16. package/src/agent/channel-delivery.ts +201 -0
  17. package/src/agent/media-generation.ts +159 -0
  18. package/src/agent/memory-prompt.ts +0 -1
  19. package/src/agent/note-registry.ts +329 -0
  20. package/src/agent/operator-actions.ts +343 -0
  21. package/src/agent/persona-registry.ts +15 -14
  22. package/src/agent/record-labels.ts +107 -0
  23. package/src/agent/reminder-schedule-format.ts +33 -24
  24. package/src/agent/reminder-schedule.ts +26 -25
  25. package/src/agent/routine-registry.ts +13 -12
  26. package/src/agent/routine-schedule-args.ts +2 -1
  27. package/src/agent/routine-schedule-format.ts +77 -53
  28. package/src/agent/routine-schedule-promotion.ts +34 -32
  29. package/src/agent/routine-schedule-receipts.ts +28 -26
  30. package/src/agent/runtime-profile-starters.ts +2 -2
  31. package/src/agent/runtime-profile.ts +18 -17
  32. package/src/agent/skill-registry.ts +25 -24
  33. package/src/cli/agent-knowledge-args.ts +5 -1
  34. package/src/cli/agent-knowledge-command.ts +39 -33
  35. package/src/cli/agent-knowledge-format.ts +80 -67
  36. package/src/cli/agent-knowledge-methods.ts +1 -1
  37. package/src/cli/agent-knowledge-runtime.ts +32 -26
  38. package/src/cli/bundle-command.ts +13 -8
  39. package/src/cli/config-overrides.ts +37 -36
  40. package/src/cli/external-runtime.ts +10 -4
  41. package/src/cli/help.ts +29 -11
  42. package/src/cli/local-library-command.ts +134 -68
  43. package/src/cli/management-commands.ts +98 -62
  44. package/src/cli/management.ts +52 -26
  45. package/src/cli/memory-command.ts +66 -32
  46. package/src/cli/parser.ts +37 -24
  47. package/src/cli/profiles-command.ts +52 -35
  48. package/src/cli/provider-auth-routes.ts +2 -1
  49. package/src/cli/routines-command.ts +44 -36
  50. package/src/cli/service-posture.ts +6 -6
  51. package/src/cli/status.ts +46 -121
  52. package/src/core/conversation-message-snapshot.ts +131 -0
  53. package/src/input/agent-workspace-activation.ts +33 -7
  54. package/src/input/agent-workspace-basic-command-editor-submission.ts +7 -3
  55. package/src/input/agent-workspace-basic-command-editors.ts +30 -10
  56. package/src/input/agent-workspace-categories.ts +276 -64
  57. package/src/input/agent-workspace-channel-command-editor-submission.ts +34 -0
  58. package/src/input/agent-workspace-channel-command-editors.ts +23 -5
  59. package/src/input/agent-workspace-channels.ts +35 -2
  60. package/src/input/agent-workspace-command-editor.ts +18 -2
  61. package/src/input/agent-workspace-config-reader.ts +16 -0
  62. package/src/input/agent-workspace-delegation-editor-submission.ts +1 -1
  63. package/src/input/agent-workspace-editors.ts +140 -2
  64. package/src/input/agent-workspace-knowledge-query-editor.ts +1 -1
  65. package/src/input/agent-workspace-learned-behavior.ts +2 -2
  66. package/src/input/agent-workspace-library-command-editor-submission.ts +1 -1
  67. package/src/input/agent-workspace-library-command-editors.ts +2 -2
  68. package/src/input/agent-workspace-local-operations.ts +218 -0
  69. package/src/input/agent-workspace-local-selection.ts +75 -0
  70. package/src/input/agent-workspace-media-command-editor-submission.ts +62 -0
  71. package/src/input/agent-workspace-media-command-editors.ts +27 -0
  72. package/src/input/agent-workspace-memory-command-editors.ts +1 -1
  73. package/src/input/agent-workspace-memory-editor.ts +2 -2
  74. package/src/input/agent-workspace-navigation.ts +38 -2
  75. package/src/input/agent-workspace-notify-editor-submission.ts +16 -2
  76. package/src/input/agent-workspace-operations-command-editor-submission.ts +63 -1
  77. package/src/input/agent-workspace-operations-command-editors.ts +80 -3
  78. package/src/input/agent-workspace-panel-route.ts +43 -0
  79. package/src/input/agent-workspace-reminder-schedule-editor.ts +1 -1
  80. package/src/input/agent-workspace-routine-schedule-editor.ts +2 -2
  81. package/src/input/agent-workspace-search.ts +169 -0
  82. package/src/input/agent-workspace-setup.ts +22 -11
  83. package/src/input/agent-workspace-skill-bundle-command-editor-submission.ts +6 -6
  84. package/src/input/agent-workspace-skill-bundle-command-editors.ts +10 -10
  85. package/src/input/agent-workspace-snapshot.ts +112 -13
  86. package/src/input/agent-workspace-task-command-editors.ts +4 -4
  87. package/src/input/agent-workspace-token.ts +18 -2
  88. package/src/input/agent-workspace-types.ts +92 -4
  89. package/src/input/agent-workspace-voice-media.ts +3 -6
  90. package/src/input/agent-workspace-web-research-editor.ts +104 -0
  91. package/src/input/agent-workspace.ts +136 -208
  92. package/src/input/command-registry.ts +4 -1
  93. package/src/input/commands/agent-runtime-profile-runtime.ts +45 -41
  94. package/src/input/commands/agent-skills-runtime.ts +83 -70
  95. package/src/input/commands/agent-workspace-runtime.ts +23 -7
  96. package/src/input/commands/brief-runtime.ts +25 -24
  97. package/src/input/commands/channels-runtime.ts +145 -31
  98. package/src/input/commands/delegation-runtime.ts +29 -23
  99. package/src/input/commands/experience-runtime.ts +6 -4
  100. package/src/input/commands/guidance-runtime.ts +4 -4
  101. package/src/input/commands/health-runtime.ts +140 -115
  102. package/src/input/commands/knowledge.ts +57 -56
  103. package/src/input/commands/local-provider-runtime.ts +36 -18
  104. package/src/input/commands/local-runtime.ts +138 -16
  105. package/src/input/commands/local-setup-review.ts +7 -7
  106. package/src/input/commands/mcp-runtime.ts +56 -35
  107. package/src/input/commands/notify-runtime.ts +38 -9
  108. package/src/input/commands/operator-actions-runtime.ts +138 -0
  109. package/src/input/commands/operator-runtime.ts +6 -17
  110. package/src/input/commands/personas-runtime.ts +45 -30
  111. package/src/input/commands/planning-runtime.ts +1 -1
  112. package/src/input/commands/platform-access-runtime.ts +29 -29
  113. package/src/input/commands/provider-accounts-runtime.ts +60 -39
  114. package/src/input/commands/qrcode-runtime.ts +45 -6
  115. package/src/input/commands/recall-bundle.ts +11 -11
  116. package/src/input/commands/recall-capture.ts +13 -11
  117. package/src/input/commands/recall-query.ts +29 -21
  118. package/src/input/commands/recall-review.ts +2 -1
  119. package/src/input/commands/routines-runtime.ts +59 -43
  120. package/src/input/commands/schedule-runtime.ts +33 -20
  121. package/src/input/commands/security-runtime.ts +4 -4
  122. package/src/input/commands/session-content.ts +80 -78
  123. package/src/input/commands/session-workflow.ts +132 -93
  124. package/src/input/commands/session.ts +3 -174
  125. package/src/input/commands/shell-core.ts +32 -17
  126. package/src/input/commands/subscription-runtime.ts +53 -179
  127. package/src/input/commands/tasks-runtime.ts +20 -20
  128. package/src/input/commands/work-plan-runtime.ts +33 -8
  129. package/src/input/commands.ts +2 -2
  130. package/src/input/feed-context-factory.ts +2 -1
  131. package/src/input/file-picker.ts +3 -2
  132. package/src/input/handler-command-route.ts +4 -7
  133. package/src/input/handler-content-actions.ts +89 -1
  134. package/src/input/handler-feed-routes.ts +19 -12
  135. package/src/input/handler-feed.ts +6 -3
  136. package/src/input/handler-interactions.ts +7 -5
  137. package/src/input/handler-modal-stack.ts +3 -3
  138. package/src/input/handler-onboarding.ts +24 -80
  139. package/src/input/handler-shortcuts.ts +15 -4
  140. package/src/input/handler.ts +47 -17
  141. package/src/input/input-history.ts +5 -6
  142. package/src/input/keybindings.ts +22 -11
  143. package/src/input/onboarding/onboarding-wizard-apply.ts +13 -0
  144. package/src/input/onboarding/onboarding-wizard-constants.ts +1 -0
  145. package/src/input/onboarding/onboarding-wizard-operator-steps.ts +147 -57
  146. package/src/input/onboarding/onboarding-wizard-steps.ts +46 -29
  147. package/src/input/onboarding/onboarding-wizard-types.ts +3 -1
  148. package/src/input/onboarding/onboarding-wizard.ts +68 -0
  149. package/src/input/profile-picker-modal.ts +31 -12
  150. package/src/input/session-picker-modal.ts +21 -4
  151. package/src/input/settings-modal-behavior.ts +0 -3
  152. package/src/input/settings-modal-subscriptions.ts +3 -3
  153. package/src/input/settings-modal-types.ts +2 -13
  154. package/src/input/settings-modal.ts +6 -52
  155. package/src/input/submission-intent.ts +0 -1
  156. package/src/input/submission-router.ts +3 -3
  157. package/src/main.ts +18 -8
  158. package/src/panels/approval-panel.ts +8 -8
  159. package/src/panels/automation-control-panel.ts +2 -2
  160. package/src/panels/base-panel.ts +1 -1
  161. package/src/panels/builtin/agent.ts +1 -1
  162. package/src/panels/builtin/operations.ts +1 -10
  163. package/src/panels/builtin/session.ts +9 -9
  164. package/src/panels/builtin/shared.ts +2 -2
  165. package/src/panels/cost-tracker-panel.ts +1 -1
  166. package/src/panels/docs-panel.ts +5 -3
  167. package/src/panels/index.ts +0 -1
  168. package/src/panels/knowledge-panel.ts +6 -5
  169. package/src/panels/memory-panel.ts +7 -6
  170. package/src/panels/panel-list-panel.ts +36 -80
  171. package/src/panels/project-planning-panel.ts +18 -11
  172. package/src/panels/provider-account-snapshot.ts +51 -25
  173. package/src/panels/provider-accounts-panel.ts +33 -18
  174. package/src/panels/provider-health-domains.ts +45 -4
  175. package/src/panels/provider-health-panel.ts +5 -4
  176. package/src/panels/qr-panel.ts +1 -1
  177. package/src/panels/schedule-panel.ts +9 -17
  178. package/src/panels/security-panel.ts +8 -8
  179. package/src/panels/session-browser-panel.ts +10 -10
  180. package/src/panels/subscription-panel.ts +3 -3
  181. package/src/panels/system-messages-panel.ts +1 -1
  182. package/src/panels/tasks-panel.ts +20 -13
  183. package/src/panels/tool-inspector-panel.ts +19 -12
  184. package/src/panels/work-plan-panel.ts +5 -5
  185. package/src/planning/project-planning-coordinator.ts +1 -1
  186. package/src/provider-auth-route-display.ts +9 -0
  187. package/src/renderer/agent-workspace-style.ts +34 -0
  188. package/src/renderer/agent-workspace.ts +228 -52
  189. package/src/renderer/autocomplete-overlay.ts +25 -6
  190. package/src/renderer/bookmark-modal.ts +19 -4
  191. package/src/renderer/buffer.ts +4 -2
  192. package/src/renderer/context-inspector.ts +50 -13
  193. package/src/renderer/diff.ts +1 -1
  194. package/src/renderer/file-picker-overlay.ts +19 -6
  195. package/src/renderer/help-overlay.ts +106 -33
  196. package/src/renderer/history-search-overlay.ts +19 -4
  197. package/src/renderer/live-tail-modal.ts +27 -5
  198. package/src/renderer/mcp-workspace.ts +164 -50
  199. package/src/renderer/model-picker-overlay.ts +58 -2
  200. package/src/renderer/model-workspace.ts +104 -20
  201. package/src/renderer/process-modal.ts +27 -6
  202. package/src/renderer/profile-picker-modal.ts +20 -4
  203. package/src/renderer/search-overlay.ts +25 -5
  204. package/src/renderer/selection-modal-overlay.ts +46 -14
  205. package/src/renderer/session-picker-modal.ts +18 -1
  206. package/src/renderer/settings-modal-helpers.ts +2 -40
  207. package/src/renderer/settings-modal.ts +83 -50
  208. package/src/renderer/tool-call.ts +20 -11
  209. package/src/runtime/agent-runtime-events.ts +6 -6
  210. package/src/runtime/bootstrap-command-context.ts +7 -1
  211. package/src/runtime/bootstrap-command-parts.ts +9 -7
  212. package/src/runtime/bootstrap-core.ts +19 -1
  213. package/src/runtime/bootstrap-hook-bridge.ts +7 -18
  214. package/src/runtime/bootstrap-shell.ts +4 -4
  215. package/src/runtime/bootstrap.ts +31 -22
  216. package/src/runtime/connected-host-auth.ts +7 -2
  217. package/src/runtime/diagnostics/panels/index.ts +2 -2
  218. package/src/runtime/diagnostics/panels/policy.ts +7 -7
  219. package/src/runtime/index.ts +2 -1
  220. package/src/runtime/onboarding/apply-file-helpers.ts +66 -0
  221. package/src/runtime/onboarding/apply.ts +80 -79
  222. package/src/runtime/onboarding/derivation.ts +5 -8
  223. package/src/runtime/onboarding/snapshot.ts +0 -15
  224. package/src/runtime/onboarding/types.ts +8 -19
  225. package/src/runtime/onboarding/verify.ts +32 -10
  226. package/src/runtime/operator-token-cleanup.ts +1 -1
  227. package/src/runtime/services.ts +91 -22
  228. package/src/runtime/store/selectors/index.ts +3 -3
  229. package/src/runtime/store/state.ts +1 -4
  230. package/src/runtime/surface-feature-flags.ts +41 -6
  231. package/src/runtime/ui-read-models.ts +3 -4
  232. package/src/runtime/ui-services.ts +6 -6
  233. package/src/shell/blocking-input.ts +2 -1
  234. package/src/shell/ui-openers.ts +3 -13
  235. package/src/tools/agent-analysis-registry-policy.ts +0 -1
  236. package/src/tools/agent-channel-send-tool.ts +133 -0
  237. package/src/tools/agent-context-policy.ts +1 -1
  238. package/src/tools/agent-knowledge-ingest-tool.ts +405 -0
  239. package/src/tools/agent-knowledge-tool.ts +170 -0
  240. package/src/tools/agent-local-registry-tool.ts +269 -69
  241. package/src/tools/agent-media-generate-tool.ts +133 -0
  242. package/src/tools/agent-notify-tool.ts +143 -0
  243. package/src/tools/agent-operator-action-tool.ts +137 -0
  244. package/src/tools/agent-operator-briefing-tool.ts +217 -0
  245. package/src/tools/agent-reminder-schedule-tool.ts +237 -0
  246. package/src/tools/agent-tool-policy-guard.ts +8 -8
  247. package/src/tools/agent-work-plan-tool.ts +256 -0
  248. package/src/version.ts +1 -1
  249. package/src/input/commands/policy-dispatch.ts +0 -339
  250. package/src/input/commands/policy.ts +0 -13
  251. package/src/panels/panel-picker.ts +0 -105
  252. package/src/panels/policy-panel.ts +0 -308
  253. package/src/renderer/panel-picker-overlay.ts +0 -202
@@ -6,7 +6,7 @@ export interface AgentKnowledgeFailureLike {
6
6
  readonly error: string;
7
7
  readonly baseUrl: string;
8
8
  readonly route: string;
9
- readonly daemonVersion?: string;
9
+ readonly connectedHostVersion?: string;
10
10
  readonly expectedSdkVersion?: string;
11
11
  }
12
12
 
@@ -42,6 +42,15 @@ function yesNo(value: boolean): string {
42
42
  return value ? 'yes' : 'no';
43
43
  }
44
44
 
45
+ export function formatAgentKnowledgeFailureKind(kind: string): string {
46
+ if (kind === 'auth_required') return 'authorization required';
47
+ if (kind === 'connected_host_unavailable') return 'connected host unavailable';
48
+ if (kind === 'connected_host_route_unavailable') return 'connected host route unavailable';
49
+ if (kind === 'connected_host_error') return 'connected host error';
50
+ if (kind === 'version_mismatch') return 'version mismatch';
51
+ return kind.replace(/[_-]+/g, ' ');
52
+ }
53
+
45
54
  function sourceLine(value: unknown): string {
46
55
  const record = isRecord(value) ? value : {};
47
56
  const title = cleanInline(record.title)
@@ -65,9 +74,9 @@ function resultLine(value: unknown): string {
65
74
  const snippet = cleanInline(record.snippet) || cleanInline(record.summary) || cleanInline(record.text);
66
75
  const parts = [
67
76
  `[${type}] ${title}`,
68
- id && id !== title ? `id=${id}` : '',
69
- score !== null ? `score=${score.toFixed(3)}` : '',
70
- url ? `url=${url}` : '',
77
+ id && id !== title ? `id ${id}` : '',
78
+ score !== null ? `score ${score.toFixed(3)}` : '',
79
+ url ? `url ${url}` : '',
71
80
  ].filter((part) => part.length > 0);
72
81
  return snippet ? `${parts.join(' ')}\n ${snippet}` : parts.join(' ');
73
82
  }
@@ -82,9 +91,9 @@ function nodeLine(value: unknown): string {
82
91
  const summary = cleanInline(record.summary);
83
92
  const parts = [
84
93
  `[${kind}] ${title}`,
85
- id && id !== title ? `id=${id}` : '',
86
- status ? `status=${status}` : '',
87
- confidence !== null ? `confidence=${confidence}` : '',
94
+ id && id !== title ? `id ${id}` : '',
95
+ status ? `status ${status}` : '',
96
+ confidence !== null ? `confidence ${confidence}` : '',
88
97
  ].filter((part) => part.length > 0);
89
98
  return summary ? `${parts.join(' ')}\n ${summary}` : parts.join(' ');
90
99
  }
@@ -96,7 +105,7 @@ function issueLine(value: unknown): string {
96
105
  const code = cleanInline(record.code) || 'issue';
97
106
  const status = cleanInline(record.status);
98
107
  const message = cleanInline(record.message);
99
- const suffix = status ? ` status=${status}` : '';
108
+ const suffix = status ? ` status ${status}` : '';
100
109
  return ` - ${id} [${severity}] ${code}${suffix}${message ? ` - ${message}` : ''}`;
101
110
  }
102
111
 
@@ -106,10 +115,14 @@ function connectorLine(value: unknown): string {
106
115
  const name = cleanInline(record.displayName) || id;
107
116
  const sourceType = cleanInline(record.sourceType);
108
117
  const description = cleanInline(record.description);
109
- const suffix = sourceType ? ` sourceType=${sourceType}` : '';
118
+ const suffix = sourceType ? ` source type ${sourceType}` : '';
110
119
  return description ? ` - ${id} ${name}${suffix}\n ${description}` : ` - ${id} ${name}${suffix}`;
111
120
  }
112
121
 
122
+ function relatedKnowledgeCountsLine(relatedEdges: number, linkedSources: number, linkedNodes: number): string {
123
+ return ` related edges ${relatedEdges} linked sources ${linkedSources} linked nodes ${linkedNodes}`;
124
+ }
125
+
113
126
  export function formatStatus(data: unknown): string {
114
127
  const record = isRecord(data) ? data : {};
115
128
  const ready = readBoolean(record, 'ready');
@@ -120,13 +133,13 @@ export function formatStatus(data: unknown): string {
120
133
  const storagePath = readString(record, 'storagePath');
121
134
  return [
122
135
  'Agent Knowledge status',
123
- ` ready: ${ready === null ? 'unknown' : yesNo(ready)}`,
124
- ` sources: ${sourceCount ?? 'unknown'}`,
125
- ` nodes: ${nodeCount ?? 'unknown'}`,
126
- ` edges: ${edgeCount ?? 'unknown'}`,
127
- ` issues: ${issueCount ?? 'unknown'}`,
128
- storagePath ? ` storage: ${storagePath}` : null,
129
- ' route: /api/goodvibes-agent/knowledge/status',
136
+ ` ready ${ready === null ? 'unknown' : yesNo(ready)}`,
137
+ ` sources ${sourceCount ?? 'unknown'}`,
138
+ ` nodes ${nodeCount ?? 'unknown'}`,
139
+ ` edges ${edgeCount ?? 'unknown'}`,
140
+ ` issues ${issueCount ?? 'unknown'}`,
141
+ storagePath ? ` storage ${storagePath}` : null,
142
+ ' route /api/goodvibes-agent/knowledge/status',
130
143
  ].filter((line): line is string => Boolean(line)).join('\n');
131
144
  }
132
145
 
@@ -137,7 +150,7 @@ export function formatEntityList(data: unknown, kind: 'sources' | 'nodes' | 'iss
137
150
  return [
138
151
  `Agent Knowledge ${kind}`,
139
152
  ' no records',
140
- ` route: /api/goodvibes-agent/knowledge/${kind}`,
153
+ ` route /api/goodvibes-agent/knowledge/${kind}`,
141
154
  ].join('\n');
142
155
  }
143
156
  const format = kind === 'sources'
@@ -163,29 +176,29 @@ export function formatItem(data: unknown, id: string): string {
163
176
  const linkedNodes = readArray(record, 'linkedNodes').length;
164
177
  if (source) {
165
178
  return [
166
- `Agent Knowledge item: ${id}`,
179
+ `Agent Knowledge item ${id}`,
167
180
  ` ${sourceLine(source)}`,
168
- ` relatedEdges=${relatedEdges} linkedSources=${linkedSources} linkedNodes=${linkedNodes}`,
181
+ relatedKnowledgeCountsLine(relatedEdges, linkedSources, linkedNodes),
169
182
  ].join('\n');
170
183
  }
171
184
  if (node) {
172
185
  return [
173
- `Agent Knowledge item: ${id}`,
186
+ `Agent Knowledge item ${id}`,
174
187
  ` ${nodeLine(node)}`,
175
- ` relatedEdges=${relatedEdges} linkedSources=${linkedSources} linkedNodes=${linkedNodes}`,
188
+ relatedKnowledgeCountsLine(relatedEdges, linkedSources, linkedNodes),
176
189
  ].join('\n');
177
190
  }
178
191
  if (issue) {
179
192
  return [
180
- `Agent Knowledge item: ${id}`,
193
+ `Agent Knowledge item ${id}`,
181
194
  issueLine(issue),
182
- ` relatedEdges=${relatedEdges} linkedSources=${linkedSources} linkedNodes=${linkedNodes}`,
195
+ relatedKnowledgeCountsLine(relatedEdges, linkedSources, linkedNodes),
183
196
  ].join('\n');
184
197
  }
185
198
  return [
186
- `Agent Knowledge item: ${id}`,
199
+ `Agent Knowledge item ${id}`,
187
200
  ' not found',
188
- ' route: /api/goodvibes-agent/knowledge/items/{id}',
201
+ ' route /api/goodvibes-agent/knowledge/items/{id}',
189
202
  ].join('\n');
190
203
  }
191
204
 
@@ -201,7 +214,7 @@ export function formatMap(data: unknown): string {
201
214
  ` nodes: ${nodes.length}`,
202
215
  ` edges: ${edges.length}`,
203
216
  ` issues: ${issues.length}`,
204
- ' route: /api/goodvibes-agent/knowledge/map',
217
+ ' route /api/goodvibes-agent/knowledge/map',
205
218
  ].join('\n');
206
219
  }
207
220
 
@@ -212,7 +225,7 @@ export function formatConnectors(data: unknown): string {
212
225
  return [
213
226
  'Agent Knowledge connectors',
214
227
  ' no connectors',
215
- ' route: /api/goodvibes-agent/knowledge/connectors',
228
+ ' route /api/goodvibes-agent/knowledge/connectors',
216
229
  ].join('\n');
217
230
  }
218
231
  return [
@@ -231,13 +244,13 @@ export function formatConnector(data: unknown, id: string): string {
231
244
  const capabilities = readArray(connector, 'capabilities').map(cleanInline).filter(Boolean);
232
245
  const examples = readArray(connector, 'examples');
233
246
  return [
234
- `Agent Knowledge connector: ${connectorId}`,
235
- ` name: ${name}`,
236
- sourceType ? ` sourceType: ${sourceType}` : null,
237
- description ? ` description: ${description}` : null,
247
+ `Agent Knowledge connector ${connectorId}`,
248
+ ` name ${name}`,
249
+ sourceType ? ` source type ${sourceType}` : null,
250
+ description ? ` description ${description}` : null,
238
251
  capabilities.length > 0 ? ` capabilities: ${capabilities.join(', ')}` : null,
239
- ` examples: ${examples.length}`,
240
- ' route: /api/goodvibes-agent/knowledge/connectors/{id}',
252
+ ` examples ${examples.length}`,
253
+ ' route /api/goodvibes-agent/knowledge/connectors/{id}',
241
254
  ].filter((line): line is string => Boolean(line)).join('\n');
242
255
  }
243
256
 
@@ -248,10 +261,10 @@ export function formatConnectorDoctor(data: unknown, id: string): string {
248
261
  const checks = readArray(record, 'checks');
249
262
  const hints = readArray(record, 'hints').map(cleanInline).filter(Boolean);
250
263
  return [
251
- `Agent Knowledge connector doctor: ${cleanInline(record.connectorId) || id}`,
252
- ` ready: ${ready === null ? 'unknown' : yesNo(ready)}`,
253
- summary ? ` summary: ${summary}` : null,
254
- checks.length > 0 ? ' checks:' : null,
264
+ `Agent Knowledge connector doctor ${cleanInline(record.connectorId) || id}`,
265
+ ` ready ${ready === null ? 'unknown' : yesNo(ready)}`,
266
+ summary ? ` summary ${summary}` : null,
267
+ checks.length > 0 ? ' checks' : null,
255
268
  ...checks.slice(0, 10).map((check) => {
256
269
  const item = isRecord(check) ? check : {};
257
270
  const checkId = cleanInline(item.id) || 'check';
@@ -260,9 +273,9 @@ export function formatConnectorDoctor(data: unknown, id: string): string {
260
273
  const detail = cleanInline(item.detail);
261
274
  return ` - ${checkId} [${status}] ${label}${detail ? ` - ${detail}` : ''}`;
262
275
  }),
263
- hints.length > 0 ? ' hints:' : null,
276
+ hints.length > 0 ? ' hints' : null,
264
277
  ...hints.slice(0, 8).map((hint) => ` - ${hint}`),
265
- ' route: /api/goodvibes-agent/knowledge/connectors/{id}/doctor',
278
+ ' route /api/goodvibes-agent/knowledge/connectors/{id}/doctor',
266
279
  ].filter((line): line is string => Boolean(line)).join('\n');
267
280
  }
268
281
 
@@ -276,16 +289,16 @@ export function formatAsk(data: unknown, query: string): string {
276
289
  const facts = readArray(answer, 'facts');
277
290
  const gaps = readArray(answer, 'gaps');
278
291
  const lines = [
279
- `Agent Knowledge answer: ${query}`,
292
+ `Agent Knowledge answer ${query}`,
280
293
  text,
281
294
  '',
282
- `confidence: ${confidence ?? 'unknown'}${synthesized === null ? '' : ` synthesized: ${yesNo(synthesized)}`}`,
295
+ `confidence ${confidence ?? 'unknown'}${synthesized === null ? '' : ` synthesized ${yesNo(synthesized)}`}`,
283
296
  ];
284
297
  if (sources.length > 0) {
285
- lines.push('', 'Sources:', ...sources.slice(0, 8).map((source) => ` - ${sourceLine(source)}`));
298
+ lines.push('', 'Sources', ...sources.slice(0, 8).map((source) => ` - ${sourceLine(source)}`));
286
299
  }
287
- if (facts.length > 0) lines.push('', `Facts: ${facts.length}`);
288
- if (gaps.length > 0) lines.push('', `Gaps: ${gaps.length}`);
300
+ if (facts.length > 0) lines.push('', `Facts ${facts.length}`);
301
+ if (gaps.length > 0) lines.push('', `Gaps ${gaps.length}`);
289
302
  return lines.join('\n');
290
303
  }
291
304
 
@@ -295,13 +308,13 @@ export function formatSearch(data: unknown, query: string): string {
295
308
  const results = items.length > 0 ? items : readArray(record, 'results');
296
309
  if (results.length === 0) {
297
310
  return [
298
- `Agent Knowledge search: ${query}`,
311
+ `Agent Knowledge search ${query}`,
299
312
  ' no results',
300
- ' route: /api/goodvibes-agent/knowledge/search',
313
+ ' route /api/goodvibes-agent/knowledge/search',
301
314
  ].join('\n');
302
315
  }
303
316
  return [
304
- `Agent Knowledge search: ${query}`,
317
+ `Agent Knowledge search ${query}`,
305
318
  ...results.slice(0, 10).map((result, index) => ` ${index + 1}. ${resultLine(result)}`),
306
319
  ].join('\n');
307
320
  }
@@ -320,10 +333,10 @@ export function formatIngest(
320
333
  const artifactId = cleanInline(record.artifactId);
321
334
  return [
322
335
  `Agent Knowledge ${label} accepted`,
323
- ` source: ${sourceId || '(pending)'}`,
324
- ` ${targetLabel}: ${canonicalUri}`,
336
+ ` knowledge source ${sourceId || '(pending)'}`,
337
+ ` ${targetLabel} ${canonicalUri}`,
325
338
  artifactId ? ` artifact: ${artifactId}` : null,
326
- ` route: ${route}`,
339
+ ` route ${route}`,
327
340
  ].filter((line): line is string => Boolean(line)).join('\n');
328
341
  }
329
342
 
@@ -335,11 +348,11 @@ export function formatBatchIngest(data: unknown, label: string): string {
335
348
  const errors = readArray(record, 'errors');
336
349
  return [
337
350
  `Agent Knowledge ${label} accepted`,
338
- ` imported: ${imported ?? sources.length}`,
339
- ` failed: ${failed ?? errors.length}`,
340
- ` sources: ${sources.length}`,
351
+ ` imported ${imported ?? sources.length}`,
352
+ ` failed ${failed ?? errors.length}`,
353
+ ` sources ${sources.length}`,
341
354
  ...sources.slice(0, 5).map((source) => ` - ${sourceLine(source)}`),
342
- ...(errors.length > 0 ? [' errors:', ...errors.slice(0, 5).map((error) => ` - ${cleanInline(error)}`)] : []),
355
+ ...(errors.length > 0 ? [' errors', ...errors.slice(0, 5).map((error) => ` - ${cleanInline(error)}`)] : []),
343
356
  ].join('\n');
344
357
  }
345
358
 
@@ -348,29 +361,29 @@ export function formatReindex(data: unknown): string {
348
361
  const status = isRecord(record.status) ? record.status : {};
349
362
  return [
350
363
  'Agent Knowledge reindex complete',
351
- ` sources: ${readNumber(status, 'sourceCount') ?? 'unknown'}`,
352
- ` nodes: ${readNumber(status, 'nodeCount') ?? 'unknown'}`,
353
- ` edges: ${readNumber(status, 'edgeCount') ?? 'unknown'}`,
354
- ` issues: ${readNumber(status, 'issueCount') ?? 'unknown'}`,
355
- ' route: /api/goodvibes-agent/knowledge/reindex',
364
+ ` sources ${readNumber(status, 'sourceCount') ?? 'unknown'}`,
365
+ ` nodes ${readNumber(status, 'nodeCount') ?? 'unknown'}`,
366
+ ` edges ${readNumber(status, 'edgeCount') ?? 'unknown'}`,
367
+ ` issues ${readNumber(status, 'issueCount') ?? 'unknown'}`,
368
+ ' route /api/goodvibes-agent/knowledge/reindex',
356
369
  ].join('\n');
357
370
  }
358
371
 
359
372
  export function formatFailure(failure: AgentKnowledgeFailureLike, json: boolean): string {
360
373
  if (json) return JSON.stringify(failure, null, 2);
361
374
  return [
362
- `Agent Knowledge error: ${failure.kind}`,
375
+ `Agent Knowledge error ${failure.kind} (${formatAgentKnowledgeFailureKind(failure.kind)})`,
363
376
  ` ${failure.error}`,
364
- ` runtime: ${failure.baseUrl}`,
365
- ` route: ${failure.route}`,
366
- failure.kind === 'version_mismatch' && failure.daemonVersion && failure.expectedSdkVersion
367
- ? ` versions: runtime=${failure.daemonVersion} expected=${failure.expectedSdkVersion}`
377
+ ` connected host ${failure.baseUrl}`,
378
+ ` route ${failure.route}`,
379
+ failure.kind === 'version_mismatch' && failure.connectedHostVersion && failure.expectedSdkVersion
380
+ ? ` versions connected host ${failure.connectedHostVersion}; expected ${failure.expectedSdkVersion}`
368
381
  : null,
369
382
  failure.kind === 'version_mismatch'
370
- ? ' next: update the connected GoodVibes host so /status matches the Agent SDK pin.'
383
+ ? ' next update the connected GoodVibes host so /status matches the Agent SDK pin.'
371
384
  : null,
372
- failure.kind === 'daemon_route_unavailable'
373
- ? ' next: update the connected GoodVibes host to the SDK version required by this Agent package.'
385
+ failure.kind === 'connected_host_route_unavailable'
386
+ ? ' next update the connected GoodVibes host to the SDK version required by this Agent package.'
374
387
  : null,
375
388
  ].filter((line): line is string => Boolean(line)).join('\n');
376
389
  }
@@ -1,4 +1,4 @@
1
- export interface DaemonCallMethod {
1
+ export interface ConnectedHostCallMethod {
2
2
  readonly kind: string;
3
3
  readonly route: string;
4
4
  }
@@ -3,24 +3,30 @@ import { join } from 'node:path';
3
3
  import { createBrowserAgentSdk } from '@pellux/goodvibes-sdk/browser/agent';
4
4
  import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
5
5
  import { SDK_VERSION, VERSION } from '../version.ts';
6
- import type { CliCommandRuntime } from './management.ts';
7
- import type { DaemonCallMethod } from './agent-knowledge-methods.ts';
6
+ import type { ConnectedHostCallMethod } from './agent-knowledge-methods.ts';
8
7
 
9
8
  export type JsonRecord = Record<string, unknown>;
10
9
 
11
- export interface AgentDaemonConnection {
10
+ export interface AgentKnowledgeConnection {
12
11
  readonly baseUrl: string;
13
12
  readonly token: string | null;
14
13
  readonly tokenPath: string;
15
14
  }
16
15
 
16
+ export interface AgentKnowledgeConnectionRuntime {
17
+ readonly configManager: {
18
+ get(key: string): unknown;
19
+ };
20
+ readonly homeDirectory: string;
21
+ }
22
+
17
23
  export interface AgentKnowledgeFailure {
18
24
  readonly ok: false;
19
- readonly kind: 'daemon_unavailable' | 'auth_required' | 'version_mismatch' | 'daemon_route_unavailable' | 'daemon_error';
25
+ readonly kind: 'connected_host_unavailable' | 'auth_required' | 'version_mismatch' | 'connected_host_route_unavailable' | 'connected_host_error';
20
26
  readonly error: string;
21
27
  readonly baseUrl: string;
22
28
  readonly route: string;
23
- readonly daemonVersion?: string;
29
+ readonly connectedHostVersion?: string;
24
30
  readonly expectedSdkVersion?: string;
25
31
  }
26
32
 
@@ -46,7 +52,7 @@ export function readPackageMetadata(): { readonly version: string; readonly sdkV
46
52
  return { version: VERSION, sdkVersion: SDK_VERSION };
47
53
  }
48
54
 
49
- export function resolveDaemonConnection(runtime: CliCommandRuntime): AgentDaemonConnection {
55
+ export function resolveConnectedHostConnection(runtime: AgentKnowledgeConnectionRuntime): AgentKnowledgeConnection {
50
56
  const host = String(runtime.configManager.get('controlPlane.host') ?? '127.0.0.1');
51
57
  const port = Number(runtime.configManager.get('controlPlane.port') ?? 3421);
52
58
  const baseUrl = `http://${host}:${Number.isFinite(port) ? port : 3421}`;
@@ -61,7 +67,7 @@ export function resolveDaemonConnection(runtime: CliCommandRuntime): AgentDaemon
61
67
  }
62
68
  }
63
69
 
64
- export async function fetchDaemonStatus(connection: AgentDaemonConnection): Promise<{ readonly ok: boolean; readonly status: number; readonly body: unknown }> {
70
+ export async function fetchConnectedHostStatus(connection: AgentKnowledgeConnection): Promise<{ readonly ok: boolean; readonly status: number; readonly body: unknown }> {
65
71
  try {
66
72
  const response = await fetch(`${connection.baseUrl}/status`, {
67
73
  headers: connection.token ? { authorization: `Bearer ${connection.token}` } : undefined,
@@ -79,7 +85,7 @@ export async function fetchDaemonStatus(connection: AgentDaemonConnection): Prom
79
85
  }
80
86
  }
81
87
 
82
- export async function classifyKnowledgeError(error: unknown, connection: AgentDaemonConnection, route: string): Promise<AgentKnowledgeFailure> {
88
+ export async function classifyKnowledgeError(error: unknown, connection: AgentKnowledgeConnection, route: string): Promise<AgentKnowledgeFailure> {
83
89
  const message = summarizeError(error);
84
90
  const lower = message.toLowerCase();
85
91
  if (lower.includes('401') || lower.includes('unauthorized') || lower.includes('auth')) {
@@ -87,29 +93,29 @@ export async function classifyKnowledgeError(error: unknown, connection: AgentDa
87
93
  }
88
94
  if (lower.includes('404') || lower.includes('not found')) {
89
95
  const metadata = readPackageMetadata();
90
- const daemon = await fetchDaemonStatus(connection);
91
- const daemonRecord = isRecord(daemon.body) ? daemon.body : {};
92
- const daemonVersion = readString(daemonRecord, 'version') ?? 'unknown';
93
- if (daemon.ok && daemonVersion !== metadata.sdkVersion) {
96
+ const connectedHost = await fetchConnectedHostStatus(connection);
97
+ const connectedHostRecord = isRecord(connectedHost.body) ? connectedHost.body : {};
98
+ const connectedHostVersion = readString(connectedHostRecord, 'version') ?? 'unknown';
99
+ if (connectedHost.ok && connectedHostVersion !== metadata.sdkVersion) {
94
100
  return {
95
101
  ok: false,
96
102
  kind: 'version_mismatch',
97
- error: `Connected GoodVibes host SDK version ${daemonVersion} does not match Agent SDK pin ${metadata.sdkVersion}; Agent Knowledge route is unavailable.`,
103
+ error: `Connected GoodVibes host SDK version ${connectedHostVersion} does not match Agent SDK pin ${metadata.sdkVersion}; Agent Knowledge route is unavailable.`,
98
104
  baseUrl: connection.baseUrl,
99
105
  route,
100
- daemonVersion,
106
+ connectedHostVersion,
101
107
  expectedSdkVersion: metadata.sdkVersion,
102
108
  };
103
109
  }
104
- return { ok: false, kind: 'daemon_route_unavailable', error: message, baseUrl: connection.baseUrl, route };
110
+ return { ok: false, kind: 'connected_host_route_unavailable', error: message, baseUrl: connection.baseUrl, route };
105
111
  }
106
112
  if (lower.includes('fetch') || lower.includes('connect') || lower.includes('econnrefused')) {
107
- return { ok: false, kind: 'daemon_unavailable', error: message, baseUrl: connection.baseUrl, route };
113
+ return { ok: false, kind: 'connected_host_unavailable', error: message, baseUrl: connection.baseUrl, route };
108
114
  }
109
- return { ok: false, kind: 'daemon_error', error: message, baseUrl: connection.baseUrl, route };
115
+ return { ok: false, kind: 'connected_host_error', error: message, baseUrl: connection.baseUrl, route };
110
116
  }
111
117
 
112
- export function createAgentSdk(connection: AgentDaemonConnection) {
118
+ export function createAgentSdk(connection: AgentKnowledgeConnection) {
113
119
  return createBrowserAgentSdk({
114
120
  baseUrl: connection.baseUrl,
115
121
  authToken: connection.token,
@@ -117,7 +123,7 @@ export function createAgentSdk(connection: AgentDaemonConnection) {
117
123
  }
118
124
 
119
125
  export async function postAgentKnowledgeJson<TData>(
120
- connection: AgentDaemonConnection,
126
+ connection: AgentKnowledgeConnection,
121
127
  route: string,
122
128
  body: JsonRecord,
123
129
  ): Promise<TData> {
@@ -164,7 +170,7 @@ function queryRoute(route: string, query: JsonRecord): string {
164
170
  }
165
171
 
166
172
  export async function getAgentKnowledgeJson<TData>(
167
- connection: AgentDaemonConnection,
173
+ connection: AgentKnowledgeConnection,
168
174
  route: string,
169
175
  query: JsonRecord = {},
170
176
  ): Promise<TData> {
@@ -211,22 +217,22 @@ export function findDisallowedKnowledgeScopeFlag(args: readonly string[]): strin
211
217
  export function formatScopeFlagRejection(flag: string): string {
212
218
  return [
213
219
  `Agent Knowledge is isolated; ${flag} is not accepted.`,
214
- 'GoodVibes Agent must not use default Knowledge/Wiki or non-Agent product spaces.',
220
+ 'GoodVibes Agent must not use default knowledge or non-Agent product spaces.',
215
221
  'Use only /api/goodvibes-agent/knowledge/* Agent-owned routes.',
216
222
  ].join('\n');
217
223
  }
218
224
 
219
225
  export async function runKnowledgeCall<TData>(
220
- runtime: CliCommandRuntime,
221
- method: DaemonCallMethod,
222
- call: (connection: AgentDaemonConnection) => Promise<TData>,
226
+ runtime: AgentKnowledgeConnectionRuntime,
227
+ method: ConnectedHostCallMethod,
228
+ call: (connection: AgentKnowledgeConnection) => Promise<TData>,
223
229
  ): Promise<AgentKnowledgeResult<TData>> {
224
- const connection = resolveDaemonConnection(runtime);
230
+ const connection = resolveConnectedHostConnection(runtime);
225
231
  if (!connection.token) {
226
232
  return {
227
233
  ok: false,
228
234
  kind: 'auth_required',
229
- error: `No runtime operator token found at ${connection.tokenPath}`,
235
+ error: `No connected-host operator token found at ${connection.tokenPath}`,
230
236
  baseUrl: connection.baseUrl,
231
237
  route: method.route,
232
238
  };
@@ -8,7 +8,6 @@ import { createRuntimeStore } from '../runtime/store/index.ts';
8
8
  import { getOnboardingCheckMarkerPath } from '../runtime/onboarding/index.ts';
9
9
  import { CONFIG_SCHEMA } from '../config/index.ts';
10
10
  import { SecretsManager } from '../config/secrets.ts';
11
- import type { ConfigKey } from '../config/index.ts';
12
11
  import type { CliCommandRuntime } from './management.ts';
13
12
  import type { CliCommandOutput } from './types.ts';
14
13
  import { getPackageVersion } from './help.ts';
@@ -35,14 +34,20 @@ function getNestedValue(source: unknown, key: string): unknown {
35
34
  let cursor = source;
36
35
  for (const part of key.split('.')) {
37
36
  if (cursor == null || typeof cursor !== 'object') return undefined;
38
- cursor = (cursor as Record<string, unknown>)[part];
37
+ cursor = Reflect.get(cursor, part);
39
38
  }
40
39
  return cursor;
41
40
  }
42
41
 
42
+ function isRecord(value: unknown): value is Record<string, unknown> {
43
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
44
+ }
45
+
43
46
  function readJsonFile(path: string): { readonly ok: true; readonly value: Record<string, unknown> } | { readonly ok: false; readonly error: string } {
44
47
  try {
45
- return { ok: true, value: JSON.parse(readFileSync(path, 'utf-8')) as Record<string, unknown> };
48
+ const value = JSON.parse(readFileSync(path, 'utf-8')) as unknown;
49
+ if (!isRecord(value)) return { ok: false, error: 'Bundle file must contain a JSON object.' };
50
+ return { ok: true, value };
46
51
  } catch (error) {
47
52
  return { ok: false, error: error instanceof Error ? error.message : String(error) };
48
53
  }
@@ -128,7 +133,7 @@ export async function handleBundleCommand(runtime: CliCommandRuntime): Promise<C
128
133
  if (!path) return { output: `Usage: ${runtime.cli.binary} bundle inspect <path>`, exitCode: 2 };
129
134
  const sourcePath = shellPaths.resolveWorkspacePath(path);
130
135
  const parsed = readJsonFile(sourcePath);
131
- if (!parsed.ok) return { output: `Invalid bundle JSON: ${parsed.error}`, exitCode: 1 };
136
+ if (!parsed.ok) return { output: `Invalid bundle JSON ${parsed.error}`, exitCode: 1 };
132
137
  const summary = inspectBundle(sourcePath, parsed.value);
133
138
  return {
134
139
  output: formatJsonOrText(runtime, summary, [
@@ -191,8 +196,8 @@ export async function handleBundleCommand(runtime: CliCommandRuntime): Promise<C
191
196
  output: formatJsonOrText(runtime, {
192
197
  path: targetPath,
193
198
  redactedConfigPaths: redactedConfig.redactedPaths,
194
- serviceIssues: service.issues,
195
- }, `Bundle exported: ${targetPath}\n redactedConfigKeys: ${redactedConfig.redactedPaths.length}\n serviceIssues: ${service.issues.length}`),
199
+ hostIntegrationIssues: service.issues,
200
+ }, `Bundle exported: ${targetPath}\n redactedConfigKeys: ${redactedConfig.redactedPaths.length}\n hostIntegrationIssues: ${service.issues.length}`),
196
201
  exitCode: 0,
197
202
  };
198
203
  }
@@ -202,7 +207,7 @@ export async function handleBundleCommand(runtime: CliCommandRuntime): Promise<C
202
207
  if (!path) return { output: `Usage: ${runtime.cli.binary} bundle import <path>`, exitCode: 2 };
203
208
  const sourcePath = shellPaths.resolveWorkspacePath(path);
204
209
  const parsed = readJsonFile(sourcePath);
205
- if (!parsed.ok) return { output: `Invalid bundle JSON: ${parsed.error}`, exitCode: 1 };
210
+ if (!parsed.ok) return { output: `Invalid bundle JSON ${parsed.error}`, exitCode: 1 };
206
211
  const config = parsed.value['config'];
207
212
  if (!config || typeof config !== 'object') return { output: 'Bundle has no config object to import.', exitCode: 1 };
208
213
  let count = 0;
@@ -214,7 +219,7 @@ export async function handleBundleCommand(runtime: CliCommandRuntime): Promise<C
214
219
  skippedRedacted++;
215
220
  continue;
216
221
  }
217
- runtime.configManager.setDynamic(setting.key as ConfigKey, value as never);
222
+ runtime.configManager.setDynamic(setting.key, value);
218
223
  count++;
219
224
  }
220
225
  return {