@cabane/companion 0.6.14 → 0.6.15
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 +38 -3
- package/dist/runtime.js +38 -3
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -7568,6 +7568,32 @@ ${reason}`,
|
|
|
7568
7568
|
`runtime_unavailable:${err.runtime}`
|
|
7569
7569
|
);
|
|
7570
7570
|
}
|
|
7571
|
+
let turnReceiptPath = null;
|
|
7572
|
+
const totalTimeoutMs = this.opts.totalTimeoutMs ?? DEFAULT_AGENT_TOTAL_TIMEOUT_MS;
|
|
7573
|
+
const closeTurnReceipt = (ok, reason) => {
|
|
7574
|
+
if (!turnReceiptPath) return;
|
|
7575
|
+
const target = turnReceiptPath;
|
|
7576
|
+
turnReceiptPath = null;
|
|
7577
|
+
try {
|
|
7578
|
+
appendFileSync2(
|
|
7579
|
+
target,
|
|
7580
|
+
`${JSON.stringify({
|
|
7581
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7582
|
+
event: "settled",
|
|
7583
|
+
turnId,
|
|
7584
|
+
ok,
|
|
7585
|
+
reason
|
|
7586
|
+
})}
|
|
7587
|
+
`,
|
|
7588
|
+
{ mode: 384 }
|
|
7589
|
+
);
|
|
7590
|
+
} catch (error) {
|
|
7591
|
+
turnLog.warn(
|
|
7592
|
+
{ err: error instanceof Error ? error.message : String(error) },
|
|
7593
|
+
"dispatcher: turn-settled diagnostic write failed"
|
|
7594
|
+
);
|
|
7595
|
+
}
|
|
7596
|
+
};
|
|
7571
7597
|
if (prepareHook && hookEnv?.CABANE_TASK_ID) {
|
|
7572
7598
|
const proof = await proveWorkspaceTools(request, adapter.name, {
|
|
7573
7599
|
...this.opts.workspaceProofFetch ? { fetchImpl: this.opts.workspaceProofFetch } : {},
|
|
@@ -7582,8 +7608,9 @@ ${reason}`,
|
|
|
7582
7608
|
try {
|
|
7583
7609
|
const diagnosticDir = join13(effectiveCwd, ".git", "cabane");
|
|
7584
7610
|
mkdirSync10(diagnosticDir, { recursive: true });
|
|
7611
|
+
const receiptPath = join13(diagnosticDir, "readiness.jsonl");
|
|
7585
7612
|
appendFileSync2(
|
|
7586
|
-
|
|
7613
|
+
receiptPath,
|
|
7587
7614
|
`${JSON.stringify({
|
|
7588
7615
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7589
7616
|
taskId: hookEnv.CABANE_TASK_ID,
|
|
@@ -7591,11 +7618,18 @@ ${reason}`,
|
|
|
7591
7618
|
checkout: effectiveCwd,
|
|
7592
7619
|
classification: proof.ok ? "ready" : "workspace_tools_missing",
|
|
7593
7620
|
failedCapability: proof.failedCapability,
|
|
7594
|
-
workspaceTools: proof
|
|
7621
|
+
workspaceTools: proof,
|
|
7622
|
+
// CT1022: the two fields the environment reaper reads — which turn
|
|
7623
|
+
// this is (so its settle can be matched among interleaved agents)
|
|
7624
|
+
// and how long it may legitimately run (so an unclosed receipt
|
|
7625
|
+
// expires on this turn's real deadline, not the reaper's guess).
|
|
7626
|
+
turnId,
|
|
7627
|
+
totalTimeoutMs
|
|
7595
7628
|
})}
|
|
7596
7629
|
`,
|
|
7597
7630
|
{ mode: 384 }
|
|
7598
7631
|
);
|
|
7632
|
+
turnReceiptPath = receiptPath;
|
|
7599
7633
|
} catch (error) {
|
|
7600
7634
|
turnLog.warn(
|
|
7601
7635
|
{ err: error instanceof Error ? error.message : String(error) },
|
|
@@ -7622,6 +7656,7 @@ ${reason}`,
|
|
|
7622
7656
|
}
|
|
7623
7657
|
if (!proof.ok) {
|
|
7624
7658
|
const reason = `workspace_tools_missing: ${proof.failedCapability}; checkout=${effectiveCwd ?? "unknown"}; runtime=${adapter.name}; recovery=restart the connector after restoring the Cabane workspace tool mount`;
|
|
7659
|
+
closeTurnReceipt(false, reason);
|
|
7625
7660
|
try {
|
|
7626
7661
|
await this.opts.api.postTurnMessage(workspaceId, payload.conversationId, {
|
|
7627
7662
|
body: `**Couldn't prepare your environment.** ${reason}`,
|
|
@@ -7733,7 +7768,6 @@ ${reason}`,
|
|
|
7733
7768
|
}
|
|
7734
7769
|
};
|
|
7735
7770
|
const idleTimeoutMs = this.opts.idleTimeoutMs ?? DEFAULT_AGENT_IDLE_TIMEOUT_MS;
|
|
7736
|
-
const totalTimeoutMs = this.opts.totalTimeoutMs ?? DEFAULT_AGENT_TOTAL_TIMEOUT_MS;
|
|
7737
7771
|
const fireTimeout = (reason) => {
|
|
7738
7772
|
if (abortController.signal.aborted) return;
|
|
7739
7773
|
timeoutReason = reason;
|
|
@@ -7835,6 +7869,7 @@ ${reason}`,
|
|
|
7835
7869
|
} finally {
|
|
7836
7870
|
if (idleTimer) clearTimeout(idleTimer);
|
|
7837
7871
|
clearTimeout(totalTimer);
|
|
7872
|
+
closeTurnReceipt(okResult, resultReason ?? null);
|
|
7838
7873
|
const userCancelled = abortController.signal.aborted && timeoutReason === null;
|
|
7839
7874
|
if (timeoutReason !== null) {
|
|
7840
7875
|
resultReason = timeoutReason;
|
package/dist/runtime.js
CHANGED
|
@@ -7221,6 +7221,32 @@ ${reason}`,
|
|
|
7221
7221
|
`runtime_unavailable:${err.runtime}`
|
|
7222
7222
|
);
|
|
7223
7223
|
}
|
|
7224
|
+
let turnReceiptPath = null;
|
|
7225
|
+
const totalTimeoutMs = this.opts.totalTimeoutMs ?? DEFAULT_AGENT_TOTAL_TIMEOUT_MS;
|
|
7226
|
+
const closeTurnReceipt = (ok, reason) => {
|
|
7227
|
+
if (!turnReceiptPath) return;
|
|
7228
|
+
const target = turnReceiptPath;
|
|
7229
|
+
turnReceiptPath = null;
|
|
7230
|
+
try {
|
|
7231
|
+
appendFileSync2(
|
|
7232
|
+
target,
|
|
7233
|
+
`${JSON.stringify({
|
|
7234
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7235
|
+
event: "settled",
|
|
7236
|
+
turnId,
|
|
7237
|
+
ok,
|
|
7238
|
+
reason
|
|
7239
|
+
})}
|
|
7240
|
+
`,
|
|
7241
|
+
{ mode: 384 }
|
|
7242
|
+
);
|
|
7243
|
+
} catch (error) {
|
|
7244
|
+
turnLog.warn(
|
|
7245
|
+
{ err: error instanceof Error ? error.message : String(error) },
|
|
7246
|
+
"dispatcher: turn-settled diagnostic write failed"
|
|
7247
|
+
);
|
|
7248
|
+
}
|
|
7249
|
+
};
|
|
7224
7250
|
if (prepareHook && hookEnv?.CABANE_TASK_ID) {
|
|
7225
7251
|
const proof = await proveWorkspaceTools(request, adapter.name, {
|
|
7226
7252
|
...this.opts.workspaceProofFetch ? { fetchImpl: this.opts.workspaceProofFetch } : {},
|
|
@@ -7235,8 +7261,9 @@ ${reason}`,
|
|
|
7235
7261
|
try {
|
|
7236
7262
|
const diagnosticDir = join13(effectiveCwd, ".git", "cabane");
|
|
7237
7263
|
mkdirSync9(diagnosticDir, { recursive: true });
|
|
7264
|
+
const receiptPath = join13(diagnosticDir, "readiness.jsonl");
|
|
7238
7265
|
appendFileSync2(
|
|
7239
|
-
|
|
7266
|
+
receiptPath,
|
|
7240
7267
|
`${JSON.stringify({
|
|
7241
7268
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7242
7269
|
taskId: hookEnv.CABANE_TASK_ID,
|
|
@@ -7244,11 +7271,18 @@ ${reason}`,
|
|
|
7244
7271
|
checkout: effectiveCwd,
|
|
7245
7272
|
classification: proof.ok ? "ready" : "workspace_tools_missing",
|
|
7246
7273
|
failedCapability: proof.failedCapability,
|
|
7247
|
-
workspaceTools: proof
|
|
7274
|
+
workspaceTools: proof,
|
|
7275
|
+
// CT1022: the two fields the environment reaper reads — which turn
|
|
7276
|
+
// this is (so its settle can be matched among interleaved agents)
|
|
7277
|
+
// and how long it may legitimately run (so an unclosed receipt
|
|
7278
|
+
// expires on this turn's real deadline, not the reaper's guess).
|
|
7279
|
+
turnId,
|
|
7280
|
+
totalTimeoutMs
|
|
7248
7281
|
})}
|
|
7249
7282
|
`,
|
|
7250
7283
|
{ mode: 384 }
|
|
7251
7284
|
);
|
|
7285
|
+
turnReceiptPath = receiptPath;
|
|
7252
7286
|
} catch (error) {
|
|
7253
7287
|
turnLog.warn(
|
|
7254
7288
|
{ err: error instanceof Error ? error.message : String(error) },
|
|
@@ -7275,6 +7309,7 @@ ${reason}`,
|
|
|
7275
7309
|
}
|
|
7276
7310
|
if (!proof.ok) {
|
|
7277
7311
|
const reason = `workspace_tools_missing: ${proof.failedCapability}; checkout=${effectiveCwd ?? "unknown"}; runtime=${adapter.name}; recovery=restart the connector after restoring the Cabane workspace tool mount`;
|
|
7312
|
+
closeTurnReceipt(false, reason);
|
|
7278
7313
|
try {
|
|
7279
7314
|
await this.opts.api.postTurnMessage(workspaceId, payload.conversationId, {
|
|
7280
7315
|
body: `**Couldn't prepare your environment.** ${reason}`,
|
|
@@ -7386,7 +7421,6 @@ ${reason}`,
|
|
|
7386
7421
|
}
|
|
7387
7422
|
};
|
|
7388
7423
|
const idleTimeoutMs = this.opts.idleTimeoutMs ?? DEFAULT_AGENT_IDLE_TIMEOUT_MS;
|
|
7389
|
-
const totalTimeoutMs = this.opts.totalTimeoutMs ?? DEFAULT_AGENT_TOTAL_TIMEOUT_MS;
|
|
7390
7424
|
const fireTimeout = (reason) => {
|
|
7391
7425
|
if (abortController.signal.aborted) return;
|
|
7392
7426
|
timeoutReason = reason;
|
|
@@ -7488,6 +7522,7 @@ ${reason}`,
|
|
|
7488
7522
|
} finally {
|
|
7489
7523
|
if (idleTimer) clearTimeout(idleTimer);
|
|
7490
7524
|
clearTimeout(totalTimer);
|
|
7525
|
+
closeTurnReceipt(okResult, resultReason ?? null);
|
|
7491
7526
|
const userCancelled = abortController.signal.aborted && timeoutReason === null;
|
|
7492
7527
|
if (timeoutReason !== null) {
|
|
7493
7528
|
resultReason = timeoutReason;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cabane/companion",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.15",
|
|
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",
|