@cabane/companion 0.6.225 → 0.6.227

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
@@ -2572,7 +2572,7 @@ var init_transcript_sink = __esm({
2572
2572
  });
2573
2573
 
2574
2574
  // packages/agent-runtime/src/turn-control/descriptions.ts
2575
- var MAX_ASK_QUESTION_BYTES, MAX_ASK_HEADLINE_BYTES, MAX_ASK_ITEMS, EXCHANGE_KINDS, APPROVAL_OPTIONS, REQUEST_OPTIONS, EXCHANGE_EXPECTS, MAX_EXCHANGE_FILES, MAX_REQUEST_BODY_BYTES, MAX_ASK_OPTION_BYTES, ASK_OPTION_NOT_A_STRING, MIN_ASK_OPTIONS, MAX_ASK_OPTIONS, ASK_TARGET_PATTERN, ASK_TARGET_INVALID, MAX_WAKE_NOTE_BYTES, MAX_WITHDRAW_REASON_BYTES, MAX_SKIP_REASON_BYTES, TURN_CONTROL_MCP_SERVER, TURN_CONTROL_TOOLS, TURN_CONTROL_TOOL_DESCRIPTIONS, TURN_CONTROL_FIELD_DESCRIPTIONS;
2575
+ var MAX_ASK_QUESTION_BYTES, MAX_ASK_HEADLINE_BYTES, MAX_ASK_ITEMS, EXCHANGE_KINDS, APPROVAL_OPTIONS, MAX_EXCHANGE_ACTION_BYTES, REQUEST_OPTIONS, EXCHANGE_EXPECTS, MAX_EXCHANGE_FILES, MAX_REQUEST_BODY_BYTES, MAX_ASK_OPTION_BYTES, ASK_OPTION_NOT_A_STRING, MIN_ASK_OPTIONS, MAX_ASK_OPTIONS, ASK_TARGET_PATTERN, ASK_TARGET_INVALID, MAX_WAKE_NOTE_BYTES, MAX_WITHDRAW_REASON_BYTES, MAX_SKIP_REASON_BYTES, TURN_CONTROL_MCP_SERVER, TURN_CONTROL_TOOLS, TURN_CONTROL_TOOL_DESCRIPTIONS, TURN_CONTROL_FIELD_DESCRIPTIONS;
2576
2576
  var init_descriptions = __esm({
2577
2577
  "packages/agent-runtime/src/turn-control/descriptions.ts"() {
2578
2578
  "use strict";
@@ -2581,6 +2581,7 @@ var init_descriptions = __esm({
2581
2581
  MAX_ASK_ITEMS = 20;
2582
2582
  EXCHANGE_KINDS = ["question", "approval", "request"];
2583
2583
  APPROVAL_OPTIONS = ["Yes", "No"];
2584
+ MAX_EXCHANGE_ACTION_BYTES = 32;
2584
2585
  REQUEST_OPTIONS = ["Done"];
2585
2586
  EXCHANGE_EXPECTS = ["confirmation", "result"];
2586
2587
  MAX_EXCHANGE_FILES = 5;
@@ -2605,8 +2606,8 @@ var init_descriptions = __esm({
2605
2606
  ];
2606
2607
  TURN_CONTROL_TOOL_DESCRIPTIONS = {
2607
2608
  answer: `Call this just before you write your answer: the text you write next is what the conversation keeps as your message. Call it once.`,
2608
- open_exchange: `Put something in front of one person that comes back with a recorded outcome, then end your turn; don't wait for it. Not for delivering finished work, and never for acknowledgement or feedback on it; the reply delivers. Open one only when the work can't continue without the answer. \`targetUserId\` is a person on your roster, by their \`@handle\`; to bring in an agent, name them with \`@handle\` in your reply.
2609
- - A question is one item (\`headline\`, optional \`question\` body, \`options\`) or \`questions\`, 1\u2013${MAX_ASK_ITEMS} items; never both. An approval or request is \`headline\` and an optional \`question\` body only. An approval is answered ${APPROVAL_OPTIONS.join(" / ")}; a request ${REQUEST_OPTIONS.join("")}, or the typed result when \`expects\` is \`result\`, or a note saying the person couldn't. A request's body carries the steps and may hold a list and code blocks; every other body is a sentence or two of framing, inline Markdown only.
2609
+ open_exchange: `Put something in front of one person that comes back with a recorded outcome, then end your turn; don't wait for it. Not for delivering finished work, and never for acknowledgement or feedback on it; the reply delivers. Open one only when the work can't continue without the answer. \`targetUserId\` is a person; to bring in an agent, name them with \`@handle\` in your reply.
2610
+ - A question is one item (\`headline\`, optional \`question\` body, \`options\`) or \`questions\`, 1\u2013${MAX_ASK_ITEMS} items; never both. An approval or request is \`headline\` and an optional \`question\` body only. An approval is answered by its \`go\` or \`hold\` word, ${APPROVAL_OPTIONS.join(" / ")} without them; a request ${REQUEST_OPTIONS.join("")}, or the typed result when \`expects\` is \`result\`, or a note saying the person couldn't. A request's body carries the steps and may hold a list and code blocks; every other body is a sentence or two of framing, inline Markdown only.
2610
2611
  - Decisions that arise together go in ONE call, in the order you want them answered. A second call is a separate exchange, never an edit.
2611
2612
  - Voice, in headline, body and options: "I" for yourself, never your own name; name everyone else who decides or acts, as on your roster. Never "you", "your", "we", "us", "our" or their contractions, nor "he", "she" or "they" for a named actor. A quotation stays accurate: say who said it.
2612
2613
  - It must stand alone, since it can arrive first: the reply carries the findings, the exchange the question; don't repeat the reply in it.
@@ -2622,7 +2623,9 @@ var init_descriptions = __esm({
2622
2623
  answer: {},
2623
2624
  open_exchange: {
2624
2625
  targetUserId: "The person: their `@handle` from your turn context's roster (preferred), or their user id.",
2625
- kind: `What the exchange is for; default \`question\`. \`question\`: the person picks among courses of action or types an answer. \`approval\`: a yes/no on one proposed action \u2014 the person answers ${APPROVAL_OPTIONS.join(" or ")}. \`request\`: something only the person can do \u2014 they answer ${REQUEST_OPTIONS.join("")}, or type the result when \`expects\` is \`result\`, or send a note saying they couldn't.`,
2626
+ kind: `What the exchange is for; default \`question\`. \`question\`: the person picks among courses of action or types an answer. \`approval\`: a yes/no on one proposed action \u2014 the person answers with its \`go\` or \`hold\` word, ${APPROVAL_OPTIONS.join(" or ")} when none is given. \`request\`: something only the person can do \u2014 they answer ${REQUEST_OPTIONS.join("")}, or type the result when \`expects\` is \`result\`, or send a note saying they couldn't.`,
2627
+ go: `An approval only: the go answer as the action itself, a short verb phrase ("Merge", "Send them", "Archive it"; not "Yes, merge it"), about 24 characters and at most ${MAX_EXCHANGE_ACTION_BYTES}. Given with \`hold\`, or neither: without them the person answers ${APPROVAL_OPTIONS.join(" or ")}.`,
2628
+ hold: `An approval only: the hold answer in the same voice ("Hold off", "Not yet", "Keep it"), at most ${MAX_EXCHANGE_ACTION_BYTES} characters and different from \`go\`. Given with \`go\`.`,
2626
2629
  expects: "A request only: `confirmation` (default) when you only need to hear it's done, `result` when you need something back. Either way the person may send only a note saying they couldn't. Refused on a question or approval.",
2627
2630
  question: `The body beneath the headline \u2014 for a question or approval one or two sentences of framing, NOT a report (up to ${MAX_ASK_QUESTION_BYTES} characters, inline markdown only); for a request the steps, with lists and code blocks allowed (up to ${MAX_REQUEST_BODY_BYTES} characters). With \`questions\`, leave it out.`,
2628
2631
  headline: `ONE clear, capitalized sentence, up to ${MAX_ASK_HEADLINE_BYTES} characters: for a question or approval, the question ending in \`?\` ("Should Ledger deploy once Mia approves?"); for a request, what to do ("Run these and send me the output"). What the person reads first in For you. Required for an approval or request.`,
@@ -6252,6 +6255,8 @@ function createTurnControlMcpServer(acts, skipState) {
6252
6255
  ).min(MIN_ASK_OPTIONS).max(MAX_ASK_OPTIONS).optional().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.open_exchange["questions.options"])
6253
6256
  })
6254
6257
  ).min(1).max(MAX_ASK_ITEMS).optional().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.open_exchange.questions),
6258
+ go: z15.string().min(1).max(MAX_EXCHANGE_ACTION_BYTES).optional().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.open_exchange.go),
6259
+ hold: z15.string().min(1).max(MAX_EXCHANGE_ACTION_BYTES).optional().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.open_exchange.hold),
6255
6260
  files: z15.array(z15.string().min(1).max(1024)).optional().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.open_exchange.files),
