@cabane/companion 0.6.115 → 0.6.117
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 +73 -10
- package/dist/runtime.js +73 -10
- package/package.json +3 -3
package/dist/cli.js
CHANGED
|
@@ -6847,6 +6847,16 @@ function readUsage(ev) {
|
|
|
6847
6847
|
cacheCreationTokens: num(usage.cache_write_input_tokens)
|
|
6848
6848
|
};
|
|
6849
6849
|
}
|
|
6850
|
+
function codexUsageDelta(cumulative, baseline) {
|
|
6851
|
+
if (!baseline) return cumulative;
|
|
6852
|
+
const sub = (a, b) => Math.max(0, a - b);
|
|
6853
|
+
return {
|
|
6854
|
+
inputTokens: sub(cumulative.inputTokens, baseline.inputTokens),
|
|
6855
|
+
outputTokens: sub(cumulative.outputTokens, baseline.outputTokens),
|
|
6856
|
+
cacheReadTokens: sub(cumulative.cacheReadTokens, baseline.cacheReadTokens),
|
|
6857
|
+
cacheCreationTokens: sub(cumulative.cacheCreationTokens, baseline.cacheCreationTokens)
|
|
6858
|
+
};
|
|
6859
|
+
}
|
|
6850
6860
|
function toStatus(v) {
|
|
6851
6861
|
return v === "completed" || v === "failed" ? v : "in_progress";
|
|
6852
6862
|
}
|
|
@@ -6921,9 +6931,26 @@ function decideResume3(stored, currentCwd) {
|
|
|
6921
6931
|
}
|
|
6922
6932
|
return {
|
|
6923
6933
|
resume: state.threadId,
|
|
6924
|
-
promptFingerprint: typeof state.promptFingerprint === "string" ? state.promptFingerprint : null
|
|
6934
|
+
promptFingerprint: typeof state.promptFingerprint === "string" ? state.promptFingerprint : null,
|
|
6935
|
+
usageBaseline: readUsageBaseline(state.usageBaseline)
|
|
6925
6936
|
};
|
|
6926
6937
|
}
|
|
6938
|
+
function readUsageBaseline(raw) {
|
|
6939
|
+
if (!raw || typeof raw !== "object") return null;
|
|
6940
|
+
const rec2 = raw;
|
|
6941
|
+
const read = (key) => {
|
|
6942
|
+
const v = rec2[key];
|
|
6943
|
+
return typeof v === "number" && Number.isFinite(v) && v >= 0 ? v : null;
|
|
6944
|
+
};
|
|
6945
|
+
const inputTokens = read("inputTokens");
|
|
6946
|
+
const outputTokens = read("outputTokens");
|
|
6947
|
+
const cacheReadTokens = read("cacheReadTokens");
|
|
6948
|
+
const cacheCreationTokens = read("cacheCreationTokens");
|
|
6949
|
+
if (inputTokens === null || outputTokens === null || cacheReadTokens === null || cacheCreationTokens === null) {
|
|
6950
|
+
return null;
|
|
6951
|
+
}
|
|
6952
|
+
return { inputTokens, outputTokens, cacheReadTokens, cacheCreationTokens };
|
|
6953
|
+
}
|
|
6927
6954
|
|
|
6928
6955
|
// packages/agent-runtime/src/codex/loop.ts
|
|
6929
6956
|
async function* decodeCodexStream(events, ctx) {
|
|
@@ -6935,6 +6962,8 @@ async function* decodeCodexStream(events, ctx) {
|
|
|
6935
6962
|
let ok = false;
|
|
6936
6963
|
let reason;
|
|
6937
6964
|
let usage;
|
|
6965
|
+
let cumulativeUsage;
|
|
6966
|
+
let threadIdForSession = ctx.resumedThreadId;
|
|
6938
6967
|
let settled = false;
|
|
6939
6968
|
function* flushInterim() {
|
|
6940
6969
|
const sealed = sealHeld2(held, false);
|
|
@@ -6945,11 +6974,17 @@ async function* decodeCodexStream(events, ctx) {
|
|
|
6945
6974
|
if (ctx.signal.aborted) return;
|
|
6946
6975
|
if (ev.type === "thread.started") {
|
|
6947
6976
|
const threadId = readThreadId(ev);
|
|
6977
|
+
if (threadId) threadIdForSession = threadId;
|
|
6948
6978
|
if (threadId && !sessionEmitted) {
|
|
6949
6979
|
const state = encodeSession3({
|
|
6950
6980
|
threadId,
|
|
6951
6981
|
cwd: ctx.cwd ?? "",
|
|
6952
|
-
promptFingerprint: ctx.promptFingerprint ?? null
|
|
6982
|
+
promptFingerprint: ctx.promptFingerprint ?? null,
|
|
6983
|
+
// CT1645: the baseline this turn INHERITED, carried through unchanged.
|
|
6984
|
+
// This early write exists so a turn that dies mid-stream still leaves
|
|
6985
|
+
// the thread id recorded; it cannot yet know what this turn will spend.
|
|
6986
|
+
// The closing write below records the new baseline.
|
|
6987
|
+
usageBaseline: ctx.usageBaseline ?? null
|
|
6953
6988
|
});
|
|
6954
6989
|
if (threadId !== ctx.resumedThreadId || state !== ctx.storedState) {
|
|
6955
6990
|
sessionEmitted = true;
|
|
@@ -7024,7 +7059,8 @@ async function* decodeCodexStream(events, ctx) {
|
|
|
7024
7059
|
const sealed = sealHeld2(held, true);
|
|
7025
7060
|
held = null;
|
|
7026
7061
|
if (sealed) yield sealed;
|
|
7027
|
-
|
|
7062
|
+
cumulativeUsage = readUsage(ev);
|
|
7063
|
+
usage = cumulativeUsage ? codexUsageDelta(cumulativeUsage, ctx.usageBaseline ?? null) : void 0;
|
|
7028
7064
|
ok = true;
|
|
7029
7065
|
settled = true;
|
|
7030
7066
|
break;
|
|
@@ -7050,6 +7086,15 @@ async function* decodeCodexStream(events, ctx) {
|
|
|
7050
7086
|
if (sealed) yield sealed;
|
|
7051
7087
|
reason = "no_terminal";
|
|
7052
7088
|
}
|
|
7089
|
+
if (ok && cumulativeUsage && threadIdForSession) {
|
|
7090
|
+
const closing = encodeSession3({
|
|
7091
|
+
threadId: threadIdForSession,
|
|
7092
|
+
cwd: ctx.cwd ?? "",
|
|
7093
|
+
promptFingerprint: ctx.promptFingerprint ?? null,
|
|
7094
|
+
usageBaseline: cumulativeUsage
|
|
7095
|
+
});
|
|
7096
|
+
yield { type: "session", state: closing };
|
|
7097
|
+
}
|
|
7053
7098
|
const resolvedConfig = ctx.resolvedReasoningEffort ? { reasoningEffort: ctx.resolvedReasoningEffort } : void 0;
|
|
7054
7099
|
yield {
|
|
7055
7100
|
type: "result",
|
|
@@ -7348,6 +7393,7 @@ function createCodexAdapter(deps = {}) {
|
|
|
7348
7393
|
const decision = decideResume3(req.session, directory);
|
|
7349
7394
|
const resumeThreadId = "resume" in decision ? decision.resume : null;
|
|
7350
7395
|
const threadPromptFingerprint = "resume" in decision ? decision.promptFingerprint : null;
|
|
7396
|
+
const threadUsageBaseline = "resume" in decision ? decision.usageBaseline : null;
|
|
7351
7397
|
if ("fresh" in decision && decision.reason === "cwd_mismatch") {
|
|
7352
7398
|
deps.onWarn?.(
|
|
7353
7399
|
"codex adapter: stored session directory no longer matches the current environment \u2014 starting a fresh thread (SJ527-analogue guard)",
|
|
@@ -7407,6 +7453,7 @@ function createCodexAdapter(deps = {}) {
|
|
|
7407
7453
|
// was actually sent.
|
|
7408
7454
|
promptFingerprint: spec.promptRidesInput ? spec.promptFingerprint : threadPromptFingerprint,
|
|
7409
7455
|
storedState: req.session,
|
|
7456
|
+
usageBaseline: threadUsageBaseline,
|
|
7410
7457
|
// CT601: Codex reports no model in-stream, so record what the thread was
|
|
7411
7458
|
// started with (null on the default token). Same for the reasoning effort.
|
|
7412
7459
|
resolvedModel: spec.model,
|
|
@@ -7497,9 +7544,9 @@ var OP_FAILURE = {
|
|
|
7497
7544
|
message: "files.read returned more than the result ceiling"
|
|
7498
7545
|
}
|
|
7499
7546
|
};
|
|
7500
|
-
var sessionEvent3 = (threadId, cwd = DIR2, degraded = false, promptFingerprint = fingerprintPrompt(PROMPT)) => ({
|
|
7547
|
+
var sessionEvent3 = (threadId, cwd = DIR2, degraded = false, promptFingerprint = fingerprintPrompt(PROMPT), usageBaseline = null) => ({
|
|
7501
7548
|
type: "session",
|
|
7502
|
-
state: encodeSession3({ threadId, cwd, promptFingerprint }),
|
|
7549
|
+
state: encodeSession3({ threadId, cwd, promptFingerprint, usageBaseline }),
|
|
7503
7550
|
...degraded ? { degraded: true } : {}
|
|
7504
7551
|
});
|
|
7505
7552
|
var CODEX_CONFORMANCE_FIXTURES = [
|
|
@@ -7527,6 +7574,16 @@ var CODEX_CONFORMANCE_FIXTURES = [
|
|
|
7527
7574
|
expected: [
|
|
7528
7575
|
sessionEvent3(NEW_THREAD_ID),
|
|
7529
7576
|
{ type: "text", body: "Hello there.", terminal: true },
|
|
7577
|
+
// CT1645: the closing session write — the thread's ending totals, recorded
|
|
7578
|
+
// as the baseline the NEXT turn subtracts. This is a fresh thread, so the
|
|
7579
|
+
// `result` usage below is the frame verbatim (nothing to subtract yet);
|
|
7580
|
+
// what makes it per-turn is this figure being carried into turn two.
|
|
7581
|
+
sessionEvent3(NEW_THREAD_ID, DIR2, false, fingerprintPrompt(PROMPT), {
|
|
7582
|
+
inputTokens: 100,
|
|
7583
|
+
outputTokens: 50,
|
|
7584
|
+
cacheReadTokens: 20,
|
|
7585
|
+
cacheCreationTokens: 5
|
|
7586
|
+
}),
|
|
7530
7587
|
{
|
|
7531
7588
|
type: "result",
|
|
7532
7589
|
ok: true,
|
|
@@ -8252,7 +8309,8 @@ var CODEX_CONFORMANCE_FIXTURES = [
|
|
|
8252
8309
|
session: encodeSession3({
|
|
8253
8310
|
threadId: "th1",
|
|
8254
8311
|
cwd: DIR2,
|
|
8255
|
-
promptFingerprint: fingerprintPrompt(PROMPT)
|
|
8312
|
+
promptFingerprint: fingerprintPrompt(PROMPT),
|
|
8313
|
+
usageBaseline: null
|
|
8256
8314
|
})
|
|
8257
8315
|
}),
|
|
8258
8316
|
nativeStream: [threadStarted("th1"), agentMessage("m1", "Back again."), turnCompleted()],
|
|
@@ -8297,7 +8355,8 @@ var CODEX_CONFORMANCE_FIXTURES = [
|
|
|
8297
8355
|
session: encodeSession3({
|
|
8298
8356
|
threadId: "th1",
|
|
8299
8357
|
cwd: DIR2,
|
|
8300
|
-
promptFingerprint: fingerprintPrompt("an older composed prompt")
|
|
8358
|
+
promptFingerprint: fingerprintPrompt("an older composed prompt"),
|
|
8359
|
+
usageBaseline: null
|
|
8301
8360
|
})
|
|
8302
8361
|
}),
|
|
8303
8362
|
nativeStream: [threadStarted("th1"), agentMessage("m1", "Back again."), turnCompleted()],
|
|
@@ -8322,7 +8381,8 @@ var CODEX_CONFORMANCE_FIXTURES = [
|
|
|
8322
8381
|
session: encodeSession3({
|
|
8323
8382
|
threadId: "old",
|
|
8324
8383
|
cwd: "/env/gone",
|
|
8325
|
-
promptFingerprint: fingerprintPrompt(PROMPT)
|
|
8384
|
+
promptFingerprint: fingerprintPrompt(PROMPT),
|
|
8385
|
+
usageBaseline: null
|
|
8326
8386
|
})
|
|
8327
8387
|
}),
|
|
8328
8388
|
nativeStream: [
|
|
@@ -9073,6 +9133,7 @@ var MANAGER_ENV_KEYS = ["DBUS_SESSION_BUS_ADDRESS", "XDG_RUNTIME_DIR", "PATH"];
|
|
|
9073
9133
|
var managerEnvKey = (env) => MANAGER_ENV_KEYS.map((k) => `${k}=${env[k] ?? ""}`).join("\0");
|
|
9074
9134
|
function createTurnContainment(turnId, deps = {}) {
|
|
9075
9135
|
const probe = deps.capabilityProbe ?? scopeCapabilityUsable;
|
|
9136
|
+
const fallbackGraceMs = deps.fallbackGraceMs ?? FALLBACK_GRACE_MS;
|
|
9076
9137
|
const ownUnit = (deps.ownSystemdUnit ?? readCurrentSystemdUnit)();
|
|
9077
9138
|
const scopeUnits = [];
|
|
9078
9139
|
const groups = [];
|
|
@@ -9194,7 +9255,7 @@ function createTurnContainment(turnId, deps = {}) {
|
|
|
9194
9255
|
} catch {
|
|
9195
9256
|
}
|
|
9196
9257
|
}
|
|
9197
|
-
await sleep3(
|
|
9258
|
+
await sleep3(fallbackGraceMs);
|
|
9198
9259
|
const afterTerm = processGroupMembers(pgid);
|
|
9199
9260
|
if (!afterTerm.ok) {
|
|
9200
9261
|
result.failures.push({
|
|
@@ -9488,6 +9549,7 @@ var DEFAULT_LEASE_RENEWAL_MS = 3e4;
|
|
|
9488
9549
|
function initialOutcome() {
|
|
9489
9550
|
return {
|
|
9490
9551
|
sessionWritten: false,
|
|
9552
|
+
lastSessionStateWritten: null,
|
|
9491
9553
|
sessionDegraded: false,
|
|
9492
9554
|
sessionWriteRejected: false,
|
|
9493
9555
|
okResult: false,
|
|
@@ -10277,8 +10339,9 @@ var TurnExecution = class {
|
|
|
10277
10339
|
if (event.type === "session") {
|
|
10278
10340
|
o.latestSessionState = event.state;
|
|
10279
10341
|
if (event.degraded) o.sessionDegraded = true;
|
|
10280
|
-
if (
|
|
10342
|
+
if (o.lastSessionStateWritten !== event.state) {
|
|
10281
10343
|
o.sessionWritten = true;
|
|
10344
|
+
o.lastSessionStateWritten = event.state;
|
|
10282
10345
|
try {
|
|
10283
10346
|
await this.opts.api.setActiveRun(
|
|
10284
10347
|
workspaceId,
|
package/dist/runtime.js
CHANGED
|
@@ -6260,6 +6260,16 @@ function readUsage(ev) {
|
|
|
6260
6260
|
cacheCreationTokens: num(usage.cache_write_input_tokens)
|
|
6261
6261
|
};
|
|
6262
6262
|
}
|
|
6263
|
+
function codexUsageDelta(cumulative, baseline) {
|
|
6264
|
+
if (!baseline) return cumulative;
|
|
6265
|
+
const sub = (a, b) => Math.max(0, a - b);
|
|
6266
|
+
return {
|
|
6267
|
+
inputTokens: sub(cumulative.inputTokens, baseline.inputTokens),
|
|
6268
|
+
outputTokens: sub(cumulative.outputTokens, baseline.outputTokens),
|
|
6269
|
+
cacheReadTokens: sub(cumulative.cacheReadTokens, baseline.cacheReadTokens),
|
|
6270
|
+
cacheCreationTokens: sub(cumulative.cacheCreationTokens, baseline.cacheCreationTokens)
|
|
6271
|
+
};
|
|
6272
|
+
}
|
|
6263
6273
|
function toStatus(v) {
|
|
6264
6274
|
return v === "completed" || v === "failed" ? v : "in_progress";
|
|
6265
6275
|
}
|
|
@@ -6334,9 +6344,26 @@ function decideResume3(stored, currentCwd) {
|
|
|
6334
6344
|
}
|
|
6335
6345
|
return {
|
|
6336
6346
|
resume: state.threadId,
|
|
6337
|
-
promptFingerprint: typeof state.promptFingerprint === "string" ? state.promptFingerprint : null
|
|
6347
|
+
promptFingerprint: typeof state.promptFingerprint === "string" ? state.promptFingerprint : null,
|
|
6348
|
+
usageBaseline: readUsageBaseline(state.usageBaseline)
|
|
6338
6349
|
};
|
|
6339
6350
|
}
|
|
6351
|
+
function readUsageBaseline(raw) {
|
|
6352
|
+
if (!raw || typeof raw !== "object") return null;
|
|
6353
|
+
const rec = raw;
|
|
6354
|
+
const read = (key) => {
|
|
6355
|
+
const v = rec[key];
|
|
6356
|
+
return typeof v === "number" && Number.isFinite(v) && v >= 0 ? v : null;
|
|
6357
|
+
};
|
|
6358
|
+
const inputTokens = read("inputTokens");
|
|
6359
|
+
const outputTokens = read("outputTokens");
|
|
6360
|
+
const cacheReadTokens = read("cacheReadTokens");
|
|
6361
|
+
const cacheCreationTokens = read("cacheCreationTokens");
|
|
6362
|
+
if (inputTokens === null || outputTokens === null || cacheReadTokens === null || cacheCreationTokens === null) {
|
|
6363
|
+
return null;
|
|
6364
|
+
}
|
|
6365
|
+
return { inputTokens, outputTokens, cacheReadTokens, cacheCreationTokens };
|
|
6366
|
+
}
|
|
6340
6367
|
|
|
6341
6368
|
// packages/agent-runtime/src/codex/loop.ts
|
|
6342
6369
|
async function* decodeCodexStream(events, ctx) {
|
|
@@ -6348,6 +6375,8 @@ async function* decodeCodexStream(events, ctx) {
|
|
|
6348
6375
|
let ok = false;
|
|
6349
6376
|
let reason;
|
|
6350
6377
|
let usage;
|
|
6378
|
+
let cumulativeUsage;
|
|
6379
|
+
let threadIdForSession = ctx.resumedThreadId;
|
|
6351
6380
|
let settled = false;
|
|
6352
6381
|
function* flushInterim() {
|
|
6353
6382
|
const sealed = sealHeld2(held, false);
|
|
@@ -6358,11 +6387,17 @@ async function* decodeCodexStream(events, ctx) {
|
|
|
6358
6387
|
if (ctx.signal.aborted) return;
|
|
6359
6388
|
if (ev.type === "thread.started") {
|
|
6360
6389
|
const threadId = readThreadId(ev);
|
|
6390
|
+
if (threadId) threadIdForSession = threadId;
|
|
6361
6391
|
if (threadId && !sessionEmitted) {
|
|
6362
6392
|
const state = encodeSession3({
|
|
6363
6393
|
threadId,
|
|
6364
6394
|
cwd: ctx.cwd ?? "",
|
|
6365
|
-
promptFingerprint: ctx.promptFingerprint ?? null
|
|
6395
|
+
promptFingerprint: ctx.promptFingerprint ?? null,
|
|
6396
|
+
// CT1645: the baseline this turn INHERITED, carried through unchanged.
|
|
6397
|
+
// This early write exists so a turn that dies mid-stream still leaves
|
|
6398
|
+
// the thread id recorded; it cannot yet know what this turn will spend.
|
|
6399
|
+
// The closing write below records the new baseline.
|
|
6400
|
+
usageBaseline: ctx.usageBaseline ?? null
|
|
6366
6401
|
});
|
|
6367
6402
|
if (threadId !== ctx.resumedThreadId || state !== ctx.storedState) {
|
|
6368
6403
|
sessionEmitted = true;
|
|
@@ -6437,7 +6472,8 @@ async function* decodeCodexStream(events, ctx) {
|
|
|
6437
6472
|
const sealed = sealHeld2(held, true);
|
|
6438
6473
|
held = null;
|
|
6439
6474
|
if (sealed) yield sealed;
|
|
6440
|
-
|
|
6475
|
+
cumulativeUsage = readUsage(ev);
|
|
6476
|
+
usage = cumulativeUsage ? codexUsageDelta(cumulativeUsage, ctx.usageBaseline ?? null) : void 0;
|
|
6441
6477
|
ok = true;
|
|
6442
6478
|
settled = true;
|
|
6443
6479
|
break;
|
|
@@ -6463,6 +6499,15 @@ async function* decodeCodexStream(events, ctx) {
|
|
|
6463
6499
|
if (sealed) yield sealed;
|
|
6464
6500
|
reason = "no_terminal";
|
|
6465
6501
|
}
|
|
6502
|
+
if (ok && cumulativeUsage && threadIdForSession) {
|
|
6503
|
+
const closing = encodeSession3({
|
|
6504
|
+
threadId: threadIdForSession,
|
|
6505
|
+
cwd: ctx.cwd ?? "",
|
|
6506
|
+
promptFingerprint: ctx.promptFingerprint ?? null,
|
|
6507
|
+
usageBaseline: cumulativeUsage
|
|
6508
|
+
});
|
|
6509
|
+
yield { type: "session", state: closing };
|
|
6510
|
+
}
|
|
6466
6511
|
const resolvedConfig = ctx.resolvedReasoningEffort ? { reasoningEffort: ctx.resolvedReasoningEffort } : void 0;
|
|
6467
6512
|
yield {
|
|
6468
6513
|
type: "result",
|
|
@@ -6761,6 +6806,7 @@ function createCodexAdapter(deps = {}) {
|
|
|
6761
6806
|
const decision = decideResume3(req.session, directory);
|
|
6762
6807
|
const resumeThreadId = "resume" in decision ? decision.resume : null;
|
|
6763
6808
|
const threadPromptFingerprint = "resume" in decision ? decision.promptFingerprint : null;
|
|
6809
|
+
const threadUsageBaseline = "resume" in decision ? decision.usageBaseline : null;
|
|
6764
6810
|
if ("fresh" in decision && decision.reason === "cwd_mismatch") {
|
|
6765
6811
|
deps.onWarn?.(
|
|
6766
6812
|
"codex adapter: stored session directory no longer matches the current environment \u2014 starting a fresh thread (SJ527-analogue guard)",
|
|
@@ -6820,6 +6866,7 @@ function createCodexAdapter(deps = {}) {
|
|
|
6820
6866
|
// was actually sent.
|
|
6821
6867
|
promptFingerprint: spec.promptRidesInput ? spec.promptFingerprint : threadPromptFingerprint,
|
|
6822
6868
|
storedState: req.session,
|
|
6869
|
+
usageBaseline: threadUsageBaseline,
|
|
6823
6870
|
// CT601: Codex reports no model in-stream, so record what the thread was
|
|
6824
6871
|
// started with (null on the default token). Same for the reasoning effort.
|
|
6825
6872
|
resolvedModel: spec.model,
|
|
@@ -6910,9 +6957,9 @@ var OP_FAILURE = {
|
|
|
6910
6957
|
message: "files.read returned more than the result ceiling"
|
|
6911
6958
|
}
|
|
6912
6959
|
};
|
|
6913
|
-
var sessionEvent3 = (threadId, cwd = DIR2, degraded = false, promptFingerprint = fingerprintPrompt(PROMPT)) => ({
|
|
6960
|
+
var sessionEvent3 = (threadId, cwd = DIR2, degraded = false, promptFingerprint = fingerprintPrompt(PROMPT), usageBaseline = null) => ({
|
|
6914
6961
|
type: "session",
|
|
6915
|
-
state: encodeSession3({ threadId, cwd, promptFingerprint }),
|
|
6962
|
+
state: encodeSession3({ threadId, cwd, promptFingerprint, usageBaseline }),
|
|
6916
6963
|
...degraded ? { degraded: true } : {}
|
|
6917
6964
|
});
|
|
6918
6965
|
var CODEX_CONFORMANCE_FIXTURES = [
|
|
@@ -6940,6 +6987,16 @@ var CODEX_CONFORMANCE_FIXTURES = [
|
|
|
6940
6987
|
expected: [
|
|
6941
6988
|
sessionEvent3(NEW_THREAD_ID),
|
|
6942
6989
|
{ type: "text", body: "Hello there.", terminal: true },
|
|
6990
|
+
// CT1645: the closing session write — the thread's ending totals, recorded
|
|
6991
|
+
// as the baseline the NEXT turn subtracts. This is a fresh thread, so the
|
|
6992
|
+
// `result` usage below is the frame verbatim (nothing to subtract yet);
|
|
6993
|
+
// what makes it per-turn is this figure being carried into turn two.
|
|
6994
|
+
sessionEvent3(NEW_THREAD_ID, DIR2, false, fingerprintPrompt(PROMPT), {
|
|
6995
|
+
inputTokens: 100,
|
|
6996
|
+
outputTokens: 50,
|
|
6997
|
+
cacheReadTokens: 20,
|
|
6998
|
+
cacheCreationTokens: 5
|
|
6999
|
+
}),
|
|
6943
7000
|
{
|
|
6944
7001
|
type: "result",
|
|
6945
7002
|
ok: true,
|
|
@@ -7665,7 +7722,8 @@ var CODEX_CONFORMANCE_FIXTURES = [
|
|
|
7665
7722
|
session: encodeSession3({
|
|
7666
7723
|
threadId: "th1",
|
|
7667
7724
|
cwd: DIR2,
|
|
7668
|
-
promptFingerprint: fingerprintPrompt(PROMPT)
|
|
7725
|
+
promptFingerprint: fingerprintPrompt(PROMPT),
|
|
7726
|
+
usageBaseline: null
|
|
7669
7727
|
})
|
|
7670
7728
|
}),
|
|
7671
7729
|
nativeStream: [threadStarted("th1"), agentMessage("m1", "Back again."), turnCompleted()],
|
|
@@ -7710,7 +7768,8 @@ var CODEX_CONFORMANCE_FIXTURES = [
|
|
|
7710
7768
|
session: encodeSession3({
|
|
7711
7769
|
threadId: "th1",
|
|
7712
7770
|
cwd: DIR2,
|
|
7713
|
-
promptFingerprint: fingerprintPrompt("an older composed prompt")
|
|
7771
|
+
promptFingerprint: fingerprintPrompt("an older composed prompt"),
|
|
7772
|
+
usageBaseline: null
|
|
7714
7773
|
})
|
|
7715
7774
|
}),
|
|
7716
7775
|
nativeStream: [threadStarted("th1"), agentMessage("m1", "Back again."), turnCompleted()],
|
|
@@ -7735,7 +7794,8 @@ var CODEX_CONFORMANCE_FIXTURES = [
|
|
|
7735
7794
|
session: encodeSession3({
|
|
7736
7795
|
threadId: "old",
|
|
7737
7796
|
cwd: "/env/gone",
|
|
7738
|
-
promptFingerprint: fingerprintPrompt(PROMPT)
|
|
7797
|
+
promptFingerprint: fingerprintPrompt(PROMPT),
|
|
7798
|
+
usageBaseline: null
|
|
7739
7799
|
})
|
|
7740
7800
|
}),
|
|
7741
7801
|
nativeStream: [
|
|
@@ -8496,6 +8556,7 @@ var MANAGER_ENV_KEYS = ["DBUS_SESSION_BUS_ADDRESS", "XDG_RUNTIME_DIR", "PATH"];
|
|
|
8496
8556
|
var managerEnvKey = (env) => MANAGER_ENV_KEYS.map((k) => `${k}=${env[k] ?? ""}`).join("\0");
|
|
8497
8557
|
function createTurnContainment(turnId, deps = {}) {
|
|
8498
8558
|
const probe = deps.capabilityProbe ?? scopeCapabilityUsable;
|
|
8559
|
+
const fallbackGraceMs = deps.fallbackGraceMs ?? FALLBACK_GRACE_MS;
|
|
8499
8560
|
const ownUnit = (deps.ownSystemdUnit ?? readCurrentSystemdUnit)();
|
|
8500
8561
|
const scopeUnits = [];
|
|
8501
8562
|
const groups = [];
|
|
@@ -8617,7 +8678,7 @@ function createTurnContainment(turnId, deps = {}) {
|
|
|
8617
8678
|
} catch {
|
|
8618
8679
|
}
|
|
8619
8680
|
}
|
|
8620
|
-
await sleep2(
|
|
8681
|
+
await sleep2(fallbackGraceMs);
|
|
8621
8682
|
const afterTerm = processGroupMembers(pgid);
|
|
8622
8683
|
if (!afterTerm.ok) {
|
|
8623
8684
|
result.failures.push({
|
|
@@ -8911,6 +8972,7 @@ var DEFAULT_LEASE_RENEWAL_MS = 3e4;
|
|
|
8911
8972
|
function initialOutcome() {
|
|
8912
8973
|
return {
|
|
8913
8974
|
sessionWritten: false,
|
|
8975
|
+
lastSessionStateWritten: null,
|
|
8914
8976
|
sessionDegraded: false,
|
|
8915
8977
|
sessionWriteRejected: false,
|
|
8916
8978
|
okResult: false,
|
|
@@ -9700,8 +9762,9 @@ var TurnExecution = class {
|
|
|
9700
9762
|
if (event.type === "session") {
|
|
9701
9763
|
o.latestSessionState = event.state;
|
|
9702
9764
|
if (event.degraded) o.sessionDegraded = true;
|
|
9703
|
-
if (
|
|
9765
|
+
if (o.lastSessionStateWritten !== event.state) {
|
|
9704
9766
|
o.sessionWritten = true;
|
|
9767
|
+
o.lastSessionStateWritten = event.state;
|
|
9705
9768
|
try {
|
|
9706
9769
|
await this.opts.api.setActiveRun(
|
|
9707
9770
|
workspaceId,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cabane/companion",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.117",
|
|
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",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"prepublishOnly": "pnpm build"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@anthropic-ai/claude-agent-sdk": "0.3.
|
|
33
|
-
"@openai/codex-sdk": "0.
|
|
32
|
+
"@anthropic-ai/claude-agent-sdk": "0.3.280",
|
|
33
|
+
"@openai/codex-sdk": "0.155.1",
|
|
34
34
|
"@hono/node-server": "1.19.14",
|
|
35
35
|
"@inquirer/prompts": "7.10.1",
|
|
36
36
|
"commander": "12.1.0",
|