@ouro.bot/cli 0.1.0-alpha.154 → 0.1.0-alpha.156

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,22 @@
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.156",
6
+ "changes": [
7
+ "polish: observe tool now hidden (like settle/rest/descend)",
8
+ "polish(bb): batch rapid tool status messages within 500ms debounce window",
9
+ "polish(tools): word-boundary truncation instead of mid-word cut",
10
+ "polish(commands): /commands output uses em dash separators",
11
+ "polish(bb): re-enable typing indicator after each status message"
12
+ ]
13
+ },
14
+ {
15
+ "version": "0.1.0-alpha.155",
16
+ "changes": [
17
+ "polish(debug): dynamic toggle, richer descriptions, human-readable results"
18
+ ]
19
+ },
4
20
  {
5
21
  "version": "0.1.0-alpha.154",
6
22
  "changes": [
@@ -8,22 +8,28 @@ function createToolActivityCallbacks(options) {
8
8
  component: "engine",
9
9
  event: "engine.tool_activity_callbacks_created",
10
10
  message: "tool activity callbacks initialized",
11
- meta: { isDebug: options.isDebug },
11
+ meta: {},
12
12
  });
13
+ // Track the last description so we can reference it in END messages
14
+ let lastDescription = null;
13
15
  return {
14
16
  onToolStart(name, args) {
15
17
  const description = (0, tool_description_1.humanReadableToolDescription)(name, args);
16
18
  if (description === null)
17
- return; // hidden tool (settle, rest)
19
+ return; // hidden tool (settle, rest, descend)
20
+ lastDescription = description;
18
21
  options.onDescription(description);
19
22
  },
20
23
  onToolEnd(name, summary, success) {
24
+ const desc = lastDescription ?? name;
25
+ // Strip trailing "..." from description for the result line
26
+ const cleanDesc = desc.endsWith("...") ? desc.slice(0, -3) : desc;
21
27
  if (!success) {
22
- options.onFailure(`${name} failed: ${summary}`);
28
+ options.onFailure(`\u2717 ${cleanDesc} — ${summary}`);
23
29
  return;
24
30
  }
25
- if (options.isDebug) {
26
- options.onResult(`${name}: ${summary}`);
31
+ if (options.isDebug()) {
32
+ options.onResult(`\u2713 ${cleanDesc}`);
27
33
  }
28
34
  },
29
35
  };
@@ -9,9 +9,16 @@ function basename(filePath) {
9
9
  function truncate(text, max) {
10
10
  if (text.length <= max)
11
11
  return text;
12
- return text.slice(0, max - 1) + "\u2026";
12
+ // Cut at last space before maxLen to avoid mid-word truncation
13
+ const slice = text.slice(0, max - 1);
14
+ const lastSpace = slice.lastIndexOf(" ");
15
+ if (lastSpace > 0)
16
+ return text.slice(0, lastSpace) + "\u2026";
17
+ // No space found (single long word) — hard truncate
18
+ return slice + "\u2026";
13
19
  }
14
20
  const TOOL_DESCRIPTIONS = {
21
+ // File operations
15
22
  shell: (args) => {
16
23
  const cmd = args.command;
17
24
  if (!cmd)
@@ -36,11 +43,11 @@ const TOOL_DESCRIPTIONS = {
36
43
  return "editing a file...";
37
44
  return `editing ${basename(fp)}...`;
38
45
  },
39
- recall: (args) => {
40
- const q = args.query;
41
- if (!q)
42
- return "searching memory...";
43
- return `searching memory for '${truncate(q, 40)}'...`;
46
+ glob: (args) => {
47
+ const p = args.pattern;
48
+ if (!p)
49
+ return "searching for files...";
50
+ return `searching for ${truncate(p, 40)}...`;
44
51
  },
45
52
  grep: (args) => {
46
53
  const p = args.pattern;
@@ -48,21 +55,65 @@ const TOOL_DESCRIPTIONS = {
48
55
  return "searching code...";
49
56
  return `searching code for '${truncate(p, 40)}'...`;
50
57
  },
51
- glob: (args) => {
52
- const p = args.pattern;
53
- if (!p)
54
- return "searching for files...";
55
- return `searching for ${truncate(p, 40)}...`;
58
+ // Memory and knowledge
59
+ recall: (args) => {
60
+ const q = args.query;
61
+ if (!q)
62
+ return "searching memory...";
63
+ return `searching memory for '${truncate(q, 40)}'...`;
64
+ },
65
+ diary_write: (args) => {
66
+ const about = args.about;
67
+ return about ? `noting something about ${truncate(about, 30)}...` : "noting something down...";
68
+ },
69
+ save_friend_note: () => "making a note about you...",
70
+ get_friend_note: () => "checking my notes...",
71
+ load_skill: (args) => {
72
+ const name = args.name || args.skill;
73
+ return name ? `loading ${name} skill...` : "loading a skill...";
74
+ },
75
+ // Session and context
76
+ query_session: (args) => {
77
+ const mode = args.mode;
78
+ if (mode === "search")
79
+ return `searching session for '${truncate(args.query || "", 30)}'...`;
80
+ if (mode === "status")
81
+ return "checking inner dialog status...";
82
+ return "checking session history...";
83
+ },
84
+ web_search: (args) => {
85
+ const q = args.query;
86
+ return q ? `searching the web for '${truncate(q, 35)}'...` : "searching the web...";
87
+ },
88
+ coding_spawn: (args) => {
89
+ const runner = args.runner;
90
+ return runner ? `starting ${runner} coding session...` : "starting coding session...";
91
+ },
92
+ coding_status: () => "checking coding sessions...",
93
+ coding_tail: () => "reading coding output...",
94
+ coding_kill: () => "stopping coding session...",
95
+ bridge_manage: () => "managing conversation bridge...",
96
+ // Communication
97
+ send_message: (args) => {
98
+ const to = args.to;
99
+ return to ? `sending a message to ${to}...` : "sending a message...";
100
+ },
101
+ surface: () => "sharing a thought...",
102
+ // Metacognitive (agent's inner life)
103
+ ponder: (args) => {
104
+ const thought = args.thought;
105
+ return thought ? `thinking about ${truncate(thought, 40)}...` : "thinking deeper...";
106
+ },
107
+ observe: () => null,
108
+ claude: () => "reasoning...",
109
+ set_reasoning_effort: (args) => {
110
+ const level = args.level;
111
+ return level ? `setting thinking depth to ${level}...` : "adjusting thinking depth...";
56
112
  },
57
- query_session: () => "checking session history...",
58
- web_search: () => "searching the web...",
59
- coding_spawn: () => "starting coding session...",
60
- ponder: () => "thinking deeper...",
61
- observe: () => "listening...",
62
- diary_write: () => "noting something down...",
63
- save_friend_note: () => "making a note...",
113
+ // Hidden — these ARE the response or end-of-turn
64
114
  settle: () => null,
65
115
  rest: () => null,
116
+ descend: () => null,
66
117
  };
67
118
  function humanReadableToolDescription(name, args) {
68
119
  (0, runtime_1.emitNervesEvent)({
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.enrichReactionText = enrichReactionText;
37
+ exports.createStatusBatcher = createStatusBatcher;
37
38
  exports.handleBlueBubblesEvent = handleBlueBubblesEvent;
38
39
  exports.recoverMissedBlueBubblesMessages = recoverMissedBlueBubblesMessages;
39
40
  exports.createBlueBubblesWebhookHandler = createBlueBubblesWebhookHandler;
@@ -81,6 +82,44 @@ function enrichReactionText(baseText, originalText, maxLen) {
81
82
  : originalText;
82
83
  return `${baseText} to: "${truncated}"`;
83
84
  }
85
+ /**
86
+ * Accumulates status descriptions and debounces them.
87
+ * If multiple descriptions arrive within `delayMs`, they are joined with ` · `
88
+ * and sent as a single message. Flush sends immediately and clears the timer.
89
+ */
90
+ function createStatusBatcher(send, delayMs) {
91
+ (0, runtime_1.emitNervesEvent)({
92
+ component: "senses",
93
+ event: "senses.bluebubbles_status_batcher_created",
94
+ message: "status batcher initialized",
95
+ meta: { delayMs },
96
+ });
97
+ let pending = [];
98
+ let timer = null;
99
+ function fire() {
100
+ if (pending.length === 0)
101
+ return;
102
+ const combined = pending.join(" \u00b7 ");
103
+ pending = [];
104
+ timer = null;
105
+ send(combined);
106
+ }
107
+ return {
108
+ add(text) {
109
+ pending.push(text);
110
+ if (timer !== null)
111
+ clearTimeout(timer);
112
+ timer = setTimeout(fire, delayMs);
113
+ },
114
+ flush() {
115
+ if (timer !== null) {
116
+ clearTimeout(timer);
117
+ timer = null;
118
+ }
119
+ fire();
120
+ },
121
+ };
122
+ }
84
123
  const defaultDeps = {
85
124
  getAgentName: identity_1.getAgentName,
86
125
  buildSystem: prompt_1.buildSystem,
@@ -401,15 +440,18 @@ function createBlueBubblesCallbacks(client, chat, replyTarget, isGroupChat) {
401
440
  text,
402
441
  replyToMessageGuid: replyTarget.getReplyToMessageGuid(),
403
442
  });
443
+ // Re-enable typing indicator — sending a message clears the typing bubble
444
+ await client.setTyping(chat, true);
404
445
  });
405
446
  }
447
+ const statusBatcher = createStatusBatcher((text) => sendStatus(text), 500);
406
448
  const toolCallbacks = (0, tool_activity_callbacks_1.createToolActivityCallbacks)({
407
- onDescription: (text) => sendStatus(text),
449
+ onDescription: (text) => statusBatcher.add(text),
408
450
  /* v8 ignore next -- onResult only called in debug mode; tested via tool-activity-callbacks.test.ts @preserve */
409
- onResult: (text) => sendStatus(text),
451
+ onResult: (text) => { statusBatcher.flush(); sendStatus(text); },
410
452
  /* v8 ignore next -- onFailure only called on tool failure; tested via tool-activity-callbacks.test.ts @preserve */
411
- onFailure: (text) => sendStatus(`\u2717 ${text}`),
412
- isDebug: (0, commands_1.getDebugMode)(),
453
+ onFailure: (text) => { statusBatcher.flush(); sendStatus(text); },
454
+ isDebug: commands_1.getDebugMode,
413
455
  });
414
456
  return {
415
457
  onModelStart() {
@@ -471,6 +513,7 @@ function createBlueBubblesCallbacks(client, chat, replyTarget, isGroupChat) {
471
513
  textBuffer = "";
472
514
  },
473
515
  async flush() {
516
+ statusBatcher.flush();
474
517
  await queue;
475
518
  const trimmed = textBuffer.trim();
476
519
  if (!trimmed) {
@@ -495,6 +538,7 @@ function createBlueBubblesCallbacks(client, chat, replyTarget, isGroupChat) {
495
538
  });
496
539
  },
497
540
  async finish() {
541
+ statusBatcher.flush();
498
542
  if (!typingActive) {
499
543
  await queue;
500
544
  return;
@@ -72,7 +72,7 @@ function registerDefaultCommands(registry) {
72
72
  channels: ["cli", "teams"],
73
73
  handler: (ctx) => {
74
74
  const cmds = registry.list(ctx.channel);
75
- const lines = cmds.map((c) => `/${c.name} - ${c.description}`);
75
+ const lines = cmds.map((c) => `/${c.name} \u2014 ${c.description}`);
76
76
  return { action: "response", message: lines.join("\n") };
77
77
  },
78
78
  });
@@ -87,11 +87,16 @@ function registerDefaultCommands(registry) {
87
87
  });
88
88
  registry.register({
89
89
  name: "debug",
90
- description: "toggle debug mode (verbose tool output)",
91
- channels: ["cli", "teams", "bluebubbles"],
90
+ description: "toggle debug mode — see more detail about what I'm doing",
91
+ channels: ["cli", "teams", "bluebubbles", "mcp"],
92
92
  handler: () => {
93
93
  _debugMode = !_debugMode;
94
- return { action: "response", message: `debug mode: ${_debugMode ? "ON" : "OFF"}` };
94
+ return {
95
+ action: "response",
96
+ message: _debugMode
97
+ ? "debug mode on — you'll see more detail about what I'm doing"
98
+ : "debug mode off — back to clean output",
99
+ };
95
100
  },
96
101
  });
97
102
  (0, runtime_1.emitNervesEvent)({
@@ -433,8 +433,8 @@ function createTeamsCallbacks(stream, controller, sendMessage, options) {
433
433
  /* v8 ignore next -- onResult only called in debug mode; tested via tool-activity-callbacks.test.ts @preserve */
434
434
  onResult: (text) => safeUpdate(text),
435
435
  /* v8 ignore next -- onFailure tested via onToolEnd failure test @preserve */
436
- onFailure: (text) => safeUpdate(`\u2717 ${text}`),
437
- isDebug: (0, commands_2.getDebugMode)(),
436
+ onFailure: (text) => safeUpdate(text),
437
+ isDebug: commands_2.getDebugMode,
438
438
  });
439
439
  return {
440
440
  onToolStart: (name, args) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.154",
3
+ "version": "0.1.0-alpha.156",
4
4
  "main": "dist/heart/daemon/ouro-entry.js",
5
5
  "bin": {
6
6
  "cli": "dist/heart/daemon/ouro-bot-entry.js",