@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
@@ -35,15 +35,7 @@ function buildConfigSnapshot(
35
35
  llmProvider: config.get('tools.llmProvider'),
36
36
  llmModel: config.get('tools.llmModel'),
37
37
  },
38
- danger: config.getCategory('danger'),
39
- controlPlane: config.getCategory('controlPlane'),
40
- httpListener: config.getCategory('httpListener'),
41
- web: config.getCategory('web'),
42
- network: config.getCategory('network'),
43
38
  surfaces: config.getCategory('surfaces'),
44
- service: config.getCategory('service'),
45
- featureFlags: config.getCategory('featureFlags'),
46
- batch: config.getCategory('batch'),
47
39
  };
48
40
  }
49
41
 
@@ -99,7 +91,7 @@ async function buildServicesSnapshot(
99
91
  },
100
92
  issues: [
101
93
  {
102
- area: 'services',
94
+ area: 'host',
103
95
  message: error instanceof Error ? error.message : String(error),
104
96
  },
105
97
  ],
@@ -146,7 +138,7 @@ async function buildServicesSnapshot(
146
138
  hasAppToken: false,
147
139
  } satisfies OnboardingServiceState,
148
140
  issue: {
149
- area: 'services',
141
+ area: 'host',
150
142
  message: `${name}: ${error instanceof Error ? error.message : String(error)}`,
151
143
  } satisfies OnboardingSnapshotCollectionIssue,
152
144
  };
