@memorax/memorax-code 0.1.8 → 0.1.10

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 (102) hide show
  1. package/README.md +10 -0
  2. package/bin/memorax-code-codebuddy.mjs +4 -0
  3. package/bin/memorax-code-setup.mjs +182 -65
  4. package/bin/memorax-code.mjs +74 -45
  5. package/docs/configuration.md +82 -22
  6. package/docs/troubleshooting.md +69 -5
  7. package/lib/automatic-update.mjs +233 -0
  8. package/lib/memorax-code-adapter-common/src/automatic-update-state.d.mts +24 -0
  9. package/lib/memorax-code-adapter-common/src/automatic-update-state.mjs +73 -0
  10. package/lib/memorax-code-adapter-common/src/clients/codebuddy-command.mjs +82 -0
  11. package/lib/memorax-code-adapter-common/src/config-utils.d.mts +2 -0
  12. package/lib/memorax-code-adapter-common/src/config-utils.mjs +11 -0
  13. package/lib/memorax-code-adapter-common/src/hooks/client-hook-launcher.mjs +3 -0
  14. package/lib/memorax-code-adapter-common/src/hooks/ensure-backend-runner.mjs +45 -10
  15. package/lib/memorax-code-adapter-common/src/repo-memory/repo-memory-job-worker.mjs +88 -3
  16. package/lib/memorax-code-adapter-common/src/windows-cli-invocation.mjs +11 -1
  17. package/lib/memorax-code-backend/dist/app/backend-server.js +2 -2
  18. package/lib/memorax-code-backend/dist/app/memory-observability.js +2 -2
  19. package/lib/memorax-code-backend/dist/clients/codebuddy/jsonl-history.js +208 -0
  20. package/lib/memorax-code-backend/dist/clients/codebuddy/lifecycle.js +44 -0
  21. package/lib/memorax-code-backend/dist/clients/codebuddy/memory-hook-runtime.js +250 -0
  22. package/lib/memorax-code-backend/dist/clients/codebuddy/turn-id.js +16 -0
  23. package/lib/memorax-code-backend/dist/clients/codex/plugin-install.js +129 -7
  24. package/lib/memorax-code-backend/dist/clients/codex/rollout-turn.js +52 -2
  25. package/lib/memorax-code-backend/dist/config/memorax-code.js +14 -1
  26. package/lib/memorax-code-backend/dist/entrypoints/backend-cli.js +43 -6
  27. package/lib/memorax-code-backend/dist/lifecycle/active-clients.js +3 -0
  28. package/lib/memorax-code-backend/dist/lifecycle/automatic-update-scheduler.js +133 -0
  29. package/lib/memorax-code-backend/dist/lifecycle/client-plugin-removal.js +14 -2
  30. package/lib/memorax-code-backend/dist/lifecycle/client-selection.js +6 -4
  31. package/lib/memorax-code-backend/dist/lifecycle/orchestrator.js +48 -9
  32. package/lib/memorax-code-backend/dist/memory/cli.js +4 -2
  33. package/lib/memorax-code-backend/dist/memory/hook-command.js +31 -1
  34. package/lib/memorax-code-backend/dist/memory/reminder-trace-recorder.js +5 -1
  35. package/lib/memorax-code-backend/dist/memory/service.js +12 -0
  36. package/lib/memorax-code-backend/dist/shared/windows-cli-invocation.js +10 -1
  37. package/lib/memorax-code-backend/dist/trace/config.js +12 -0
  38. package/lib/memorax-code-backend/dist/trace/context.js +21 -1
  39. package/lib/memorax-code-backend/dist/trace/store.js +12 -1
  40. package/lib/memorax-code-backend/package.json +1 -1
  41. package/lib/memorax-code-claude-adapter/.claude-plugin/plugin.json +1 -1
  42. package/lib/memorax-code-claude-adapter/hooks/runtime-shell.json +1 -1
  43. package/lib/memorax-code-claude-adapter/package.json +1 -1
  44. package/lib/memorax-code-claude-adapter/runtime-hooks/ensure-backend.mjs +2 -0
  45. package/lib/memorax-code-claude-adapter/src/plugin-install.mjs +3 -0
  46. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/.claude-plugin/plugin.json +1 -1
  47. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/hooks/runtime-shell.json +1 -1
  48. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/automatic-update-state.d.mts +24 -0
  49. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/automatic-update-state.mjs +73 -0
  50. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/clients/codebuddy-command.mjs +82 -0
  51. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/config-utils.d.mts +2 -0
  52. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/config-utils.mjs +11 -0
  53. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/hooks/client-hook-launcher.mjs +3 -0
  54. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/hooks/ensure-backend-runner.mjs +45 -10
  55. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/repo-memory/repo-memory-job-worker.mjs +88 -3
  56. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/windows-cli-invocation.mjs +11 -1
  57. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/package.json +1 -1
  58. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/runtime-hooks/ensure-backend.mjs +2 -0
  59. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/src/plugin-install.mjs +3 -0
  60. package/lib/memorax-code-codebuddy-adapter/.codebuddy-plugin/plugin.json +7 -0
  61. package/lib/memorax-code-codebuddy-adapter/hooks/common-runtime.mjs +13 -0
  62. package/lib/memorax-code-codebuddy-adapter/hooks/hooks.json +38 -0
  63. package/lib/memorax-code-codebuddy-adapter/hooks/repo-memory-job.mjs +40 -0
  64. package/lib/memorax-code-codebuddy-adapter/hooks/runtime-hook.mjs +279 -0
  65. package/lib/memorax-code-codebuddy-adapter/package.json +9 -0
  66. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/SKILL.md +85 -0
  67. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/agents/claude.yaml +10 -0
  68. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/agents/openai.yaml +7 -0
  69. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/defaults.json +12 -0
  70. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/references/memorax-add.md +88 -0
  71. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/references/memorax-search.md +93 -0
  72. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/references/personal-read.md +46 -0
  73. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/references/personal-write.md +120 -0
  74. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/references/repo-build.md +319 -0
  75. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/references/repo-read.md +103 -0
  76. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/references/repo-templates.md +390 -0
  77. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/references/repo-update.md +127 -0
  78. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/scripts/collect_all.py +579 -0
  79. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/scripts/detect_updates.py +919 -0
  80. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/scripts/git_commit_facets.py +222 -0
  81. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/scripts/github_resource_facets.py +512 -0
  82. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/scripts/gitlab_resource_facets.py +517 -0
  83. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/scripts/prepare_repo_memory.py +411 -0
  84. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/scripts/user_profile_memory.py +528 -0
  85. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/scripts/validate_memory.py +248 -0
  86. package/lib/memorax-code-codebuddy-adapter/src/cli.mjs +58 -0
  87. package/lib/memorax-code-codebuddy-adapter/src/config.mjs +277 -0
  88. package/lib/memorax-code-codebuddy-adapter/src/hook-manifest.mjs +47 -0
  89. package/lib/memorax-code-codebuddy-adapter/src/runtime-observation.mjs +65 -0
  90. package/lib/memorax-code-codex-adapter/.codex-plugin/plugin.json +1 -1
  91. package/lib/memorax-code-codex-adapter/hooks/runtime-shell.json +1 -1
  92. package/lib/memorax-code-codex-adapter/package.json +1 -1
  93. package/lib/memorax-code-codex-adapter/runtime-hooks/ensure-backend.mjs +4 -1
  94. package/lib/memorax-code-dsh-adapter/package.json +2 -1
  95. package/lib/memorax-code-dsh-adapter/src/profile-lifecycle.mjs +1 -0
  96. package/lib/memorax-code-opencode-adapter/package.json +1 -1
  97. package/lib/npm-invocation.mjs +51 -8
  98. package/lib/resolve-codebuddy-command.mjs +112 -0
  99. package/lib/run-entrypoint.mjs +25 -1
  100. package/lib/windows-cli-invocation.mjs +11 -1
  101. package/lib/windows-user-path.mjs +218 -0
  102. package/package.json +5 -3
