@cabane/companion 0.6.64 → 0.6.66
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 +27 -49
- package/dist/runtime.js +27 -49
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2597,15 +2597,16 @@ var CabaneApi = class {
|
|
|
2597
2597
|
// (transport errors + 5xx), never a 4xx, so no `(turnId, kind)` row is
|
|
2598
2598
|
// double-posted. The caller threads its turn abort signal so a cancel
|
|
2599
2599
|
// mid-commit aborts the in-flight POST rather than letting it land.
|
|
2600
|
-
// CT11: `kind`
|
|
2601
|
-
//
|
|
2602
|
-
//
|
|
2603
|
-
//
|
|
2604
|
-
//
|
|
2605
|
-
//
|
|
2606
|
-
//
|
|
2607
|
-
//
|
|
2608
|
-
//
|
|
2600
|
+
// CT11: `kind` includes `'stopped'` for the terminal cancel marker — same
|
|
2601
|
+
// wire shape as `progress`/`final`, distinguished only by `kind` so the chat
|
|
2602
|
+
// drawer's turn-group renderer treats it as a closing row. CT1295: this
|
|
2603
|
+
// companion no longer WRITES that kind — the server does, in the transaction
|
|
2604
|
+
// that terminalizes the stopped turn — so the value survives here only as
|
|
2605
|
+
// wire vocabulary the server also speaks. `seq` is the companion's per-turn
|
|
2606
|
+
// monotonic counter, stamped on the row so the merged timeline orders the
|
|
2607
|
+
// commit deterministically against the persisted tool/thinking rows. Both
|
|
2608
|
+
// fields are optional on the wire — an older companion that didn't mint seq
|
|
2609
|
+
// still validates (the server defaults to 0).
|
|
2609
2610
|
postTurnMessage(workspaceId, conversationId, body, signal) {
|
|
2610
2611
|
return this.durableCommit(
|
|
2611
2612
|
"message",
|
|
@@ -4379,7 +4380,7 @@ var BASE_CLAUDE_CODE_CONFORMANCE_FIXTURES = [
|
|
|
4379
4380
|
{
|
|
4380
4381
|
// HIGHEST-RISK: cancel mid-stream. The abort lands after the tool result;
|
|
4381
4382
|
// the adapter stops before the closing reply — no final text, no `result`
|
|
4382
|
-
// event.
|
|
4383
|
+
// event. CT1295: the server writes the `kind:'stopped'` marker.
|
|
4383
4384
|
name: "cancel mid-stream",
|
|
4384
4385
|
request: makeRequest(),
|
|
4385
4386
|
nativeStream: [
|
|
@@ -5500,7 +5501,7 @@ var OPENCODE_CONFORMANCE_FIXTURES = [
|
|
|
5500
5501
|
{
|
|
5501
5502
|
// HIGHEST-RISK: cancel mid-stream. The abort lands after the tool result; the
|
|
5502
5503
|
// adapter stops before the closing reply — no final text, no `result` event.
|
|
5503
|
-
//
|
|
5504
|
+
// CT1295: the server writes the `kind:'stopped'` marker.
|
|
5504
5505
|
name: "cancel mid-stream",
|
|
5505
5506
|
request: makeRequest2(),
|
|
5506
5507
|
nativeStream: [
|
|
@@ -6792,7 +6793,7 @@ var CODEX_CONFORMANCE_FIXTURES = [
|
|
|
6792
6793
|
{
|
|
6793
6794
|
// HIGHEST-RISK: cancel mid-stream. The abort lands after the tool result; the
|
|
6794
6795
|
// adapter stops before the closing reply — no final text, no `result` event.
|
|
6795
|
-
//
|
|
6796
|
+
// CT1295: the server writes the `kind:'stopped'` marker.
|
|
6796
6797
|
name: "cancel mid-stream",
|
|
6797
6798
|
request: makeRequest3(),
|
|
6798
6799
|
nativeStream: [
|
|
@@ -7253,14 +7254,7 @@ function createSkipState() {
|
|
|
7253
7254
|
return { skipped: false, reason: null };
|
|
7254
7255
|
}
|
|
7255
7256
|
function createAskState() {
|
|
7256
|
-
return {
|
|
7257
|
-
targetUserId: null,
|
|
7258
|
-
question: null,
|
|
7259
|
-
headline: null,
|
|
7260
|
-
options: null,
|
|
7261
|
-
questions: null,
|
|
7262
|
-
order: null
|
|
7263
|
-
};
|
|
7257
|
+
return { targetUserId: null, question: null, headline: null, options: null, questions: null };
|
|
7264
7258
|
}
|
|
7265
7259
|
function createWakeState() {
|
|
7266
7260
|
return { afterSeconds: null, at: null, note: null, cancelled: false };
|
|
@@ -7406,7 +7400,6 @@ function createTurnControlMcpServer(sendState, skipState, askState, subAgentCrea
|
|
|
7406
7400
|
};
|
|
7407
7401
|
}
|
|
7408
7402
|
askState.targetUserId = args.targetUserId;
|
|
7409
|
-
askState.order = controlOrder?.next() ?? null;
|
|
7410
7403
|
if (hasArray) {
|
|
7411
7404
|
askState.questions = args.questions;
|
|
7412
7405
|
askState.question = null;
|
|
@@ -7948,8 +7941,10 @@ var TurnCommitter = class {
|
|
|
7948
7941
|
// End-of-turn progress promotion. The held-text flush is now the adapter's
|
|
7949
7942
|
// job (it emits the closing reply as a `text` event before `result`), so this
|
|
7950
7943
|
// only asks the pump to promote agent-authored interim text. A wordless turn
|
|
7951
|
-
// stays wordless and the dispatcher closes it with a
|
|
7952
|
-
//
|
|
7944
|
+
// stays wordless and the dispatcher closes it with a `silent`/`skipped`
|
|
7945
|
+
// marker (CT1295: a CANCELLED turn is closed by the SERVER's `stopped`
|
|
7946
|
+
// marker, not from this side). Guards on the abort signal, so on cancel no
|
|
7947
|
+
// `final` is forced.
|
|
7953
7948
|
async finalize(okResult) {
|
|
7954
7949
|
await this.pump.finalize(okResult);
|
|
7955
7950
|
}
|
|
@@ -7980,10 +7975,15 @@ var TurnCommitter = class {
|
|
|
7980
7975
|
}
|
|
7981
7976
|
// CT1281: the order the control tools were CALLED, for the addressed rows the
|
|
7982
7977
|
// server writes from this one commit. It reports a position only for an intent
|
|
7983
|
-
// that actually made it into the commit —
|
|
7984
|
-
//
|
|
7985
|
-
//
|
|
7986
|
-
//
|
|
7978
|
+
// that actually made it into the commit — a self-send the committer stripped
|
|
7979
|
+
// contributes no row and so has no place in the line. An intent with no
|
|
7980
|
+
// recorded call (the runtime's auto-declared reply) is deliberately absent, and
|
|
7981
|
+
// the server sorts it after every recorded one — it binds the turn's closing
|
|
7982
|
+
// words.
|
|
7983
|
+
//
|
|
7984
|
+
// The ask is absent by design, not by omission: its carrier queues last among
|
|
7985
|
+
// the turn's rows however early the tool fired, so there is no position to
|
|
7986
|
+
// report.
|
|
7987
7987
|
orderField(fields) {
|
|
7988
7988
|
const order = {};
|
|
7989
7989
|
const replyOrder = this.deps.replyState.order;
|
|
@@ -7991,9 +7991,6 @@ var TurnCommitter = class {
|
|
|
7991
7991
|
if (fields.dispatch !== void 0 && this.deps.sendState.order !== null) {
|
|
7992
7992
|
order.send = this.deps.sendState.order;
|
|
7993
7993
|
}
|
|
7994
|
-
if (fields.ask !== void 0 && this.deps.askState.order !== null) {
|
|
7995
|
-
order.ask = this.deps.askState.order;
|
|
7996
|
-
}
|
|
7997
7994
|
return Object.keys(order).length > 0 ? { turnControlOrder: order } : {};
|
|
7998
7995
|
}
|
|
7999
7996
|
// The declared reply: explicit `reply_to` first, else the runtime's own
|
|
@@ -8067,7 +8064,6 @@ var TurnCommitter = class {
|
|
|
8067
8064
|
var PREPARING_TOOL_NAME = "preparing";
|
|
8068
8065
|
var PREPARE_FAILED_PREFIX = "**Couldn't prepare your environment.** I wasn't able to provision a working directory for this conversation, so I can't run this turn. The provisioning command reported:";
|
|
8069
8066
|
var MISSING_SECRET_PREFIX = "**Missing secret on this companion.** This agent's tools need a credential this device hasn't been given, so I can't run this turn safely. Declare it in this companion\u2019s secret store (`~/.cabane/secrets.json`) and try again. Missing:";
|
|
8070
|
-
var STOPPED_MARKER_BODY = "(stopped)";
|
|
8071
8067
|
var RUNTIME_UNAVAILABLE_PREFIX = "**This agent's runtime isn't available on this companion.** The model this agent uses needs a runtime this device isn't running, so I can't run this turn here. Details:";
|
|
8072
8068
|
var UNEXPECTED_ROLE_REASON = `refused the wake trigger (role "system" isn't dispatchable on this companion) \u2014 the companion is likely running outdated code; refresh it, then re-address the agent`;
|
|
8073
8069
|
var SKIPPED_MARKER_BODY = "(skipped)";
|
|
@@ -8685,7 +8681,6 @@ ${reason}`,
|
|
|
8685
8681
|
);
|
|
8686
8682
|
if (intent.ask) {
|
|
8687
8683
|
askState.targetUserId = intent.ask.targetUserId;
|
|
8688
|
-
askState.order = intent.askOrder ?? null;
|
|
8689
8684
|
if (intent.ask.questions && intent.ask.questions.length > 0) {
|
|
8690
8685
|
askState.questions = intent.ask.questions;
|
|
8691
8686
|
askState.question = null;
|
|
@@ -8900,23 +8895,6 @@ ${reason}`,
|
|
|
8900
8895
|
}
|
|
8901
8896
|
}
|
|
8902
8897
|
}
|
|
8903
|
-
if (userCancelled) {
|
|
8904
|
-
try {
|
|
8905
|
-
await this.opts.api.postTurnMessage(workspaceId, payload.conversationId, {
|
|
8906
|
-
body: STOPPED_MARKER_BODY,
|
|
8907
|
-
kind: "stopped",
|
|
8908
|
-
turnId,
|
|
8909
|
-
seq: nextSeq(),
|
|
8910
|
-
// CT113: the stopped marker is still "about" the triggering message.
|
|
8911
|
-
parentMessageId: payload.messageId
|
|
8912
|
-
});
|
|
8913
|
-
} catch (err) {
|
|
8914
|
-
turnLog.warn(
|
|
8915
|
-
{ err: err instanceof Error ? err.message : String(err) },
|
|
8916
|
-
"dispatcher: stopped-marker commit failed"
|
|
8917
|
-
);
|
|
8918
|
-
}
|
|
8919
|
-
}
|
|
8920
8898
|
const body = {
|
|
8921
8899
|
activeRunStartedAt: null,
|
|
8922
8900
|
// CT277: the server keys the turn-end metadata UPDATE (ended_at + tokens)
|
package/dist/runtime.js
CHANGED
|
@@ -2017,15 +2017,16 @@ var CabaneApi = class {
|
|
|
2017
2017
|
// (transport errors + 5xx), never a 4xx, so no `(turnId, kind)` row is
|
|
2018
2018
|
// double-posted. The caller threads its turn abort signal so a cancel
|
|
2019
2019
|
// mid-commit aborts the in-flight POST rather than letting it land.
|
|
2020
|
-
// CT11: `kind`
|
|
2021
|
-
//
|
|
2022
|
-
//
|
|
2023
|
-
//
|
|
2024
|
-
//
|
|
2025
|
-
//
|
|
2026
|
-
//
|
|
2027
|
-
//
|
|
2028
|
-
//
|
|
2020
|
+
// CT11: `kind` includes `'stopped'` for the terminal cancel marker — same
|
|
2021
|
+
// wire shape as `progress`/`final`, distinguished only by `kind` so the chat
|
|
2022
|
+
// drawer's turn-group renderer treats it as a closing row. CT1295: this
|
|
2023
|
+
// companion no longer WRITES that kind — the server does, in the transaction
|
|
2024
|
+
// that terminalizes the stopped turn — so the value survives here only as
|
|
2025
|
+
// wire vocabulary the server also speaks. `seq` is the companion's per-turn
|
|
2026
|
+
// monotonic counter, stamped on the row so the merged timeline orders the
|
|
2027
|
+
// commit deterministically against the persisted tool/thinking rows. Both
|
|
2028
|
+
// fields are optional on the wire — an older companion that didn't mint seq
|
|
2029
|
+
// still validates (the server defaults to 0).
|
|
2029
2030
|
postTurnMessage(workspaceId, conversationId, body, signal) {
|
|
2030
2031
|
return this.durableCommit(
|
|
2031
2032
|
"message",
|
|
@@ -3878,7 +3879,7 @@ var BASE_CLAUDE_CODE_CONFORMANCE_FIXTURES = [
|
|
|
3878
3879
|
{
|
|
3879
3880
|
// HIGHEST-RISK: cancel mid-stream. The abort lands after the tool result;
|
|
3880
3881
|
// the adapter stops before the closing reply — no final text, no `result`
|
|
3881
|
-
// event.
|
|
3882
|
+
// event. CT1295: the server writes the `kind:'stopped'` marker.
|
|
3882
3883
|
name: "cancel mid-stream",
|
|
3883
3884
|
request: makeRequest(),
|
|
3884
3885
|
nativeStream: [
|
|
@@ -4999,7 +5000,7 @@ var OPENCODE_CONFORMANCE_FIXTURES = [
|
|
|
4999
5000
|
{
|
|
5000
5001
|
// HIGHEST-RISK: cancel mid-stream. The abort lands after the tool result; the
|
|
5001
5002
|
// adapter stops before the closing reply — no final text, no `result` event.
|
|
5002
|
-
//
|
|
5003
|
+
// CT1295: the server writes the `kind:'stopped'` marker.
|
|
5003
5004
|
name: "cancel mid-stream",
|
|
5004
5005
|
request: makeRequest2(),
|
|
5005
5006
|
nativeStream: [
|
|
@@ -6291,7 +6292,7 @@ var CODEX_CONFORMANCE_FIXTURES = [
|
|
|
6291
6292
|
{
|
|
6292
6293
|
// HIGHEST-RISK: cancel mid-stream. The abort lands after the tool result; the
|
|
6293
6294
|
// adapter stops before the closing reply — no final text, no `result` event.
|
|
6294
|
-
//
|
|
6295
|
+
// CT1295: the server writes the `kind:'stopped'` marker.
|
|
6295
6296
|
name: "cancel mid-stream",
|
|
6296
6297
|
request: makeRequest3(),
|
|
6297
6298
|
nativeStream: [
|
|
@@ -6752,14 +6753,7 @@ function createSkipState() {
|
|
|
6752
6753
|
return { skipped: false, reason: null };
|
|
6753
6754
|
}
|
|
6754
6755
|
function createAskState() {
|
|
6755
|
-
return {
|
|
6756
|
-
targetUserId: null,
|
|
6757
|
-
question: null,
|
|
6758
|
-
headline: null,
|
|
6759
|
-
options: null,
|
|
6760
|
-
questions: null,
|
|
6761
|
-
order: null
|
|
6762
|
-
};
|
|
6756
|
+
return { targetUserId: null, question: null, headline: null, options: null, questions: null };
|
|
6763
6757
|
}
|
|
6764
6758
|
function createWakeState() {
|
|
6765
6759
|
return { afterSeconds: null, at: null, note: null, cancelled: false };
|
|
@@ -6905,7 +6899,6 @@ function createTurnControlMcpServer(sendState, skipState, askState, subAgentCrea
|
|
|
6905
6899
|
};
|
|
6906
6900
|
}
|
|
6907
6901
|
askState.targetUserId = args.targetUserId;
|
|
6908
|
-
askState.order = controlOrder?.next() ?? null;
|
|
6909
6902
|
if (hasArray) {
|
|
6910
6903
|
askState.questions = args.questions;
|
|
6911
6904
|
askState.question = null;
|
|
@@ -7447,8 +7440,10 @@ var TurnCommitter = class {
|
|
|
7447
7440
|
// End-of-turn progress promotion. The held-text flush is now the adapter's
|
|
7448
7441
|
// job (it emits the closing reply as a `text` event before `result`), so this
|
|
7449
7442
|
// only asks the pump to promote agent-authored interim text. A wordless turn
|
|
7450
|
-
// stays wordless and the dispatcher closes it with a
|
|
7451
|
-
//
|
|
7443
|
+
// stays wordless and the dispatcher closes it with a `silent`/`skipped`
|
|
7444
|
+
// marker (CT1295: a CANCELLED turn is closed by the SERVER's `stopped`
|
|
7445
|
+
// marker, not from this side). Guards on the abort signal, so on cancel no
|
|
7446
|
+
// `final` is forced.
|
|
7452
7447
|
async finalize(okResult) {
|
|
7453
7448
|
await this.pump.finalize(okResult);
|
|
7454
7449
|
}
|
|
@@ -7479,10 +7474,15 @@ var TurnCommitter = class {
|
|
|
7479
7474
|
}
|
|
7480
7475
|
// CT1281: the order the control tools were CALLED, for the addressed rows the
|
|
7481
7476
|
// server writes from this one commit. It reports a position only for an intent
|
|
7482
|
-
// that actually made it into the commit —
|
|
7483
|
-
//
|
|
7484
|
-
//
|
|
7485
|
-
//
|
|
7477
|
+
// that actually made it into the commit — a self-send the committer stripped
|
|
7478
|
+
// contributes no row and so has no place in the line. An intent with no
|
|
7479
|
+
// recorded call (the runtime's auto-declared reply) is deliberately absent, and
|
|
7480
|
+
// the server sorts it after every recorded one — it binds the turn's closing
|
|
7481
|
+
// words.
|
|
7482
|
+
//
|
|
7483
|
+
// The ask is absent by design, not by omission: its carrier queues last among
|
|
7484
|
+
// the turn's rows however early the tool fired, so there is no position to
|
|
7485
|
+
// report.
|
|
7486
7486
|
orderField(fields) {
|
|
7487
7487
|
const order = {};
|
|
7488
7488
|
const replyOrder = this.deps.replyState.order;
|
|
@@ -7490,9 +7490,6 @@ var TurnCommitter = class {
|
|
|
7490
7490
|
if (fields.dispatch !== void 0 && this.deps.sendState.order !== null) {
|
|
7491
7491
|
order.send = this.deps.sendState.order;
|
|
7492
7492
|
}
|
|
7493
|
-
if (fields.ask !== void 0 && this.deps.askState.order !== null) {
|
|
7494
|
-
order.ask = this.deps.askState.order;
|
|
7495
|
-
}
|
|
7496
7493
|
return Object.keys(order).length > 0 ? { turnControlOrder: order } : {};
|
|
7497
7494
|
}
|
|
7498
7495
|
// The declared reply: explicit `reply_to` first, else the runtime's own
|
|
@@ -7566,7 +7563,6 @@ var TurnCommitter = class {
|
|
|
7566
7563
|
var PREPARING_TOOL_NAME = "preparing";
|
|
7567
7564
|
var PREPARE_FAILED_PREFIX = "**Couldn't prepare your environment.** I wasn't able to provision a working directory for this conversation, so I can't run this turn. The provisioning command reported:";
|
|
7568
7565
|
var MISSING_SECRET_PREFIX = "**Missing secret on this companion.** This agent's tools need a credential this device hasn't been given, so I can't run this turn safely. Declare it in this companion\u2019s secret store (`~/.cabane/secrets.json`) and try again. Missing:";
|
|
7569
|
-
var STOPPED_MARKER_BODY = "(stopped)";
|
|
7570
7566
|
var RUNTIME_UNAVAILABLE_PREFIX = "**This agent's runtime isn't available on this companion.** The model this agent uses needs a runtime this device isn't running, so I can't run this turn here. Details:";
|
|
7571
7567
|
var UNEXPECTED_ROLE_REASON = `refused the wake trigger (role "system" isn't dispatchable on this companion) \u2014 the companion is likely running outdated code; refresh it, then re-address the agent`;
|
|
7572
7568
|
var SKIPPED_MARKER_BODY = "(skipped)";
|
|
@@ -8184,7 +8180,6 @@ ${reason}`,
|
|
|
8184
8180
|
);
|
|
8185
8181
|
if (intent.ask) {
|
|
8186
8182
|
askState.targetUserId = intent.ask.targetUserId;
|
|
8187
|
-
askState.order = intent.askOrder ?? null;
|
|
8188
8183
|
if (intent.ask.questions && intent.ask.questions.length > 0) {
|
|
8189
8184
|
askState.questions = intent.ask.questions;
|
|
8190
8185
|
askState.question = null;
|
|
@@ -8399,23 +8394,6 @@ ${reason}`,
|
|
|
8399
8394
|
}
|
|
8400
8395
|
}
|
|
8401
8396
|
}
|
|
8402
|
-
if (userCancelled) {
|
|
8403
|
-
try {
|
|
8404
|
-
await this.opts.api.postTurnMessage(workspaceId, payload.conversationId, {
|
|
8405
|
-
body: STOPPED_MARKER_BODY,
|
|
8406
|
-
kind: "stopped",
|
|
8407
|
-
turnId,
|
|
8408
|
-
seq: nextSeq(),
|
|
8409
|
-
// CT113: the stopped marker is still "about" the triggering message.
|
|
8410
|
-
parentMessageId: payload.messageId
|
|
8411
|
-
});
|
|
8412
|
-
} catch (err) {
|
|
8413
|
-
turnLog.warn(
|
|
8414
|
-
{ err: err instanceof Error ? err.message : String(err) },
|
|
8415
|
-
"dispatcher: stopped-marker commit failed"
|
|
8416
|
-
);
|
|
8417
|
-
}
|
|
8418
|
-
}
|
|
8419
8397
|
const body = {
|
|
8420
8398
|
activeRunStartedAt: null,
|
|
8421
8399
|
// CT277: the server keys the turn-end metadata UPDATE (ended_at + tokens)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cabane/companion",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.66",
|
|
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",
|