@cabane/companion 0.6.62 → 0.6.63

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
@@ -7173,16 +7173,32 @@ var WAKE_ME_TOOL_NAME = `mcp__${COMPANION_LOCAL_MCP_SERVER}__${WAKE_ME_TOOL}`;
7173
7173
  var CANCEL_WAKE_TOOL = "cancel_wake";
7174
7174
  var CANCEL_WAKE_TOOL_NAME = `mcp__${COMPANION_LOCAL_MCP_SERVER}__${CANCEL_WAKE_TOOL}`;
7175
7175
  function createReplyState() {
7176
- return { answersMessageId: null };
7176
+ return { answersMessageId: null, order: null };
7177
7177
  }
7178
7178
  function createSendState() {
7179
- return { agentId: null, message: null };
7179
+ return { agentId: null, message: null, order: null };
7180
+ }
7181
+ function createTurnControlOrder() {
7182
+ let calls = 0;
7183
+ return {
7184
+ next: () => {
7185
+ calls += 1;
7186
+ return calls;
7187
+ }
7188
+ };
7180
7189
  }
7181
7190
  function createSkipState() {
7182
7191
  return { skipped: false, reason: null };
7183
7192
  }
7184
7193
  function createAskState() {
7185
- return { targetUserId: null, question: null, headline: null, options: null, questions: null };
7194
+ return {
7195
+ targetUserId: null,
7196
+ question: null,
7197
+ headline: null,
7198
+ options: null,
7199
+ questions: null,
7200
+ order: null
7201
+ };
7186
7202
  }
7187
7203
  function createWakeState() {
7188
7204
  return { afterSeconds: null, at: null, note: null, cancelled: false };
@@ -7212,7 +7228,7 @@ function wakeCommitField(state) {
7212
7228
  }
7213
7229
  };
7214
7230
  }