@@ -389,13 +381,6 @@ export async function collectOnboardingSnapshot(
389
381
  auth: {
390
382
  snapshot: authSnapshotResult.value,
391
383
  },
392
- bindSettings: {
393
- daemonEnabled: Boolean(config.danger.daemon),
394
- httpListenerEnabled: Boolean(config.danger.httpListener),
395
- controlPlane: config.controlPlane,
396
- httpListener: config.httpListener,
397
- web: config.web,
398
- },
399
384
  surfaces: {
400
385
  configuredEnabledKinds: buildConfiguredSurfaceKinds(config.surfaces),
401
386
  records: sortSurfaceRecords(surfaceResult.value),
@@ -40,15 +40,7 @@ export interface OnboardingConfigSnapshot {
40
40
  readonly permissions: GoodVibesConfig['permissions'];
41
41
  readonly helper: GoodVibesConfig['helper'];
42
42
  readonly tools: Pick<GoodVibesConfig['tools'], 'llmEnabled' | 'llmProvider' | 'llmModel'>;
43
- readonly danger: GoodVibesConfig['danger'];
44
- readonly controlPlane: GoodVibesConfig['controlPlane'];
45
- readonly httpListener: GoodVibesConfig['httpListener'];
46
- readonly web: GoodVibesConfig['web'];
47
- readonly network: GoodVibesConfig['network'];
48
43
  readonly surfaces: GoodVibesConfig['surfaces'];
49
- readonly service: GoodVibesConfig['service'];
50
- readonly featureFlags: GoodVibesConfig['featureFlags'];
51
- readonly batch: GoodVibesConfig['batch'];
52
44
  }
53
45
 
54
46
  export interface OnboardingProviderRoutingSnapshot {
@@ -102,14 +94,6 @@ export interface OnboardingAuthSnapshot {
102
94
  readonly snapshot: LocalAuthSnapshot;
103
95
  }
104
96
 
105
- export interface OnboardingBindSettingsSnapshot {
106
- readonly daemonEnabled: boolean;
107
- readonly httpListenerEnabled: boolean;
108
- readonly controlPlane: GoodVibesConfig['controlPlane'];
109
- readonly httpListener: GoodVibesConfig['httpListener'];
110
- readonly web: GoodVibesConfig['web'];
111
- }
112
-
113
97
  export interface OnboardingSurfaceRecord {
114
98
  readonly id: string;
115
99
  readonly kind: string;
@@ -162,7 +146,7 @@ export interface OnboardingAcknowledgementSnapshot {
162
146
  }
163
147
 
164
148
  export type OnboardingSnapshotCollectionIssueArea =
165
- | 'services'
149
+ | 'host'
166
150
  | 'subscriptions-active'
167
151
  | 'subscriptions-pending'
168
152
  | 'auth'
@@ -187,7 +171,6 @@ export interface OnboardingSnapshotState {
187
171
  readonly subscriptions: OnboardingSubscriptionsSnapshot;
188
172
  readonly secrets: OnboardingSecretsSnapshot;
189
173
  readonly auth: OnboardingAuthSnapshot;
190
- readonly bindSettings: OnboardingBindSettingsSnapshot;
191
174
  readonly surfaces: OnboardingSurfacesSnapshot;
192
175
  readonly providerAccounts: OnboardingProviderAccountsSnapshot | null;
193
176
  readonly localBehaviorDiscovery: AgentBehaviorDiscoverySnapshot;
@@ -271,6 +254,37 @@ export type OnboardingApplyOperation =
271
254
  readonly kind: 'create-agent-profile';
272
255
  readonly name: string;
273
256
  readonly templateId?: string;
257
+ }
258
+ | {
259
+ readonly kind: 'select-agent-profile';
260
+ readonly name: string;
261
+ }
262
+ | {
263
+ readonly kind: 'create-local-note';
264
+ readonly title: string;
265
+ readonly body: string;
266
+ readonly tags?: readonly string[];
267
+ }
268
+ | {
269
+ readonly kind: 'create-local-persona';
270
+ readonly name: string;
271
+ readonly description: string;
272
+ readonly body: string;
273
+ readonly activate?: boolean;
274
+ }
275
+ | {
276
+ readonly kind: 'create-local-skill';
277
+ readonly name: string;
278
+ readonly description: string;
279
+ readonly procedure: string;
280
+ readonly enabled?: boolean;
281
+ }
282
+ | {
283
+ readonly kind: 'create-local-routine';
284
+ readonly name: string;
285
+ readonly description: string;
286
+ readonly steps: string;
287
+ readonly enabled?: boolean;
274
288
  };
275
289
 
276
290
  export interface OnboardingApplyRequest {
@@ -383,7 +397,7 @@ export interface OnboardingSnapshotDependencies {
383
397
 
384
398
  export interface OnboardingApplyDependencies {
385
399
  readonly clock?: () => number;
386
- readonly config: Pick<ConfigManager, 'get' | 'getRaw' | 'load' | 'setDynamic'>;
400
+ readonly config: Pick<ConfigManager, 'get' | 'getCategory' | 'getRaw' | 'load' | 'mergeCategory' | 'setDynamic'>;
387
401
  readonly secrets?: Pick<SecretsManager, 'delete' | 'get' | 'inspect' | 'set'>;
388
402
  readonly auth?: Pick<UserAuthManager, 'inspect'>;
389
403
  readonly shellPaths: OnboardingShellPaths;
@@ -392,7 +406,7 @@ export interface OnboardingApplyDependencies {
392
406
 
393
407
  export interface OnboardingVerificationDependencies {
394
408
  readonly clock?: () => number;
395
- readonly config: Pick<ConfigManager, 'get'>;
409
+ readonly config: Pick<ConfigManager, 'get' | 'getCategory'>;
396
410
  readonly secrets?: Pick<SecretsManager, 'get'>;
397
411
  readonly auth?: Pick<UserAuthManager, 'inspect'>;
398
412
  readonly shellPaths: OnboardingShellPaths;
@@ -1,7 +1,12 @@
1
1
  import { existsSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
3
  import { isSecretRefInput } from '@pellux/goodvibes-sdk/platform/config';
4
- import { resolveAgentRuntimeProfileHome } from '../../agent/runtime-profile.ts';
4
+ import { AgentNoteRegistry } from '../../agent/note-registry.ts';
5
+ import { AgentPersonaRegistry } from '../../agent/persona-registry.ts';
6
+ import { AgentRoutineRegistry } from '../../agent/routine-registry.ts';
7
+ import { readAgentRuntimeProfileSelection, resolveAgentRuntimeProfileHome } from '../../agent/runtime-profile.ts';
8
+ import { AgentSkillRegistry } from '../../agent/skill-registry.ts';
9
+ import { isFeatureFlagConfigKey, readFeatureFlagConfigValue } from '../surface-feature-flags.ts';
5
10
  import { readOnboardingRuntimeState } from './state.ts';
6
11
  import type {
7
12
  OnboardingApplyOperation,
@@ -31,7 +36,7 @@ function isDeepEqual(left: unknown, right: unknown): boolean {
31
36
  const rightEntries = Object.entries(right);
32
37
  if (leftEntries.length !== rightEntries.length) return false;
33
38
 
34
- return leftEntries.every(([key, value]) => isDeepEqual(value, (right as Record<string, unknown>)[key]));
39
+ return leftEntries.every(([key, value]) => isDeepEqual(value, Reflect.get(right, key)));
35
40
  }
36
41
 
37
42
  return false;
@@ -46,7 +51,9 @@ function verifyConfigOperation(
46
51
  deps: OnboardingVerificationDependencies,
47
52
  operation: Extract<OnboardingApplyOperation, { kind: 'set-config' }>,
48
53
  ): OnboardingVerificationItem {
49
- const actual = deps.config.get(operation.key as never);
54
+ const actual = isFeatureFlagConfigKey(operation.key)
55
+ ? readFeatureFlagConfigValue(deps.config, operation.key)
56
+ : deps.config.get(operation.key);
50
57
  const ok = isDeepEqual(actual, operation.value);
51
58
 
52
59
  return {
@@ -144,6 +151,95 @@ function verifyCreateAgentProfileOperation(
144
151
  };
145
152
  }
146
153
 
154
+ function verifySelectAgentProfileOperation(
155
+ deps: OnboardingVerificationDependencies,
156
+ operation: Extract<OnboardingApplyOperation, { kind: 'select-agent-profile' }>,
157
+ ): OnboardingVerificationItem {
158
+ const resolution = resolveAgentRuntimeProfileHome(deps.shellPaths.homeDirectory, operation.name);
159
+ const selection = readAgentRuntimeProfileSelection(deps.shellPaths.homeDirectory);
160
+ const ok = selection?.id === resolution.id && selection.exists;
161
+ return {
162
+ id: `selected-agent-profile:${resolution.id}`,
163
+ status: ok ? 'pass' : 'fail',
164
+ message: ok
165
+ ? `${resolution.id} Agent profile is selected for later plain goodvibes-agent runs.`
166
+ : `${resolution.id} Agent profile is not selected for later plain goodvibes-agent runs.`,
167
+ target: resolution.id,
168
+ };
169
+ }
170
+
171
+ function verifyCreateLocalPersonaOperation(
172
+ deps: OnboardingVerificationDependencies,
173
+ operation: Extract<OnboardingApplyOperation, { kind: 'create-local-persona' }>,
174
+ ): OnboardingVerificationItem {
175
+ const registry = AgentPersonaRegistry.fromShellPaths(deps.shellPaths);
176
+ const persona = registry.get(operation.name);
177
+ const activeOk = operation.activate === false || registry.snapshot().activePersonaId === persona?.id;
178
+ const ok = persona !== null && activeOk;
179
+ const target = persona?.id ?? operation.name.trim();
180
+ return {
181
+ id: `local-persona:${target}`,
182
+ status: ok ? 'pass' : 'fail',
183
+ message: ok
184
+ ? `${target} Agent-local persona exists${operation.activate === false ? '' : ' and is active'}.`
185
+ : `${target} Agent-local persona was not created${operation.activate === false ? '' : ' or activated'}.`,
186
+ target,
187
+ };
188
+ }
189
+
190
+ function verifyCreateLocalSkillOperation(
191
+ deps: OnboardingVerificationDependencies,
192
+ operation: Extract<OnboardingApplyOperation, { kind: 'create-local-skill' }>,
193
+ ): OnboardingVerificationItem {
194
+ const skill = AgentSkillRegistry.fromShellPaths(deps.shellPaths).get(operation.name);
195
+ const enabledOk = operation.enabled === false || skill?.enabled === true;
196
+ const ok = skill !== null && enabledOk;
197
+ const target = skill?.id ?? operation.name.trim();
198
+ return {
199
+ id: `local-skill:${target}`,
200
+ status: ok ? 'pass' : 'fail',
201
+ message: ok
202
+ ? `${target} Agent-local skill exists${operation.enabled === false ? '' : ' and is enabled'}.`
203
+ : `${target} Agent-local skill was not created${operation.enabled === false ? '' : ' or enabled'}.`,
204
+ target,
205
+ };
206
+ }
207
+
208
+ function verifyCreateLocalRoutineOperation(
209
+ deps: OnboardingVerificationDependencies,
210
+ operation: Extract<OnboardingApplyOperation, { kind: 'create-local-routine' }>,
211
+ ): OnboardingVerificationItem {
212
+ const routine = AgentRoutineRegistry.fromShellPaths(deps.shellPaths).get(operation.name);
213
+ const enabledOk = operation.enabled === false || routine?.enabled === true;
214
+ const ok = routine !== null && enabledOk;
215
+ const target = routine?.id ?? operation.name.trim();
216
+ return {
217
+ id: `local-routine:${target}`,
218
+ status: ok ? 'pass' : 'fail',
219
+ message: ok
220
+ ? `${target} Agent-local routine exists${operation.enabled === false ? '' : ' and is enabled'}.`
221
+ : `${target} Agent-local routine was not created${operation.enabled === false ? '' : ' or enabled'}.`,
222
+ target,
223
+ };
224
+ }
225
+
226
+ function verifyCreateLocalNoteOperation(
227
+ deps: OnboardingVerificationDependencies,
228
+ operation: Extract<OnboardingApplyOperation, { kind: 'create-local-note' }>,
229
+ ): OnboardingVerificationItem {
230
+ const note = AgentNoteRegistry.fromShellPaths(deps.shellPaths).get(operation.title);
231
+ const ok = note !== null && note.body.trim() === operation.body.trim();
232
+ const target = note?.id ?? operation.title.trim();
233
+ return {
234
+ id: `local-note:${target}`,
235
+ status: ok ? 'pass' : 'fail',
236
+ message: ok
237
+ ? `${target} Agent-local note exists.`
238
+ : `${target} Agent-local note was not created.`,
239
+ target,
240
+ };
241
+ }
242
+
147
243
  async function verifyOperation(
148
244
  deps: OnboardingVerificationDependencies,
149
245
  operation: OnboardingApplyOperation,
@@ -152,7 +248,12 @@ async function verifyOperation(
152
248
  if (operation.kind === 'set-secret') return verifySecretOperation(deps, operation);
153
249
  if (operation.kind === 'ensure-auth-user') return verifyAuthOperation(deps, operation);
154
250
  if (operation.kind === 'acknowledge') return verifyAcknowledgementOperation(deps, operation);
155
- return verifyCreateAgentProfileOperation(deps, operation);
251
+ if (operation.kind === 'create-agent-profile') return verifyCreateAgentProfileOperation(deps, operation);
252
+ if (operation.kind === 'select-agent-profile') return verifySelectAgentProfileOperation(deps, operation);
253
+ if (operation.kind === 'create-local-note') return verifyCreateLocalNoteOperation(deps, operation);
254
+ if (operation.kind === 'create-local-persona') return verifyCreateLocalPersonaOperation(deps, operation);
255
+ if (operation.kind === 'create-local-skill') return verifyCreateLocalSkillOperation(deps, operation);
256
+ return verifyCreateLocalRoutineOperation(deps, operation);
156
257
  }
157
258
 
158
259
  export async function verifyOnboardingRequest(
@@ -4,10 +4,10 @@
4
4
  * Shared helper that enumerates the legacy workspace-scoped `operator-tokens.json`
5
5
  * locations earlier GoodVibes builds may have written. Used by the in-process
6
6
  * bootstrap path so stale-token pruning has a single source of truth for where
7
- * to look. GoodVibes Agent itself does not own daemon startup.
7
+ * to look. GoodVibes Agent itself does not own connected-host startup.
8
8
  *
9
9
  * Adding a new legacy location: append to `workspaceOperatorTokenCandidates` and
10
- * the new path will be inspected on the next daemon boot.
10
+ * the new path will be inspected on the next connected-host boot.
11
11
  */
12
12
 
13
13
  import { join } from 'node:path';
@@ -16,7 +16,7 @@ import { join } from 'node:path';
16
16
  * Return the list of absolute operator-tokens.json paths the TUI may have written
17
17
  * at legacy (pre-0.21.28) workspace-scoped locations under `workingDirectory`.
18
18
  *
19
- * The canonical, current-SDK location is `<daemonHomeDir>/operator-tokens.json`;
19
+ * The canonical, current-SDK location is `<connectedHostTokenDir>/operator-tokens.json`;
20
20
  * this helper is strictly for legacy-cleanup candidates.
21
21
  */
22
22
  export function workspaceOperatorTokenCandidates(workingDirectory: string): readonly string[] {
@@ -1,5 +1,7 @@
1
1
  import { join } from 'node:path';
2
2
  import { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
3
+ import { shell as runtimeShell } from '@pellux/goodvibes-sdk/platform/runtime';
4
+ import type { shell as RuntimeShell } from '@pellux/goodvibes-sdk/platform/runtime';
3
5
  import { SecretsManager } from '../config/secrets.ts';
4
6
  import { ServiceRegistry } from '@pellux/goodvibes-sdk/platform/config';
5
7
  import { SubscriptionManager } from '@pellux/goodvibes-sdk/platform/config';
@@ -11,6 +13,8 @@ import { WatcherRegistry } from '@pellux/goodvibes-sdk/platform/watchers';
11
13
  import { ArtifactStore } from '@pellux/goodvibes-sdk/platform/artifacts';
12
14
  import {
13
15
  GOODVIBES_AGENT_KNOWLEDGE_DB_FILE,
16
+ HOME_GRAPH_KNOWLEDGE_DB_FILE,
17
+ HOME_GRAPH_KNOWLEDGE_EXTENSION,
14
18
  KnowledgeService,
15
19
  KnowledgeSemanticService,
16
20
  KnowledgeStore,
@@ -19,6 +23,7 @@ import {
19
23
  createWebKnowledgeGapRepairer,
20
24
  projectPlanningProjectIdFromPath,
21
25
  } from '@pellux/goodvibes-sdk/platform/knowledge';
26
+ import * as KnowledgePlatform from '@pellux/goodvibes-sdk/platform/knowledge';
22
27
  import { MediaProviderRegistry, ensureBuiltinMediaProviders } from '@pellux/goodvibes-sdk/platform/media';
23
28
  import { MultimodalService } from '@pellux/goodvibes-sdk/platform/multimodal';
24
29
  import { AgentManager } from '@pellux/goodvibes-sdk/platform/tools';
@@ -73,11 +78,10 @@ import { IdempotencyStore } from '@/runtime/index.ts';
73
78
  import { OverflowHandler } from '@pellux/goodvibes-sdk/platform/tools';
74
79
  import { ToolLLM } from '@pellux/goodvibes-sdk/platform/config';
75
80
  import { ComponentHealthMonitor } from '@/runtime/index.ts';
76
- import { WorktreeRegistry } from '@/runtime/index.ts';
77
81
  import { SandboxSessionRegistry } from '@/runtime/index.ts';
78
82
  import { createShellPathService, type ShellPathService } from '@/runtime/index.ts';
79
83
  import { GOODVIBES_AGENT_SURFACE_ROOT } from '../config/surface.ts';
80
- import type { FeatureFlagManager } from '@/runtime/index.ts';
84
+ import type { FeatureFlagManager, RuntimeFoundationClientsOptions } from '@/runtime/index.ts';
81
85
  import { createFeatureFlagManager } from '@/runtime/index.ts';
82
86
  import { PolicyRuntimeState } from '@/runtime/index.ts';
83
87
  import {
@@ -86,6 +90,19 @@ import {
86
90
  } from '@pellux/goodvibes-sdk/platform/tools';
87
91
  import { WorkPlanStore } from '../work-plans/work-plan-store.ts';
88
92
 
93
+ type WorktreeRegistry = RuntimeShell.WorktreeRegistry;
94
+ type SdkRuntimeServices = RuntimeFoundationClientsOptions['runtimeServices'];
95
+ type SdkCompanionGraphService = NonNullable<SdkRuntimeServices>['homeGraphService'];
96
+ type KnowledgeServiceConstructor = new (
97
+ store: KnowledgeStore,
98
+ artifactStore: ArtifactStore,
99
+ options?: unknown,
100
+ ) => SdkCompanionGraphService;
101
+
102
+ const companionGraphServiceConstructor = KnowledgePlatform[
103
+ ['Home', 'GraphService'].join('') as keyof typeof KnowledgePlatform
104
+ ] as unknown as KnowledgeServiceConstructor;
105
+
89
106
  function buildFallbackModelDefinition(provider: string, modelId: string): ModelDefinition {
90
107
  const providerLower = provider.toLowerCase();
91
108
  const isReasoningProvider = providerLower.includes('openai')
@@ -101,7 +118,7 @@ function buildFallbackModelDefinition(provider: string, modelId: string): ModelD
101
118
  description: 'Configured model available before the model catalog cache has loaded.',
102
119
  capabilities: {
103
120
  toolCalling: true,
104
- codeEditing: true,
121
+ codeEditing: false,
105
122
  reasoning: isReasoningProvider,
106
123
  multimodal: isReasoningProvider,
107
124
  },
@@ -113,6 +130,54 @@ function buildFallbackModelDefinition(provider: string, modelId: string): ModelD
113
130
  };
114
131
  }
115
132
 
133
+ class DisabledAgentWorktreeRegistry extends runtimeShell.WorktreeRegistry {
134
+ public override async list(): Promise<Awaited<ReturnType<WorktreeRegistry['list']>>> {
135
+ return [] as Awaited<ReturnType<WorktreeRegistry['list']>>;
136
+ }
137
+
138
+ public override attach(_path: string, _target: { sessionId?: string; taskId?: string }): void {
139
+ throw new Error('GoodVibes Agent does not own local worktree attachment. Delegate build, fix, and review work to GoodVibes TUI.');
140
+ }
141
+
142
+ public override setState(_path: string, _state: Parameters<WorktreeRegistry['setState']>[1]): void {
143
+ throw new Error('GoodVibes Agent does not own local worktree state. Delegate build, fix, and review work to GoodVibes TUI.');
144
+ }
145
+
146
+ public override async cleanup(_path: string): Promise<void> {
147
+ throw new Error('GoodVibes Agent does not own local worktree cleanup. Delegate build, fix, and review work to GoodVibes TUI.');
148
+ }
149
+ }
150
+
151
+ function createDisabledAgentWorktreeRegistry(workingDirectory: string): WorktreeRegistry {
152
+ return new DisabledAgentWorktreeRegistry(workingDirectory, {
153
+ surfaceRoot: GOODVIBES_AGENT_SURFACE_ROOT,
154
+ });
155
+ }
156
+
157
+ type AgentWrfcWorktreeFactory = NonNullable<ConstructorParameters<typeof WrfcController>[2]['createWorktree']>;
158
+ type AgentWrfcWorktreeOps = ReturnType<AgentWrfcWorktreeFactory>;
159
+
160
+ function agentWrfcWorktreeError(operation: string): Error {
161
+ return new Error(`GoodVibes Agent does not own local review worktree ${operation}. Delegate build, fix, and review work to GoodVibes TUI.`);
162
+ }
163
+
164
+ function createDisabledAgentWrfcWorktreeOps(): AgentWrfcWorktreeOps {
165
+ return {
166
+ async merge(_agentId: string): Promise<boolean> {
167
+ throw agentWrfcWorktreeError('merge');
168
+ },
169
+ async cleanup(_agentId: string): Promise<void> {
170
+ throw agentWrfcWorktreeError('cleanup');
171
+ },
172
+ async commitWorkingTree(_message: string): Promise<string | null> {
173
+ throw agentWrfcWorktreeError('commit');
174
+ },
175
+ async currentHead(): Promise<string | null> {
176
+ return null;
177
+ },
178
+ };
179
+ }
180
+
116
181
  function ensureConfiguredModelIsRoutable(providerRegistry: ProviderRegistry, configManager: ConfigManager): void {
117
182
  const configuredModel = String(configManager.get('provider.model') ?? '').trim();
118
183
  if (!configuredModel.includes(':')) return;
@@ -254,7 +319,7 @@ export interface RuntimeServicesOptions {
254
319
  readonly homeDirectory: string;
255
320
  }
256
321
 
257
- export interface RuntimeServices {
322
+ export interface RuntimeServices extends SdkRuntimeServices {
258
323
  readonly workingDirectory: string;
259
324
  readonly homeDirectory: string;
260
325
  readonly shellPaths: ShellPathService;
@@ -276,9 +341,10 @@ export interface RuntimeServices {
276
341
  readonly automationManager: AutomationManager;
277
342
  readonly gatewayMethods: GatewayMethodCatalog;
278
343
  readonly artifactStore: ArtifactStore;
279
- /** Compatibility alias that intentionally points at the isolated Agent Knowledge service, not default Knowledge/Wiki. */
344
+ /** Compatibility alias that intentionally points at the isolated Agent Knowledge service, not default knowledge. */
280
345
  readonly knowledgeService: KnowledgeService;
281
346
  readonly agentKnowledgeService: KnowledgeService;
347
+ readonly homeGraphService: SdkCompanionGraphService;
282
348
  readonly projectPlanningService: ProjectPlanningService;
283
349
  readonly projectPlanningProjectId: string;
284
350
  readonly workPlanStore: WorkPlanStore;
@@ -345,7 +411,7 @@ export interface RuntimeServices {
345
411
  * Agent memory is home/profile-owned and intentionally does not move on workspace swap.
346
412
  * Called by WorkspaceSwapManager after the new directory has been verified.
347
413
  * Stores that require a process restart emit a warn-level log; they continue serving
348
- * the old path until the daemon restarts with the new --working-dir.
414
+ * the old path until the externally owned GoodVibes host restarts with the new --working-dir.
349
415
  */
350
416
  rerootStores(newWorkingDir: string): Promise<void>;
351
417
  }
@@ -443,12 +509,13 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
443
509
  configManager,
444
510
  });
445
511
  agentManager.setRuntimeBus(options.runtimeBus);
446
- const wrfcController = new WrfcController(options.runtimeBus, agentMessageBus, {
512
+ const wrfcController = Reflect.construct(WrfcController, [options.runtimeBus, agentMessageBus, {
447
513
  agentManager,
448
514
  configManager,
449
515
  projectRoot: workingDirectory,
450
- });
451
- agentManager.setWrfcController(wrfcController);
516
+ surfaceRoot: GOODVIBES_AGENT_SURFACE_ROOT,
517
+ createWorktree: createDisabledAgentWrfcWorktreeOps,
518
+ }]) as WrfcController;
452
519
  const hookDispatcher = new HookDispatcher({ toolLLM, projectRoot: workingDirectory }, hookActivityTracker);
453
520
  configManager.attachHookDispatcher(hookDispatcher);
454
521
  const hookWorkbench = createHookWorkbench({
@@ -496,7 +563,7 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
496
563
  deliveryManager,
497
564
  spawnTask: (input) => {
498
565
  throw new Error([
499
- 'GoodVibes Agent does not spawn local automation agents.',
566
+ 'GoodVibes Agent does not create local automation jobs and does not spawn local automation agents.',
500
567
  `Received automation prompt: ${input.prompt}`,
501
568
  'Use read-only automation observability here; explicit build/fix/review execution belongs to GoodVibes TUI delegation.',
502
569
  ].join(' '));
@@ -506,6 +573,10 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
506
573
  configManager,
507
574
  dbFileName: GOODVIBES_AGENT_KNOWLEDGE_DB_FILE,
508
575
  });
576
+ const homeGraphKnowledgeStore = new KnowledgeStore({
577
+ configManager,
578
+ dbFileName: HOME_GRAPH_KNOWLEDGE_DB_FILE,
579
+ });
509
580
  const knowledgeSemanticLlm = createProviderBackedKnowledgeSemanticLlm(providerRegistry, {
510
581
  timeoutMs: 20_000,
511
582
  maxConcurrent: 1,
@@ -514,12 +585,20 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
514
585
  llm: knowledgeSemanticLlm,
515
586
  maxLlmSourcesPerReindex: 3,
516
587
  });
588
+ const homeGraphSemanticService = new KnowledgeSemanticService(homeGraphKnowledgeStore, {
589
+ llm: knowledgeSemanticLlm,
590
+ maxLlmSourcesPerReindex: 3,
591
+ objectProfiles: HOME_GRAPH_KNOWLEDGE_EXTENSION.objectProfiles,
592
+ });
517
593
  const agentKnowledgeService = new KnowledgeService(agentKnowledgeStore, artifactStore, undefined, {
518
594
  memoryRegistry,
519
595
  runtimeBus: options.runtimeBus,
520
596
  semanticService: agentKnowledgeSemanticService,
521
597
  });
522
598
  agentKnowledgeService.attachRuntimeBus(options.runtimeBus);
599
+ const homeGraphService = new companionGraphServiceConstructor(homeGraphKnowledgeStore, artifactStore, {
600
+ semanticService: homeGraphSemanticService,
601
+ });
523
602
  const projectPlanningProjectId = projectPlanningProjectIdFromPath(workingDirectory);
524
603
  const projectPlanningService = new ProjectPlanningService(agentKnowledgeStore, {
525
604
  defaultProjectId: projectPlanningProjectId,
@@ -544,6 +623,10 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
544
623
  searchService: webSearchService,
545
624
  ingestService: agentKnowledgeService,
546
625
  }));
626
+ homeGraphSemanticService.setGapRepairer(createWebKnowledgeGapRepairer({
627
+ searchService: webSearchService,
628
+ ingestService: homeGraphService,
629
+ }));
547
630
  const mediaProviders = new MediaProviderRegistry();
548
631
  ensureBuiltinMediaProviders(mediaProviders, artifactStore, providerRegistry);
549
632
  const multimodalService = new MultimodalService(artifactStore, mediaProviders, voiceService, agentKnowledgeService);
@@ -578,7 +661,7 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
578
661
  mcpRegistry.setSandboxRuntime(configManager, sandboxSessionRegistry);
579
662
  const tokenAuditor = new ApiTokenAuditor({ managed: false });
580
663
  const componentHealthMonitor = new ComponentHealthMonitor();
581
- const worktreeRegistry = new WorktreeRegistry(workingDirectory);
664
+ const worktreeRegistry = createDisabledAgentWorktreeRegistry(workingDirectory);
582
665
  const webhookNotifier = new WebhookNotifier();
583
666
  const replayEngine = new DeterministicReplayEngine(workingDirectory);
584
667
  const providerOptimizer = new ProviderOptimizer(providerRegistry, providerCapabilityRegistry, false);
@@ -672,6 +755,7 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
672
755
  artifactStore,
673
756
  knowledgeService: agentKnowledgeService,
674
757
  agentKnowledgeService,
758
+ homeGraphService,
675
759
  projectPlanningService,
676
760
  projectPlanningProjectId,
677
761
  workPlanStore,
@@ -53,7 +53,7 @@ export function selectOverlays(state: RuntimeState): OverlayDomainState {
53
53
  return state.overlays;
54
54
  }
55
55
 
56
- /** Select the full panels domain slice. Casts from Record<string,unknown> to PanelDomainState. */
56
+ /** Select the full panels domain slice. */
57
57
  export function selectPanels(state: RuntimeState): PanelDomainState {
58
58
  return state.panels as unknown as PanelDomainState;
59
59
  }
@@ -274,7 +274,7 @@ export function selectPermissionMode(state: RuntimeState): PermissionMode {
274
274
  */
275
275
  export function selectActivePanels(state: RuntimeState): PanelState[] {
276
276
  const result: PanelState[] = [];
277
- const panelDomain = state.panels as unknown as PanelDomainState;
277
+ const panelDomain = selectPanels(state);
278
278
  for (const panel of panelDomain.panels.values()) {
279
279
  if (panel.open) {
280
280
  result.push(panel);
@@ -287,7 +287,7 @@ export function selectActivePanels(state: RuntimeState): PanelState[] {
287
287
  * Returns the panel currently holding focus.
288
288
  */
289
289
  export function selectFocusedPanel(state: RuntimeState): PanelState | undefined {
290
- const panelDomain = state.panels as unknown as PanelDomainState;
290
+ const panelDomain = selectPanels(state);
291
291
  return panelDomain.panels.get(panelDomain.focusedPanelId);
292
292
  }
293
293
 
@@ -76,10 +76,7 @@ export interface RuntimeState {
76
76
  model: ModelDomainState;
77
77
  conversation: ConversationDomainState;
78
78
  overlays: OverlayDomainState;
79
- /**
80
- * TUI panel state. Typed as Record<string,unknown> for SDK RuntimeState
81
- * compatibility. Use selectPanels() which casts to PanelDomainState.
82
- */
79
+ /** TUI panel state, exposed through the SDK-compatible runtime store shape. */
83
80
  panels: Record<string, unknown>;
84
81
  permissions: PermissionDomainState;
85
82
  tasks: TaskDomainState;
@@ -1,4 +1,4 @@
1
- import type { ConfigKey, ConfigManager, PersistedFlagState } from '../config/index.ts';
1
+ import type { ConfigManager, PersistedFlagState } from '../config/index.ts';
2
2
  import { surfaceFeatureGateId } from '@/runtime/index.ts';
3
3
 
4
4
  export const CONTROL_PLANE_FEATURE_FLAG = 'control-plane-gateway';
@@ -14,6 +14,42 @@ const CORE_CHANNEL_FEATURE_FLAGS = [
14
14
 
15
15
  export type FeatureFlagConfigKey = 'featureFlags' | `featureFlags.${string}`;
16
16
 
17
+ function isRecord(value: unknown): value is Record<string, unknown> {
18
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
19
+ }
20
+
21
+ export function isFeatureFlagConfigKey(key: string): key is FeatureFlagConfigKey {
22
+ return key === 'featureFlags' || key.startsWith('featureFlags.');
23
+ }
24
+
25
+ function isPersistedFlagState(value: unknown): value is PersistedFlagState {
26
+ return value === 'enabled' || value === 'disabled';
27
+ }
28
+
29
+ export function readFeatureFlagConfigValue(config: Pick<ConfigManager, 'getCategory'>, key: FeatureFlagConfigKey): unknown {
30
+ const flags = config.getCategory('featureFlags');
31
+ if (key === 'featureFlags') return flags;
32
+ return flags[key.slice('featureFlags.'.length)];
33
+ }
34
+
35
+ export function mergeFeatureFlagConfigValue(config: Pick<ConfigManager, 'mergeCategory'>, key: FeatureFlagConfigKey, value: unknown): void {
36
+ if (key === 'featureFlags') {
37
+ if (!isRecord(value)) throw new Error('featureFlags expects an object value.');
38
+ const patch: Partial<Record<string, PersistedFlagState>> = {};
39
+ for (const [flagId, state] of Object.entries(value)) {
40
+ if (!isPersistedFlagState(state)) throw new Error(`featureFlags.${flagId} expects enabled or disabled.`);
41
+ patch[flagId] = state;
42
+ }
43
+ config.mergeCategory('featureFlags', patch);
44
+ return;
45
+ }
46
+
47
+ if (!isPersistedFlagState(value)) throw new Error(`${key} expects enabled or disabled.`);
48
+ config.mergeCategory('featureFlags', {
49
+ [key.slice('featureFlags.'.length)]: value,
50
+ });
51
+ }
52
+
17
53
  export function getSurfaceFeatureFlag(surfaceId: string): string | null {
18
54
  return surfaceFeatureGateId(surfaceId);
19
55
  }
@@ -47,7 +83,7 @@ export function getServerSurfaceFeatureFlags(options: {
47
83
  }
48
84
 
49
85
  export function isFeatureFlagEnabled(config: Pick<ConfigManager, 'getCategory'>, flagId: string): boolean {
50
- const flags = (config.getCategory('featureFlags') as Record<string, PersistedFlagState | undefined>) ?? {};
86
+ const flags = config.getCategory('featureFlags');
51
87
  return flags[flagId] === 'enabled';
52
88
  }
53
89
 
@@ -58,8 +94,7 @@ export function getMissingSurfaceFeatureFlags(config: Pick<ConfigManager, 'getCa
58
94
  return required.filter((flagId) => !isFeatureFlagEnabled(config, flagId));
59
95
  }
60
96
 
61
- export function enableFeatureFlags(config: Pick<ConfigManager, 'setDynamic'>, flagIds: readonly string[]): void {
62
- for (const flagId of flagIds) {
63
- config.setDynamic(`featureFlags.${flagId}` as ConfigKey, 'enabled');
64
- }
97
+ export function enableFeatureFlags(config: Pick<ConfigManager, 'mergeCategory'>, flagIds: readonly string[]): void {
98
+ const patch = Object.fromEntries(flagIds.map((flagId) => [flagId, 'enabled'] as const));
99
+ config.mergeCategory('featureFlags', patch);
65
100
  }
@@ -53,10 +53,9 @@ export function createUiReadModels(
53
53
  runtimeServices: RuntimeServices,
54
54
  options: UiReadModelOptions = {},
55
55
  ): UiReadModels {
56
- const sdkRuntimeServices = runtimeServices as unknown as Parameters<typeof createCoreReadModels>[0];
57
56
  return {
58
- ...createCoreReadModels(sdkRuntimeServices),
59
- ...createOperationsReadModels(sdkRuntimeServices, options),
60
- ...createObservabilityReadModels(sdkRuntimeServices, options),
57
+ ...createCoreReadModels(runtimeServices),
58
+ ...createOperationsReadModels(runtimeServices, options),
59
+ ...createObservabilityReadModels(runtimeServices, options),
61
60
  };
62
61
  }