@ouro.bot/cli 0.1.0-alpha.3 → 0.1.0-alpha.300

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 (289) hide show
  1. package/README.md +188 -190
  2. package/SerpentGuide.ouro/agent.json +82 -0
  3. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +6 -3
  4. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +2 -2
  5. package/SerpentGuide.ouro/psyche/identities/python.md +31 -0
  6. package/assets/ouroboros.png +0 -0
  7. package/changelog.json +1888 -0
  8. package/dist/arc/attention-types.js +8 -0
  9. package/dist/arc/cares.js +140 -0
  10. package/dist/arc/episodes.js +117 -0
  11. package/dist/arc/intentions.js +133 -0
  12. package/dist/arc/json-store.js +117 -0
  13. package/dist/arc/obligations.js +237 -0
  14. package/dist/arc/packets.js +203 -0
  15. package/dist/arc/presence.js +185 -0
  16. package/dist/heart/active-work.js +832 -0
  17. package/dist/heart/agent-entry.js +37 -2
  18. package/dist/heart/attachments/image-normalize.js +194 -0
  19. package/dist/heart/attachments/materialize.js +230 -0
  20. package/dist/heart/attachments/render.js +29 -0
  21. package/dist/heart/attachments/store.js +103 -0
  22. package/dist/heart/attachments/types.js +138 -0
  23. package/dist/heart/auth/auth-flow.js +456 -0
  24. package/dist/heart/bridges/manager.js +358 -0
  25. package/dist/heart/bridges/state-machine.js +135 -0
  26. package/dist/heart/bridges/store.js +123 -0
  27. package/dist/heart/bundle-state.js +168 -0
  28. package/dist/heart/commitments.js +111 -0
  29. package/dist/heart/config-registry.js +304 -0
  30. package/dist/heart/config.js +123 -28
  31. package/dist/heart/core.js +738 -191
  32. package/dist/heart/cross-chat-delivery.js +131 -0
  33. package/dist/heart/daemon/agent-config-check.js +149 -0
  34. package/dist/heart/daemon/agent-discovery.js +157 -0
  35. package/dist/heart/daemon/agent-service.js +360 -0
  36. package/dist/heart/daemon/cadence.js +70 -0
  37. package/dist/heart/daemon/cli-defaults.js +574 -0
  38. package/dist/heart/daemon/cli-exec.js +1945 -0
  39. package/dist/heart/daemon/cli-parse.js +808 -0
  40. package/dist/heart/daemon/cli-render.js +503 -0
  41. package/dist/heart/daemon/cli-types.js +8 -0
  42. package/dist/heart/daemon/daemon-cli.js +29 -673
  43. package/dist/heart/daemon/daemon-entry.js +259 -8
  44. package/dist/heart/daemon/daemon-health.js +136 -0
  45. package/dist/heart/daemon/daemon-runtime-sync.js +231 -0
  46. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  47. package/dist/heart/daemon/daemon.js +745 -18
  48. package/dist/heart/daemon/health-monitor.js +38 -0
  49. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  50. package/dist/heart/daemon/hooks/bundle-meta.js +206 -0
  51. package/dist/heart/daemon/inner-status.js +89 -0
  52. package/dist/heart/daemon/launchd.js +171 -0
  53. package/dist/heart/daemon/log-tailer.js +82 -12
  54. package/dist/heart/daemon/logs-prune.js +105 -0
  55. package/dist/heart/daemon/message-router.js +17 -8
  56. package/dist/heart/daemon/os-cron-deps.js +134 -0
  57. package/dist/heart/daemon/ouro-bot-entry.js +1 -1
  58. package/dist/heart/daemon/process-manager.js +181 -1
  59. package/dist/heart/daemon/pulse.js +463 -0
  60. package/dist/heart/daemon/run-hooks.js +39 -0
  61. package/dist/heart/daemon/runtime-logging.js +70 -15
  62. package/dist/heart/daemon/runtime-metadata.js +219 -0
  63. package/dist/heart/daemon/runtime-mode.js +67 -0
  64. package/dist/heart/daemon/safe-mode.js +161 -0
  65. package/dist/heart/daemon/sense-manager.js +335 -0
  66. package/dist/heart/daemon/session-id-resolver.js +131 -0
  67. package/dist/heart/daemon/skill-management-installer.js +94 -0
  68. package/dist/heart/daemon/socket-client.js +307 -0
  69. package/dist/heart/daemon/task-scheduler.js +3 -25
  70. package/dist/heart/daemon/thoughts.js +510 -0
  71. package/dist/heart/delegation.js +62 -0
  72. package/dist/heart/habits/habit-migration.js +181 -0
  73. package/dist/heart/habits/habit-parser.js +140 -0
  74. package/dist/heart/habits/habit-scheduler.js +371 -0
  75. package/dist/heart/hatch/hatch-animation.js +35 -0
  76. package/dist/heart/{daemon → hatch}/hatch-flow.js +31 -130
  77. package/dist/heart/{daemon → hatch}/hatch-specialist.js +7 -2
  78. package/dist/heart/hatch/specialist-orchestrator.js +129 -0
  79. package/dist/heart/hatch/specialist-prompt.js +101 -0
  80. package/dist/heart/hatch/specialist-tools.js +283 -0
  81. package/dist/heart/identity.js +241 -54
  82. package/dist/heart/kicks.js +2 -20
  83. package/dist/heart/mcp/mcp-server.js +653 -0
  84. package/dist/heart/migrate-config.js +127 -0
  85. package/dist/heart/model-capabilities.js +59 -0
  86. package/dist/heart/outlook/outlook-http.js +439 -0
  87. package/dist/heart/outlook/outlook-read.js +1618 -0
  88. package/dist/heart/outlook/outlook-render.js +1032 -0
  89. package/dist/heart/outlook/outlook-types.js +7 -0
  90. package/dist/heart/outlook/outlook-view.js +194 -0
  91. package/dist/heart/progress-story.js +42 -0
  92. package/dist/heart/provider-failover.js +88 -0
  93. package/dist/heart/provider-ping.js +162 -0
  94. package/dist/heart/providers/anthropic-token.js +163 -0
  95. package/dist/heart/providers/anthropic.js +181 -41
  96. package/dist/heart/providers/azure.js +98 -11
  97. package/dist/heart/providers/error-classification.js +63 -0
  98. package/dist/heart/providers/github-copilot.js +136 -0
  99. package/dist/heart/providers/minimax-vlm.js +189 -0
  100. package/dist/heart/providers/minimax.js +23 -5
  101. package/dist/heart/providers/openai-codex.js +33 -22
  102. package/dist/heart/sense-truth.js +61 -0
  103. package/dist/heart/session-activity.js +172 -0
  104. package/dist/heart/session-recall.js +216 -0
  105. package/dist/heart/start-of-turn-packet.js +339 -0
  106. package/dist/heart/streaming.js +120 -33
  107. package/dist/heart/sync.js +332 -0
  108. package/dist/heart/target-resolution.js +127 -0
  109. package/dist/heart/tempo.js +93 -0
  110. package/dist/heart/temporal-view.js +41 -0
  111. package/dist/heart/tool-activity-callbacks.js +36 -0
  112. package/dist/heart/tool-description.js +135 -0
  113. package/dist/heart/tool-friction.js +55 -0
  114. package/dist/heart/tool-loop.js +200 -0
  115. package/dist/heart/turn-context.js +358 -0
  116. package/dist/heart/turn-coordinator.js +28 -0
  117. package/dist/heart/versioning/ouro-bot-global-installer.js +128 -0
  118. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +5 -4
  119. package/dist/heart/versioning/ouro-path-installer.js +221 -0
  120. package/dist/heart/{daemon → versioning}/ouro-uti.js +11 -2
  121. package/dist/heart/versioning/ouro-version-manager.js +295 -0
  122. package/dist/heart/versioning/staged-restart.js +146 -0
  123. package/dist/heart/versioning/update-checker.js +113 -0
  124. package/dist/heart/versioning/update-hooks.js +142 -0
  125. package/dist/heart/versioning/wrapper-publish-guard.js +86 -0
  126. package/dist/mind/associative-recall.js +135 -66
  127. package/dist/mind/bundle-manifest.js +77 -1
  128. package/dist/mind/context.js +125 -14
  129. package/dist/mind/diary-integrity.js +60 -0
  130. package/dist/mind/{memory.js → diary.js} +84 -96
  131. package/dist/mind/embedding-provider.js +60 -0
  132. package/dist/mind/file-state.js +179 -0
  133. package/dist/mind/first-impressions.js +16 -2
  134. package/dist/mind/friends/channel.js +64 -0
  135. package/dist/mind/friends/group-context.js +144 -0
  136. package/dist/mind/friends/resolver.js +37 -0
  137. package/dist/mind/friends/store-file.js +58 -3
  138. package/dist/mind/friends/trust-explanation.js +74 -0
  139. package/dist/mind/friends/types.js +9 -1
  140. package/dist/mind/journal-index.js +161 -0
  141. package/dist/mind/obligation-steering.js +221 -0
  142. package/dist/mind/pending.js +76 -9
  143. package/dist/mind/phrases.js +1 -0
  144. package/dist/mind/prompt.js +1011 -107
  145. package/dist/mind/scrutiny.js +173 -0
  146. package/dist/mind/token-estimate.js +8 -12
  147. package/dist/nerves/cli-logging.js +22 -3
  148. package/dist/nerves/coverage/audit.js +1 -1
  149. package/dist/nerves/coverage/file-completeness.js +59 -5
  150. package/dist/nerves/coverage/run-artifacts.js +1 -1
  151. package/dist/nerves/event-buffer.js +111 -0
  152. package/dist/nerves/index.js +224 -4
  153. package/dist/nerves/observation.js +20 -0
  154. package/dist/nerves/redact.js +79 -0
  155. package/dist/nerves/runtime.js +5 -1
  156. package/dist/outlook-ui/assets/index-Ck8agNeO.js +61 -0
  157. package/dist/outlook-ui/assets/index-LwChZTgL.css +1 -0
  158. package/dist/outlook-ui/index.html +15 -0
  159. package/dist/repertoire/ado-client.js +17 -56
  160. package/dist/repertoire/ado-semantic.js +11 -10
  161. package/dist/repertoire/api-client.js +97 -0
  162. package/dist/repertoire/bitwarden-store.js +319 -0
  163. package/dist/repertoire/bundle-templates.js +72 -0
  164. package/dist/repertoire/bw-installer.js +79 -0
  165. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  166. package/dist/repertoire/coding/context-pack.js +330 -0
  167. package/dist/repertoire/coding/feedback.js +301 -0
  168. package/dist/repertoire/coding/index.js +4 -1
  169. package/dist/repertoire/coding/manager.js +220 -13
  170. package/dist/repertoire/coding/spawner.js +58 -12
  171. package/dist/repertoire/coding/tools.js +209 -7
  172. package/dist/repertoire/commerce-errors.js +109 -0
  173. package/dist/repertoire/commerce-self-test.js +156 -0
  174. package/dist/repertoire/credential-access.js +527 -0
  175. package/dist/repertoire/data/ado-endpoints.json +188 -0
  176. package/dist/repertoire/duffel-client.js +185 -0
  177. package/dist/repertoire/github-client.js +14 -55
  178. package/dist/repertoire/graph-client.js +11 -52
  179. package/dist/repertoire/guardrails.js +375 -0
  180. package/dist/repertoire/mcp-client.js +255 -0
  181. package/dist/repertoire/mcp-manager.js +305 -0
  182. package/dist/repertoire/mcp-tools.js +63 -0
  183. package/dist/repertoire/shell-sessions.js +133 -0
  184. package/dist/repertoire/skills.js +14 -23
  185. package/dist/repertoire/stripe-client.js +131 -0
  186. package/dist/repertoire/tasks/board.js +43 -5
  187. package/dist/repertoire/tasks/fix.js +182 -0
  188. package/dist/repertoire/tasks/index.js +28 -10
  189. package/dist/repertoire/tasks/lifecycle.js +2 -2
  190. package/dist/repertoire/tasks/parser.js +3 -2
  191. package/dist/repertoire/tasks/scanner.js +194 -37
  192. package/dist/repertoire/tasks/transitions.js +11 -28
  193. package/dist/repertoire/tool-results.js +29 -0
  194. package/dist/repertoire/tools-attachments.js +316 -0
  195. package/dist/repertoire/tools-base.js +45 -707
  196. package/dist/repertoire/tools-bluebubbles.js +94 -0
  197. package/dist/repertoire/tools-bridge.js +141 -0
  198. package/dist/repertoire/tools-bundle.js +984 -0
  199. package/dist/repertoire/tools-config.js +185 -0
  200. package/dist/repertoire/tools-continuity.js +248 -0
  201. package/dist/repertoire/tools-credential.js +182 -0
  202. package/dist/repertoire/tools-files.js +342 -0
  203. package/dist/repertoire/tools-flight.js +224 -0
  204. package/dist/repertoire/tools-flow.js +105 -0
  205. package/dist/repertoire/tools-github.js +1 -7
  206. package/dist/repertoire/tools-memory.js +374 -0
  207. package/dist/repertoire/tools-session.js +739 -0
  208. package/dist/repertoire/tools-shell.js +120 -0
  209. package/dist/repertoire/tools-stripe.js +180 -0
  210. package/dist/repertoire/tools-surface.js +243 -0
  211. package/dist/repertoire/tools-teams.js +64 -61
  212. package/dist/repertoire/tools-travel.js +125 -0
  213. package/dist/repertoire/tools-user-profile.js +144 -0
  214. package/dist/repertoire/tools-vault.js +110 -0
  215. package/dist/repertoire/tools.js +149 -98
  216. package/dist/repertoire/travel-api-client.js +360 -0
  217. package/dist/repertoire/user-profile.js +118 -0
  218. package/dist/repertoire/vault-setup.js +241 -0
  219. package/dist/scripts/claude-code-hook.js +41 -0
  220. package/dist/scripts/claude-code-stop-hook.js +47 -0
  221. package/dist/senses/attention-queue.js +116 -0
  222. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  223. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  224. package/dist/senses/bluebubbles/client.js +568 -0
  225. package/dist/senses/bluebubbles/entry.js +13 -0
  226. package/dist/senses/bluebubbles/inbound-log.js +113 -0
  227. package/dist/senses/bluebubbles/index.js +1427 -0
  228. package/dist/senses/bluebubbles/media.js +390 -0
  229. package/dist/senses/bluebubbles/model.js +282 -0
  230. package/dist/senses/bluebubbles/mutation-log.js +116 -0
  231. package/dist/senses/bluebubbles/replay.js +129 -0
  232. package/dist/senses/bluebubbles/runtime-state.js +109 -0
  233. package/dist/senses/bluebubbles/session-cleanup.js +72 -0
  234. package/dist/senses/cli/bracketed-paste.js +82 -0
  235. package/dist/senses/cli/image-paste.js +287 -0
  236. package/dist/senses/cli/image-ref-navigation.js +75 -0
  237. package/dist/senses/cli/ink-app.js +156 -0
  238. package/dist/senses/cli/inline-diff.js +64 -0
  239. package/dist/senses/cli/input-keys.js +174 -0
  240. package/dist/senses/cli/kill-ring.js +86 -0
  241. package/dist/senses/cli/message-list.js +51 -0
  242. package/dist/senses/cli/ouro-tui.js +595 -0
  243. package/dist/senses/cli/spinner-imperative.js +135 -0
  244. package/dist/senses/cli/spinner.js +101 -0
  245. package/dist/senses/cli/status-line.js +60 -0
  246. package/dist/senses/cli/streaming-markdown.js +526 -0
  247. package/dist/senses/cli/tool-display.js +83 -0
  248. package/dist/senses/cli/tool-render.js +85 -0
  249. package/dist/senses/cli/tui-store.js +240 -0
  250. package/dist/senses/cli/virtual-list.js +35 -0
  251. package/dist/senses/cli-entry.js +1 -1
  252. package/dist/senses/cli-layout.js +187 -0
  253. package/dist/senses/cli.js +772 -264
  254. package/dist/senses/commands.js +65 -1
  255. package/dist/senses/continuity.js +94 -0
  256. package/dist/senses/habit-turn-message.js +108 -0
  257. package/dist/senses/inner-dialog-worker.js +112 -19
  258. package/dist/senses/inner-dialog.js +633 -86
  259. package/dist/senses/pipeline.js +560 -0
  260. package/dist/senses/shared-turn.js +195 -0
  261. package/dist/senses/surface-tool.js +68 -0
  262. package/dist/senses/teams.js +814 -196
  263. package/dist/senses/trust-gate.js +112 -2
  264. package/package.json +25 -9
  265. package/skills/agent-commerce.md +106 -0
  266. package/skills/browser-navigation.md +110 -0
  267. package/skills/commerce-setup-guide.md +116 -0
  268. package/skills/commerce-setup.md +84 -0
  269. package/skills/configure-dev-tools.md +81 -0
  270. package/skills/travel-planning.md +138 -0
  271. package/AdoptionSpecialist.ouro/agent.json +0 -20
  272. package/AdoptionSpecialist.ouro/psyche/identities/python.md +0 -1
  273. package/dist/heart/daemon/subagent-installer.js +0 -125
  274. package/dist/inner-worker-entry.js +0 -4
  275. package/subagents/README.md +0 -73
  276. package/subagents/work-doer.md +0 -233
  277. package/subagents/work-merger.md +0 -624
  278. package/subagents/work-planner.md +0 -373
  279. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  280. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  281. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  282. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  283. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  284. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  285. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  286. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  287. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  288. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +0 -0
  289. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