package/README.md CHANGED
@@ -54,6 +54,16 @@ Both setup paths automatically detect supported coding agents. Later setup
54
54
  runs reuse a complete saved configuration; use
55
55
  `memorax-code setup --reconfigure` to replace it.
56
56
 
57
+ On Windows, interactive setup also verifies npm's global command directory and
58
+ adds it to the current setup process and the Windows user `PATH` when needed.
59
+ If the current shell cannot find `memorax-code`, bootstrap setup with:
60
+
61
+ ```powershell
62
+ $NpmGlobalBin = (npm prefix -g).Trim()
63
+ $env:Path = "$NpmGlobalBin;$env:Path"
64
+ & (Join-Path $NpmGlobalBin "memorax-code.cmd") setup
65
+ ```
66
+
57
67
  After the first installation, restart or refresh the detected coding agents
58
68
  before opening a new session. In Codex, enable **MemoraX Code Codex Adapter**
59
69
  from Plugins or `/plugins` if it is not already enabled.
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { runCodeBuddyAdapterCli } from "../lib/run-entrypoint.mjs";
3
+
4
+ await runCodeBuddyAdapterCli();
@@ -21,6 +21,7 @@ import { stagePackagedClientHookRuntime } from "../lib/client-hook-runtime.mjs";
21
21
  import { discoverDshProfiles } from "../lib/dsh-plugin-install.mjs";
22
22
  import { ensureClaudeCommandEnv } from "../lib/resolve-claude-command.mjs";
23
23
  import { ensureCodexCommandEnv } from "../lib/resolve-codex-command.mjs";
24
+ import { defaultCodeBuddyHome, ensureCodeBuddyCommandEnv } from "../lib/resolve-codebuddy-command.mjs";
24
25
  import { reconcileSetup } from "../lib/setup-reconcile.mjs";
25
26
  import { detectSetupMemoryPreferences } from "../lib/setup-memory-preferences.mjs";
26
27
  import { ensureTrialSetupCredential } from "../lib/trial-setup.mjs";
@@ -44,12 +45,18 @@ const DSH_OPTIONAL_ENV = "MEMORAX_CODE_DSH_ADAPTER_OPTIONAL";
44
45
  const skipCodexPluginInstall = truthyEnv(process.env.MEMORAX_CODE_SKIP_CODEX_PLUGIN_INSTALL);
45
46
  const skipClaudeAdapterInstall = truthyEnv(process.env.MEMORAX_CODE_SKIP_CLAUDE_ADAPTER_INSTALL);
46
47
  const skipOpenCodeAdapterInstall = truthyEnv(process.env.MEMORAX_CODE_SKIP_OPENCODE_ADAPTER_INSTALL);
48
+ const skipCodeBuddyAdapterInstall = truthyEnv(process.env.MEMORAX_CODE_SKIP_CODEBUDDY_ADAPTER_INSTALL);
47
49
  const updateMode = truthyEnv(process.env.MEMORAX_CODE_SETUP_UPDATE);
50
+ const automaticUpdateMode = truthyEnv(process.env.MEMORAX_CODE_SETUP_AUTOMATIC_UPDATE);
48
51
  const setupMode = setupModeFromEnvironment(process.env.MEMORAX_CODE_SETUP_MODE);
49
52
  if (!setupMode) {
50
53
  logRed("Setup mode is invalid.");
51
54
  process.exit(1);
52
55
  }
56
+ if (automaticUpdateMode && !updateMode) {
57
+ logRed("Automatic update setup requires update mode.");
58
+ process.exit(1);
59
+ }
53
60
 
54
61
  const scriptDir = dirname(fileURLToPath(import.meta.url));
55
62
  const memoraxCodeBin = join(scriptDir, "memorax-code.mjs");
@@ -59,9 +66,12 @@ const codexRuntime = ensureCodexCommandEnv();
59
66
  const codexCommand = codexRuntime.command;
60
67
  const claudeRuntime = ensureClaudeCommandEnv();
61
68
  const claudeCommand = claudeRuntime.command;
69
+ const codeBuddyRuntime = ensureCodeBuddyCommandEnv();
70
+ const codeBuddyCommand = codeBuddyRuntime.command;
62
71
  const previousClients = readPersistedClientSelection();