6256
6261
  replaces: z15.object({
6257
6262
  askId: z15.string().uuid().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.open_exchange["replaces.askId"]),
@@ -6275,6 +6280,11 @@ function createTurnControlMcpServer(acts, skipState) {
6275
6280
  ...args.question ? { question: args.question } : {},
6276
6281
  ...args.options ? { options: args.options } : {},
6277
6282
  ...args.questions ? { questions: args.questions } : {},
6283
+ // Forwarded whole, so the server's rule (both or neither, an
6284
+ // approval's only) refuses them by name rather than one half
6285
+ // being dropped here unseen.
6286
+ ...args.go !== void 0 ? { go: args.go } : {},
6287
+ ...args.hold !== void 0 ? { hold: args.hold } : {},
6278
6288
  ...args.files ? { files: args.files } : {}
6279
6289
  }
6280
6290
  });
@@ -10566,14 +10576,15 @@ import { hostname as hostname2 } from "os";
10566
10576
  // src/log-copy.ts
10567
10577
  init_failure();
10568
10578
  init_bundled_binaries();
10579
+ var RESTART = "then `cabane stop` and `cabane start` to restart the companion";
10569
10580
  function turnFailureCopy(reason, runtime) {
10570
10581
  const failure = decodeFailureReason(reason);
10571
10582
  if (failure?.kind === "auth_expired") {
10572
10583
  if (runtime === "claude-code")
10573
- return "Claude Code sign-in has expired on this device. Open Claude Code, run /login, then reply in Cabane to try again.";
10584
+ return `Claude Code is signed out on this device. To sign back in, run \`claude auth login\`, ${RESTART}. Then reply in Cabane to try again.`;
10574
10585
  if (runtime === "codex")
10575
- return "Codex sign-in has expired on this device. Run codex login, then reply in Cabane to try again.";
10576
- return "Sign-in has expired on this device. Sign in to the agent, then reply in Cabane to try again.";
10586
+ return `Codex is signed out on this device. To sign back in, run \`codex login\`, ${RESTART}. Then reply in Cabane to try again.`;
10587
+ return `The agent is signed out on this device. Sign in to their harness, ${RESTART}. Then reply in Cabane to try again.`;
10577
10588
  }
10578
10589
  if (failure?.kind === "usage_capped")
10579
10590
  return failure.resetsAt ? `The usage limit is reached; it resets around ${new Date(failure.resetsAt).toLocaleTimeString()}. Reply in Cabane after it resets.` : "The usage limit is reached. Try again later in Cabane.";
package/dist/runtime.js CHANGED
@@ -1501,14 +1501,15 @@ var RATE_PATTERNS = [/rate[_ ]?limit/, /\b429\b/, /too many requests/];
1501
1501
  var BARE_LIMIT = /\blimit (reached|exceeded)\b/;
1502
1502
 
1503
1503
  // src/log-copy.ts
1504
+ var RESTART = "then `cabane stop` and `cabane start` to restart the companion";
1504
1505
  function turnFailureCopy(reason, runtime) {
1505
1506
  const failure = decodeFailureReason(reason);
1506
1507
  if (failure?.kind === "auth_expired") {
1507
1508
  if (runtime === "claude-code")
1508
- return "Claude Code sign-in has expired on this device. Open Claude Code, run /login, then reply in Cabane to try again.";
1509
+ return `Claude Code is signed out on this device. To sign back in, run \`claude auth login\`, ${RESTART}. Then reply in Cabane to try again.`;
1509
1510
  if (runtime === "codex")
1510
- return "Codex sign-in has expired on this device. Run codex login, then reply in Cabane to try again.";
1511
- return "Sign-in has expired on this device. Sign in to the agent, then reply in Cabane to try again.";
1511
+ return `Codex is signed out on this device. To sign back in, run \`codex login\`, ${RESTART}. Then reply in Cabane to try again.`;
1512
+ return `The agent is signed out on this device. Sign in to their harness, ${RESTART}. Then reply in Cabane to try again.`;
1512
1513
  }
1513
1514
  if (failure?.kind === "usage_capped")
1514
1515
  return failure.resetsAt ? `The usage limit is reached; it resets around ${new Date(failure.resetsAt).toLocaleTimeString()}. Reply in Cabane after it resets.` : "The usage limit is reached. Try again later in Cabane.";
@@ -2938,6 +2939,7 @@ var MAX_ASK_QUESTION_BYTES = 400;
2938
2939
  var MAX_ASK_HEADLINE_BYTES = 120;
2939
2940
  var MAX_ASK_ITEMS = 20;
2940
2941
  var APPROVAL_OPTIONS = ["Yes", "No"];
2942
+ var MAX_EXCHANGE_ACTION_BYTES = 32;
2941
2943
  var REQUEST_OPTIONS = ["Done"];
2942
2944
  var MAX_EXCHANGE_FILES = 5;
2943
2945
  var MAX_REQUEST_BODY_BYTES = 2e3;
@@ -2958,8 +2960,8 @@ var TURN_CONTROL_TOOLS = [
2958
2960
  ];
2959
2961
  var TURN_CONTROL_TOOL_DESCRIPTIONS = {
2960
2962
  answer: `Call this just before you write your answer: the text you write next is what the conversation keeps as your message. Call it once.`,
2961
- open_exchange: `Put something in front of one person that comes back with a recorded outcome, then end your turn; don't wait for it. Not for delivering finished work, and never for acknowledgement or feedback on it; the reply delivers. Open one only when the work can't continue without the answer. \`targetUserId\` is a person on your roster, by their \`@handle\`; to bring in an agent, name them with \`@handle\` in your reply.
2962
- - A question is one item (\`headline\`, optional \`question\` body, \`options\`) or \`questions\`, 1\u2013${MAX_ASK_ITEMS} items; never both. An approval or request is \`headline\` and an optional \`question\` body only. An approval is answered ${APPROVAL_OPTIONS.join(" / ")}; a request ${REQUEST_OPTIONS.join("")}, or the typed result when \`expects\` is \`result\`, or a note saying the person couldn't. A request's body carries the steps and may hold a list and code blocks; every other body is a sentence or two of framing, inline Markdown only.
2963
+ open_exchange: `Put something in front of one person that comes back with a recorded outcome, then end your turn; don't wait for it. Not for delivering finished work, and never for acknowledgement or feedback on it; the reply delivers. Open one only when the work can't continue without the answer. \`targetUserId\` is a person; to bring in an agent, name them with \`@handle\` in your reply.
2964
+ - A question is one item (\`headline\`, optional \`question\` body, \`options\`) or \`questions\`, 1\u2013${MAX_ASK_ITEMS} items; never both. An approval or request is \`headline\` and an optional \`question\` body only. An approval is answered by its \`go\` or \`hold\` word, ${APPROVAL_OPTIONS.join(" / ")} without them; a request ${REQUEST_OPTIONS.join("")}, or the typed result when \`expects\` is \`result\`, or a note saying the person couldn't. A request's body carries the steps and may hold a list and code blocks; every other body is a sentence or two of framing, inline Markdown only.
2963
2965
  - Decisions that arise together go in ONE call, in the order you want them answered. A second call is a separate exchange, never an edit.
2964
2966
  - Voice, in headline, body and options: "I" for yourself, never your own name; name everyone else who decides or acts, as on your roster. Never "you", "your", "we", "us", "our" or their contractions, nor "he", "she" or "they" for a named actor. A quotation stays accurate: say who said it.
2965
2967
  - It must stand alone, since it can arrive first: the reply carries the findings, the exchange the question; don't repeat the reply in it.
@@ -2975,7 +2977,9 @@ var TURN_CONTROL_FIELD_DESCRIPTIONS = {
2975
2977
  answer: {},
2976
2978
  open_exchange: {
2977
2979
  targetUserId: "The person: their `@handle` from your turn context's roster (preferred), or their user id.",
2978
- kind: `What the exchange is for; default \`question\`. \`question\`: the person picks among courses of action or types an answer. \`approval\`: a yes/no on one proposed action \u2014 the person answers ${APPROVAL_OPTIONS.join(" or ")}. \`request\`: something only the person can do \u2014 they answer ${REQUEST_OPTIONS.join("")}, or type the result when \`expects\` is \`result\`, or send a note saying they couldn't.`,
2980
+ kind: `What the exchange is for; default \`question\`. \`question\`: the person picks among courses of action or types an answer. \`approval\`: a yes/no on one proposed action \u2014 the person answers with its \`go\` or \`hold\` word, ${APPROVAL_OPTIONS.join(" or ")} when none is given. \`request\`: something only the person can do \u2014 they answer ${REQUEST_OPTIONS.join("")}, or type the result when \`expects\` is \`result\`, or send a note saying they couldn't.`,
2981
+ go: `An approval only: the go answer as the action itself, a short verb phrase ("Merge", "Send them", "Archive it"; not "Yes, merge it"), about 24 characters and at most ${MAX_EXCHANGE_ACTION_BYTES}. Given with \`hold\`, or neither: without them the person answers ${APPROVAL_OPTIONS.join(" or ")}.`,
2982
+ hold: `An approval only: the hold answer in the same voice ("Hold off", "Not yet", "Keep it"), at most ${MAX_EXCHANGE_ACTION_BYTES} characters and different from \`go\`. Given with \`go\`.`,
2979
2983
  expects: "A request only: `confirmation` (default) when you only need to hear it's done, `result` when you need something back. Either way the person may send only a note saying they couldn't. Refused on a question or approval.",
2980
2984
  question: `The body beneath the headline \u2014 for a question or approval one or two sentences of framing, NOT a report (up to ${MAX_ASK_QUESTION_BYTES} characters, inline markdown only); for a request the steps, with lists and code blocks allowed (up to ${MAX_REQUEST_BODY_BYTES} characters). With \`questions\`, leave it out.`,
2981
2985
  headline: `ONE clear, capitalized sentence, up to ${MAX_ASK_HEADLINE_BYTES} characters: for a question or approval, the question ending in \`?\` ("Should Ledger deploy once Mia approves?"); for a request, what to do ("Run these and send me the output"). What the person reads first in For you. Required for an approval or request.`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cabane/companion",
3
- "version": "0.6.225",
3
+ "version": "0.6.227",
4
4
  "type": "module",
5
5
  "description": "The Cabane Companion (headless): connect an 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",