@cabane/companion 0.6.27 → 0.6.29
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 +55 -6
- package/dist/runtime.js +55 -6
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -7200,6 +7200,9 @@ var TurnCommitter = class {
|
|
|
7200
7200
|
|
|
7201
7201
|
// src/workspace-readiness.ts
|
|
7202
7202
|
var CLASSIC_REQUIRED = ["read", "list", "search", "write", "edit"];
|
|
7203
|
+
var INITIALIZE_RETRY_DELAYS_MS = [250, 750, 1500];
|
|
7204
|
+
var INITIALIZE_ATTEMPT_TIMEOUT_MS = 4e3;
|
|
7205
|
+
var INITIALIZE_RETRY_BUDGET_MS = 1e4;
|
|
7203
7206
|
async function proveWorkspaceTools(req, runtime, opts = {}) {
|
|
7204
7207
|
const base = {
|
|
7205
7208
|
ok: false,
|
|
@@ -7225,7 +7228,7 @@ async function proveWorkspaceTools(req, runtime, opts = {}) {
|
|
|
7225
7228
|
"x-cabane-active-conversation": req.cabane.activeConversationId
|
|
7226
7229
|
};
|
|
7227
7230
|
try {
|
|
7228
|
-
const initialized = await
|
|
7231
|
+
const initialized = await initializeWithRetry(fetchImpl, req.cabane.mcpUrl, headers, {
|
|
7229
7232
|
jsonrpc: "2.0",
|
|
7230
7233
|
id: 1,
|
|
7231
7234
|
method: "initialize",
|
|
@@ -7237,6 +7240,8 @@ async function proveWorkspaceTools(req, runtime, opts = {}) {
|
|
|
7237
7240
|
});
|
|
7238
7241
|
if (initialized.status === 401 || initialized.status === 403)
|
|
7239
7242
|
return fail(base, "authentication_failed", `initialize returned HTTP ${initialized.status}`);
|
|
7243
|
+
if (initialized.transient)
|
|
7244
|
+
return fail(base, "workspace_endpoint_unreachable", initialized.detail);
|
|
7240
7245
|
if (!initialized.ok) return fail(base, "initialization_failed", initialized.detail);
|
|
7241
7246
|
base.initialized = true;
|
|
7242
7247
|
base.authenticated = true;
|
|
@@ -7271,11 +7276,47 @@ async function proveWorkspaceTools(req, runtime, opts = {}) {
|
|
|
7271
7276
|
} catch (error) {
|
|
7272
7277
|
return fail(
|
|
7273
7278
|
base,
|
|
7274
|
-
"
|
|
7279
|
+
"workspace_endpoint_unreachable",
|
|
7275
7280
|
error instanceof Error ? error.message : String(error)
|
|
7276
7281
|
);
|
|
7277
7282
|
}
|
|
7278
7283
|
}
|
|
7284
|
+
async function initializeWithRetry(fetchImpl, url, headers, body) {
|
|
7285
|
+
let lastFailure = null;
|
|
7286
|
+
const deadline = Date.now() + INITIALIZE_RETRY_BUDGET_MS;
|
|
7287
|
+
for (let attempt = 0; attempt <= INITIALIZE_RETRY_DELAYS_MS.length; attempt += 1) {
|
|
7288
|
+
try {
|
|
7289
|
+
const remainingMs = deadline - Date.now();
|
|
7290
|
+
if (remainingMs <= 0) break;
|
|
7291
|
+
const result = await rpc(
|
|
7292
|
+
fetchImpl,
|
|
7293
|
+
url,
|
|
7294
|
+
headers,
|
|
7295
|
+
body,
|
|
7296
|
+
Math.min(INITIALIZE_ATTEMPT_TIMEOUT_MS, remainingMs)
|
|
7297
|
+
);
|
|
7298
|
+
if (result.status === 401 || result.status === 403 || result.ok) return result;
|
|
7299
|
+
if (result.status < 500) return result;
|
|
7300
|
+
lastFailure = { ...result, transient: true };
|
|
7301
|
+
} catch (error) {
|
|
7302
|
+
lastFailure = {
|
|
7303
|
+
ok: false,
|
|
7304
|
+
status: 0,
|
|
7305
|
+
sessionId: null,
|
|
7306
|
+
value: null,
|
|
7307
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
7308
|
+
transient: true
|
|
7309
|
+
};
|
|
7310
|
+
}
|
|
7311
|
+
const retryDelayMs = INITIALIZE_RETRY_DELAYS_MS[attempt];
|
|
7312
|
+
if (retryDelayMs === void 0 || Date.now() + retryDelayMs >= deadline) break;
|
|
7313
|
+
await delay(retryDelayMs);
|
|
7314
|
+
}
|
|
7315
|
+
return lastFailure;
|
|
7316
|
+
}
|
|
7317
|
+
function delay(ms) {
|
|
7318
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
7319
|
+
}
|
|
7279
7320
|
function fail(proof, capability, detail) {
|
|
7280
7321
|
proof.failedCapability = capability;
|
|
7281
7322
|
proof.detail = detail.slice(0, 300);
|
|
@@ -7289,8 +7330,13 @@ function safeEndpoint(value) {
|
|
|
7289
7330
|
return null;
|
|
7290
7331
|
}
|
|
7291
7332
|
}
|
|
7292
|
-
async function rpc(fetchImpl, url, headers, body) {
|
|
7293
|
-
const response = await fetchImpl(url, {
|
|
7333
|
+
async function rpc(fetchImpl, url, headers, body, timeoutMs) {
|
|
7334
|
+
const response = await fetchImpl(url, {
|
|
7335
|
+
method: "POST",
|
|
7336
|
+
headers,
|
|
7337
|
+
body: JSON.stringify(body),
|
|
7338
|
+
...timeoutMs ? { signal: AbortSignal.timeout(timeoutMs) } : {}
|
|
7339
|
+
});
|
|
7294
7340
|
const text = await response.text();
|
|
7295
7341
|
const value = parseRpcBody(text);
|
|
7296
7342
|
return {
|
|
@@ -7927,7 +7973,8 @@ ${reason}`,
|
|
|
7927
7973
|
);
|
|
7928
7974
|
}
|
|
7929
7975
|
if (!proof.ok) {
|
|
7930
|
-
const
|
|
7976
|
+
const recovery = proof.failedCapability === "workspace_endpoint_unreachable" ? "the Cabane workspace endpoint was unreachable; retry this dispatch" : "restart the connector after restoring the Cabane workspace tool mount";
|
|
7977
|
+
const reason = `workspace_tools_missing: ${proof.failedCapability}; checkout=${effectiveCwd}; runtime=${adapter.name}; recovery=${recovery}`;
|
|
7931
7978
|
closeTurnReceipt(false, reason);
|
|
7932
7979
|
try {
|
|
7933
7980
|
await this.opts.api.postTurnMessage(workspaceId, payload.conversationId, {
|
|
@@ -9528,7 +9575,9 @@ var CompanionSupervisor = class {
|
|
|
9528
9575
|
// the heartbeat cadence (fresh presence for the manifest + UI) and on demand.
|
|
9529
9576
|
async refreshHarnessStatuses() {
|
|
9530
9577
|
try {
|
|
9531
|
-
const signals = await probeHarnessSignals(this.config
|
|
9578
|
+
const signals = await probeHarnessSignals(this.config, {
|
|
9579
|
+
probeClaudePresence: this.probeClaudePresence
|
|
9580
|
+
});
|
|
9532
9581
|
this.harnessSignals = signals;
|
|
9533
9582
|
this.harnessVersions = {
|
|
9534
9583
|
claudeCode: signals.claudeVersion,
|
package/dist/runtime.js
CHANGED
|
@@ -6312,6 +6312,9 @@ var TurnCommitter = class {
|
|
|
6312
6312
|
|
|
6313
6313
|
// src/workspace-readiness.ts
|
|
6314
6314
|
var CLASSIC_REQUIRED = ["read", "list", "search", "write", "edit"];
|
|
6315
|
+
var INITIALIZE_RETRY_DELAYS_MS = [250, 750, 1500];
|
|
6316
|
+
var INITIALIZE_ATTEMPT_TIMEOUT_MS = 4e3;
|
|
6317
|
+
var INITIALIZE_RETRY_BUDGET_MS = 1e4;
|
|
6315
6318
|
async function proveWorkspaceTools(req, runtime, opts = {}) {
|
|
6316
6319
|
const base = {
|
|
6317
6320
|
ok: false,
|
|
@@ -6337,7 +6340,7 @@ async function proveWorkspaceTools(req, runtime, opts = {}) {
|
|
|
6337
6340
|
"x-cabane-active-conversation": req.cabane.activeConversationId
|
|
6338
6341
|
};
|
|
6339
6342
|
try {
|
|
6340
|
-
const initialized = await
|
|
6343
|
+
const initialized = await initializeWithRetry(fetchImpl, req.cabane.mcpUrl, headers, {
|
|
6341
6344
|
jsonrpc: "2.0",
|
|
6342
6345
|
id: 1,
|
|
6343
6346
|
method: "initialize",
|
|
@@ -6349,6 +6352,8 @@ async function proveWorkspaceTools(req, runtime, opts = {}) {
|
|
|
6349
6352
|
});
|
|
6350
6353
|
if (initialized.status === 401 || initialized.status === 403)
|
|
6351
6354
|
return fail(base, "authentication_failed", `initialize returned HTTP ${initialized.status}`);
|
|
6355
|
+
if (initialized.transient)
|
|
6356
|
+
return fail(base, "workspace_endpoint_unreachable", initialized.detail);
|
|
6352
6357
|
if (!initialized.ok) return fail(base, "initialization_failed", initialized.detail);
|
|
6353
6358
|
base.initialized = true;
|
|
6354
6359
|
base.authenticated = true;
|
|
@@ -6383,11 +6388,47 @@ async function proveWorkspaceTools(req, runtime, opts = {}) {
|
|
|
6383
6388
|
} catch (error) {
|
|
6384
6389
|
return fail(
|
|
6385
6390
|
base,
|
|
6386
|
-
"
|
|
6391
|
+
"workspace_endpoint_unreachable",
|
|
6387
6392
|
error instanceof Error ? error.message : String(error)
|
|
6388
6393
|
);
|
|
6389
6394
|
}
|
|
6390
6395
|
}
|
|
6396
|
+
async function initializeWithRetry(fetchImpl, url, headers, body) {
|
|
6397
|
+
let lastFailure = null;
|
|
6398
|
+
const deadline = Date.now() + INITIALIZE_RETRY_BUDGET_MS;
|
|
6399
|
+
for (let attempt = 0; attempt <= INITIALIZE_RETRY_DELAYS_MS.length; attempt += 1) {
|
|
6400
|
+
try {
|
|
6401
|
+
const remainingMs = deadline - Date.now();
|
|
6402
|
+
if (remainingMs <= 0) break;
|
|
6403
|
+
const result = await rpc(
|
|
6404
|
+
fetchImpl,
|
|
6405
|
+
url,
|
|
6406
|
+
headers,
|
|
6407
|
+
body,
|
|
6408
|
+
Math.min(INITIALIZE_ATTEMPT_TIMEOUT_MS, remainingMs)
|
|
6409
|
+
);
|
|
6410
|
+
if (result.status === 401 || result.status === 403 || result.ok) return result;
|
|
6411
|
+
if (result.status < 500) return result;
|
|
6412
|
+
lastFailure = { ...result, transient: true };
|
|
6413
|
+
} catch (error) {
|
|
6414
|
+
lastFailure = {
|
|
6415
|
+
ok: false,
|
|
6416
|
+
status: 0,
|
|
6417
|
+
sessionId: null,
|
|
6418
|
+
value: null,
|
|
6419
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
6420
|
+
transient: true
|
|
6421
|
+
};
|
|
6422
|
+
}
|
|
6423
|
+
const retryDelayMs = INITIALIZE_RETRY_DELAYS_MS[attempt];
|
|
6424
|
+
if (retryDelayMs === void 0 || Date.now() + retryDelayMs >= deadline) break;
|
|
6425
|
+
await delay(retryDelayMs);
|
|
6426
|
+
}
|
|
6427
|
+
return lastFailure;
|
|
6428
|
+
}
|
|
6429
|
+
function delay(ms) {
|
|
6430
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
6431
|
+
}
|
|
6391
6432
|
function fail(proof, capability, detail) {
|
|
6392
6433
|
proof.failedCapability = capability;
|
|
6393
6434
|
proof.detail = detail.slice(0, 300);
|
|
@@ -6401,8 +6442,13 @@ function safeEndpoint(value) {
|
|
|
6401
6442
|
return null;
|
|
6402
6443
|
}
|
|
6403
6444
|
}
|
|
6404
|
-
async function rpc(fetchImpl, url, headers, body) {
|
|
6405
|
-
const response = await fetchImpl(url, {
|
|
6445
|
+
async function rpc(fetchImpl, url, headers, body, timeoutMs) {
|
|
6446
|
+
const response = await fetchImpl(url, {
|
|
6447
|
+
method: "POST",
|
|
6448
|
+
headers,
|
|
6449
|
+
body: JSON.stringify(body),
|
|
6450
|
+
...timeoutMs ? { signal: AbortSignal.timeout(timeoutMs) } : {}
|
|
6451
|
+
});
|
|
6406
6452
|
const text = await response.text();
|
|
6407
6453
|
const value = parseRpcBody(text);
|
|
6408
6454
|
return {
|
|
@@ -7039,7 +7085,8 @@ ${reason}`,
|
|
|
7039
7085
|
);
|
|
7040
7086
|
}
|
|
7041
7087
|
if (!proof.ok) {
|
|
7042
|
-
const
|
|
7088
|
+
const recovery = proof.failedCapability === "workspace_endpoint_unreachable" ? "the Cabane workspace endpoint was unreachable; retry this dispatch" : "restart the connector after restoring the Cabane workspace tool mount";
|
|
7089
|
+
const reason = `workspace_tools_missing: ${proof.failedCapability}; checkout=${effectiveCwd}; runtime=${adapter.name}; recovery=${recovery}`;
|
|
7043
7090
|
closeTurnReceipt(false, reason);
|
|
7044
7091
|
try {
|
|
7045
7092
|
await this.opts.api.postTurnMessage(workspaceId, payload.conversationId, {
|
|
@@ -8640,7 +8687,9 @@ var CompanionSupervisor = class {
|
|
|
8640
8687
|
// the heartbeat cadence (fresh presence for the manifest + UI) and on demand.
|
|
8641
8688
|
async refreshHarnessStatuses() {
|
|
8642
8689
|
try {
|
|
8643
|
-
const signals = await probeHarnessSignals(this.config
|
|
8690
|
+
const signals = await probeHarnessSignals(this.config, {
|
|
8691
|
+
probeClaudePresence: this.probeClaudePresence
|
|
8692
|
+
});
|
|
8644
8693
|
this.harnessSignals = signals;
|
|
8645
8694
|
this.harnessVersions = {
|
|
8646
8695
|
claudeCode: signals.claudeVersion,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cabane/companion",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.29",
|
|
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",
|