@cabane/companion 0.6.195 → 0.6.197

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
@@ -1682,7 +1682,7 @@ var init_api = __esm({
1682
1682
  // Single-shot, NEVER retried: a failed renewal has no answer worth replaying
1683
1683
  // and the next tick asks again; retrying stretches one tick over the next.
1684
1684
  //
1685
- // ALL FAILURE IS `unknown`. Only the server SAYING the turn is over may stop a
1685
+ // Only the server SAYING the turn is over may stop a
1686
1686
  // running loop; a 500, a dropped connection, an expired token or an
1687
1687
  // unparseable body says nothing about the turn, and reading it as death would
1688
1688
  // kill healthy turns on every API hiccup. Fixed here, at the boundary, so no
@@ -1706,8 +1706,8 @@ var init_api = __esm({
1706
1706
  }
1707
1707
  );
1708
1708
  return res?.state === "running" || res?.state === "ended" ? res.state : "unknown";
1709
- } catch {
1710
- return "unknown";
1709
+ } catch (err) {
1710
+ return isTurnEndedRefusal(err) ? "ended" : "unknown";
1711
1711
  }
1712
1712
  }
1713
1713
  // Flips `active_run_started_at` and optionally captures the SDK session
@@ -10557,8 +10557,8 @@ var init_dispatcher = __esm({
10557
10557
  this.aborts = opts.aborts ?? /* @__PURE__ */ new Map();
10558
10558
  }
10559
10559
  opts;
10560
- // (conversation|agent) → per-TURN controllers. Stop is pair-scoped and must
10561
- // reach every live loop for the pair.
10560
+ // (conversation|agent) → per-turn controllers. A delayed cancel for an old
10561
+ // turn must never reach its successor.
10562
10562
  aborts;
10563
10563
  // Pairs already told their session couldn't be saved: the notice is once per
10564
10564
  // pair, while the rejection repeats every turn.
@@ -10609,19 +10609,22 @@ var init_dispatcher = __esm({
10609
10609
  { turnId: opts.turnId ?? randomUUID4(), resumed: opts.resumed === true }
10610
10610
  );
10611
10611
  }
10612
- // Cancel a (conversation, agent) run in flight in THIS process. True if one
10613
- // was aborted.
10614
- cancel(conversationId, agentId) {
10612
+ // Cancel the named turn. An older server omits turnId and cancels the pair.
10613
+ cancel(conversationId, agentId, turnId) {
10615
10614
  const key = runKey(conversationId, agentId);
10616
10615
  const pair = this.aborts.get(key);
10617
10616
  if (!pair || pair.size === 0) return false;
10618
- for (const ac of [...pair.values()]) {
10617
+ const controllers = turnId === void 0 ? [...pair.values()] : [pair.get(turnId)];
10618
+ let aborted = false;
10619
+ for (const ac of controllers) {
10620
+ if (!ac) continue;
10621
+ aborted = true;
10619
10622
  try {
10620
10623
  ac.abort();
10621
10624
  } catch {
10622
10625
  }
10623
10626
  }
10624
- return true;
10627
+ return aborted;
10625
10628
  }
10626
10629
  // Abort every run in flight in THIS process, whatever its conversation. For
10627
10630
  // an agent taken off this device: nothing it is still running here is
@@ -11376,7 +11379,6 @@ import { join as join7 } from "path";
11376
11379
  // src/device-state.ts
11377
11380
  var DEVICE_STATES = ["waiting", "online", "offline", "deactivated"];
11378
11381
  var DEFAULT_DEVICE_OFFLINE_THRESHOLD_MS = 9e4;
11379
- var DEFAULT_DEVICE_RECONNECT_GRACE_MS = 9e4;
11380
11382
  var HARNESS_STATES = [
11381
11383
  "checking",
11382
11384
  "connected",
@@ -14919,7 +14921,11 @@ var CompanionSupervisor = class {
14919
14921
  };
14920
14922
  const agent2 = wr.agents.get(payload2.agentId);
14921
14923
  if (agent2) {
14922
- const aborted = agent2.dispatcher.cancel(payload2.conversationId, payload2.agentId);
14924
+ const aborted = agent2.dispatcher.cancel(
14925
+ payload2.conversationId,
14926
+ payload2.agentId,
14927
+ payload2.turnId
14928
+ );
14923
14929
  if (aborted) {
14924
14930
  this.log.debug(
14925
14931
  {
@@ -16380,7 +16386,7 @@ function defaultSpawnDetached(args) {
16380
16386
  // src/terminal-copy.ts
16381
16387
  init_cabane_command();
16382
16388
  var UNPAIRED = "This device isn't paired yet. Get a setup line from a workspace's Settings \u2192 Devices and paste it here.";
16383
- var lease = DEFAULT_DEVICE_OFFLINE_THRESHOLD_MS + DEFAULT_DEVICE_RECONNECT_GRACE_MS;
16389
+ var lease = DEFAULT_DEVICE_OFFLINE_THRESHOLD_MS;
16384
16390
  function age(at, now) {
16385
16391
  const seconds = Math.max(0, Math.floor((now - Date.parse(at)) / 1e3));
16386
16392
  return seconds < 60 ? `${seconds}s` : seconds < 3600 ? `${Math.floor(seconds / 60)}m` : `${Math.floor(seconds / 3600)}h`;
package/dist/runtime.js CHANGED
@@ -2110,7 +2110,7 @@ var CabaneApi = class {
2110
2110
  // Single-shot, NEVER retried: a failed renewal has no answer worth replaying
2111
2111
  // and the next tick asks again; retrying stretches one tick over the next.
2112
2112
  //
2113
- // ALL FAILURE IS `unknown`. Only the server SAYING the turn is over may stop a
2113
+ // Only the server SAYING the turn is over may stop a
2114
2114
  // running loop; a 500, a dropped connection, an expired token or an
2115
2115
  // unparseable body says nothing about the turn, and reading it as death would
2116
2116
  // kill healthy turns on every API hiccup. Fixed here, at the boundary, so no
@@ -2134,8 +2134,8 @@ var CabaneApi = class {
2134
2134
  }
2135
2135
  );
2136
2136
  return res?.state === "running" || res?.state === "ended" ? res.state : "unknown";
2137
- } catch {
2138
- return "unknown";
2137
+ } catch (err) {
2138
+ return isTurnEndedRefusal(err) ? "ended" : "unknown";
2139
2139
  }
2140
2140
  }
2141
2141
  // Flips `active_run_started_at` and optionally captures the SDK session
@@ -8257,8 +8257,8 @@ var Dispatcher = class {
8257
8257
  this.aborts = opts.aborts ?? /* @__PURE__ */ new Map();
8258
8258
  }
8259
8259
  opts;
8260
- // (conversation|agent) → per-TURN controllers. Stop is pair-scoped and must
8261
- // reach every live loop for the pair.
8260
+ // (conversation|agent) → per-turn controllers. A delayed cancel for an old
8261
+ // turn must never reach its successor.
8262
8262
  aborts;
8263
8263
  // Pairs already told their session couldn't be saved: the notice is once per
8264
8264
  // pair, while the rejection repeats every turn.
@@ -8309,19 +8309,22 @@ var Dispatcher = class {
8309
8309
  { turnId: opts.turnId ?? randomUUID4(), resumed: opts.resumed === true }
8310
8310
  );
8311
8311
  }
8312
- // Cancel a (conversation, agent) run in flight in THIS process. True if one
8313
- // was aborted.
8314
- cancel(conversationId, agentId) {
8312
+ // Cancel the named turn. An older server omits turnId and cancels the pair.
8313
+ cancel(conversationId, agentId, turnId) {
8315
8314
  const key = runKey(conversationId, agentId);
8316
8315
  const pair = this.aborts.get(key);
8317
8316
  if (!pair || pair.size === 0) return false;
8318
- for (const ac of [...pair.values()]) {
8317
+ const controllers = turnId === void 0 ? [...pair.values()] : [pair.get(turnId)];
8318
+ let aborted = false;
8319
+ for (const ac of controllers) {
8320
+ if (!ac) continue;
8321
+ aborted = true;
8319
8322
  try {
8320
8323
  ac.abort();
8321
8324
  } catch {
8322
8325
  }
8323
8326
  }
8324
- return true;
8327
+ return aborted;
8325
8328
  }
8326
8329
  // Abort every run in flight in THIS process, whatever its conversation. For
8327
8330
  // an agent taken off this device: nothing it is still running here is
@@ -10528,7 +10531,11 @@ var CompanionSupervisor = class {
10528
10531
  };
10529
10532
  const agent2 = wr.agents.get(payload2.agentId);
10530
10533
  if (agent2) {
10531
- const aborted = agent2.dispatcher.cancel(payload2.conversationId, payload2.agentId);
10534
+ const aborted = agent2.dispatcher.cancel(
10535
+ payload2.conversationId,
10536
+ payload2.agentId,
10537
+ payload2.turnId
10538
+ );
10532
10539
  if (aborted) {
10533
10540
  this.log.debug(
10534
10541
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cabane/companion",
3
- "version": "0.6.195",
3
+ "version": "0.6.197",
4
4
  "type": "module",
5
5
  "description": "The Cabane Companion (headless): connect an 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",