@cabane/companion 0.6.2 → 0.6.3

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.
package/dist/cli.js CHANGED
@@ -7331,7 +7331,10 @@ ${reason}`,
7331
7331
  ...this.opts.local.claudeCode ? { claudeCode: this.opts.local.claudeCode } : {}
7332
7332
  });
7333
7333
  const onWarn = (msg, meta) => turnLog.warn(meta ?? {}, msg);
7334
- const adapters = [createClaudeCodeAdapter({ queryFn: this.opts.queryFn, onWarn })];
7334
+ const adapters = [];
7335
+ if (this.opts.claudeCodeAvailable?.() ?? true) {
7336
+ adapters.push(createClaudeCodeAdapter({ queryFn: this.opts.queryFn, onWarn }));
7337
+ }
7335
7338
  if (this.opts.opencodeServerUrl) {
7336
7339
  adapters.push(createOpencodeAdapter({ serverUrl: this.opts.opencodeServerUrl, onWarn }));
7337
7340
  }
@@ -8384,7 +8387,7 @@ var CompanionSupervisor = class {
8384
8387
  // until the first re-probe lands. Same exit-0 `claude --version` signal
8385
8388
  // either way, so the manifest's claude-code advertising is unchanged in
8386
8389
  // meaning — just refreshed on the beat instead of frozen at boot.
8387
- claudeCode: this.harnessSignals?.claudeOnPath ?? this.claudeCode,
8390
+ claudeCode: this.claudeCodePresent(),
8388
8391
  opencode: !!this.config.opencode?.serverUrl,
8389
8392
  // CT481: advertise codex when the operator enabled it (config-gated,
8390
8393
  // like opencode — the CLI's presence is the operator's responsibility;
@@ -8607,6 +8610,13 @@ var CompanionSupervisor = class {
8607
8610
  "companion: stopped agent (unassigned)"
8608
8611
  );
8609
8612
  }
8613
+ // CT833: is Claude Code on this machine right now? The ONE signal both the
8614
+ // heartbeat manifest and the dispatcher's adapter registry read, so what the
8615
+ // device advertises and what it can actually select can't disagree. Live (the
8616
+ // per-beat re-probe), falling back to the boot probe until the first one lands.
8617
+ claudeCodePresent() {
8618
+ return this.harnessSignals?.claudeOnPath ?? this.claudeCode;
8619
+ }
8610
8620
  buildDispatcher(ctx) {
8611
8621
  if (this.dispatcherFactory) return this.dispatcherFactory(ctx);
8612
8622
  return new Dispatcher({
@@ -8624,6 +8634,10 @@ var CompanionSupervisor = class {
8624
8634
  }),
8625
8635
  runConfig: ctx.runConfig,
8626
8636
  log: this.log,
8637
+ // CT833: register the claude-code adapter only when `claude` is actually on
8638
+ // this machine — read per turn (not captured here), so a harness installed
8639
+ // after boot works on the next turn exactly as it appears on the next beat.
8640
+ claudeCodeAvailable: () => this.claudeCodePresent(),
8627
8641
  // CT270: the opencode server URL (operator-configured), when this device
8628
8642
  // offers the opencode runtime. Threaded so an opencode turn selects the
8629
8643
  // opencode adapter; unset leaves the device claude-code-only.
package/dist/runtime.js CHANGED
@@ -6984,7 +6984,10 @@ ${reason}`,
6984
6984
  ...this.opts.local.claudeCode ? { claudeCode: this.opts.local.claudeCode } : {}
6985
6985
  });
6986
6986
  const onWarn = (msg, meta) => turnLog.warn(meta ?? {}, msg);
6987
- const adapters = [createClaudeCodeAdapter({ queryFn: this.opts.queryFn, onWarn })];
6987
+ const adapters = [];
6988
+ if (this.opts.claudeCodeAvailable?.() ?? true) {
6989
+ adapters.push(createClaudeCodeAdapter({ queryFn: this.opts.queryFn, onWarn }));
6990
+ }
6988
6991
  if (this.opts.opencodeServerUrl) {
6989
6992
  adapters.push(createOpencodeAdapter({ serverUrl: this.opts.opencodeServerUrl, onWarn }));
6990
6993
  }
@@ -8037,7 +8040,7 @@ var CompanionSupervisor = class {
8037
8040
  // until the first re-probe lands. Same exit-0 `claude --version` signal
8038
8041
  // either way, so the manifest's claude-code advertising is unchanged in
8039
8042
  // meaning — just refreshed on the beat instead of frozen at boot.
8040
- claudeCode: this.harnessSignals?.claudeOnPath ?? this.claudeCode,
8043
+ claudeCode: this.claudeCodePresent(),
8041
8044
  opencode: !!this.config.opencode?.serverUrl,
8042
8045
  // CT481: advertise codex when the operator enabled it (config-gated,
8043
8046
  // like opencode — the CLI's presence is the operator's responsibility;
@@ -8260,6 +8263,13 @@ var CompanionSupervisor = class {
8260
8263
  "companion: stopped agent (unassigned)"
8261
8264
  );
8262
8265
  }
8266
+ // CT833: is Claude Code on this machine right now? The ONE signal both the
8267
+ // heartbeat manifest and the dispatcher's adapter registry read, so what the
8268
+ // device advertises and what it can actually select can't disagree. Live (the
8269
+ // per-beat re-probe), falling back to the boot probe until the first one lands.
8270
+ claudeCodePresent() {
8271
+ return this.harnessSignals?.claudeOnPath ?? this.claudeCode;
8272
+ }
8263
8273
  buildDispatcher(ctx) {
8264
8274
  if (this.dispatcherFactory) return this.dispatcherFactory(ctx);
8265
8275
  return new Dispatcher({
@@ -8277,6 +8287,10 @@ var CompanionSupervisor = class {
8277
8287
  }),
8278
8288
  runConfig: ctx.runConfig,
8279
8289
  log: this.log,
8290
+ // CT833: register the claude-code adapter only when `claude` is actually on
8291
+ // this machine — read per turn (not captured here), so a harness installed
8292
+ // after boot works on the next turn exactly as it appears on the next beat.
8293
+ claudeCodeAvailable: () => this.claudeCodePresent(),
8280
8294
  // CT270: the opencode server URL (operator-configured), when this device
8281
8295
  // offers the opencode runtime. Threaded so an opencode turn selects the
8282
8296
  // opencode adapter; unset leaves the device claude-code-only.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cabane/companion",
3
- "version": "0.6.2",
3
+ "version": "0.6.3",
4
4
  "type": "module",
5
5
  "description": "The Cabane Companion (headless): connect a coding agent on your machine to your Cabane workspace as a responder — drive work against your own codebase, files, and MCP servers without putting any of it in Cabane.",
6
6
  "license": "UNLICENSED",