@cabane/companion 0.6.116 → 0.6.118

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
@@ -3200,9 +3200,9 @@ var CabaneApi = class {
3200
3200
  // Commit one outgoing act (ask, withdraw_ask, wake_me, cancel_wake) at
3201
3201
  // invocation. The server records the effect and receipt in one transaction;
3202
3202
  // an ok:false response is a recorded refusal for the tool to report.
3203
- // Retries retain the caller's callId and recover the same receipt while the
3204
- // HTTP route admits the request. Currently that route rejects ended spans
3205
- // before receipt lookup: a 409 cannot prove an earlier attempt had no effect.
3203
+ // Retries retain the caller's callId and recover the same receipt, even
3204
+ // when the turn settled between attempts (CT1447): the route consults the
3205
+ // receipt before it refuses an ended turn, so a 4xx proves no attempt wrote.
3206
3206
  // The caller's signal bounds how long the model waits for the tool result.
3207
3207
  turnAct(workspaceId, turnId, act, signal) {
3208
3208
  return this.request(
@@ -8488,6 +8488,9 @@ async function performAct(acts, act) {
8488
8488
  AbortSignal.timeout(TURN_ACT_TIMEOUT_MS)
8489
8489
  );
8490
8490
  } catch (err) {
8491
+ if (err instanceof ApiError && err.status >= 500) {
8492
+ return uncertainOutcome(`${err.status}: ${apiErrorMessage(err)}`);
8493
+ }
8491
8494
  if (err instanceof ApiError) {
8492
8495
  if (err.status === 409 && apiErrorCode(err) === "no_active_turn") {
8493
8496
  return toolError(
@@ -8496,14 +8499,16 @@ async function performAct(acts, act) {
8496
8499
  }
8497
8500
  return toolError(`The act was refused (${err.status}): ${apiErrorMessage(err)}`);
8498
8501
  }
8499
- const message = err instanceof Error ? err.message : String(err);
8500
- return toolError(
8501
- `Cabane could not be reached (${message}), so it is UNKNOWN whether this act was recorded \u2014 it may have committed with only the response lost. Do NOT simply repeat the call: a repeat is a second, separate act, not a retry. Carry on, and say in your reply that you could not confirm it.`
8502
- );
8502
+ return uncertainOutcome(err instanceof Error ? err.message : String(err));
8503
8503
  }
8504
8504
  if (!result.ok) return toolError(JSON.stringify(result));
8505
8505
  return { content: [{ type: "text", text: JSON.stringify(result) }] };
8506
8506
  }
8507
+ function uncertainOutcome(cause) {
8508
+ return toolError(
8509
+ `The outcome of this act could not be confirmed (${cause}). It may already have been performed, with only the response lost. Do NOT simply repeat the call: a repeat is a second, separate act, not a retry. Carry on, and say in your reply that you could not confirm it.`
8510
+ );
8511
+ }
8507
8512
  function createTurnControlMcpServer(acts, skipState) {
8508
8513
  const ACT_TOOL = { readOnlyHint: false, destructiveHint: false, openWorldHint: false };
8509
8514
  const CANCEL_TOOL = { ...ACT_TOOL, idempotentHint: true };
@@ -9133,6 +9138,7 @@ var MANAGER_ENV_KEYS = ["DBUS_SESSION_BUS_ADDRESS", "XDG_RUNTIME_DIR", "PATH"];
9133
9138
  var managerEnvKey = (env) => MANAGER_ENV_KEYS.map((k) => `${k}=${env[k] ?? ""}`).join("\0");
9134
9139
  function createTurnContainment(turnId, deps = {}) {
9135
9140
  const probe = deps.capabilityProbe ?? scopeCapabilityUsable;
9141
+ const fallbackGraceMs = deps.fallbackGraceMs ?? FALLBACK_GRACE_MS;
9136
9142
  const ownUnit = (deps.ownSystemdUnit ?? readCurrentSystemdUnit)();
9137
9143
  const scopeUnits = [];
9138
9144
  const groups = [];
@@ -9254,7 +9260,7 @@ function createTurnContainment(turnId, deps = {}) {
9254
9260
  } catch {
9255
9261
  }
9256
9262
  }
9257
- await sleep3(FALLBACK_GRACE_MS);
9263
+ await sleep3(fallbackGraceMs);
9258
9264
  const afterTerm = processGroupMembers(pgid);
9259
9265
  if (!afterTerm.ok) {
9260
9266
  result.failures.push({
package/dist/runtime.js CHANGED
@@ -2534,9 +2534,9 @@ var CabaneApi = class {
2534
2534
  // Commit one outgoing act (ask, withdraw_ask, wake_me, cancel_wake) at
2535
2535
  // invocation. The server records the effect and receipt in one transaction;
2536
2536
  // an ok:false response is a recorded refusal for the tool to report.
2537
- // Retries retain the caller's callId and recover the same receipt while the
2538
- // HTTP route admits the request. Currently that route rejects ended spans
2539
- // before receipt lookup: a 409 cannot prove an earlier attempt had no effect.
2537
+ // Retries retain the caller's callId and recover the same receipt, even
2538
+ // when the turn settled between attempts (CT1447): the route consults the
2539
+ // receipt before it refuses an ended turn, so a 4xx proves no attempt wrote.
2540
2540
  // The caller's signal bounds how long the model waits for the tool result.
2541
2541
  turnAct(workspaceId, turnId, act, signal) {
2542
2542
  return this.request(
@@ -7911,6 +7911,9 @@ async function performAct(acts, act) {
7911
7911
  AbortSignal.timeout(TURN_ACT_TIMEOUT_MS)
7912
7912
  );
7913
7913
  } catch (err) {
7914
+ if (err instanceof ApiError && err.status >= 500) {
7915
+ return uncertainOutcome(`${err.status}: ${apiErrorMessage(err)}`);
7916
+ }
7914
7917
  if (err instanceof ApiError) {
7915
7918
  if (err.status === 409 && apiErrorCode(err) === "no_active_turn") {
7916
7919
  return toolError(
@@ -7919,14 +7922,16 @@ async function performAct(acts, act) {
7919
7922
  }
7920
7923
  return toolError(`The act was refused (${err.status}): ${apiErrorMessage(err)}`);
7921
7924
  }
7922
- const message = err instanceof Error ? err.message : String(err);
7923
- return toolError(
7924
- `Cabane could not be reached (${message}), so it is UNKNOWN whether this act was recorded \u2014 it may have committed with only the response lost. Do NOT simply repeat the call: a repeat is a second, separate act, not a retry. Carry on, and say in your reply that you could not confirm it.`
7925
- );
7925
+ return uncertainOutcome(err instanceof Error ? err.message : String(err));
7926
7926
  }
7927
7927
  if (!result.ok) return toolError(JSON.stringify(result));
7928
7928
  return { content: [{ type: "text", text: JSON.stringify(result) }] };
7929
7929
  }
7930
+ function uncertainOutcome(cause) {
7931
+ return toolError(
7932
+ `The outcome of this act could not be confirmed (${cause}). It may already have been performed, with only the response lost. Do NOT simply repeat the call: a repeat is a second, separate act, not a retry. Carry on, and say in your reply that you could not confirm it.`
7933
+ );
7934
+ }
7930
7935
  function createTurnControlMcpServer(acts, skipState) {
7931
7936
  const ACT_TOOL = { readOnlyHint: false, destructiveHint: false, openWorldHint: false };
7932
7937
  const CANCEL_TOOL = { ...ACT_TOOL, idempotentHint: true };
@@ -8556,6 +8561,7 @@ var MANAGER_ENV_KEYS = ["DBUS_SESSION_BUS_ADDRESS", "XDG_RUNTIME_DIR", "PATH"];
8556
8561
  var managerEnvKey = (env) => MANAGER_ENV_KEYS.map((k) => `${k}=${env[k] ?? ""}`).join("\0");
8557
8562
  function createTurnContainment(turnId, deps = {}) {
8558
8563
  const probe = deps.capabilityProbe ?? scopeCapabilityUsable;
8564
+ const fallbackGraceMs = deps.fallbackGraceMs ?? FALLBACK_GRACE_MS;
8559
8565
  const ownUnit = (deps.ownSystemdUnit ?? readCurrentSystemdUnit)();
8560
8566
  const scopeUnits = [];
8561
8567
  const groups = [];
@@ -8677,7 +8683,7 @@ function createTurnContainment(turnId, deps = {}) {
8677
8683
  } catch {
8678
8684
  }
8679
8685
  }
8680
- await sleep2(FALLBACK_GRACE_MS);
8686
+ await sleep2(fallbackGraceMs);
8681
8687
  const afterTerm = processGroupMembers(pgid);
8682
8688
  if (!afterTerm.ok) {
8683
8689
  result.failures.push({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cabane/companion",
3
- "version": "0.6.116",
3
+ "version": "0.6.118",
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",