@cabane/companion 0.6.43 → 0.6.45

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
@@ -6678,7 +6678,6 @@ var SUMMON_AGENT_TOOL = "summon_agent";
6678
6678
  var SUMMON_AGENT_TOOL_NAME = `mcp__${COMPANION_LOCAL_MCP_SERVER}__${SUMMON_AGENT_TOOL}`;
6679
6679
  var COMPANION_LOCAL_TOOL_GLOB = `mcp__${COMPANION_LOCAL_MCP_SERVER}__*`;
6680
6680
  var SKIP_TURN_TOOL = "skip_turn";
6681
- var SKIP_TURN_TOOL_NAME = `mcp__${COMPANION_LOCAL_MCP_SERVER}__${SKIP_TURN_TOOL}`;
6682
6681
  var ASK_TOOL = "ask";
6683
6682
  var ASK_TOOL_NAME = `mcp__${COMPANION_LOCAL_MCP_SERVER}__${ASK_TOOL}`;
6684
6683
  var SUB_AGENT_TOOL = "sub_agent";
@@ -8828,11 +8827,7 @@ var mcpSseServerSchema = z15.object({
8828
8827
  url: z15.string().url(),
8829
8828
  headers: z15.record(z15.string(), z15.string()).optional()
8830
8829
  });