@@ -0,0 +1,339 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.buildCapabilitiesSection = buildCapabilitiesSection;
37
+ exports.buildStartOfTurnPacket = buildStartOfTurnPacket;
38
+ exports.renderStartOfTurnPacket = renderStartOfTurnPacket;
39
+ exports.renderCompactStartOfTurnPacket = renderCompactStartOfTurnPacket;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const runtime_1 = require("../nerves/runtime");
43
+ const bundle_state_1 = require("./bundle-state");
44
+ const tempo_1 = require("./tempo");
45
+ function estimateTokens(text) {
46
+ return Math.ceil(text.length / 4);
47
+ }
48
+ // --- Section builders (pure derivation from authored data, no embellishment) ---
49
+ function buildPlotLine(episodes, tempo) {
50
+ if (episodes.length === 0)
51
+ return "";
52
+ const limit = tempo === "crisis" ? 3 : tempo === "brief" ? 2 : 5;
53
+ const selected = episodes.slice(0, limit);
54
+ const lines = selected.map((ep) => {
55
+ const parts = [`- ${ep.summary}`];
56
+ if (ep.whyItMattered && tempo !== "brief") {
57
+ parts[0] += ` (${ep.whyItMattered})`;
58
+ }
59
+ return parts[0];
60
+ });
61
+ return lines.join("\n");
62
+ }
63
+ function buildObligationsSection(obligations) {
64
+ if (obligations.length === 0)
65
+ return "";
66
+ return obligations
67
+ .map((ob) => {
68
+ const parts = [`- ${ob.content}`];
69
+ if (ob.meaning?.resumeHint) {
70
+ parts.push(` [hint: ${ob.meaning.resumeHint}]`);
71
+ }
72
+ if (ob.meaning?.stalenessClass && ob.meaning.stalenessClass !== "fresh") {
73
+ parts.push(` (${ob.meaning.stalenessClass})`);
74
+ }
75
+ if (ob.meaning?.waitingOn) {
76
+ parts.push(` waiting on ${ob.meaning.waitingOn.kind}: ${ob.meaning.waitingOn.target}`);
77
+ }
78
+ return parts.join("");
79
+ })
80
+ .join("\n");
81
+ }
82
+ function buildCaresSection(cares) {
83
+ if (cares.length === 0)
84
+ return "";
85
+ return cares
86
+ .map((c) => {
87
+ const parts = [`- ${c.label}`];
88
+ if (c.salience !== "low") {
89
+ parts.push(` [${c.salience}]`);
90
+ }
91
+ if (c.currentRisk) {
92
+ parts.push(` risk: ${c.currentRisk}`);
93
+ }
94
+ return parts.join("");
95
+ })
96
+ .join("\n");
97
+ }
98
+ function buildPresenceSection(peers) {
99
+ if (peers.length === 0)
100
+ return "";
101
+ return peers
102
+ .map((p) => `- ${p.agentName}: ${p.availability}/${p.lane}`)
103
+ .join("\n");
104
+ }
105
+ function buildResumeHint(view, obligations) {
106
+ // Compose from authored obligation resumeHints and top intentions
107
+ const hints = [];
108
+ const effectiveObligations = obligations ?? view.activeObligations;
109
+ for (const ob of effectiveObligations) {
110
+ if (ob.meaning?.resumeHint) {
111
+ hints.push(ob.meaning.resumeHint);
112
+ }
113
+ }
114
+ for (const intent of view.openIntentions.slice(0, 3)) {
115
+ hints.push(intent.content);
116
+ }
117
+ if (hints.length === 0) {
118
+ // Fall back to top obligation content
119
+ if (effectiveObligations.length > 0) {
120
+ hints.push(effectiveObligations[0].content);
121
+ }
122
+ }
123
+ if (hints.length === 0)
124
+ return "";
125
+ return hints.join("; ");
126
+ }
127
+ /**
128
+ * Build a compact summary of capability changes between runtime versions.
129
+ * Reads bundle-meta.json for version info and changelog.json for change descriptions.
130
+ * Returns undefined if no version change detected or files are missing/malformed.
131
+ */
132
+ function buildCapabilitiesSection(bundleRoot) {
133
+ let meta;
134
+ try {
135
+ const raw = fs.readFileSync(path.join(bundleRoot, "bundle-meta.json"), "utf-8");
136
+ meta = JSON.parse(raw);
137
+ }
138
+ catch {
139
+ (0, runtime_1.emitNervesEvent)({
140
+ component: "heart",
141
+ event: "heart.capabilities_check",
142
+ message: "bundle-meta.json missing or malformed",
143
+ meta: { bundleRoot },
144
+ });
145
+ return undefined;
146
+ }
147
+ const currentVersion = meta.runtimeVersion;
148
+ const previousVersion = meta.previousRuntimeVersion;
149
+ if (typeof currentVersion !== "string" || typeof previousVersion !== "string") {
150
+ return undefined;
151
+ }
152
+ if (currentVersion === previousVersion) {
153
+ return undefined;
154
+ }
155
+ (0, runtime_1.emitNervesEvent)({
156
+ component: "heart",
157
+ event: "heart.capabilities_version_change",
158
+ message: `runtime version changed from ${previousVersion} to ${currentVersion}`,
159
+ meta: { previousVersion, currentVersion },
160
+ });
161
+ let changelog;
162
+ try {
163
+ const raw = fs.readFileSync(path.join(bundleRoot, "changelog.json"), "utf-8");
164
+ changelog = JSON.parse(raw);
165
+ }
166
+ catch {
167
+ // changelog missing -- still report the version change
168
+ }
169
+ const parts = [`Updated from ${previousVersion} to ${currentVersion}`];
170
+ if (changelog && Array.isArray(changelog)) {
171
+ const relevantChanges = [];
172
+ for (const entry of changelog) {
173
+ if (entry.version === previousVersion)
174
+ break;
175
+ if (Array.isArray(entry.changes)) {
176
+ relevantChanges.push(...entry.changes);
177
+ }
178
+ }
179
+ if (relevantChanges.length > 0) {
180
+ parts.push(`: ${relevantChanges.join("; ")}`);
181
+ }
182
+ }
183
+ return parts.join("");
184
+ }
185
+ function buildStartOfTurnPacket(view, opts) {
186
+ const tempo = view.tempo;
187
+ const tokenBudget = tempo_1.TEMPO_BUDGETS[tempo];
188
+ const effectiveObligations = opts?.canonicalObligations ? opts.canonicalObligations.all : view.activeObligations;
189
+ const packet = {
190
+ plotLine: buildPlotLine(view.recentEpisodes, tempo),
191
+ obligations: buildObligationsSection(effectiveObligations),
192
+ cares: buildCaresSection(view.activeCares),
193
+ presence: buildPresenceSection(view.peerPresence),
194
+ resumeHint: buildResumeHint(view, opts?.canonicalObligations ? effectiveObligations : undefined),
195
+ tempo,
196
+ tokenBudget,
197
+ assembledAt: new Date().toISOString(),
198
+ };
199
+ (0, runtime_1.emitNervesEvent)({
200
+ component: "heart",
201
+ event: "heart.start_of_turn_packet_built",
202
+ message: `start-of-turn packet built: tempo=${tempo}`,
203
+ meta: {
204
+ tempo,
205
+ plotLineTokens: estimateTokens(packet.plotLine),
206
+ obligationsTokens: estimateTokens(packet.obligations),
207
+ caresTokens: estimateTokens(packet.cares),
208
+ presenceTokens: estimateTokens(packet.presence),
209
+ resumeHintTokens: estimateTokens(packet.resumeHint),
210
+ },
211
+ });
212
+ return packet;
213
+ }
214
+ /**
215
+ * Renders a start-of-turn packet to prompt text, respecting token budget.
216
+ * Truncation priority (last truncated first):
217
+ * resumeHint (PROTECTED) > obligations > cares > plotLine > presence
218
+ * So presence is truncated first, then plotLine, then cares, then obligations.
219
+ * resumeHint is never truncated.
220
+ */
221
+ function renderStartOfTurnPacket(packet) {
222
+ const budget = packet.tokenBudget;
223
+ // Assemble sections in priority order (highest priority first for budget allocation)
224
+ // Each section is { label, content, priority } where lower priority number = truncated first
225
+ const sections = [
226
+ // bundleState and syncFailure share the top remediation tier — both
227
+ // are actionable "fix your git" signals. bundleState is preferred
228
+ // because it's structured (array of enum values) while syncFailure is
229
+ // a legacy free-form string; both render when populated.
230
+ { label: "bundleState", content: (0, bundle_state_1.renderBundleStateHint)(packet.bundleState ?? []), priority: 7 },
231
+ { label: "syncFailure", content: packet.syncFailure ?? "", priority: 7 },
232
+ { label: "resume", content: packet.resumeHint, priority: 6 },
233
+ { label: "obligations", content: packet.obligations, priority: 5 },
234
+ { label: "cares", content: packet.cares, priority: 4 },
235
+ { label: "plot", content: packet.plotLine, priority: 3 },
236
+ { label: "capabilities", content: packet.capabilities ?? "", priority: 2 },
237
+ { label: "presence", content: packet.presence, priority: 1 },
238
+ ].filter((s) => s.content.length > 0);
239
+ if (sections.length === 0) {
240
+ (0, runtime_1.emitNervesEvent)({
241
+ component: "heart",
242
+ event: "heart.start_of_turn_packet_rendered",
243
+ message: "start-of-turn packet rendered: empty",
244
+ meta: { tokens: 0, tempo: packet.tempo },
245
+ });
246
+ return "";
247
+ }
248
+ // Build the rendered output, truncating lower-priority sections first
249
+ let rendered = formatSections(sections);
250
+ let tokens = estimateTokens(rendered);
251
+ // Truncate sections from lowest priority until we fit budget
252
+ const sortedByPriority = [...sections].sort((a, b) => a.priority - b.priority);
253
+ for (const section of sortedByPriority) {
254
+ if (tokens <= budget.max)
255
+ break;
256
+ // Skip resumeHint — it's PROTECTED
257
+ if (section.label === "resume")
258
+ continue;
259
+ // Remove this section entirely
260
+ const idx = sections.findIndex((s) => s.label === section.label);
261
+ sections.splice(idx, 1);
262
+ rendered = formatSections(sections);
263
+ tokens = estimateTokens(rendered);
264
+ }
265
+ // If still over budget after removing all non-protected sections, trim what's left
266
+ if (tokens > budget.max) {
267
+ const maxChars = budget.max * 4;
268
+ rendered = rendered.slice(0, maxChars);
269
+ }
270
+ (0, runtime_1.emitNervesEvent)({
271
+ component: "heart",
272
+ event: "heart.start_of_turn_packet_rendered",
273
+ message: `start-of-turn packet rendered: ${tokens} tokens`,
274
+ meta: { tokens, tempo: packet.tempo, sectionCount: sections.length },
275
+ });
276
+ return rendered;
277
+ }
278
+ function formatSections(sections) {
279
+ const parts = [];
280
+ for (const section of sections) {
281
+ switch (section.label) {
282
+ case "resume":
283
+ parts.push(`**Next:** ${section.content}`);
284
+ break;
285
+ case "obligations":
286
+ parts.push(`**Owed:**\n${section.content}`);
287
+ break;
288
+ case "cares":
289
+ parts.push(`**Cares:**\n${section.content}`);
290
+ break;
291
+ case "plot":
292
+ parts.push(`**Recent:**\n${section.content}`);
293
+ break;
294
+ case "presence":
295
+ parts.push(`**Peers:**\n${section.content}`);
296
+ break;
297
+ case "capabilities":
298
+ parts.push(`**Capabilities:** ${section.content}`);
299
+ break;
300
+ case "syncFailure":
301
+ parts.push(`**Sync warning:** ${section.content}`);
302
+ break;
303
+ case "bundleState":
304
+ parts.push(`**Bundle:** ${section.content}`);
305
+ break;
306
+ }
307
+ }
308
+ return parts.join("\n\n");
309
+ }
310
+ /**
311
+ * Ultra-compact version for coding context (max 200 tokens).
312
+ * Just resumeHint + top obligation + top care, single-line bullets.
313
+ */
314
+ function renderCompactStartOfTurnPacket(packet) {
315
+ const parts = [];
316
+ if (packet.resumeHint) {
317
+ parts.push(`next: ${packet.resumeHint}`);
318
+ }
319
+ if (packet.obligations) {
320
+ // Just first line of obligations
321
+ const firstOb = packet.obligations.split("\n")[0];
322
+ parts.push(`owed: ${firstOb.replace(/^- /, "")}`);
323
+ }
324
+ if (packet.cares) {
325
+ const firstCare = packet.cares.split("\n")[0];
326
+ parts.push(`care: ${firstCare.replace(/^- /, "")}`);
327
+ }
328
+ const compact = parts.join(" | ");
329
+ // Hard cap at 200 tokens (800 chars)
330
+ const maxChars = 200 * 4;
331
+ const result = compact.length > maxChars ? compact.slice(0, maxChars) : compact;
332
+ (0, runtime_1.emitNervesEvent)({
333
+ component: "heart",
334
+ event: "heart.start_of_turn_packet_compact_rendered",
335
+ message: `compact start-of-turn packet: ${estimateTokens(result)} tokens`,
336
+ meta: { tokens: estimateTokens(result) },
337
+ });
338
+ return result;
339
+ }
@@ -1,16 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.FinalAnswerParser = void 0;
3
+ exports.SettleStreamer = exports.SettleParser = void 0;
4
4
  exports.toResponsesInput = toResponsesInput;