63
72
  const existingSetup = previousClients !== undefined;
64
73
  const persistedDshSelection = readPersistedDshSelection();
74
+ const dshEnabledByConfig = persistedDshSelection !== false;
65
75
  let dshProfiles = [];
66
76
  let dshProfilesVerified = true;
67
77
  try {
@@ -73,13 +83,17 @@ try {
73
83
  }
74
84
  const dshSelected = dshProfilesVerified
75
85
  && dshProfiles.length > 0
76
- && persistedDshSelection !== false;
77
- if (!canPromptOnStderr()) {
86
+ && dshEnabledByConfig;
87
+ if (automaticUpdateMode && !existingSetup) {
88
+ logRed("Automatic update setup requires an existing [clients] selection.");
89
+ process.exit(1);
90
+ }
91
+ if (!automaticUpdateMode && !canPromptOnStderr()) {
78
92
  logRed("Setup requires an interactive terminal.");
79
93
  log("Run `memorax-code setup` from a terminal, or use `memorax-code status` to inspect an existing setup.");
80
94
  process.exit(1);
81
95
  }
82
- const scriptedAnswers = process.stdin.isTTY !== true
96
+ const scriptedAnswers = !automaticUpdateMode && process.stdin.isTTY !== true
83
97
  ? parseScriptedAnswers(readFileSync(0, "utf8"))
84
98
  : undefined;
85
99
  if (seedMissingMemoraxCodeConfig() === "failed") {
@@ -100,7 +114,7 @@ try {
100
114
  process.exit(1);
101
115
  }
102
116
  runCommonPreflight();
103
- const requestedClients = ["codex", "claude", "opencode"];
117
+ const requestedClients = ["codex", "claude", "opencode", "codebuddy"];
104
118
  const codexPreflight = requestedClients.includes("codex") && !skipCodexPluginInstall
105
119
  ? runCodexPreflight({
106
120
  integrationSelected: !existingSetup || previousClients.includes("codex"),
@@ -116,14 +130,22 @@ const opencodePreflight = requestedClients.includes("opencode") && !skipOpenCode
116
130
  integrationSelected: !existingSetup || previousClients.includes("opencode"),
117
131
  })
118
132
  : { ok: true };
133
+ const codebuddyPreflight = requestedClients.includes("codebuddy") && !skipCodeBuddyAdapterInstall
134
+ ? runCodeBuddyPreflight({
135
+ integrationSelected: !existingSetup || previousClients.includes("codebuddy"),
136
+ })
137
+ : { ok: true };
119
138
  const detectedClients = requestedClients.filter((client) => {
120
139
  if (client === "codex") return !skipCodexPluginInstall && codexPreflight.ok;
121
140
  if (client === "claude") return !skipClaudeAdapterInstall && claudePreflight.ok;
122
- return !skipOpenCodeAdapterInstall && opencodePreflight.ok;
141
+ if (client === "opencode") return !skipOpenCodeAdapterInstall && opencodePreflight.ok;
142
+ return !skipCodeBuddyAdapterInstall && codebuddyPreflight.ok;
123
143
  });
124
- const selectedClients = existingSetup
125
- ? await chooseUpdateClients(previousClients, detectedClients, scriptedAnswers)
126
- : detectedClients;
144
+ const selectedClients = automaticUpdateMode
145
+ ? previousClients
146
+ : existingSetup
147
+ ? await chooseUpdateClients(previousClients, detectedClients, scriptedAnswers)
148
+ : detectedClients;
127
149
  const installClients = detectedClients.filter((client) => selectedClients.includes(client));
128
150
  if (existingSetup) {
129
151
  log(clientSelectionMessage(selectedClients, { dshSelected }));
@@ -144,12 +166,16 @@ if (requestedClients.includes("claude") && !skipClaudeAdapterInstall && !claudeP
144
166
  if (requestedClients.includes("opencode") && !skipOpenCodeAdapterInstall && !opencodePreflight.ok) {
145
167
  log("OpenCode runtime or configuration was not detected; skipping its adapter setup.");
146
168
  }
169
+ if (requestedClients.includes("codebuddy") && !skipCodeBuddyAdapterInstall && !codebuddyPreflight.ok) {
170
+ log("CodeBuddy/WorkBuddy runtime was not detected; skipping its adapter setup.");
171
+ }
147
172
  if (writeClientSelectionConfig(selectedClients) === "failed") {
148
173
  printPostinstallSummary("not-verified");
149
174
  process.exit(1);
150
175
  }
151
- const clientMode = clientModeFor(installClients, {
152
- includeDsh: dshProfilesVerified && persistedDshSelection !== false,
176
+ const lifecycleClients = automaticUpdateMode ? selectedClients : installClients;
177
+ const clientMode = clientModeFor(lifecycleClients, {
178
+ includeDsh: dshProfilesVerified && dshEnabledByConfig,
153
179
  });
154
180
  let memoraxConfigResult = "skipped";
155
181
  if (!updateMode) {
@@ -179,11 +205,12 @@ if (memoraxConfigResult === "configured") {
179
205
  const codexClientEnabled = installClients.includes("codex");
180
206
  const claudeClientEnabled = installClients.includes("claude");
181
207
  const opencodeClientEnabled = installClients.includes("opencode");
208
+ const codebuddyClientEnabled = installClients.includes("codebuddy");
182
209
  const codexClientNewlyEnabled = codexClientEnabled
183
210
  && existingSetup
184
211
  && !previousClients.includes("codex");
185
212
  const codexPluginRequiresActivation = codexClientEnabled
186
- && codexPreflight.pluginCache.versions.length === 0;
213
+ && codexPreflight.pluginRegistration.ready !== true;
187
214
  const codexHooksBeforeUpdate = codexClientEnabled
188
215
  && existingSetup
189
216
  && !codexClientNewlyEnabled
@@ -202,9 +229,19 @@ if (codexClientEnabled && result.status !== 0) {
202
229
 
203
230
  if (codexClientEnabled && result.status === 0) {
204
231
  if (existingSetup && (codexClientNewlyEnabled || codexPluginRequiresActivation)) {
205
- activateCodexPluginHooks();
232
+ const activationResult = activateCodexPluginHooks();
233
+ if (automaticUpdateMode && activationResult !== "activated") {
234
+ logRed("Automatic update stopped because the current MemoraX Code Codex Hooks could not be activated and trusted.");
235
+ printPostinstallSummary("not-verified");
236
+ process.exit(1);
237
+ }
206
238
  } else if (existingSetup) {
207
- await maybeTrustUpdatedCodexPluginHooks(scriptedAnswers, codexHooksBeforeUpdate);
239
+ const trustResult = maybeTrustUpdatedCodexPluginHooks(codexHooksBeforeUpdate);
240
+ if (automaticUpdateMode && trustResult !== "trusted" && trustResult !== "unchanged") {
241
+ logRed("Automatic update stopped because the current MemoraX Code Codex Hooks could not be verified and trusted.");
242
+ printPostinstallSummary("not-verified");
243
+ process.exit(1);
244
+ }
208
245
  } else {
209
246
  activateCodexPluginHooks();
210
247
  }
@@ -227,6 +264,11 @@ const opencodeSkipReason = setupClientSkipReason({
227
264
  selected: selectedClients.includes("opencode"),
228
265
  enabled: opencodeClientEnabled,
229
266
  });
267
+ const codebuddySkipReason = setupClientSkipReason({
268
+ explicitlySkipped: skipCodeBuddyAdapterInstall,
269
+ selected: selectedClients.includes("codebuddy"),
270
+ enabled: codebuddyClientEnabled,
271
+ });
230
272
 
231
273
  const backendAndAdapters = await startBackendAndCheck({
232
274
  skipCodexAdapter,
@@ -238,6 +280,9 @@ const backendAndAdapters = await startBackendAndCheck({
238
280
  skipOpenCodeAdapter,
239
281
  opencodeAdapterRequired: !skipOpenCodeAdapter,
240
282
  opencodeSkipReason,
283
+ skipCodeBuddyAdapter: !codebuddyClientEnabled,
284
+ codebuddyAdapterRequired: codebuddyClientEnabled,
285
+ codebuddySkipReason,
241
286
  });
242
287
  const backendAndAdaptersStatus = backendAndAdapters.status;
243
288
  if (backendAndAdaptersStatus === "enabled") {
@@ -249,11 +294,13 @@ if (backendAndAdaptersStatus === "enabled") {
249
294
  claudeAdapterEnabled: !skipClaudeAdapter,
250
295
  dshAdapterEnabled: backendAndAdapters.dshAdapterEnabled,
251
296
  opencodeAdapterEnabled: !skipOpenCodeAdapter,
297
+ codebuddyAdapterEnabled: codebuddyClientEnabled,
252
298
  });
253
299
  printCommonCommands({
254
300
  codexAdapterEnabled: !skipCodexAdapter,
255
301
  claudeAdapterEnabled: !skipClaudeAdapter,
256
302
  opencodeAdapterEnabled: !skipOpenCodeAdapter,
303
+ codebuddyAdapterEnabled: codebuddyClientEnabled,
257
304
  });
258
305
  }
259
306
  printPostinstallSummary(
@@ -352,7 +399,7 @@ async function chooseUpdateClients(previousClients, detectedClients, scriptedAns
352
399
  } finally {
353
400
  rl?.close();
354
401
  }
355
- return ["codex", "claude", "opencode"].filter((client) => selected.has(client));
402
+ return ["codex", "claude", "opencode", "codebuddy"].filter((client) => selected.has(client));
356
403
  }
357
404
 
358
405
  async function configureMemoraxMemoryFromAnswers(answers, detectedPreferences, {
@@ -552,7 +599,7 @@ function inspectCodexPluginHooksForUpdate() {
552
599
  return report?.hooks;
553
600
  }
554
601
 
555
- async function maybeTrustUpdatedCodexPluginHooks(scriptedAnswers, previousHooks) {
602
+ function maybeTrustUpdatedCodexPluginHooks(previousHooks) {
556
603
  if (!previousHooks) {
557
604
  warnUpdatedHookTrustSkipped("Existing Codex hooks could not be inspected before the plugin cache refresh.");
558
605
  return "skipped";
@@ -574,21 +621,6 @@ async function maybeTrustUpdatedCodexPluginHooks(scriptedAnswers, previousHooks)
574
621
  if (report.hooks.length === 0) return "unchanged";
575
622
 
576
623
  printUpdatedCodexHooks(report.hooks, previousHooks);
577
- if (!canPromptForUpdate()) {
578
- warnUpdatedHookTrustSkipped("This update is running without an interactive terminal, so the new or changed Hooks remain untrusted.");
579
- return "skipped";
580
- }
581
- const answer = await updatedHookTrustAnswer(scriptedAnswers);
582
- if (answer === undefined) {
583
- warnUpdatedHookTrustSkipped("No Hook authorization response was received, so the new or changed Hooks remain untrusted.");
584
- return "skipped";
585
- }
586
- const normalizedAnswer = answer.trim();
587
- if (normalizedAnswer && !/^y(?:es)?$/i.test(normalizedAnswer)) {
588
- warnUpdatedHookTrustSkipped("Hook authorization was declined, so the new or changed Hooks remain untrusted.");
589
- return "skipped";
590
- }
591
-
592
624
  const trustEnv = hookTrustCommandEnv(HOOK_TRUST_SELECTION_ENV, report.hooks);
593
625
  const trusted = runNodeMemoraxCodeCommand(codexPluginHookArgs("trust-hooks", ["--yes"]), {
594
626
  env: trustEnv,
@@ -598,7 +630,7 @@ async function maybeTrustUpdatedCodexPluginHooks(scriptedAnswers, previousHooks)
598
630
  logGreen(`Trusted ${report.hooks.length} new or changed MemoraX Code Codex Hook${report.hooks.length === 1 ? "" : "s"}.`);
599
631
  return "trusted";
600
632
  }
601
- warnUpdatedHookTrustSkipped("The reviewed Hooks changed again or could not be written to Codex config.");
633
+ warnUpdatedHookTrustSkipped("The verified Hooks changed again or could not be written to Codex config.");
602
634
  return "failed";
603
635
  }
604
636
 
@@ -659,7 +691,7 @@ function hookTrustCommandEnv(name, hooks) {
659
691
 
660
692
  function printUpdatedCodexHooks(hooks, previousHooks) {
661
693
  const previousByKey = new Map(previousHooks.map((hook) => [hook.key, hook.currentHash]));
662
- log("This MemoraX Code update includes new or changed Codex Hooks that require authorization:");
694
+ log("This MemoraX Code update includes new or changed Codex Hooks that will be trusted automatically after verification:");
663
695
  for (const hook of hooks) {
664
696
  const change = previousByKey.has(hook.key) ? "changed" : "new";
665
697
  const label = hook.statusMessage ? ` (${hook.statusMessage})` : "";
@@ -669,19 +701,6 @@ function printUpdatedCodexHooks(hooks, previousHooks) {
669
701
  }
670
702
  }
671
703
 
672
- async function updatedHookTrustAnswer(scriptedAnswers) {
673
- if (scriptedAnswers) {
674
- log("Trust these new or changed Codex Hooks? [Y/n]");
675
- return scriptedAnswers.shift();
676
- }
677
- const rl = createInterface({ input: process.stdin, output: process.stderr });
678
- try {
679
- return await rl.question(`${PREFIX} Trust these new or changed Codex Hooks? [Y/n] `);
680
- } finally {
681
- rl.close();
682
- }
683
- }
684
-
685
704
  function parseScriptedAnswers(input) {
686
705
  if (input.length === 0) return [];
687
706
  const answers = input.split(/\r?\n/);
@@ -704,10 +723,6 @@ function activateCodexPluginHooks() {
704
723
  return "failed";
705
724
  }
706
725
 
707
- function canPromptForUpdate() {
708
- return canPromptOnStderr();
709
- }
710
-
711
726
  function canPromptOnStderr() {
712
727
  return process.env.MEMORAX_CODE_SETUP_ASSUME_INTERACTIVE === "1"
713
728
  || (process.stdin.isTTY === true && process.stderr.isTTY === true);
@@ -742,6 +757,7 @@ function readPersistedClientSelection() {
742
757
  clients.codex ? "codex" : undefined,
743
758
  clients.claude ? "claude" : undefined,
744
759
  clients.opencode === true ? "opencode" : undefined,
760
+ clients.codebuddy === true ? "codebuddy" : undefined,
745
761
  ].filter(Boolean);
746
762
  } catch {
747
763
  return undefined;
@@ -773,7 +789,8 @@ function writeClientSelectionConfig(clients) {
773
789
  function setManagedClientSelection(text, clients) {
774
790
  const withOpenCode = setTomlField(text, "clients", "opencode", String(clients.includes("opencode")));
775
791
  const withClaude = setTomlField(withOpenCode, "clients", "claude", String(clients.includes("claude")));
776
- return setTomlField(withClaude, "clients", "codex", String(clients.includes("codex")));
792
+ const withCodeBuddy = setTomlField(withClaude, "clients", "codebuddy", String(clients.includes("codebuddy")));
793
+ return setTomlField(withCodeBuddy, "clients", "codex", String(clients.includes("codex")));
777
794
  }
778
795
 
779
796
  function writeMemoraxConfig({ userId, endpoint, outputLanguage, apiKey }) {
@@ -826,6 +843,7 @@ function defaultMemoraxCodeConfig() {
826
843
  "claude = true # Manage the Claude adapter.",
827
844
  "dsh = true # Manage the DeepSeek Harness adapter when Profiles exist.",
828
845
  "opencode = true # Manage the OpenCode adapter.",
846
+ "codebuddy = true # Manage the CodeBuddy/WorkBuddy adapter.",
829
847
  "",
830
848
  "# MemoraX remote-memory connection.",
831
849
  "[memorax]",
@@ -871,6 +889,10 @@ function defaultMemoraxCodeConfig() {
871
889
  "enabled = true # Enable local OpenCode session memory trace collection.",
872
890
  "capture_content = true # Store content in local OpenCode trace events.",
873
891
  "",
892
+ "[trace.codebuddy]",
893
+ "enabled = true # Enable local CodeBuddy session memory trace collection.",
894
+ "capture_content = true # Store content in local CodeBuddy trace events.",
895
+ "",
874
896
  ].join("\n");
875
897
  }
876
898
 
@@ -940,6 +962,9 @@ function runCommonPreflight() {
940
962
  if (skipOpenCodeAdapterInstall) {
941
963
  log("OpenCode adapter setup is disabled for this setup; other client setup can still continue.");
942
964
  }
965
+ if (skipCodeBuddyAdapterInstall) {
966
+ log("CodeBuddy/WorkBuddy adapter setup is disabled for this setup; other client setup can still continue.");
967
+ }
943
968
  return {};
944
969
  }
945
970
 
@@ -956,11 +981,21 @@ function runCodexPreflight({ integrationSelected = true } = {}) {
956
981
  }
957
982
  const pluginCache = installedPluginCache();
958
983
  log(`Existing Codex plugin cache: ${pluginCache.versions.length > 0 ? `found (${pluginCache.versions.join(", ")})` : "not installed"}`);
984
+ const pluginRegistration = inspectCodexPluginRegistrationForSetup();
985
+ if (!pluginRegistration.verified) {
986
+ log("Codex plugin state: could not be verified; setup will attempt a full activation.");
987
+ } else if (!pluginRegistration.registered) {
988
+ log("Codex plugin state: not installed in Codex; setup will repair it.");
989
+ } else if (!pluginRegistration.enabled) {
990
+ log("Codex plugin state: disabled; setup will attempt to enable it.");
991
+ } else {
992
+ log(`Codex plugin state: enabled${pluginRegistration.version ? ` (${pluginRegistration.version})` : ""}.`);
993
+ }
959
994
  log(`Codex client process: ${codexClientRunning() ? "running" : "not detected"}`);
960
995
  log(integrationSelected
961
996
  ? "Keeping Codex provider config unchanged and enabling the shared memory hook integration."
962
997
  : "Keeping Codex provider config unchanged while checking whether to enable its integration.");
963
- return { ok: true, pluginCache };
998
+ return { ok: true, pluginCache, pluginRegistration };
964
999
  }
965
1000
 
966
1001
  function runClaudePreflight({ integrationSelected = true } = {}) {
@@ -999,6 +1034,25 @@ function runOpenCodePreflight({ integrationSelected = true } = {}) {
999
1034
  return { ok: true };
1000
1035
  }
1001
1036
 
1037
+ function runCodeBuddyPreflight({ integrationSelected = true } = {}) {
1038
+ const version = runExternalCommand(codeBuddyCommand, ["--version"], { print: false, timeout: 10_000 });
1039
+ const runtimeLabel = codeBuddyRuntime.source === "app-bundled"
1040
+ ? "WorkBuddy App CodeBuddy runtime"
1041
+ : codeBuddyRuntime.source === "path"
1042
+ ? "CodeBuddy CLI"
1043
+ : codeBuddyRuntime.source === "configured"
1044
+ ? "Configured CodeBuddy runtime"
1045
+ : "CodeBuddy CLI";
1046
+ log(`${runtimeLabel}: ${commandSummary(version) ?? "not runnable"}`);
1047
+ const home = defaultCodeBuddyHome();
1048
+ log(`WorkBuddy data directory: ${existsSync(home) ? "found" : "not detected"}`);
1049
+ if (version.status !== 0) return { ok: false };
1050
+ log(integrationSelected
1051
+ ? "Keeping CodeBuddy provider config unchanged and enabling the shared memory Hook integration."
1052
+ : "Keeping CodeBuddy provider config unchanged while checking whether to enable its integration.");
1053
+ return { ok: true };
1054
+ }
1055
+
1002
1056
  function installedPluginCache() {
1003
1057
  for (const marketplaceName of [CLI_MARKETPLACE_NAME, PERSONAL_MARKETPLACE_NAME]) {
1004
1058
  const versions = installedPluginCacheVersions(marketplaceName);
@@ -1009,6 +1063,38 @@ function installedPluginCache() {
1009
1063
  return { marketplaceName: CLI_MARKETPLACE_NAME, versions: [] };
1010
1064
  }
1011
1065
 
1066
+ function inspectCodexPluginRegistrationForSetup() {
1067
+ const result = runNodeMemoraxCodeCommand(["codex-plugin", "registration", "--json"], {
1068
+ print: false,
1069
+ timeout: 10_000,
1070
+ });
1071
+ if (result.status !== 0) {
1072
+ return { verified: false, ready: false, registered: false, enabled: false };
1073
+ }
1074
+ try {
1075
+ const report = JSON.parse(String(result.stdout ?? ""));
1076
+ if (!report
1077
+ || report.ok !== true
1078
+ || report.action !== "codex-plugin-registration"
1079
+ || typeof report.available !== "boolean"
1080
+ || typeof report.registered !== "boolean"
1081
+ || typeof report.enabled !== "boolean"
1082
+ || (report.version !== undefined && typeof report.version !== "string")) {
1083
+ return { verified: false, ready: false, registered: false, enabled: false };
1084
+ }
1085
+ return {
1086
+ verified: true,
1087
+ ready: report.registered && report.enabled,
1088
+ available: report.available,
1089
+ registered: report.registered,
1090
+ enabled: report.enabled,
1091
+ ...(report.version ? { version: report.version } : {}),
1092
+ };
1093
+ } catch {
1094
+ return { verified: false, ready: false, registered: false, enabled: false };
1095
+ }
1096
+ }
1097
+
1012
1098
  function installedPluginCacheVersions(marketplaceName) {
1013
1099
  const cacheRoot = join(codexHome(), "plugins", "cache", marketplaceName, PLUGIN_NAME);
1014
1100
  if (!existsSync(cacheRoot)) return [];
@@ -1032,6 +1118,9 @@ async function startBackendAndCheck({
1032
1118
  skipOpenCodeAdapter = false,
1033
1119
  opencodeAdapterRequired = !skipOpenCodeAdapter,
1034
1120
  opencodeSkipReason,
1121
+ skipCodeBuddyAdapter = false,
1122
+ codebuddyAdapterRequired = !skipCodeBuddyAdapter,
1123
+ codebuddySkipReason,
1035
1124
  } = {}) {
1036
1125
  const adapterFlags = clientLifecycleFlags({ clientMode });
1037
1126
  const startArgs = ["start", ...adapterFlags];
@@ -1052,6 +1141,7 @@ async function startBackendAndCheck({
1052
1141
  codexAdapterRequired: !skipCodexAdapter,
1053
1142
  claudeAdapterRequired,
1054
1143
  opencodeAdapterRequired,
1144
+ codebuddyAdapterRequired,
1055
1145
  }),
1056
1146
  onEvent: (event) => {
1057
1147
  if (event.type === "start" && event.attempt === 1) {
@@ -1082,6 +1172,8 @@ async function startBackendAndCheck({
1082
1172
  claudeSkipReason,
1083
1173
  skipOpenCodeAdapter,
1084
1174
  opencodeSkipReason,
1175
+ skipCodeBuddyAdapter,
1176
+ codebuddySkipReason,
1085
1177
  });
1086
1178
  }
1087
1179
  },
@@ -1104,6 +1196,8 @@ function printReconcileFailure(result, {
1104
1196
  claudeSkipReason,
1105
1197
  skipOpenCodeAdapter,
1106
1198
  opencodeSkipReason,
1199
+ skipCodeBuddyAdapter,
1200
+ codebuddySkipReason,
1107
1201
  }) {
1108
1202
  if (result.reason === "hook-runtime-activation-failed") {
1109
1203
  logRed("Client Hook runtime activation failed; automatic lifecycle recovery was skipped.");
@@ -1121,6 +1215,7 @@ function printReconcileFailure(result, {
1121
1215
  codexSkipReason,
1122
1216
  claudeSkipReason,
1123
1217
  opencodeSkipReason,
1218
+ codebuddySkipReason,
1124
1219
  });
1125
1220
  }
1126
1221
  }
@@ -1157,10 +1252,10 @@ function clientLifecycleFlags({ clientMode = "all" } = {}) {
1157
1252
  }
1158
1253
 
1159
1254
  function clientModeFor(clients, { includeDsh = false } = {}) {
1160
- const selected = ["codex", "claude", "dsh", "opencode"].filter((client) => (
1255
+ const selected = ["codex", "claude", "dsh", "opencode", "codebuddy"].filter((client) => (
1161
1256
  client === "dsh" ? includeDsh : clients.includes(client)
1162
1257
  ));
1163
- if (selected.length === 4) return "all";
1258
+ if (selected.length === 5) return "all";
1164
1259
  return selected.length > 0 ? selected.join(",") : "none";
1165
1260
  }
1166
1261
 
@@ -1177,26 +1272,29 @@ function clientSelectionMessage(clients, { dshSelected = false } = {}) {
1177
1272
  clients.includes("claude") ? "Claude Code" : undefined,
1178
1273
  "DeepSeek Harness",
1179
1274
  clients.includes("opencode") ? "OpenCode" : undefined,
1275
+ clients.includes("codebuddy") ? "CodeBuddy/WorkBuddy" : undefined,
1180
1276
  ].filter(Boolean);
1181
1277
  return `Configuring MemoraX Code for ${joinedLabels(labels)}.`;
1182
1278
  }
1183
1279
  const hasCodex = clients.includes("codex");
1184
1280
  const hasClaude = clients.includes("claude");
1185
1281
  const hasOpenCode = clients.includes("opencode");
1186
- if (hasCodex && hasClaude && hasOpenCode) return "Configuring MemoraX Code for Codex, Claude Code, and OpenCode.";
1187
- if (hasCodex && hasClaude) return "Configuring MemoraX Code for Codex and Claude Code.";
1188
- if (hasCodex && hasOpenCode) return "Configuring MemoraX Code for Codex and OpenCode.";
1189
- if (hasClaude && hasOpenCode) return "Configuring MemoraX Code for Claude Code and OpenCode.";
1190
- if (hasCodex) return "Configuring MemoraX Code for Codex only.";
1191
- if (hasClaude) return "Configuring MemoraX Code for Claude Code only.";
1192
- if (hasOpenCode) return "Configuring MemoraX Code for OpenCode only.";
1282
+ const hasCodeBuddy = clients.includes("codebuddy");
1283
+ const labels = [
1284
+ hasCodex ? "Codex" : undefined,
1285
+ hasClaude ? "Claude Code" : undefined,
1286
+ hasOpenCode ? "OpenCode" : undefined,
1287
+ hasCodeBuddy ? "CodeBuddy/WorkBuddy" : undefined,
1288
+ ].filter(Boolean);
1289
+ if (labels.length > 0) return `Configuring MemoraX Code for ${joinedLabels(labels)}.`;
1193
1290
  return "Skipping client adapter setup for this setup.";
1194
1291
  }
1195
1292
 
1196
1293
  function clientLabel(client) {
1197
1294
  if (client === "codex") return "Codex";
1198
1295
  if (client === "claude") return "Claude Code";
1199
- return "OpenCode";
1296
+ if (client === "opencode") return "OpenCode";
1297
+ return "CodeBuddy/WorkBuddy";
1200
1298
  }
1201
1299
 
1202
1300
  function detectedClientMessage(clients, dshProfiles = []) {
@@ -1354,11 +1452,13 @@ function printNextSteps({
1354
1452
  claudeAdapterEnabled = true,
1355
1453
  dshAdapterEnabled = false,
1356
1454
  opencodeAdapterEnabled = true,
1455
+ codebuddyAdapterEnabled = true,
1357
1456
  } = {}) {
1358
1457
  const clientText = enabledClientText({
1359
1458
  codexAdapterEnabled,
1360
1459
  claudeAdapterEnabled,
1361
1460
  opencodeAdapterEnabled,
1461
+ codebuddyAdapterEnabled,
1362
1462
  });
1363
1463
  if (clientText && existingSetup) {
1364
1464
  logGreen(`${bold("The new Hook runtime is active")}; existing sessions with the stable shell select it on their next user prompt.`);
@@ -1378,6 +1478,7 @@ function printNextSteps({
1378
1478
  codexAdapterEnabled,
1379
1479
  claudeAdapterEnabled,
1380
1480
  opencodeAdapterEnabled,
1481
+ codebuddyAdapterEnabled,
1381
1482
  });
1382
1483
  if (clientText || !dshAdapterEnabled) {
1383
1484
  log(`If MemoraX Code is not active ${existingSetup ? "on the next prompt" : "in new sessions"}, run ${statusCommands}.`);
@@ -1391,11 +1492,13 @@ function enabledClientText({
1391
1492
  codexAdapterEnabled = true,
1392
1493
  claudeAdapterEnabled = true,
1393
1494
  opencodeAdapterEnabled = true,
1495
+ codebuddyAdapterEnabled = true,
1394
1496
  } = {}) {
1395
1497
  const labels = [
1396
1498
  codexAdapterEnabled ? "Codex" : undefined,
1397
1499
  claudeAdapterEnabled ? "Claude Code" : undefined,
1398
1500
  opencodeAdapterEnabled ? "OpenCode" : undefined,
1501
+ codebuddyAdapterEnabled ? "CodeBuddy/WorkBuddy" : undefined,
1399
1502
  ].filter(Boolean);
1400
1503
  if (labels.length < 2) return labels[0] ?? "";
1401
1504
  if (labels.length === 2) return `${labels[0]} or ${labels[1]}`;
@@ -1406,11 +1509,13 @@ function statusCommandText({
1406
1509
  codexAdapterEnabled = true,
1407
1510
  claudeAdapterEnabled = true,
1408
1511
  opencodeAdapterEnabled = true,
1512
+ codebuddyAdapterEnabled = true,
1409
1513
  } = {}) {
1410
1514
  const commands = ["`memorax-code status`"];
1411
1515
  if (codexAdapterEnabled) commands.push("`memorax-code-codex status`");
1412
1516
  if (claudeAdapterEnabled) commands.push("`memorax-code-claude status`");
1413
1517
  if (opencodeAdapterEnabled) commands.push("`memorax-code-opencode status`");
1518
+ if (codebuddyAdapterEnabled) commands.push("`memorax-code-codebuddy status`");
1414
1519
  if (commands.length === 1) return commands[0];
1415
1520
  if (commands.length === 2) return `${commands[0]} and ${commands[1]}`;
1416
1521
  return `${commands.slice(0, -1).join(", ")}, and ${commands.at(-1)}`;
@@ -1490,17 +1595,19 @@ function readMemoraxInstallStatus() {
1490
1595
  }
1491
1596
  }
1492
1597
 
1493
- function printUnavailableDiagnostics({ codexSkipReason, claudeSkipReason, opencodeSkipReason } = {}) {
1598
+ function printUnavailableDiagnostics({ codexSkipReason, claudeSkipReason, opencodeSkipReason, codebuddySkipReason } = {}) {
1494
1599
  logRed("MemoraX Code is not enabled for new client sessions.");
1495
- logRed("Check `memorax-code status`, `memorax-code-codex status`, `memorax-code-claude status`, and `memorax-code-opencode status` for Backend and adapter details.");
1496
- logRed("If Codex, Claude Code, OpenCode, or DeepSeek Harness is open, restart or refresh it after fixing the reported status.");
1600
+ logRed("Check `memorax-code status`, the selected adapter status commands, and `memorax-code-codebuddy status` for Backend and integration details.");
1601
+ logRed("If Codex, Claude Code, OpenCode, CodeBuddy/WorkBuddy, or DeepSeek Harness is open, restart or refresh it after fixing the reported status.");
1497
1602
  if (codexSkipReason) printCodexSkippedDiagnostics(codexSkipReason);
1498
1603
  if (claudeSkipReason) printClaudeSkippedDiagnostics(claudeSkipReason);
1499
1604
  if (opencodeSkipReason) printOpenCodeSkippedDiagnostics(opencodeSkipReason);
1605
+ if (codebuddySkipReason) printCodeBuddySkippedDiagnostics(codebuddySkipReason);
1500
1606
  printCommonCommands({
1501
1607
  codexAdapterEnabled: !codexSkipReason,
1502
1608
  claudeAdapterEnabled: !claudeSkipReason,
1503
1609
  opencodeAdapterEnabled: !opencodeSkipReason,
1610
+ codebuddyAdapterEnabled: !codebuddySkipReason,
1504
1611
  });
1505
1612
  }
1506
1613
 
@@ -1521,6 +1628,11 @@ function printOpenCodeSkippedDiagnostics() {
1521
1628
  log("Run `memorax-code start --clients opencode` after installing OpenCode, then restart or refresh OpenCode.");
1522
1629
  }
1523
1630
 
1631
+ function printCodeBuddySkippedDiagnostics() {
1632
+ logRed("CodeBuddy/WorkBuddy adapter setup was skipped for this setup, so MemoraX Code left the CodeBuddy integration unchanged.");
1633
+ log("Run `memorax-code start --clients codebuddy` after installing CodeBuddy/WorkBuddy, then restart or refresh it.");
1634
+ }
1635
+
1524
1636
  function printFailureSuggestions() {
1525
1637
  logRed("Suggested recovery: run `memorax-code stop`, then `memorax-code start`, then `memorax-code status`.");
1526
1638
  logRed("If the Backend port is busy, stop the process using 127.0.0.1:8787 and retry `memorax-code start`.");
@@ -1550,6 +1662,7 @@ function printCommonCommands({
1550
1662
  codexAdapterEnabled = true,
1551
1663
  claudeAdapterEnabled = true,
1552
1664
  opencodeAdapterEnabled = true,
1665
+ codebuddyAdapterEnabled = true,
1553
1666
  } = {}) {
1554
1667
  log("Common commands:");
1555
1668
  log("- `memorax-code status`: check the local backend and adapter state.");
@@ -1559,12 +1672,14 @@ function printCommonCommands({
1559
1672
  if (codexAdapterEnabled) log("- `memorax-code-codex sessions`: verify recent native Codex session registration.");
1560
1673
  if (claudeAdapterEnabled) log("- `memorax-code-claude sessions`: verify recent native Claude Code session registration.");
1561
1674
  if (opencodeAdapterEnabled) log("- `memorax-code-opencode doctor`: verify the managed OpenCode plugin, runtime evidence, and Backend health.");
1675
+ if (codebuddyAdapterEnabled) log("- `memorax-code-codebuddy status`: verify the managed CodeBuddy/WorkBuddy plugin and Hook integration.");
1562
1676
  }
1563
1677
 
1564
1678
  function memoraxCodeEnabled(statusResult, {
1565
1679
  codexAdapterRequired = true,
1566
1680
  claudeAdapterRequired = true,
1567
1681
  opencodeAdapterRequired = true,
1682
+ codebuddyAdapterRequired = true,
1568
1683
  } = {}) {
1569
1684
  const output = `${statusResult.stdout ?? ""}\n${statusResult.stderr ?? ""}`;
1570
1685
  const normalized = stripAnsi(output);
@@ -1576,11 +1691,13 @@ function memoraxCodeEnabled(statusResult, {
1576
1691
  const codexAdapterOk = /Codex adapter:\s*ok\b/im.test(normalized);
1577
1692
  const claudeAdapterOk = /Claude adapter:\s*ok\b/im.test(normalized);
1578
1693
  const opencodeAdapterOk = /OpenCode adapter:\s*ok\b/im.test(normalized);
1694
+ const codebuddyAdapterOk = /CodeBuddy adapter:\s*ok\b/im.test(normalized);
1579
1695
  return backendOk
1580
1696
  && serviceOk
1581
1697
  && (!codexAdapterRequired || codexAdapterOk)
1582
1698
  && (!claudeAdapterRequired || claudeAdapterOk)
1583
- && (!opencodeAdapterRequired || opencodeAdapterOk);
1699
+ && (!opencodeAdapterRequired || opencodeAdapterOk)
1700
+ && (!codebuddyAdapterRequired || codebuddyAdapterOk);
1584
1701
  }
1585
1702
 
1586
1703
  function log(message) {