8831
- var mcpServerDefSchema = z15.union([
8832
- mcpHttpServerSchema,
8833
- mcpSseServerSchema,
8834
- mcpStdioServerSchema
8835
- ]);
8830
+ var mcpServerDefSchema = z15.union([mcpHttpServerSchema, mcpSseServerSchema, mcpStdioServerSchema]);
8836
8831
  var thinkingConfigSchema = z15.discriminatedUnion("type", [
8837
8832
  z15.object({ type: z15.literal("adaptive") }),
8838
8833
  z15.object({ type: z15.literal("enabled"), budgetTokens: z15.number().int().positive().optional() }),
@@ -8974,6 +8969,7 @@ var COMPANION_VERSION = pkg.version;
8974
8969
 
8975
8970
  // src/supervisor.ts
8976
8971
  var HEARTBEAT_INTERVAL_MS = 3e4;
8972
+ var SHUTDOWN_HEARTBEAT_WAIT_MS = 1e3;
8977
8973
  function positiveIntEnv(name) {
8978
8974
  const raw = process.env[name];
8979
8975
  if (!raw) return void 0;
@@ -9054,7 +9050,8 @@ var CompanionSupervisor = class {
9054
9050
  { protocolVersion: TURN_PROTOCOL_VERSION, version: COMPANION_VERSION },
9055
9051
  "companion: starting"
9056
9052
  );
9057
- void this.refreshHarnessStatuses();
9053
+ const startupHarnessRefresh = this.refreshHarnessStatuses();
9054
+ this.trackHeartbeat(startupHarnessRefresh);
9058
9055
  if (!this.config.deviceToken) {
9059
9056
  this.log.warn("companion: not paired (no device token) \u2014 run `cabane-companion pair`");
9060
9057
  process.stdout.write(
@@ -9085,7 +9082,11 @@ var CompanionSupervisor = class {
9085
9082
  });
9086
9083
  this.deviceSub.start();
9087
9084
  await this.refreshAssignments();
9088
- this.kickHeartbeat();
9085
+ const firstHeartbeat = startupHarnessRefresh.then(async () => {
9086
+ if (this.stopped) return;
9087
+ await this.sendHeartbeat();
9088
+ });
9089
+ this.trackHeartbeat(firstHeartbeat);
9089
9090
  this.heartbeatTimer = setInterval(() => this.kickHeartbeat(), HEARTBEAT_INTERVAL_MS);
9090
9091
  this.heartbeatTimer.unref?.();
9091
9092
  this.pollTimer = setInterval(() => void this.refreshAssignments(), ASSIGNMENTS_POLL_MS);
@@ -9103,8 +9104,10 @@ var CompanionSupervisor = class {
9103
9104
  }
9104
9105
  // ---- device-level loops ----
9105
9106
  kickHeartbeat() {
9106
- if (this.inFlightHeartbeat) return;
9107
- const pending = this.sendHeartbeat();
9107
+ if (this.stopped || this.inFlightHeartbeat) return;
9108
+ this.trackHeartbeat(this.sendHeartbeat());
9109
+ }
9110
+ trackHeartbeat(pending) {
9108
9111
  this.inFlightHeartbeat = pending;
9109
9112
  void pending.finally(() => {
9110
9113
  if (this.inFlightHeartbeat === pending) this.inFlightHeartbeat = null;
@@ -9858,7 +9861,7 @@ var CompanionSupervisor = class {
9858
9861
  if (wr.sub) wr.sub.stop();
9859
9862
  }
9860
9863
  await Promise.all([
9861
- ...heartbeat ? [heartbeat] : [],
9864
+ ...heartbeat ? [waitForBoundedHeartbeat(heartbeat)] : [],
9862
9865
  ...this.deviceSub ? [this.deviceSub.finished] : [],
9863
9866
  ...[...this.workspaces.values()].flatMap((wr) => wr.sub ? [wr.sub.finished] : [])
9864
9867
  ]);
@@ -9871,6 +9874,18 @@ var CompanionSupervisor = class {
9871
9874
  this.reexecFn();
9872
9875
  }
9873
9876
  };
9877
+ async function waitForBoundedHeartbeat(heartbeat) {
9878
+ let timer = null;
9879
+ const timeout = new Promise((resolve) => {
9880
+ timer = setTimeout(resolve, SHUTDOWN_HEARTBEAT_WAIT_MS);
9881
+ timer.unref?.();
9882
+ });
9883
+ try {
9884
+ await Promise.race([heartbeat, timeout]);
9885
+ } finally {
9886
+ if (timer) clearTimeout(timer);
9887
+ }
9888
+ }
9874
9889
  function defaultReexec() {
9875
9890
  clearRuntimeState();
9876
9891
  void import("child_process").then(({ spawn: spawn6 }) => {
package/dist/runtime.js CHANGED
@@ -6187,7 +6187,6 @@ var SUMMON_AGENT_TOOL = "summon_agent";
6187
6187
  var SUMMON_AGENT_TOOL_NAME = `mcp__${COMPANION_LOCAL_MCP_SERVER}__${SUMMON_AGENT_TOOL}`;
6188
6188
  var COMPANION_LOCAL_TOOL_GLOB = `mcp__${COMPANION_LOCAL_MCP_SERVER}__*`;
6189
6189
  var SKIP_TURN_TOOL = "skip_turn";
6190
- var SKIP_TURN_TOOL_NAME = `mcp__${COMPANION_LOCAL_MCP_SERVER}__${SKIP_TURN_TOOL}`;
6191
6190
  var ASK_TOOL = "ask";
6192
6191
  var ASK_TOOL_NAME = `mcp__${COMPANION_LOCAL_MCP_SERVER}__${ASK_TOOL}`;
6193
6192
  var SUB_AGENT_TOOL = "sub_agent";
@@ -8337,11 +8336,7 @@ var mcpSseServerSchema = z15.object({
8337
8336
  url: z15.string().url(),
8338
8337
  headers: z15.record(z15.string(), z15.string()).optional()
8339
8338
  });
8340
- var mcpServerDefSchema = z15.union([
8341
- mcpHttpServerSchema,
8342
- mcpSseServerSchema,
8343
- mcpStdioServerSchema
8344
- ]);
8339
+ var mcpServerDefSchema = z15.union([mcpHttpServerSchema, mcpSseServerSchema, mcpStdioServerSchema]);
8345
8340
  var thinkingConfigSchema = z15.discriminatedUnion("type", [
8346
8341
  z15.object({ type: z15.literal("adaptive") }),
8347
8342
  z15.object({ type: z15.literal("enabled"), budgetTokens: z15.number().int().positive().optional() }),
@@ -8483,6 +8478,7 @@ var COMPANION_VERSION = pkg.version;
8483
8478
 
8484
8479
  // src/supervisor.ts
8485
8480
  var HEARTBEAT_INTERVAL_MS = 3e4;
8481
+ var SHUTDOWN_HEARTBEAT_WAIT_MS = 1e3;
8486
8482
  function positiveIntEnv(name) {
8487
8483
  const raw = process.env[name];
8488
8484
  if (!raw) return void 0;
@@ -8563,7 +8559,8 @@ var CompanionSupervisor = class {
8563
8559
  { protocolVersion: TURN_PROTOCOL_VERSION, version: COMPANION_VERSION },
8564
8560
  "companion: starting"
8565
8561
  );
8566
- void this.refreshHarnessStatuses();
8562
+ const startupHarnessRefresh = this.refreshHarnessStatuses();
8563
+ this.trackHeartbeat(startupHarnessRefresh);
8567
8564
  if (!this.config.deviceToken) {
8568
8565
  this.log.warn("companion: not paired (no device token) \u2014 run `cabane-companion pair`");
8569
8566
  process.stdout.write(
@@ -8594,7 +8591,11 @@ var CompanionSupervisor = class {
8594
8591
  });
8595
8592
  this.deviceSub.start();
8596
8593
  await this.refreshAssignments();
8597
- this.kickHeartbeat();
8594
+ const firstHeartbeat = startupHarnessRefresh.then(async () => {
8595
+ if (this.stopped) return;
8596
+ await this.sendHeartbeat();
8597
+ });
8598
+ this.trackHeartbeat(firstHeartbeat);
8598
8599
  this.heartbeatTimer = setInterval(() => this.kickHeartbeat(), HEARTBEAT_INTERVAL_MS);
8599
8600
  this.heartbeatTimer.unref?.();
8600
8601
  this.pollTimer = setInterval(() => void this.refreshAssignments(), ASSIGNMENTS_POLL_MS);
@@ -8612,8 +8613,10 @@ var CompanionSupervisor = class {
8612
8613
  }
8613
8614
  // ---- device-level loops ----
8614
8615
  kickHeartbeat() {
8615
- if (this.inFlightHeartbeat) return;
8616
- const pending = this.sendHeartbeat();
8616
+ if (this.stopped || this.inFlightHeartbeat) return;
8617
+ this.trackHeartbeat(this.sendHeartbeat());
8618
+ }
8619
+ trackHeartbeat(pending) {
8617
8620
  this.inFlightHeartbeat = pending;
8618
8621
  void pending.finally(() => {
8619
8622
  if (this.inFlightHeartbeat === pending) this.inFlightHeartbeat = null;
@@ -9367,7 +9370,7 @@ var CompanionSupervisor = class {
9367
9370
  if (wr.sub) wr.sub.stop();
9368
9371
  }
9369
9372
  await Promise.all([
9370
- ...heartbeat ? [heartbeat] : [],
9373
+ ...heartbeat ? [waitForBoundedHeartbeat(heartbeat)] : [],
9371
9374
  ...this.deviceSub ? [this.deviceSub.finished] : [],
9372
9375
  ...[...this.workspaces.values()].flatMap((wr) => wr.sub ? [wr.sub.finished] : [])
9373
9376
  ]);
@@ -9380,6 +9383,18 @@ var CompanionSupervisor = class {
9380
9383
  this.reexecFn();
9381
9384
  }
9382
9385
  };
9386
+ async function waitForBoundedHeartbeat(heartbeat) {
9387
+ let timer = null;
9388
+ const timeout = new Promise((resolve) => {
9389
+ timer = setTimeout(resolve, SHUTDOWN_HEARTBEAT_WAIT_MS);
9390
+ timer.unref?.();
9391
+ });
9392
+ try {
9393
+ await Promise.race([heartbeat, timeout]);
9394
+ } finally {
9395
+ if (timer) clearTimeout(timer);
9396
+ }
9397
+ }
9383
9398
  function defaultReexec() {
9384
9399
  clearRuntimeState();
9385
9400
  void import("child_process").then(({ spawn: spawn5 }) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cabane/companion",
3
- "version": "0.6.43",
3
+ "version": "0.6.45",
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",