5
5
  exports.toResponsesTools = toResponsesTools;
6
6
  exports.streamChatCompletion = streamChatCompletion;
7
7
  exports.streamResponsesApi = streamResponsesApi;
8
8
  const runtime_1 = require("../nerves/runtime");
9
9
  // Character-level state machine that extracts the answer value from
10
- // `final_answer` tool call JSON arguments as they stream in.
10
+ // `settle` tool call JSON arguments as they stream in.
11
11
  // Scans for prefix `"answer":"` or `"answer": "` in the character stream,
12
12
  // then emits text handling JSON escapes, stopping at unescaped closing `"`.
13
- class FinalAnswerParser {
13
+ class SettleParser {
14
14
  // Possible prefixes to match (with and without space after colon)
15
15
  static PREFIXES = ['"answer":"', '"answer": "'];
16
16
  // Buffer of characters seen so far (pre-activation only)
@@ -29,7 +29,7 @@ class FinalAnswerParser {
29
29
  if (!this._active) {
30
30
  this.buf += ch;
31
31
  // Check if any prefix has been fully matched in the buffer
32
- for (const prefix of FinalAnswerParser.PREFIXES) {
32
+ for (const prefix of SettleParser.PREFIXES) {
33
33
  if (this.buf.endsWith(prefix)) {
34
34
  this._active = true;
35
35
  break;
@@ -76,7 +76,96 @@ class FinalAnswerParser {
76
76
  return out;
77
77
  }
78
78
  }
79
- exports.FinalAnswerParser = FinalAnswerParser;
79
+ exports.SettleParser = SettleParser;
80
+ // Shared helper: wraps SettleParser with onClearText + onTextChunk wiring.
81
+ // Used by all streaming providers (Chat Completions, Responses API, Anthropic)
82
+ // so the eager-match settle streaming pattern lives in one place.
83
+ class SettleStreamer {
84
+ parser = new SettleParser();
85
+ _detected = false;
86
+ callbacks;
87
+ enabled;
88
+ constructor(callbacks, enabled = true) {
89
+ this.callbacks = callbacks;
90
+ this.enabled = enabled;
91
+ }
92
+ get detected() { return this._detected; }
93
+ get streamed() { return this.parser.active; }
94
+ /** Mark settle as detected. Calls onClearText on the callbacks. */
95
+ activate() {
96
+ if (!this.enabled)
97
+ return;
98
+ if (this._detected)
99
+ return;
100
+ this._detected = true;
101
+ this.callbacks.onClearText?.();
102
+ }
103
+ /** Feed an argument delta through the parser. Emits text via onTextChunk. */
104
+ processDelta(delta) {
105
+ if (!this.enabled)
106
+ return;
107
+ if (!this._detected)
108
+ return;
109
+ const text = this.parser.process(delta);
110
+ if (text)
111
+ this.callbacks.onTextChunk(text);
112
+ }
113
+ }
114
+ exports.SettleStreamer = SettleStreamer;
115
+ function toResponsesUserContent(content) {
116
+ if (typeof content === "string") {
117
+ return content;
118
+ }
119
+ if (!Array.isArray(content)) {
120
+ return "";
121
+ }
122
+ const parts = [];
123
+ for (const part of content) {
124
+ if (!part || typeof part !== "object") {
125
+ continue;
126
+ }
127
+ if (part.type === "text" && typeof part.text === "string") {
128
+ parts.push({ type: "input_text", text: part.text });
129
+ continue;
130
+ }
131
+ if (part.type === "image_url") {
132
+ const imageUrl = typeof part.image_url?.url === "string" ? part.image_url.url : "";
133
+ if (!imageUrl)
134
+ continue;
135
+ parts.push({
136
+ type: "input_image",
137
+ image_url: imageUrl,
138
+ detail: part.image_url?.detail ?? "auto",
139
+ });
140
+ continue;
141
+ }
142
+ if (part.type === "input_audio" &&
143
+ typeof part.input_audio?.data === "string" &&
144
+ (part.input_audio.format === "mp3" || part.input_audio.format === "wav")) {
145
+ parts.push({
146
+ type: "input_audio",
147
+ input_audio: {
148
+ data: part.input_audio.data,
149
+ format: part.input_audio.format,
150
+ },
151
+ });
152
+ continue;
153
+ }
154
+ if (part.type === "file") {
155
+ const fileRecord = { type: "input_file" };
156
+ if (typeof part.file?.file_data === "string")
157
+ fileRecord.file_data = part.file.file_data;
158
+ if (typeof part.file?.file_id === "string")
159
+ fileRecord.file_id = part.file.file_id;
160
+ if (typeof part.file?.filename === "string")
161
+ fileRecord.filename = part.file.filename;
162
+ if (typeof part.file?.file_data === "string" || typeof part.file?.file_id === "string") {
163
+ parts.push(fileRecord);
164
+ }
165
+ }
166
+ }
167
+ return parts.length > 0 ? parts : "";
168
+ }
80
169
  function toResponsesInput(messages) {
81
170
  let instructions = "";
82
171
  const input = [];
@@ -90,7 +179,7 @@ function toResponsesInput(messages) {
90
179
  }
91
180
  if (msg.role === "user") {
92
181
  const u = msg;
93
- input.push({ role: "user", content: typeof u.content === "string" ? u.content : "" });
182
+ input.push({ role: "user", content: toResponsesUserContent(u.content) });
94
183
  continue;
95
184
  }
96
185
  if (msg.role === "assistant") {
@@ -102,10 +191,16 @@ function toResponsesInput(messages) {
102
191
  }
103
192
  }
104
193
  if (a.content) {
105
- input.push({ role: "assistant", content: typeof a.content === "string" ? a.content : "" });
194
+ const assistantItem = { role: "assistant", content: typeof a.content === "string" ? a.content : "" };
195
+ if (a.phase)
196
+ assistantItem.phase = a.phase;
197
+ input.push(assistantItem);
106
198
  }
107
199
  if (a.tool_calls) {
108
200
  for (const tc of a.tool_calls) {
201
+ /* v8 ignore next -- type narrowing: OpenAI SDK only emits function tool_calls @preserve */
202
+ if (tc.type !== "function")
203
+ continue;
109
204
  input.push({
110
205
  type: "function_call",
111
206
  call_id: tc.id,
@@ -138,7 +233,7 @@ function toResponsesTools(ccTools) {
138
233
  strict: false,
139
234
  }));
140
235
  }
141
- async function streamChatCompletion(client, createParams, callbacks, signal) {
236
+ async function streamChatCompletion(client, createParams, callbacks, signal, eagerSettleStreaming = true) {
142
237
  (0, runtime_1.emitNervesEvent)({
143
238
  component: "engine",
144
239
  event: "engine.stream_start",
@@ -152,8 +247,7 @@ async function streamChatCompletion(client, createParams, callbacks, signal) {
152
247
  let toolCalls = {};
153
248
  let streamStarted = false;
154
249
  let usage;
155
- const answerParser = new FinalAnswerParser();
156
- let finalAnswerDetected = false;
250
+ const answerStreamer = new SettleStreamer(callbacks, eagerSettleStreaming);
157
251
  // State machine for parsing inline <think> tags (MiniMax pattern)
158
252
  let contentBuf = "";
159
253
  let inThinkTag = false;
@@ -268,24 +362,21 @@ async function streamChatCompletion(client, createParams, callbacks, signal) {
268
362
  toolCalls[tc.index].id = tc.id;
269
363
  if (tc.function?.name) {
270
364
  toolCalls[tc.index].name = tc.function.name;
271
- // Detect final_answer tool call on first name delta.
365
+ // Detect settle tool call on first name delta.
272
366
  // Only activate streaming if this is the sole tool call (index 0
273
367
  // and no other indices seen). Mixed calls are rejected by core.ts.
274
- if (tc.function.name === "final_answer" && !finalAnswerDetected
368
+ if (tc.function.name === "settle" && !answerStreamer.detected
275
369
  && tc.index === 0 && Object.keys(toolCalls).length === 1) {
276
- finalAnswerDetected = true;
277
- callbacks.onClearText?.();
370
+ answerStreamer.activate();
278
371
  }
279
372
  }
280
373
  if (tc.function?.arguments) {
281
374
  toolCalls[tc.index].arguments += tc.function.arguments;
282
- // Feed final_answer argument deltas to the parser for progressive
375
+ // Feed settle argument deltas to the parser for progressive
283
376
  // streaming, but only when it appears to be the sole tool call.
284
- if (finalAnswerDetected && toolCalls[tc.index].name === "final_answer"
377
+ if (answerStreamer.detected && toolCalls[tc.index].name === "settle"
285
378
  && Object.keys(toolCalls).length === 1) {
286
- const text = answerParser.process(tc.function.arguments);
287
- if (text)
288
- callbacks.onTextChunk(text);
379
+ answerStreamer.processDelta(tc.function.arguments);
289
380
  }
290
381
  }
291
382
  }
@@ -299,10 +390,10 @@ async function streamChatCompletion(client, createParams, callbacks, signal) {
299
390
  toolCalls: Object.values(toolCalls),
300
391
  outputItems: [],
301
392
  usage,
302
- finalAnswerStreamed: answerParser.active,
393
+ settleStreamed: answerStreamer.streamed,
303
394
  };
304
395
  }
305
- async function streamResponsesApi(client, createParams, callbacks, signal) {
396
+ async function streamResponsesApi(client, createParams, callbacks, signal, eagerSettleStreaming = true) {
306
397
  (0, runtime_1.emitNervesEvent)({
307
398
  component: "engine",
308
399
  event: "engine.stream_start",
@@ -317,9 +408,8 @@ async function streamResponsesApi(client, createParams, callbacks, signal) {
317
408
  const outputItems = [];
318
409
  let currentToolCall = null;
319
410
  let usage;
320
- const answerParser = new FinalAnswerParser();
411
+ const answerStreamer = new SettleStreamer(callbacks, eagerSettleStreaming);
321
412
  let functionCallCount = 0;
322
- let finalAnswerDetected = false;
323
413
  for await (const event of response) {
324
414
  if (signal?.aborted)
325
415
  break;
@@ -348,12 +438,11 @@ async function streamResponsesApi(client, createParams, callbacks, signal) {
348
438
  name: String(event.item.name),
349
439
  arguments: "",
350
440
  };
351
- // Detect final_answer function call -- clear any streamed noise.
441
+ // Detect settle function call -- clear any streamed noise.
352
442
  // Only activate when this is the first (and so far only) function call.
353
443
  // Mixed calls are rejected by core.ts; no need to stream their args.
354
- if (String(event.item.name) === "final_answer" && functionCallCount === 1) {
355
- finalAnswerDetected = true;
356
- callbacks.onClearText?.();
444
+ if (String(event.item.name) === "settle" && functionCallCount === 1) {
445
+ answerStreamer.activate();
357
446
  }
358
447
  }
359
448
  break;
@@ -361,13 +450,11 @@ async function streamResponsesApi(client, createParams, callbacks, signal) {
361
450
  case "response.function_call_arguments.delta": {
362
451
  if (currentToolCall) {
363
452
  currentToolCall.arguments += event.delta;
364
- // Feed final_answer argument deltas to the parser for progressive
453
+ // Feed settle argument deltas to the parser for progressive
365
454
  // streaming, but only when it appears to be the sole function call.
366
- if (finalAnswerDetected && currentToolCall.name === "final_answer"
455
+ if (answerStreamer.detected && currentToolCall.name === "settle"
367
456
  && functionCallCount === 1) {
368
- const text = answerParser.process(String(event.delta));
369
- if (text)
370
- callbacks.onTextChunk(text);
457
+ answerStreamer.processDelta(String(event.delta));
371
458
  }
372
459
  }
373
460
  break;
@@ -407,6 +494,6 @@ async function streamResponsesApi(client, createParams, callbacks, signal) {
407
494
  toolCalls,
408
495
  outputItems,
409
496
  usage,
410
- finalAnswerStreamed: answerParser.active,
497
+ settleStreamed: answerStreamer.streamed,
411
498
  };
412
499
  }