7215
- function createTurnControlMcpServer(sendState, skipState, askState, subAgentCreate, wakeState, replyState) {
7231
+ function createTurnControlMcpServer(sendState, skipState, askState, subAgentCreate, wakeState, replyState, controlOrder) {
7216
7232
  return createSdkMcpServer({
7217
7233
  name: COMPANION_LOCAL_MCP_SERVER,
7218
7234
  version: "0.0.0",
@@ -7229,6 +7245,7 @@ function createTurnControlMcpServer(sendState, skipState, askState, subAgentCrea
7229
7245
  async (args) => {
7230
7246
  sendState.agentId = args.agentId;
7231
7247
  sendState.message = args.message;
7248
+ sendState.order = controlOrder?.next() ?? null;
7232
7249
  return {
7233
7250
  content: [{ type: "text", text: JSON.stringify({ sent: args.agentId }) }]
7234
7251
  };
@@ -7244,6 +7261,7 @@ function createTurnControlMcpServer(sendState, skipState, askState, subAgentCrea
7244
7261
  },
7245
7262
  async (args) => {
7246
7263
  replyState.answersMessageId = args.messageId;
7264
+ replyState.order = controlOrder?.next() ?? null;
7247
7265
  return {
7248
7266
  content: [
7249
7267
  {
@@ -7326,6 +7344,7 @@ function createTurnControlMcpServer(sendState, skipState, askState, subAgentCrea
7326
7344
  };
7327
7345
  }
7328
7346
  askState.targetUserId = args.targetUserId;
7347
+ askState.order = controlOrder?.next() ?? null;
7329
7348
  if (hasArray) {
7330
7349
  askState.questions = args.questions;
7331
7350
  askState.question = null;
@@ -7889,12 +7908,31 @@ var TurnCommitter = class {
7889
7908
  // a wordless turn has no answer to bind, and the server's mute-settle
7890
7909
  // notice speaks for it.
7891
7910
  turnControlFields(kind) {
7892
- return {
7911
+ const fields = {
7893
7912
  ...this.answersField(kind),
7894
7913
  ...this.sendField(),
7895
7914
  ...this.askField(),
7896
7915
  ...this.wakeField()
7897
7916
  };
7917
+ return { ...fields, ...this.orderField(fields) };
7918
+ }
7919
+ // CT1281: the order the control tools were CALLED, for the addressed rows the
7920
+ // server writes from this one commit. It reports a position only for an intent
7921
+ // that actually made it into the commit — an ask whose payload was incomplete,
7922
+ // or a self-send the committer stripped, contributes no row and so has no place
7923
+ // in the line. An intent with no recorded call (the runtime's auto-declared
7924
+ // reply) is deliberately absent: the server sorts it last, which is what it is.
7925
+ orderField(fields) {
7926
+ const order = {};
7927
+ const replyOrder = this.deps.replyState.order;
7928
+ if (fields.answersMessageId !== void 0 && replyOrder !== null) order.reply = replyOrder;
7929
+ if (fields.dispatch !== void 0 && this.deps.sendState.order !== null) {
7930
+ order.send = this.deps.sendState.order;
7931
+ }
7932
+ if (fields.ask !== void 0 && this.deps.askState.order !== null) {
7933
+ order.ask = this.deps.askState.order;
7934
+ }
7935
+ return Object.keys(order).length > 0 ? { turnControlOrder: order } : {};
7898
7936
  }
7899
7937
  // The declared reply: explicit `reply_to` first, else the runtime's own
7900
7938
  // declaration for the turn that just answers — see
@@ -8353,6 +8391,7 @@ ${reason}`,
8353
8391
  const askState = createAskState();
8354
8392
  const wakeState = createWakeState();
8355
8393
  const replyState = createReplyState();
8394
+ const controlOrder = createTurnControlOrder();
8356
8395
  let spawnedSubAgent = false;
8357
8396
  const subAgentCreate = async (args) => {
8358
8397
  const dispatchTarget = args.agentId ?? payload.agentId;
@@ -8384,7 +8423,8 @@ ${reason}`,
8384
8423
  askState,
8385
8424
  subAgentCreate,
8386
8425
  wakeState,
8387
- replyState
8426
+ replyState,
8427
+ controlOrder
8388
8428
  );
8389
8429
  const request = buildCompanionTurnRequest({
8390
8430
  turnContext,
@@ -8503,11 +8543,12 @@ ${reason}`,
8503
8543
  signal: abortController.signal,
8504
8544
  log: turnLog,
8505
8545
  nextSeq,
8506
- // The committer reads this at commit to attach the addressed send onto the
8507
- // turn's `final` row.
8546
+ // The committer reads this at commit to carry the addressed send on the
8547
+ // terminal row; the server writes the send itself as a distinct message.
8508
8548
  sendState,
8509
- // CT326: likewise the ask payload attached to the `final` row so the
8510
- // server creates the `asks` row atomically with the message it rides on.
8549
+ // CT326: likewise the ask payload. CT1281: the server writes the ask as its
8550
+ // own addressed message to the human which ENQUEUES like any other send
8551
+ // and creates the `asks` row against that carrier, not against turn speech.
8511
8552
  askState,
8512
8553
  // CT442: likewise the wake payload — attached to the `final` row so the
8513
8554
  // server arms the wake schedule atomically with the reply it rode on.
@@ -8532,6 +8573,7 @@ ${reason}`,
8532
8573
  );
8533
8574
  if (intent.ask) {
8534
8575
  askState.targetUserId = intent.ask.targetUserId;
8576
+ askState.order = intent.askOrder ?? null;
8535
8577
  if (intent.ask.questions && intent.ask.questions.length > 0) {
8536
8578
  askState.questions = intent.ask.questions;
8537
8579
  askState.question = null;
@@ -8560,8 +8602,12 @@ ${reason}`,
8560
8602
  if (intent.sendAgentId && intent.sendBody) {
8561
8603
  sendState.agentId = intent.sendAgentId;
8562
8604
  sendState.message = intent.sendBody;
8605
+ sendState.order = intent.sendOrder ?? null;
8606
+ }
8607
+ if (intent.answersMessageId) {
8608
+ replyState.answersMessageId = intent.answersMessageId;
8609
+ replyState.order = intent.replyOrder ?? null;
8563
8610
  }
8564
- if (intent.answersMessageId) replyState.answersMessageId = intent.answersMessageId;
8565
8611
  if (intent.skipped) {
8566
8612
  skipState.skipped = true;
8567
8613
  skipState.reason = intent.skipReason;
package/dist/runtime.js CHANGED
@@ -6672,16 +6672,32 @@ var WAKE_ME_TOOL_NAME = `mcp__${COMPANION_LOCAL_MCP_SERVER}__${WAKE_ME_TOOL}`;
6672
6672
  var CANCEL_WAKE_TOOL = "cancel_wake";
6673
6673
  var CANCEL_WAKE_TOOL_NAME = `mcp__${COMPANION_LOCAL_MCP_SERVER}__${CANCEL_WAKE_TOOL}`;
6674
6674
  function createReplyState() {
6675
- return { answersMessageId: null };
6675
+ return { answersMessageId: null, order: null };
6676
6676
  }
6677
6677
  function createSendState() {
6678
- return { agentId: null, message: null };
6678
+ return { agentId: null, message: null, order: null };
6679
+ }
6680
+ function createTurnControlOrder() {
6681
+ let calls = 0;
6682
+ return {
6683
+ next: () => {
6684
+ calls += 1;
6685
+ return calls;
6686
+ }
6687
+ };
6679
6688
  }
6680
6689
  function createSkipState() {
6681
6690
  return { skipped: false, reason: null };
6682
6691
  }
6683
6692
  function createAskState() {
6684
- return { targetUserId: null, question: null, headline: null, options: null, questions: null };
6693
+ return {
6694
+ targetUserId: null,
6695
+ question: null,
6696
+ headline: null,
6697
+ options: null,
6698
+ questions: null,
6699
+ order: null
6700
+ };
6685
6701
  }
6686
6702
  function createWakeState() {
6687
6703
  return { afterSeconds: null, at: null, note: null, cancelled: false };
@@ -6711,7 +6727,7 @@ function wakeCommitField(state) {
6711
6727
  }
6712
6728
  };
6713
6729
  }
6714
- function createTurnControlMcpServer(sendState, skipState, askState, subAgentCreate, wakeState, replyState) {
6730
+ function createTurnControlMcpServer(sendState, skipState, askState, subAgentCreate, wakeState, replyState, controlOrder) {
6715
6731
  return createSdkMcpServer({
6716
6732
  name: COMPANION_LOCAL_MCP_SERVER,
6717
6733
  version: "0.0.0",
@@ -6728,6 +6744,7 @@ function createTurnControlMcpServer(sendState, skipState, askState, subAgentCrea
6728
6744
  async (args) => {
6729
6745
  sendState.agentId = args.agentId;
6730
6746
  sendState.message = args.message;
6747
+ sendState.order = controlOrder?.next() ?? null;
6731
6748
  return {
6732
6749
  content: [{ type: "text", text: JSON.stringify({ sent: args.agentId }) }]
6733
6750
  };
@@ -6743,6 +6760,7 @@ function createTurnControlMcpServer(sendState, skipState, askState, subAgentCrea
6743
6760
  },
6744
6761
  async (args) => {
6745
6762
  replyState.answersMessageId = args.messageId;
6763
+ replyState.order = controlOrder?.next() ?? null;
6746
6764
  return {
6747
6765
  content: [
6748
6766
  {
@@ -6825,6 +6843,7 @@ function createTurnControlMcpServer(sendState, skipState, askState, subAgentCrea
6825
6843
  };
6826
6844
  }
6827
6845
  askState.targetUserId = args.targetUserId;
6846
+ askState.order = controlOrder?.next() ?? null;
6828
6847
  if (hasArray) {
6829
6848
  askState.questions = args.questions;
6830
6849
  askState.question = null;
@@ -7388,12 +7407,31 @@ var TurnCommitter = class {
7388
7407
  // a wordless turn has no answer to bind, and the server's mute-settle
7389
7408
  // notice speaks for it.
7390
7409
  turnControlFields(kind) {
7391
- return {
7410
+ const fields = {
7392
7411
  ...this.answersField(kind),
7393
7412
  ...this.sendField(),
7394
7413
  ...this.askField(),
7395
7414
  ...this.wakeField()
7396
7415
  };
7416
+ return { ...fields, ...this.orderField(fields) };
7417
+ }
7418
+ // CT1281: the order the control tools were CALLED, for the addressed rows the
7419
+ // server writes from this one commit. It reports a position only for an intent
7420
+ // that actually made it into the commit — an ask whose payload was incomplete,
7421
+ // or a self-send the committer stripped, contributes no row and so has no place
7422
+ // in the line. An intent with no recorded call (the runtime's auto-declared
7423
+ // reply) is deliberately absent: the server sorts it last, which is what it is.
7424
+ orderField(fields) {
7425
+ const order = {};
7426
+ const replyOrder = this.deps.replyState.order;
7427
+ if (fields.answersMessageId !== void 0 && replyOrder !== null) order.reply = replyOrder;
7428
+ if (fields.dispatch !== void 0 && this.deps.sendState.order !== null) {
7429
+ order.send = this.deps.sendState.order;
7430
+ }
7431
+ if (fields.ask !== void 0 && this.deps.askState.order !== null) {
7432
+ order.ask = this.deps.askState.order;
7433
+ }
7434
+ return Object.keys(order).length > 0 ? { turnControlOrder: order } : {};
7397
7435
  }
7398
7436
  // The declared reply: explicit `reply_to` first, else the runtime's own
7399
7437
  // declaration for the turn that just answers — see
@@ -7852,6 +7890,7 @@ ${reason}`,
7852
7890
  const askState = createAskState();
7853
7891
  const wakeState = createWakeState();
7854
7892
  const replyState = createReplyState();
7893
+ const controlOrder = createTurnControlOrder();
7855
7894
  let spawnedSubAgent = false;
7856
7895
  const subAgentCreate = async (args) => {
7857
7896
  const dispatchTarget = args.agentId ?? payload.agentId;
@@ -7883,7 +7922,8 @@ ${reason}`,
7883
7922
  askState,
7884
7923
  subAgentCreate,
7885
7924
  wakeState,
7886
- replyState
7925
+ replyState,
7926
+ controlOrder
7887
7927
  );
7888
7928
  const request = buildCompanionTurnRequest({
7889
7929
  turnContext,
@@ -8002,11 +8042,12 @@ ${reason}`,
8002
8042
  signal: abortController.signal,
8003
8043
  log: turnLog,
8004
8044
  nextSeq,
8005
- // The committer reads this at commit to attach the addressed send onto the
8006
- // turn's `final` row.
8045
+ // The committer reads this at commit to carry the addressed send on the
8046
+ // terminal row; the server writes the send itself as a distinct message.
8007
8047
  sendState,
8008
- // CT326: likewise the ask payload attached to the `final` row so the
8009
- // server creates the `asks` row atomically with the message it rides on.
8048
+ // CT326: likewise the ask payload. CT1281: the server writes the ask as its
8049
+ // own addressed message to the human which ENQUEUES like any other send
8050
+ // and creates the `asks` row against that carrier, not against turn speech.
8010
8051
  askState,
8011
8052
  // CT442: likewise the wake payload — attached to the `final` row so the
8012
8053
  // server arms the wake schedule atomically with the reply it rode on.
@@ -8031,6 +8072,7 @@ ${reason}`,
8031
8072
  );
8032
8073
  if (intent.ask) {
8033
8074
  askState.targetUserId = intent.ask.targetUserId;
8075
+ askState.order = intent.askOrder ?? null;
8034
8076
  if (intent.ask.questions && intent.ask.questions.length > 0) {
8035
8077
  askState.questions = intent.ask.questions;
8036
8078
  askState.question = null;
@@ -8059,8 +8101,12 @@ ${reason}`,
8059
8101
  if (intent.sendAgentId && intent.sendBody) {
8060
8102
  sendState.agentId = intent.sendAgentId;
8061
8103
  sendState.message = intent.sendBody;
8104
+ sendState.order = intent.sendOrder ?? null;
8105
+ }
8106
+ if (intent.answersMessageId) {
8107
+ replyState.answersMessageId = intent.answersMessageId;
8108
+ replyState.order = intent.replyOrder ?? null;
8062
8109
  }
8063
- if (intent.answersMessageId) replyState.answersMessageId = intent.answersMessageId;
8064
8110
  if (intent.skipped) {
8065
8111
  skipState.skipped = true;
8066
8112
  skipState.reason = intent.skipReason;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cabane/companion",
3
- "version": "0.6.62",
3
+ "version": "0.6.63",
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",