@ouro.bot/cli 0.1.0-alpha.16 → 0.1.0-alpha.160

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.
Files changed (165) hide show
  1. package/AdoptionSpecialist.ouro/agent.json +3 -2
  2. package/AdoptionSpecialist.ouro/psyche/SOUL.md +3 -3
  3. package/AdoptionSpecialist.ouro/psyche/identities/monty.md +2 -2
  4. package/README.md +186 -191
  5. package/changelog.json +1081 -0
  6. package/dist/heart/active-work.js +633 -0
  7. package/dist/heart/bridges/manager.js +358 -0
  8. package/dist/heart/bridges/state-machine.js +135 -0
  9. package/dist/heart/bridges/store.js +123 -0
  10. package/dist/heart/commitments.js +105 -0
  11. package/dist/heart/config.js +40 -30
  12. package/dist/heart/core.js +608 -123
  13. package/dist/heart/cross-chat-delivery.js +146 -0
  14. package/dist/heart/daemon/agent-discovery.js +81 -0
  15. package/dist/heart/daemon/agent-service.js +360 -0
  16. package/dist/heart/daemon/auth-flow.js +477 -0
  17. package/dist/heart/daemon/cadence.js +70 -0
  18. package/dist/heart/daemon/daemon-cli.js +2467 -205
  19. package/dist/heart/daemon/daemon-entry.js +131 -4
  20. package/dist/heart/daemon/daemon-health.js +136 -0
  21. package/dist/heart/daemon/daemon-runtime-sync.js +212 -0
  22. package/dist/heart/daemon/daemon-tombstone.js +123 -0
  23. package/dist/heart/daemon/daemon.js +434 -17
  24. package/dist/heart/daemon/habit-migration.js +181 -0
  25. package/dist/heart/daemon/habit-parser.js +119 -0
  26. package/dist/heart/daemon/habit-scheduler.js +369 -0
  27. package/dist/heart/daemon/hatch-animation.js +10 -3
  28. package/dist/heart/daemon/hatch-flow.js +30 -111
  29. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  30. package/dist/heart/daemon/hooks/bundle-meta.js +92 -0
  31. package/dist/heart/daemon/inner-status.js +89 -0
  32. package/dist/heart/daemon/launchd.js +159 -0
  33. package/dist/heart/daemon/log-tailer.js +4 -3
  34. package/dist/heart/daemon/mcp-server.js +591 -0
  35. package/dist/heart/daemon/message-router.js +17 -8
  36. package/dist/heart/daemon/os-cron-deps.js +134 -0
  37. package/dist/heart/daemon/ouro-bot-global-installer.js +128 -0
  38. package/dist/heart/daemon/ouro-path-installer.js +78 -34
  39. package/dist/heart/daemon/ouro-version-manager.js +171 -0
  40. package/dist/heart/daemon/outlook-http.js +307 -0
  41. package/dist/heart/daemon/outlook-read.js +1281 -0
  42. package/dist/heart/daemon/outlook-render.js +1032 -0
  43. package/dist/heart/daemon/outlook-types.js +7 -0
  44. package/dist/heart/daemon/outlook-view.js +194 -0
  45. package/dist/heart/daemon/process-manager.js +75 -0
  46. package/dist/heart/daemon/run-hooks.js +39 -0
  47. package/dist/heart/daemon/runtime-logging.js +58 -15
  48. package/dist/heart/daemon/runtime-metadata.js +219 -0
  49. package/dist/heart/daemon/runtime-mode.js +67 -0
  50. package/dist/heart/daemon/safe-mode.js +161 -0
  51. package/dist/heart/daemon/sense-manager.js +50 -2
  52. package/dist/heart/daemon/session-id-resolver.js +131 -0
  53. package/dist/heart/daemon/skill-management-installer.js +94 -0
  54. package/dist/heart/daemon/socket-client.js +202 -0
  55. package/dist/heart/daemon/specialist-orchestrator.js +2 -2
  56. package/dist/heart/daemon/specialist-prompt.js +13 -8
  57. package/dist/heart/daemon/specialist-tools.js +53 -4
  58. package/dist/heart/daemon/staged-restart.js +114 -0
  59. package/dist/heart/daemon/task-scheduler.js +3 -25
  60. package/dist/heart/daemon/thoughts.js +507 -0
  61. package/dist/heart/daemon/update-checker.js +111 -0
  62. package/dist/heart/daemon/update-hooks.js +138 -0
  63. package/dist/heart/daemon/wrapper-publish-guard.js +86 -0
  64. package/dist/heart/delegation.js +62 -0
  65. package/dist/heart/identity.js +136 -55
  66. package/dist/heart/kicks.js +2 -20
  67. package/dist/heart/migrate-config.js +127 -0
  68. package/dist/heart/model-capabilities.js +48 -0
  69. package/dist/heart/obligations.js +197 -0
  70. package/dist/heart/progress-story.js +42 -0
  71. package/dist/heart/provider-failover.js +88 -0
  72. package/dist/heart/provider-ping.js +172 -0
  73. package/dist/heart/providers/anthropic-token.js +163 -0
  74. package/dist/heart/providers/anthropic.js +196 -36
  75. package/dist/heart/providers/azure.js +116 -10
  76. package/dist/heart/providers/github-copilot.js +157 -0
  77. package/dist/heart/providers/minimax.js +33 -3
  78. package/dist/heart/providers/openai-codex.js +51 -16
  79. package/dist/heart/session-activity.js +172 -0
  80. package/dist/heart/session-recall.js +216 -0
  81. package/dist/heart/streaming.js +117 -33
  82. package/dist/heart/target-resolution.js +127 -0
  83. package/dist/heart/tool-activity-callbacks.js +36 -0
  84. package/dist/heart/tool-description.js +135 -0
  85. package/dist/heart/tool-loop.js +200 -0
  86. package/dist/heart/turn-coordinator.js +28 -0
  87. package/dist/mind/associative-recall.js +122 -32
  88. package/dist/mind/bundle-manifest.js +14 -0
  89. package/dist/mind/context.js +125 -14
  90. package/dist/mind/{memory.js → diary.js} +70 -56
  91. package/dist/mind/first-impressions.js +16 -2
  92. package/dist/mind/friends/channel.js +56 -0
  93. package/dist/mind/friends/group-context.js +144 -0
  94. package/dist/mind/friends/store-file.js +19 -0
  95. package/dist/mind/friends/trust-explanation.js +74 -0
  96. package/dist/mind/friends/types.js +8 -0
  97. package/dist/mind/journal-index.js +161 -0
  98. package/dist/mind/obligation-steering.js +221 -0
  99. package/dist/mind/obligations.js +134 -0
  100. package/dist/mind/pending.js +76 -9
  101. package/dist/mind/phrases.js +1 -0
  102. package/dist/mind/prompt.js +651 -91
  103. package/dist/mind/token-estimate.js +8 -12
  104. package/dist/nerves/cli-logging.js +15 -2
  105. package/dist/nerves/coverage/run-artifacts.js +1 -1
  106. package/dist/nerves/event-buffer.js +111 -0
  107. package/dist/nerves/index.js +63 -3
  108. package/dist/nerves/observation.js +20 -0
  109. package/dist/nerves/runtime.js +5 -1
  110. package/dist/repertoire/ado-semantic.js +6 -0
  111. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  112. package/dist/repertoire/coding/context-pack.js +254 -0
  113. package/dist/repertoire/coding/feedback.js +301 -0
  114. package/dist/repertoire/coding/index.js +4 -1
  115. package/dist/repertoire/coding/manager.js +210 -4
  116. package/dist/repertoire/coding/spawner.js +58 -12
  117. package/dist/repertoire/coding/tools.js +176 -4
  118. package/dist/repertoire/guardrails.js +291 -0
  119. package/dist/repertoire/mcp-client.js +254 -0
  120. package/dist/repertoire/mcp-manager.js +198 -0
  121. package/dist/repertoire/skills.js +14 -23
  122. package/dist/repertoire/tasks/board.js +43 -5
  123. package/dist/repertoire/tasks/fix.js +182 -0
  124. package/dist/repertoire/tasks/index.js +28 -10
  125. package/dist/repertoire/tasks/lifecycle.js +2 -2
  126. package/dist/repertoire/tasks/parser.js +3 -2
  127. package/dist/repertoire/tasks/scanner.js +194 -37
  128. package/dist/repertoire/tasks/transitions.js +11 -28
  129. package/dist/repertoire/tools-base.js +992 -273
  130. package/dist/repertoire/tools-bluebubbles.js +94 -0
  131. package/dist/repertoire/tools-github.js +1 -6
  132. package/dist/repertoire/tools-teams.js +12 -59
  133. package/dist/repertoire/tools.js +281 -101
  134. package/dist/scripts/claude-code-hook.js +41 -0
  135. package/dist/scripts/claude-code-stop-hook.js +47 -0
  136. package/dist/senses/attention-queue.js +97 -0
  137. package/dist/senses/bluebubbles-client.js +258 -5
  138. package/dist/senses/bluebubbles-entry.js +2 -0
  139. package/dist/senses/bluebubbles-inbound-log.js +109 -0
  140. package/dist/senses/bluebubbles-media.js +339 -0
  141. package/dist/senses/bluebubbles-model.js +12 -4
  142. package/dist/senses/bluebubbles-mutation-log.js +45 -5
  143. package/dist/senses/bluebubbles-runtime-state.js +109 -0
  144. package/dist/senses/bluebubbles-session-cleanup.js +72 -0
  145. package/dist/senses/bluebubbles.js +1040 -45
  146. package/dist/senses/cli-entry.js +1 -1
  147. package/dist/senses/cli-layout.js +187 -0
  148. package/dist/senses/cli.js +419 -152
  149. package/dist/senses/commands.js +38 -1
  150. package/dist/senses/continuity.js +94 -0
  151. package/dist/senses/habit-turn-message.js +108 -0
  152. package/dist/senses/inner-dialog-worker.js +112 -19
  153. package/dist/senses/inner-dialog.js +592 -84
  154. package/dist/senses/pipeline.js +502 -0
  155. package/dist/senses/shared-turn.js +196 -0
  156. package/dist/senses/surface-tool.js +95 -0
  157. package/dist/senses/teams.js +667 -120
  158. package/dist/senses/trust-gate.js +112 -2
  159. package/package.json +12 -4
  160. package/skills/configure-dev-tools.md +81 -0
  161. package/subagents/README.md +4 -70
  162. package/dist/heart/daemon/subagent-installer.js +0 -134
  163. package/subagents/work-doer.md +0 -233
  164. package/subagents/work-merger.md +0 -624
  165. package/subagents/work-planner.md +0 -373
