@ouro.bot/cli 0.1.0-alpha.952 → 0.1.0-alpha.953

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/changelog.json CHANGED
@@ -1,6 +1,13 @@
1
1
  {
2
2
  "_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
3
3
  "versions": [
4
+ {
5
+ "version": "0.1.0-alpha.953",
6
+ "changes": [
7
+ "Shepherd works both ways on any channel: every notice ends with \"Reply here and I'll pass your answer on.\", and when you answer one in iMessage, Teams or any other conversation, your agent recognizes the notice as its own, reads that coding session in Herdr or cmux, passes your answer on, and tells you what it sent.",
8
+ "iMessage no longer drops a slow reply: a turn now has ten minutes instead of two before it is treated as hung, and a newer message from you still replaces an older turn. A turn that truly hangs can now mean up to ten minutes of silence, so send another message to move on. The health check calls a turn stalled only after five minutes."
9
+ ]
10
+ },
4
11
  {
5
12
  "version": "0.1.0-alpha.952",
6
13
  "changes": [
@@ -1,5 +1,5 @@
1
1
  {
2
- "runtimeVersion": "0.1.0-alpha.952",
2
+ "runtimeVersion": "0.1.0-alpha.953",
3
3
  "bundleSchemaVersion": 3,
4
4
  "lastUpdated": "2026-09-03T00:00:00.000Z"
5
5
  }
@@ -1,7 +1,7 @@
1
1
  <?xml version="1.0"?>
2
2
  <Container version="2">
3
3
  <Name>ouro-butler</Name>
4
- <Repository>ghcr.io/ourostack/ouroboros-butler:0.1.0-alpha.952</Repository>
4
+ <Repository>ghcr.io/ourostack/ouroboros-butler:0.1.0-alpha.953</Repository>
5
5
  <Registry>https://github.com/ourostack/ouroboros/pkgs/container/ouroboros-butler</Registry>
6
6
  <Network>host</Network>
7
7
  <Shell>sh</Shell>
@@ -56,7 +56,7 @@ function deferredFileName(deliveryId) {
56
56
  return `${(0, crypto_1.createHash)("sha256").update(deliveryId).digest("hex").slice(0, 32)}.json`;
57
57
  }
58
58
  function recordedText(record) {
59
- return `[sent by ${record.originLabel}] ${record.content}`;
59
+ return `[you sent this via ${record.originLabel}] ${record.content}`;
60
60
  }
61
61
  function recordError(message, meta) {
62
62
  (0, runtime_1.emitNervesEvent)({ level: "warn", component: "mind", event: "mind.outbound_record_error", message, meta });
@@ -68,7 +68,10 @@ function parseDeferred(raw) {
68
68
  return null;
69
69
  return value;
70
70
  }
71
- /** How a recorded message names who sent it: `[sent by <label>]`. */
71
+ /**
72
+ * How a recorded message names the way it was sent: `[you sent this via <label>]`. Every record is the agent's own
73
+ * message, so a reply to it on any channel is a reply to the agent, which owns and can act on it.
74
+ */
72
75
  exports.OUTBOUND_ORIGIN_LABELS = {
73
76
  shepherd: "Shepherd",
74
77
  send_message: "send_message",
@@ -229,7 +229,7 @@ exports.shepherdSendToolDefinition = {
229
229
  type: "function",
230
230
  function: {
231
231
  name: "shepherd_send",
232
- description: `Type into one coding agent's terminal on this machine for the human you are talking with, because they asked you to. Use it only to submit that human's own instruction or keypress ("tell it to run the tests", "approve that", "stop it"): never on your own initiative, and never for anyone else. Give exactly one of text or key. text is one line (at most ${exports.SEND_TEXT_MAX_CHARS} characters, no control characters), typed as "[<your configured name> for <their name>] <text>" and submitted with Enter. key is pressed alone: one of ${exports.SEND_KEYS.join(", ")} (a menu or permission prompt, escape to interrupt, ctrl-c to cancel). enter, tab, a digit, y and n can approve or choose on a prompt, so they need screen from a shepherd_read made just before, and nothing is sent if the terminal changed since; tell the human what a prompt asks before approving it unless they have seen it. Pass screen with text too when the text answers what is on screen. To interrupt and then instruct, send escape, read again, then send the text. It also types into the terminal the human has focused on this machine. submission.state accepted means only that the terminal host accepted input; it may still be queued behind credential approval or a busy agent. It does not prove receiver receipt, resumed execution, restored capability or useful progress. Report those as unverified, never "unblocked" or "all unblocked" from this result or an unchanged screen. Each stronger claim needs fresh evidence from the exact target instance after this attempt, tied to this instruction; receipt alone is not progress or restored credentials. unknown may already have arrived: preserve the attempt and do not blindly resend.`,
232
+ description: `Type into one coding agent's terminal on this machine for the human you are talking with, because they asked you to. Use it only to submit that human's own instruction or keypress ("tell it to run the tests", "approve that", "stop it"): never on your own initiative, and never for anyone else. When they answer a Shepherd notice you sent them, on any channel, with something meant for that coding session, that is such a request: shepherd_read the session the notice names, check it still shows the agent and folder the notice named, send their answer, then tell them what you sent. A thank-you or a question for you is not; if it is unclear which session or what to send, ask. Give exactly one of text or key. text is one line (at most ${exports.SEND_TEXT_MAX_CHARS} characters, no control characters), typed as "[<your configured name> for <their name>] <text>" and submitted with Enter. key is pressed alone: one of ${exports.SEND_KEYS.join(", ")} (a menu or permission prompt, escape to interrupt, ctrl-c to cancel). enter, tab, a digit, y and n can approve or choose on a prompt, so they need screen from a shepherd_read made just before, and nothing is sent if the terminal changed since; tell the human what a prompt asks before approving it unless they have seen it. Pass screen with text too when the text answers what is on screen. To interrupt and then instruct, send escape, read again, then send the text. It also types into the terminal the human has focused on this machine. submission.state accepted means only that the terminal host accepted input; it may still be queued behind credential approval or a busy agent. It does not prove receiver receipt, resumed execution, restored capability or useful progress. Report those as unverified, never "unblocked" or "all unblocked" from this result or an unchanged screen. Each stronger claim needs fresh evidence from the exact target instance after this attempt, tied to this instruction; receipt alone is not progress or restored credentials. unknown may already have arrived: preserve the attempt and do not blindly resend.`,
233
233
  parameters: {
234
234
  type: "object",
235
235
  properties: {
@@ -325,9 +325,10 @@ const defaultDeps = {
325
325
  const BLUEBUBBLES_RUNTIME_SYNC_INTERVAL_MS = 30_000;
326
326
  const BLUEBUBBLES_RECOVERY_PASS_DELAY_MS = 1_000;
327
327
  const BLUEBUBBLES_RECOVERY_PASS_INTERVAL_MS = 30_000;
328
- const BLUEBUBBLES_LIVE_TURN_TIMEOUT_MS = 2 * 60_000;
329
- const BLUEBUBBLES_RECOVERY_TURN_TIMEOUT_MS = 10 * 60_000;
330
- const BLUEBUBBLES_LIVE_TURN_STALLED_MS = 90_000;
328
+ // A turn that is still thinking after this long is treated as hung. It is generous on purpose: a slow reply that
329
+ // arrives is worth far more than a dropped one, and a newer message from the person still supersedes an older turn.
330
+ const BLUEBUBBLES_TURN_TIMEOUT_MS = 10 * 60_000;
331
+ const BLUEBUBBLES_LIVE_TURN_STALLED_MS = 5 * 60_000;
331
332
  const BLUEBUBBLES_CALLBACK_CLEANUP_TIMEOUT_MS = 2_000;
332
333
  const BLUEBUBBLES_ACTIVITY_OPERATION_TIMEOUT_MS = 20_000;
333
334
  const BLUEBUBBLES_CATCHUP_PAGE_SIZE = 50;
@@ -1728,7 +1729,7 @@ async function handleBlueBubblesNormalizedEvent(event, resolvedDeps, source, opt
1728
1729
  const [groupHasFamilyMember, hasExistingGroupWithFamily] = trustContext;
1729
1730
  lifecycleSignal?.throwIfAborted();
1730
1731
  // ── Call shared pipeline ────────────────────────────────────────
1731
- const timeoutMs = options.timeoutMs ?? BLUEBUBBLES_LIVE_TURN_TIMEOUT_MS;
1732
+ const timeoutMs = options.timeoutMs ?? BLUEBUBBLES_TURN_TIMEOUT_MS;
1732
1733
  timeoutPromise = new Promise((resolve) => {
1733
1734
  resolveTimeout = resolve;
1734
1735
  });
@@ -3019,7 +3020,7 @@ async function catchUpMissedBlueBubblesMessages(deps = {}, previousState, option
3019
3020
  }
3020
3021
  semanticGenerationOwned = true;
3021
3022
  const handled = await handleCapturedBlueBubblesSemanticEvent(captured, resolvedDeps, "upstream-catchup", {
3022
- timeoutMs: BLUEBUBBLES_RECOVERY_TURN_TIMEOUT_MS,
3023
+ timeoutMs: BLUEBUBBLES_TURN_TIMEOUT_MS,
3023
3024
  autonomyBudgetTrigger: "recovery",
3024
3025
  observationReservation,
3025
3026
  lifecycleSignal: options.lifecycleSignal,
@@ -3135,7 +3136,7 @@ async function recoverCapturedBlueBubblesInboundMessages(deps = {}, options = {}
3135
3136
  normalized,
3136
3137
  writeResult: "semantic_capture_duplicate",
3137
3138
  }, resolvedDeps, "webhook", {
3138
- timeoutMs: BLUEBUBBLES_RECOVERY_TURN_TIMEOUT_MS,
3139
+ timeoutMs: BLUEBUBBLES_TURN_TIMEOUT_MS,
3139
3140
  autonomyBudgetTrigger: "recovery",
3140
3141
  semanticRecovery: true,
3141
3142
  observationReservation,
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.NOTICE_RETRY_MS = exports.NOTICE_LIST_MAX = exports.NOTICE_COALESCE_MS = void 0;
36
+ exports.NOTICE_REPLY_LINE = exports.NOTICE_RETRY_MS = exports.NOTICE_LIST_MAX = exports.NOTICE_COALESCE_MS = void 0;
37
37
  exports.noticeWanted = noticeWanted;
38
38
  exports.plain = plain;
39
39
  exports.noticeLine = noticeLine;
@@ -132,11 +132,13 @@ function noticeLine(record, location) {
132
132
  case "working":
133
133
  return `${subject} is still working in the background and has news. ${why}`;
134
134
  case "unclear":
135
- return `Shepherd could not determine the current state of ${subject}. ${why}`;
135
+ return `I could not determine the current state of ${subject}. ${why}`;
136
136
  default:
137
- return `Shepherd could not complete its observation of ${subject}; the agent's state was not determined. ${why}`;
137
+ return `I could not complete my observation of ${subject}; the agent's state was not determined. ${why}`;
138
138
  }
139
139
  }
140
+ /** Closes every notice: the person answers in the same conversation, and the agent relays it with `shepherd_send`. */
141
+ exports.NOTICE_REPLY_LINE = "Reply here and I'll pass your answer on.";
140
142
  /** A bounded display of latest observations; all input records retain delivery custody. */
141
143
  function noticeMessage(records, refs = new Map(), context = {}) {
142
144
  const latest = new Map();
@@ -160,7 +162,7 @@ function noticeMessage(records, refs = new Map(), context = {}) {
160
162
  const more = sessions.length - lines.length;
161
163
  const body = sessions.length === 1 ? lines[0]
162
164
  : [`Updates from ${sessions.length} coding sessions:`, ...lines.map(line => `- ${line}`), ...(more > 0 ? [`- and ${more} more.`] : [])].join("\n");
163
- return context.recovered ? `Includes recovered historical observations, not live status:\n${body}` : body;
165
+ return `${context.recovered ? `Includes recovered historical observations, not live status:\n${body}` : body}\n\n${exports.NOTICE_REPLY_LINE}`;
164
166
  }
165
167
  /**
166
168
  * The channels this agent can reach people on from this machine: its enabled Teams sense, and its enabled BlueBubbles
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.952",
3
+ "version": "0.1.0-alpha.953",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@ouro.bot/cli",
9
- "version": "0.1.0-alpha.952",
9
+ "version": "0.1.0-alpha.953",
10
10
  "dependencies": {
11
11
  "@anthropic-ai/sdk": "^0.78.0",
12
12
  "@azure/identity": "^4.13.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.952",
3
+ "version": "0.1.0-alpha.953",
4
4
  "engines": {
5
5
  "node": ">=22"
6
6
  },