@@ -1,6 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.__internal = void 0;
4
3
  exports.estimateTokensForMessage = estimateTokensForMessage;
5
4
  exports.estimateTokensForMessages = estimateTokensForMessages;
6
5
  const runtime_1 = require("../nerves/runtime");
@@ -53,7 +52,7 @@ function countCharsInContent(content) {
53
52
  return c.text.length;
54
53
  if (typeof c.content === "string")
55
54
  return c.content.length;
56
- return safeStringify(content).length;
55
+ return safeStringify(c).length;
57
56
  }
58
57
  return 0;
59
58
  }
@@ -70,12 +69,13 @@ function countCharsInToolCalls(toolCalls) {
70
69
  if (typeof t.type === "string")
71
70
  total += t.type.length;
72
71
  if (t.function && typeof t.function === "object") {
73
- if (typeof t.function.name === "string")
74
- total += t.function.name.length;
75
- if (typeof t.function.arguments === "string")
76
- total += t.function.arguments.length;
77
- else if (t.function.arguments != null)
78
- total += safeStringify(t.function.arguments).length;
72
+ const fn = t.function;
73
+ if (typeof fn.name === "string")
74
+ total += fn.name.length;
75
+ if (typeof fn.arguments === "string")
76
+ total += fn.arguments.length;
77
+ else if (fn.arguments != null)
78
+ total += safeStringify(fn.arguments).length;
79
79
  }
80
80
  }
81
81
  return total;
@@ -113,7 +113,3 @@ function estimateTokensForMessages(msgs) {
113
113
  total += estimateTokensForMessage(msg);
114
114
  return total;
115
115
  }
116
- exports.__internal = {
117
- CHARS_PER_TOKEN,
118
- PER_MESSAGE_OVERHEAD_TOKENS,
119
- };
@@ -5,20 +5,33 @@ const config_1 = require("../heart/config");
5
5
  const nerves_1 = require("../nerves");
6
6
  const runtime_1 = require("./runtime");
7
7
  const runtime_2 = require("./runtime");
8
+ const LEVEL_PRIORITY = { debug: 10, info: 20, warn: 30, error: 40 };
9
+ /** Wrap a sink so it only receives events at or above the given level. */
10
+ /* v8 ignore start -- internal filter plumbing, exercised via integration @preserve */
11
+ function filterSink(sink, minLevel) {
12
+ const minPriority = LEVEL_PRIORITY[minLevel] ?? 0;
13
+ return (entry) => {
14
+ if ((LEVEL_PRIORITY[entry.level] ?? 0) >= minPriority)
15
+ sink(entry);
16
+ };
17
+ }
8
18
  function resolveCliSinks(sinks) {
9
19
  const requested = sinks && sinks.length > 0 ? sinks : ["terminal", "ndjson"];
10
20
  return [...new Set(requested)];
11
21
  }
12
22
  function configureCliRuntimeLogger(_friendId, options = {}) {
13
23
  const sinkKinds = resolveCliSinks(options.sinks);
24
+ const level = options.level ?? "info";
14
25
  const sinks = sinkKinds.map((sinkKind) => {
15
26
  if (sinkKind === "terminal") {
16
- return (0, nerves_1.createTerminalSink)();
27
+ // Terminal only shows warnings and errors — INFO is too noisy
28
+ // for an interactive session. Full detail goes to the ndjson file.
29
+ return filterSink((0, nerves_1.createTerminalSink)(), "warn");
17
30
  }
18
31
  return (0, nerves_1.createNdjsonFileSink)((0, config_1.logPath)("cli", "runtime"));
19
32
  });
20
33
  const logger = (0, nerves_1.createLogger)({
21
- level: options.level ?? "info",
34
+ level,
22
35
  sinks,
23
36
  });
24
37
  (0, runtime_2.setRuntimeLogger)(logger);
@@ -14,7 +14,7 @@ const path_1 = require("path");
14
14
  const os_1 = require("os");
15
15
  exports.REPO_SLUG = "ouroboros-agent-harness";
16
16
  function getTestRunsRoot(repoSlug = exports.REPO_SLUG) {
17
- return (0, path_1.join)((0, os_1.homedir)(), ".agentstate", "test-runs", repoSlug);
17
+ return (0, path_1.join)((0, os_1.tmpdir)(), "ouroboros-test-runs", repoSlug);
18
18
  }
19
19
  function createRunId(now = new Date()) {
20
20
  return now.toISOString().replace(/[:.]/g, "-");
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createBufferedSink = createBufferedSink;
4
+ const runtime_1 = require("./runtime");
5
+ const DEFAULT_MAX_SIZE = 1000;
6
+ const DEFAULT_TTL_MS = 5 * 60 * 1000; // 5 minutes
7
+ function createBufferedSink(inner, options = {}) {
8
+ const maxSize = options.maxSize ?? DEFAULT_MAX_SIZE;
9
+ const ttlMs = options.ttlMs ?? DEFAULT_TTL_MS;
10
+ const nowMs = options.nowMs ?? (() => Date.now());
11
+ const buffer = [];
12
+ let dropped = 0;
13
+ let sinkHealthy = true;
14
+ let unhealthySince = null;
15
+ function tryInner(event) {
16
+ try {
17
+ inner(event);
18
+ return true;
19
+ }
20
+ catch {
21
+ return false;
22
+ }
23
+ }
24
+ function markUnhealthy() {
25
+ sinkHealthy = false;
26
+ unhealthySince = unhealthySince ?? nowMs();
27
+ }
28
+ function markHealthy() {
29
+ sinkHealthy = true;
30
+ unhealthySince = null;
31
+ }
32
+ function discardBuffer() {
33
+ const count = buffer.length;
34
+ dropped += count;
35
+ buffer.length = 0;
36
+ (0, runtime_1.emitNervesEvent)({
37
+ component: "nerves",
38
+ event: "nerves.buffer_ttl_discard",
39
+ message: `discarded ${count} buffered events after TTL`,
40
+ meta: { discarded: count, ttlMs },
41
+ });
42
+ }
43
+ function checkTtl() {
44
+ if (unhealthySince !== null && nowMs() - unhealthySince > ttlMs) {
45
+ discardBuffer();
46
+ // Reset unhealthySince to now so TTL starts fresh for newly buffered events
47
+ unhealthySince = nowMs();
48
+ return true;
49
+ }
50
+ return false;
51
+ }
52
+ function addToBuffer(event) {
53
+ if (buffer.length >= maxSize) {
54
+ buffer.shift();
55
+ dropped++;
56
+ }
57
+ buffer.push(event);
58
+ }
59
+ function flushBuffer() {
60
+ while (buffer.length > 0) {
61
+ const event = buffer[0];
62
+ if (tryInner(event)) {
63
+ buffer.shift();
64
+ }
65
+ else {
66
+ markUnhealthy();
67
+ return;
68
+ }
69
+ }
70
+ }
71
+ function sink(event) {
72
+ if (!sinkHealthy) {
73
+ checkTtl();
74
+ // Try sending the new event to see if inner has recovered
75
+ if (tryInner(event)) {
76
+ markHealthy();
77
+ flushBuffer();
78
+ }
79
+ else {
80
+ addToBuffer(event);
81
+ }
82
+ return;
83
+ }
84
+ if (tryInner(event)) {
85
+ return;
86
+ }
87
+ // Inner failed
88
+ markUnhealthy();
89
+ addToBuffer(event);
90
+ }
91
+ function flush() {
92
+ if (buffer.length === 0)
93
+ return;
94
+ // Test if inner is recovered by trying the first buffered event
95
+ const first = buffer[0];
96
+ if (tryInner(first)) {
97
+ buffer.shift();
98
+ markHealthy();
99
+ flushBuffer();
100
+ }
101
+ // If still broken, leave buffer intact
102
+ }
103
+ function state() {
104
+ return {
105
+ buffered: buffer.length,
106
+ dropped,
107
+ sinkHealthy,
108
+ };
109
+ }
110
+ return { sink, flush, state };
111
+ }
@@ -4,8 +4,10 @@ exports.createTraceId = createTraceId;
4
4
  exports.ensureTraceId = ensureTraceId;
5
5
  exports.createFanoutSink = createFanoutSink;
6
6
  exports.formatTerminalEntry = formatTerminalEntry;
7
+ exports.registerSpinnerHooks = registerSpinnerHooks;
7
8
  exports.createTerminalSink = createTerminalSink;
8
9
  exports.createStderrSink = createStderrSink;
10
+ exports.rotateIfNeeded = rotateIfNeeded;
9
11
  exports.createNdjsonFileSink = createNdjsonFileSink;
10
12
  exports.registerGlobalLogSink = registerGlobalLogSink;
11
13
  exports.createLogger = createLogger;
@@ -73,36 +75,94 @@ function formatTerminalEntry(entry) {
73
75
  const level = entry.level.toUpperCase();
74
76
  return `${formatTerminalTime(entry.ts)} ${level} [${entry.component}] ${entry.message}${formatTerminalMeta(entry.meta)}`;
75
77
  }
76
- function createTerminalSink(write = (chunk) => process.stderr.write(chunk), colorize = true) {
78
+ // Spinner coordination: the CLI sense registers these so log output
79
+ // doesn't interleave with the active spinner animation.
80
+ let _pauseSpinner = null;
81
+ let _resumeSpinner = null;
82
+ function registerSpinnerHooks(pause, resume) {
83
+ _pauseSpinner = pause;
84
+ _resumeSpinner = resume;
85
+ }
86
+ function createTerminalSink(write = (chunk) => { try {
87
+ process.stderr.write(chunk);
88
+ }
89
+ catch { /* EPIPE: daemon detached, no terminal */ } }, colorize = true) {
77
90
  return (entry) => {
91
+ _pauseSpinner?.();
78
92
  const line = formatTerminalEntry(entry);
79
93
  if (!colorize) {
80
94
  write(`${line}\n`);
95
+ _resumeSpinner?.();
81
96
  return;
82
97
  }
83
98
  const prefix = LEVEL_COLORS[entry.level];
84
99
  write(`${prefix}${line}\x1b[0m\n`);
100
+ _resumeSpinner?.();
85
101
  };
86
102
  }
87
103
  function createStderrSink(write = (chunk) => process.stderr.write(chunk)) {
88
104
  return createTerminalSink(write);
89
105
  }
90
- function createNdjsonFileSink(filePath) {
106
+ const DEFAULT_MAX_LOG_SIZE_BYTES = 50 * 1024 * 1024; // 50MB
107
+ const ROTATION_CHECK_INTERVAL_BYTES = 1024 * 1024; // ~1MB between stat checks
108
+ /**
109
+ * Rotate a log file: shift .1 -> .2, delete old .2, rename current -> .1.
110
+ * Uses the ndjson extension pattern: file.ndjson -> file.1.ndjson -> file.2.ndjson
111
+ */
112
+ function rotateIfNeeded(filePath, maxSizeBytes) {
113
+ let size;
114
+ try {
115
+ size = (0, fs_1.statSync)(filePath).size;
116
+ }
117
+ catch {
118
+ return false;
119
+ }
120
+ if (size < maxSizeBytes)
121
+ return false;
122
+ const ext = filePath.endsWith(".ndjson") ? ".ndjson" : "";
123
+ const base = ext ? filePath.slice(0, -ext.length) : filePath;
124
+ const file1 = `${base}.1${ext}`;
125
+ const file2 = `${base}.2${ext}`;
126
+ try {
127
+ (0, fs_1.unlinkSync)(file2);
128
+ }
129
+ catch { /* may not exist */ }
130
+ try {
131
+ (0, fs_1.renameSync)(file1, file2);
132
+ }
133
+ catch { /* may not exist */ }
134
+ try {
135
+ (0, fs_1.renameSync)(filePath, file1);
136
+ }
137
+ catch { /* best effort */ }
138
+ return true;
139
+ }
140
+ function createNdjsonFileSink(filePath, maxSizeBytes) {
91
141
  (0, fs_1.mkdirSync)((0, path_1.dirname)(filePath), { recursive: true });
92
142
  const queue = [];
93
143
  let flushing = false;
144
+ let bytesSinceCheck = 0;
145
+ const maxSize = maxSizeBytes ?? DEFAULT_MAX_LOG_SIZE_BYTES;
94
146
  function flush() {
95
147
  if (flushing || queue.length === 0)
96
148
  return;
97
149
  flushing = true;
98
150
  const line = queue.shift();
151
+ /* v8 ignore start — rotation triggers only after ~1MB of writes @preserve */
152
+ if (bytesSinceCheck >= ROTATION_CHECK_INTERVAL_BYTES) {
153
+ bytesSinceCheck = 0;
154
+ rotateIfNeeded(filePath, maxSize);
155
+ }
156
+ /* v8 ignore stop */
99
157
  (0, fs_1.appendFile)(filePath, line, "utf8", () => {
100
158
  flushing = false;
101
159
  flush();
102
160
  });
103
161
  }
104
162
  return (entry) => {
105
- queue.push(`${JSON.stringify(entry)}\n`);
163
+ const line = `${JSON.stringify(entry)}\n`;
164
+ bytesSinceCheck += line.length;
165
+ queue.push(line);
106
166
  flush();
107
167
  };
108
168
  }
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ /**
3
+ * Nerves observation layer — shared typed readers for runtime state.
4
+ *
5
+ * This module re-exports domain types that multiple consumers need
6
+ * (Outlook, CLI, agent tools) so they don't maintain parallel type universes.
7
+ *
8
+ * The Outlook UI consumes these through the HTTP API, but the same
9
+ * observation functions back CLI commands and future native clients.
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ /* v8 ignore start — module-level observability event */
13
+ const runtime_1 = require("./runtime");
14
+ (0, runtime_1.emitNervesEvent)({
15
+ component: "nerves",
16
+ event: "nerves.observation_loaded",
17
+ message: "observation layer loaded",
18
+ meta: {},
19
+ });
20
+ /* v8 ignore stop */
@@ -6,7 +6,11 @@ const index_1 = require("./index");
6
6
  let runtimeLogger = null;
7
7
  function getRuntimeLogger() {
8
8
  if (!runtimeLogger) {
9
- runtimeLogger = (0, index_1.createLogger)({ level: "info" });
9
+ // Default logger has no sinks — events emitted before the real logger is
10
+ // configured (e.g. identity resolution during startup) are silently dropped.
11
+ // This prevents INFO lines from leaking to stderr and interleaving with
12
+ // the CLI spinner when the ouro subprocess hasn't configured its logger yet.
13
+ runtimeLogger = (0, index_1.createLogger)({ level: "info", sinks: [] });
10
14
  }
11
15
  return runtimeLogger;
12
16
  }
@@ -279,6 +279,7 @@ exports.adoSemanticToolDefinitions = [
279
279
  return formatForChannel(items, ctx, organization, project);
280
280
  },
281
281
  integration: "ado",
282
+ summaryKeys: ["organization", "project"],
282
283
  },
283
284
  // -- ado_create_epic --
284
285
  {
@@ -318,6 +319,7 @@ exports.adoSemanticToolDefinitions = [
318
319
  },
319
320
  integration: "ado",
320
321
  confirmationRequired: true,
322
+ summaryKeys: ["organization", "project", "title"],
321
323
  },
322
324
  // -- ado_create_issue --
323
325
  {
@@ -359,6 +361,7 @@ exports.adoSemanticToolDefinitions = [
359
361
  },
360
362
  integration: "ado",
361
363
  confirmationRequired: true,
364
+ summaryKeys: ["organization", "project", "title"],
362
365
  },
363
366
  // -- ado_move_items --
364
367
  {
@@ -413,6 +416,7 @@ exports.adoSemanticToolDefinitions = [
413
416
  },
414
417
  integration: "ado",
415
418
  confirmationRequired: true,
419
+ summaryKeys: ["organization", "project", "workItemIds"],
416
420
  },
417
421
  // -- ado_restructure_backlog --
418
422
  {
@@ -471,6 +475,7 @@ exports.adoSemanticToolDefinitions = [
471
475
  },
472
476
  integration: "ado",
473
477
  confirmationRequired: true,
478
+ summaryKeys: ["organization", "project"],
474
479
  },
475
480
  // -- ado_validate_structure --
476
481
  {
@@ -672,6 +677,7 @@ exports.adoSemanticToolDefinitions = [
672
677
  },
673
678
  integration: "ado",
674
679
  confirmationRequired: true,
680
+ summaryKeys: ["organization", "project"],
675
681
  },
676
682
  // -- ado_detect_orphans --
677
683
  {
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ /**
3
+ * Codex JSONL event parser.
4
+ * Parses typed events from Codex --json output:
5
+ * thread.started, turn.started, turn.completed, item.completed.
6
+ * Maps events to coding session status transitions.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.parseCodexJsonlEvent = parseCodexJsonlEvent;
10
+ const runtime_1 = require("../../nerves/runtime");
11
+ const KNOWN_TYPES = new Set(["thread.started", "turn.started", "turn.completed", "item.completed"]);
12
+ /**
13
+ * Parse a single JSONL line from Codex --json output.
14
+ * Returns null for invalid JSON, empty strings, or unknown event types.
15
+ */
16
+ function parseCodexJsonlEvent(line) {
17
+ const trimmed = line.trim();
18
+ if (trimmed.length === 0)
19
+ return null;
20
+ let parsed;
21
+ try {
22
+ parsed = JSON.parse(trimmed);
23
+ }
24
+ catch {
25
+ (0, runtime_1.emitNervesEvent)({
26
+ component: "repertoire",
27
+ event: "repertoire.codex_jsonl_parse_error",
28
+ message: "failed to parse codex JSONL line",
29
+ meta: { line: trimmed.slice(0, 100) },
30
+ });
31
+ return null;
32
+ }
33
+ const type = parsed.type;
34
+ if (!type || !KNOWN_TYPES.has(type))
35
+ return null;
36
+ const event = {
37
+ type: type,
38
+ threadId: typeof parsed.thread_id === "string" ? parsed.thread_id : undefined,
39
+ turnId: typeof parsed.turn_id === "string" ? parsed.turn_id : undefined,
40
+ item: typeof parsed.item === "object" && parsed.item !== null ? parsed.item : undefined,
41
+ raw: parsed,
42
+ statusHint: mapStatusHint(type),
43
+ };
44
+ (0, runtime_1.emitNervesEvent)({
45
+ component: "repertoire",
46
+ event: "repertoire.codex_jsonl_event",
47
+ message: "parsed codex JSONL event",
48
+ meta: { type, threadId: event.threadId ?? null },
49
+ });
50
+ return event;
51
+ }
52
+ function mapStatusHint(type) {
53
+ switch (type) {
54
+ case "thread.started":
55
+ case "turn.started":
56
+ return "running";
57
+ case "turn.completed":
58
+ case "item.completed":
59
+ return null; // No automatic status change for completion events
60
+ /* v8 ignore next -- defensive default for unknown event types */
61
+ default:
62
+ return null;
63
+ }
64
+ }