@ouro.bot/cli 0.1.0-alpha.34 → 0.1.0-alpha.340

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 (314) hide show
  1. package/README.md +188 -187
  2. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +3 -2
  3. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +1 -1
  4. package/changelog.json +2031 -0
  5. package/dist/arc/attention-types.js +8 -0
  6. package/dist/arc/cares.js +140 -0
  7. package/dist/arc/episodes.js +117 -0
  8. package/dist/arc/intentions.js +133 -0
  9. package/dist/arc/json-store.js +117 -0
  10. package/dist/arc/obligations.js +237 -0
  11. package/dist/arc/packets.js +193 -0
  12. package/dist/arc/presence.js +185 -0
  13. package/dist/arc/task-lifecycle.js +65 -0
  14. package/dist/heart/active-work.js +832 -0
  15. package/dist/heart/agent-entry.js +37 -2
  16. package/dist/heart/attachments/image-normalize.js +194 -0
  17. package/dist/heart/attachments/materialize.js +97 -0
  18. package/dist/heart/attachments/originals.js +88 -0
  19. package/dist/heart/attachments/render.js +29 -0
  20. package/dist/heart/attachments/sources/adapter.js +2 -0
  21. package/dist/heart/attachments/sources/bluebubbles.js +156 -0
  22. package/dist/heart/attachments/sources/cli-local-file.js +78 -0
  23. package/dist/heart/attachments/sources/index.js +16 -0
  24. package/dist/heart/attachments/store.js +103 -0
  25. package/dist/heart/attachments/types.js +93 -0
  26. package/dist/heart/auth/auth-flow.js +463 -0
  27. package/dist/heart/bridges/manager.js +358 -0
  28. package/dist/heart/bridges/state-machine.js +135 -0
  29. package/dist/heart/bridges/store.js +123 -0
  30. package/dist/heart/bundle-state.js +168 -0
  31. package/dist/heart/commitments.js +111 -0
  32. package/dist/heart/config-registry.js +304 -0
  33. package/dist/heart/config.js +53 -21
  34. package/dist/heart/core.js +695 -195
  35. package/dist/heart/cross-chat-delivery.js +131 -0
  36. package/dist/heart/daemon/agent-config-check.js +292 -0
  37. package/dist/heart/daemon/agent-discovery.js +79 -3
  38. package/dist/heart/daemon/agent-service.js +360 -0
  39. package/dist/heart/daemon/agentic-repair.js +170 -0
  40. package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
  41. package/dist/heart/daemon/cadence.js +70 -0
  42. package/dist/heart/daemon/cli-defaults.js +591 -0
  43. package/dist/heart/daemon/cli-exec.js +2297 -0
  44. package/dist/heart/daemon/cli-help.js +306 -0
  45. package/dist/heart/daemon/cli-parse.js +824 -0
  46. package/dist/heart/daemon/cli-render-doctor.js +57 -0
  47. package/dist/heart/daemon/cli-render.js +512 -0
  48. package/dist/heart/daemon/cli-types.js +8 -0
  49. package/dist/heart/daemon/daemon-cli.js +30 -1171
  50. package/dist/heart/daemon/daemon-entry.js +358 -3
  51. package/dist/heart/daemon/daemon-health.js +141 -0
  52. package/dist/heart/daemon/daemon-runtime-sync.js +157 -12
  53. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  54. package/dist/heart/daemon/daemon.js +751 -58
  55. package/dist/heart/daemon/doctor-types.js +8 -0
  56. package/dist/heart/daemon/doctor.js +401 -0
  57. package/dist/heart/daemon/health-monitor.js +79 -1
  58. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  59. package/dist/heart/daemon/hooks/bundle-meta.js +115 -1
  60. package/dist/heart/daemon/http-health-probe.js +80 -0
  61. package/dist/heart/daemon/inner-status.js +89 -0
  62. package/dist/heart/daemon/interactive-repair.js +91 -0
  63. package/dist/heart/daemon/launchd.js +46 -9
  64. package/dist/heart/daemon/log-tailer.js +82 -12
  65. package/dist/heart/daemon/logs-prune.js +105 -0
  66. package/dist/heart/daemon/message-router.js +17 -8
  67. package/dist/heart/daemon/os-cron-deps.js +134 -0
  68. package/dist/heart/daemon/ouro-bot-entry.js +1 -1
  69. package/dist/heart/daemon/process-manager.js +201 -0
  70. package/dist/heart/daemon/provider-discovery.js +105 -0
  71. package/dist/heart/daemon/pulse.js +463 -0
  72. package/dist/heart/daemon/run-hooks.js +2 -0
  73. package/dist/heart/daemon/runtime-logging.js +67 -16
  74. package/dist/heart/daemon/runtime-metadata.js +101 -0
  75. package/dist/heart/daemon/runtime-mode.js +67 -0
  76. package/dist/heart/daemon/safe-mode.js +161 -0
  77. package/dist/heart/daemon/sense-manager.js +72 -3
  78. package/dist/heart/daemon/session-id-resolver.js +131 -0
  79. package/dist/heart/daemon/skill-management-installer.js +94 -0
  80. package/dist/heart/daemon/socket-client.js +307 -0
  81. package/dist/heart/daemon/stale-bundle-prune.js +96 -0
  82. package/dist/heart/daemon/startup-tui.js +237 -0
  83. package/dist/heart/daemon/task-scheduler.js +3 -25
  84. package/dist/heart/daemon/thoughts.js +510 -0
  85. package/dist/heart/daemon/up-progress.js +135 -0
  86. package/dist/heart/delegation.js +62 -0
  87. package/dist/heart/habits/habit-migration.js +181 -0
  88. package/dist/heart/habits/habit-parser.js +140 -0
  89. package/dist/heart/habits/habit-scheduler.js +371 -0
  90. package/dist/heart/{daemon → hatch}/hatch-flow.js +32 -120
  91. package/dist/heart/{daemon → hatch}/hatch-specialist.js +3 -3
  92. package/dist/heart/{daemon → hatch}/specialist-prompt.js +10 -7
  93. package/dist/heart/{daemon → hatch}/specialist-tools.js +49 -3
  94. package/dist/heart/identity.js +154 -59
  95. package/dist/heart/kicks.js +2 -20
  96. package/dist/heart/mcp/mcp-server.js +653 -0
  97. package/dist/heart/migrate-config.js +127 -0
  98. package/dist/heart/model-capabilities.js +59 -0
  99. package/dist/heart/outlook/outlook-http-hooks.js +64 -0
  100. package/dist/heart/outlook/outlook-http-response.js +7 -0
  101. package/dist/heart/outlook/outlook-http-routes.js +232 -0
  102. package/dist/heart/outlook/outlook-http-static.js +99 -0
  103. package/dist/heart/outlook/outlook-http-transport.js +116 -0
  104. package/dist/heart/outlook/outlook-http.js +99 -0
  105. package/dist/heart/outlook/outlook-read.js +28 -0
  106. package/dist/heart/outlook/outlook-types.js +27 -0
  107. package/dist/heart/outlook/outlook-view.js +194 -0
  108. package/dist/heart/outlook/readers/agent-machine.js +355 -0
  109. package/dist/heart/outlook/readers/continuity-readers.js +332 -0
  110. package/dist/heart/outlook/readers/runtime-readers.js +660 -0
  111. package/dist/heart/outlook/readers/sessions.js +231 -0
  112. package/dist/heart/outlook/readers/shared.js +111 -0
  113. package/dist/heart/progress-story.js +42 -0
  114. package/dist/heart/provider-failover.js +135 -0
  115. package/dist/heart/provider-models.js +81 -0
  116. package/dist/heart/provider-ping.js +234 -0
  117. package/dist/heart/providers/anthropic-token.js +163 -0
  118. package/dist/heart/providers/anthropic.js +171 -50
  119. package/dist/heart/providers/azure.js +97 -11
  120. package/dist/heart/providers/error-classification.js +63 -0
  121. package/dist/heart/providers/github-copilot.js +135 -0
  122. package/dist/heart/providers/minimax-vlm.js +189 -0
  123. package/dist/heart/providers/minimax.js +23 -6
  124. package/dist/heart/providers/openai-codex.js +33 -23
  125. package/dist/heart/session-activity.js +190 -0
  126. package/dist/heart/session-events.js +726 -0
  127. package/dist/heart/session-recall.js +162 -0
  128. package/dist/heart/start-of-turn-packet.js +341 -0
  129. package/dist/heart/streaming.js +36 -27
  130. package/dist/heart/sync.js +332 -0
  131. package/dist/heart/target-resolution.js +127 -0
  132. package/dist/heart/tempo.js +93 -0
  133. package/dist/heart/temporal-view.js +41 -0
  134. package/dist/heart/tool-activity-callbacks.js +36 -0
  135. package/dist/heart/tool-description.js +135 -0
  136. package/dist/heart/tool-friction.js +55 -0
  137. package/dist/heart/tool-loop.js +200 -0
  138. package/dist/heart/turn-context.js +358 -0
  139. package/dist/heart/turn-coordinator.js +28 -0
  140. package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +1 -1
  141. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
  142. package/dist/heart/{daemon → versioning}/ouro-path-installer.js +78 -35
  143. package/dist/heart/versioning/ouro-version-manager.js +295 -0
  144. package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
  145. package/dist/heart/{daemon → versioning}/update-checker.js +12 -2
  146. package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
  147. package/dist/mind/associative-recall.js +137 -66
  148. package/dist/mind/bundle-manifest.js +7 -1
  149. package/dist/mind/context.js +89 -93
  150. package/dist/mind/diary-integrity.js +60 -0
  151. package/dist/mind/{memory.js → diary.js} +84 -96
  152. package/dist/mind/embedding-provider.js +60 -0
  153. package/dist/mind/file-state.js +179 -0
  154. package/dist/mind/first-impressions.js +14 -1
  155. package/dist/mind/friends/channel.js +56 -0
  156. package/dist/mind/friends/group-context.js +144 -0
  157. package/dist/mind/friends/resolver.js +37 -0
  158. package/dist/mind/friends/store-file.js +58 -3
  159. package/dist/mind/friends/trust-explanation.js +74 -0
  160. package/dist/mind/friends/types.js +8 -0
  161. package/dist/mind/journal-index.js +161 -0
  162. package/dist/mind/obligation-steering.js +221 -0
  163. package/dist/mind/pending.js +74 -7
  164. package/dist/mind/prompt.js +999 -111
  165. package/dist/mind/provenance-trust.js +26 -0
  166. package/dist/mind/scrutiny.js +173 -0
  167. package/dist/mind/token-estimate.js +8 -12
  168. package/dist/nerves/cli-logging.js +7 -1
  169. package/dist/nerves/coverage/audit.js +1 -1
  170. package/dist/nerves/coverage/file-completeness.js +83 -5
  171. package/dist/nerves/coverage/run-artifacts.js +1 -1
  172. package/dist/nerves/event-buffer.js +111 -0
  173. package/dist/nerves/index.js +224 -4
  174. package/dist/nerves/observation.js +20 -0
  175. package/dist/nerves/redact.js +79 -0
  176. package/dist/nerves/runtime.js +5 -1
  177. package/dist/outlook-ui/assets/index-DC7sZefn.js +61 -0
  178. package/dist/outlook-ui/assets/index-LwChZTgL.css +1 -0
  179. package/dist/outlook-ui/index.html +15 -0
  180. package/dist/repertoire/ado-client.js +15 -56
  181. package/dist/repertoire/ado-semantic.js +11 -10
  182. package/dist/repertoire/api-client.js +97 -0
  183. package/dist/repertoire/bitwarden-store.js +319 -0
  184. package/dist/repertoire/bundle-templates.js +72 -0
  185. package/dist/repertoire/bw-installer.js +79 -0
  186. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  187. package/dist/repertoire/coding/context-pack.js +330 -0
  188. package/dist/repertoire/coding/feedback.js +197 -30
  189. package/dist/repertoire/coding/manager.js +158 -9
  190. package/dist/repertoire/coding/spawner.js +55 -9
  191. package/dist/repertoire/coding/tools.js +170 -7
  192. package/dist/repertoire/commerce-errors.js +109 -0
  193. package/dist/repertoire/commerce-self-test.js +156 -0
  194. package/dist/repertoire/credential-access.js +527 -0
  195. package/dist/repertoire/duffel-client.js +185 -0
  196. package/dist/repertoire/github-client.js +14 -55
  197. package/dist/repertoire/graph-client.js +11 -52
  198. package/dist/repertoire/guardrails.js +375 -0
  199. package/dist/repertoire/mcp-client.js +255 -0
  200. package/dist/repertoire/mcp-manager.js +305 -0
  201. package/dist/repertoire/mcp-tools.js +63 -0
  202. package/dist/repertoire/shell-sessions.js +133 -0
  203. package/dist/repertoire/skills.js +14 -23
  204. package/dist/repertoire/stripe-client.js +131 -0
  205. package/dist/repertoire/tasks/board.js +43 -5
  206. package/dist/repertoire/tasks/fix.js +182 -0
  207. package/dist/repertoire/tasks/index.js +28 -10
  208. package/dist/repertoire/tasks/lifecycle.js +2 -2
  209. package/dist/repertoire/tasks/parser.js +3 -2
  210. package/dist/repertoire/tasks/scanner.js +194 -37
  211. package/dist/repertoire/tasks/transitions.js +16 -79
  212. package/dist/repertoire/tool-results.js +29 -0
  213. package/dist/repertoire/tools-attachments.js +316 -0
  214. package/dist/repertoire/tools-base.js +45 -771
  215. package/dist/repertoire/tools-bluebubbles.js +1 -0
  216. package/dist/repertoire/tools-bridge.js +141 -0
  217. package/dist/repertoire/tools-bundle.js +984 -0
  218. package/dist/repertoire/tools-config.js +185 -0
  219. package/dist/repertoire/tools-continuity.js +248 -0
  220. package/dist/repertoire/tools-credential.js +182 -0
  221. package/dist/repertoire/tools-files.js +342 -0
  222. package/dist/repertoire/tools-flight.js +224 -0
  223. package/dist/repertoire/tools-flow.js +105 -0
  224. package/dist/repertoire/tools-github.js +1 -7
  225. package/dist/repertoire/tools-memory.js +376 -0
  226. package/dist/repertoire/tools-session.js +739 -0
  227. package/dist/repertoire/tools-shell.js +120 -0
  228. package/dist/repertoire/tools-stripe.js +180 -0
  229. package/dist/repertoire/tools-surface.js +243 -0
  230. package/dist/repertoire/tools-teams.js +12 -62
  231. package/dist/repertoire/tools-travel.js +125 -0
  232. package/dist/repertoire/tools-user-profile.js +144 -0
  233. package/dist/repertoire/tools-vault.js +110 -0
  234. package/dist/repertoire/tools.js +144 -138
  235. package/dist/repertoire/travel-api-client.js +360 -0
  236. package/dist/repertoire/user-profile.js +118 -0
  237. package/dist/repertoire/vault-setup.js +241 -0
  238. package/dist/scripts/claude-code-hook.js +41 -0
  239. package/dist/scripts/claude-code-stop-hook.js +47 -0
  240. package/dist/senses/attention-queue.js +116 -0
  241. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  242. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  243. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +225 -9
  244. package/dist/senses/bluebubbles/entry.js +13 -0
  245. package/dist/senses/bluebubbles/inbound-log.js +113 -0
  246. package/dist/senses/bluebubbles/index.js +1590 -0
  247. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -70
  248. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +43 -12
  249. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +46 -6
  250. package/dist/senses/bluebubbles/replay.js +129 -0
  251. package/dist/senses/bluebubbles/runtime-state.js +109 -0
  252. package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
  253. package/dist/senses/cli/bracketed-paste.js +82 -0
  254. package/dist/senses/cli/image-paste.js +287 -0
  255. package/dist/senses/cli/image-ref-navigation.js +75 -0
  256. package/dist/senses/cli/ink-app.js +156 -0
  257. package/dist/senses/cli/inline-diff.js +64 -0
  258. package/dist/senses/cli/input-keys.js +174 -0
  259. package/dist/senses/cli/kill-ring.js +86 -0
  260. package/dist/senses/cli/message-list.js +51 -0
  261. package/dist/senses/cli/ouro-tui.js +605 -0
  262. package/dist/senses/cli/spinner-imperative.js +135 -0
  263. package/dist/senses/cli/spinner.js +101 -0
  264. package/dist/senses/cli/status-line.js +60 -0
  265. package/dist/senses/cli/streaming-markdown.js +526 -0
  266. package/dist/senses/cli/tool-display.js +83 -0
  267. package/dist/senses/cli/tool-render.js +85 -0
  268. package/dist/senses/cli/tui-store.js +240 -0
  269. package/dist/senses/cli/virtual-list.js +35 -0
  270. package/dist/senses/cli-entry.js +1 -1
  271. package/dist/senses/cli-layout.js +187 -0
  272. package/dist/senses/cli.js +595 -246
  273. package/dist/senses/commands.js +65 -1
  274. package/dist/senses/continuity.js +94 -0
  275. package/dist/senses/habit-turn-message.js +108 -0
  276. package/dist/senses/inner-dialog-worker.js +112 -19
  277. package/dist/senses/inner-dialog.js +633 -86
  278. package/dist/senses/pipeline.js +567 -0
  279. package/dist/senses/shared-turn.js +199 -0
  280. package/dist/senses/surface-tool.js +68 -0
  281. package/dist/senses/teams.js +665 -160
  282. package/dist/senses/trust-gate.js +112 -2
  283. package/package.json +29 -7
  284. package/skills/agent-commerce.md +106 -0
  285. package/skills/browser-navigation.md +110 -0
  286. package/skills/commerce-setup-guide.md +116 -0
  287. package/skills/commerce-setup.md +84 -0
  288. package/skills/configure-dev-tools.md +81 -0
  289. package/skills/travel-planning.md +138 -0
  290. package/dist/heart/daemon/subagent-installer.js +0 -134
  291. package/dist/senses/bluebubbles-entry.js +0 -11
  292. package/dist/senses/bluebubbles.js +0 -547
  293. package/dist/senses/debug-activity.js +0 -124
  294. package/subagents/README.md +0 -73
  295. package/subagents/work-doer.md +0 -235
  296. package/subagents/work-merger.md +0 -618
  297. package/subagents/work-planner.md +0 -382
  298. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  299. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  300. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  301. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  302. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  303. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  304. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  305. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  306. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  307. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  308. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  309. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +0 -0
  310. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  311. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  312. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  313. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  314. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -35,59 +35,43 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.cosineSimilarity = cosineSimilarity;
37
37
  exports.recallFactsForQuery = recallFactsForQuery;
38
+ exports.searchJournalIndex = searchJournalIndex;
38
39
  exports.injectAssociativeRecall = injectAssociativeRecall;
39
40
  const fs = __importStar(require("fs"));
40
41
  const path = __importStar(require("path"));
41
- const config_1 = require("../heart/config");
42
- const identity_1 = require("../heart/identity");
43
42
  const runtime_1 = require("../nerves/runtime");
44
- const DEFAULT_EMBEDDING_MODEL = "text-embedding-3-small";
43
+ const diary_1 = require("./diary");
44
+ const provenance_trust_1 = require("./provenance-trust");
45
+ const embedding_provider_1 = require("./embedding-provider");
45
46
  const DEFAULT_MIN_SCORE = 0.5;
46
47
  const DEFAULT_TOP_K = 3;
47
- class OpenAIEmbeddingProvider {
48
- apiKey;
49
- model;
50
- constructor(apiKey, model = DEFAULT_EMBEDDING_MODEL) {
51
- this.apiKey = apiKey;
52
- this.model = model;
53
- }
54
- async embed(texts) {
55
- const response = await fetch("https://api.openai.com/v1/embeddings", {
56
- method: "POST",
57
- headers: {
58
- Authorization: `Bearer ${this.apiKey}`,
59
- "Content-Type": "application/json",
60
- },
61
- body: JSON.stringify({
62
- model: this.model,
63
- input: texts,
64
- }),
65
- });
66
- if (!response.ok) {
67
- throw new Error(`embedding request failed: ${response.status} ${response.statusText}`);
68
- }
69
- const payload = (await response.json());
70
- if (!payload.data || payload.data.length !== texts.length) {
71
- throw new Error("embedding response missing expected vectors");
72
- }
73
- return payload.data.map((entry) => entry.embedding);
74
- }
75
- }
76
48
  function createDefaultProvider() {
77
- const apiKey = (0, config_1.getOpenAIEmbeddingsApiKey)();
78
- if (!apiKey) {
49
+ const provider = (0, embedding_provider_1.createDefaultEmbeddingProvider)();
50
+ if (!provider) {
79
51
  throw new Error("openaiEmbeddingsApiKey not configured");
80
52
  }
81
- return new OpenAIEmbeddingProvider(apiKey);
53
+ return provider;
82
54
  }
83
- function readFacts(memoryRoot) {
84
- const factsPath = path.join(memoryRoot, "facts.jsonl");
55
+ function readFacts(diaryRoot) {
56
+ const factsPath = path.join(diaryRoot, "facts.jsonl");
85
57
  if (!fs.existsSync(factsPath))
86
58
  return [];
87
59
  const raw = fs.readFileSync(factsPath, "utf8").trim();
88
60
  if (!raw)
89
61
  return [];
90
- return raw.split("\n").map((line) => JSON.parse(line));
62
+ const facts = [];
63
+ for (const line of raw.split("\n")) {
64
+ const trimmed = line.trim();
65
+ if (!trimmed)
66
+ continue;
67
+ try {
68
+ facts.push(JSON.parse(trimmed));
69
+ }
70
+ catch {
71
+ // Skip corrupt lines (e.g. partial write from a crash).
72
+ }
73
+ }
74
+ return facts;
91
75
  }
92
76
  function getLatestUserText(messages) {
93
77
  for (let i = messages.length - 1; i >= 0; i--) {
@@ -133,6 +117,40 @@ async function recallFactsForQuery(query, facts, provider, options) {
133
117
  .sort((left, right) => right.score - left.score)
134
118
  .slice(0, topK);
135
119
  }
120
+ function readJournalIndex(journalDir) {
121
+ const indexPath = path.join(journalDir, ".index.json");
122
+ try {
123
+ const raw = fs.readFileSync(indexPath, "utf8");
124
+ const parsed = JSON.parse(raw);
125
+ if (!Array.isArray(parsed))
126
+ return [];
127
+ return parsed;
128
+ }
129
+ catch {
130
+ return [];
131
+ }
132
+ }
133
+ function searchJournalIndex(queryEmbedding, entries, options) {
134
+ const minScore = options?.minScore ?? DEFAULT_MIN_SCORE;
135
+ const topK = options?.topK ?? DEFAULT_TOP_K;
136
+ return entries
137
+ .filter((entry) => Array.isArray(entry.embedding) && entry.embedding.length > 0)
138
+ .map((entry) => ({
139
+ filename: entry.filename,
140
+ preview: entry.preview,
141
+ score: cosineSimilarity(queryEmbedding, entry.embedding),
142
+ }))
143
+ .filter((entry) => entry.score >= minScore)
144
+ .sort((left, right) => right.score - left.score)
145
+ .slice(0, topK);
146
+ }
147
+ function resolveJournalDir(diaryRoot, explicitJournalDir) {
148
+ if (explicitJournalDir)
149
+ return explicitJournalDir;
150
+ // journal/ is a sibling of diary/ at the agent root level
151
+ const agentRoot = path.dirname(diaryRoot);
152
+ return path.join(agentRoot, "journal");
153
+ }
136
154
  async function injectAssociativeRecall(messages, options) {
137
155
  try {
138
156
  if (messages[0]?.role !== "system" || typeof messages[0].content !== "string")
@@ -140,37 +158,90 @@ async function injectAssociativeRecall(messages, options) {
140
158
  const query = getLatestUserText(messages);
141
159
  if (!query)
142
160
  return;
143
- const memoryRoot = options?.memoryRoot ?? path.join((0, identity_1.getAgentRoot)(), "psyche", "memory");
144
- const facts = readFacts(memoryRoot);
145
- if (facts.length === 0)
161
+ const diaryRoot = options?.diaryRoot ?? (0, diary_1.resolveDiaryRoot)();
162
+ const facts = readFacts(diaryRoot);
163
+ const journalDir = resolveJournalDir(diaryRoot, options?.journalDir);
164
+ const journalEntries = readJournalIndex(journalDir);
165
+ if (facts.length === 0 && journalEntries.length === 0)
146
166
  return;
147
- let recalled;
148
- try {
149
- const provider = options?.provider ?? createDefaultProvider();
150
- recalled = await recallFactsForQuery(query, facts, provider, options);
151
- }
152
- catch {
153
- // Embeddings unavailable — fall back to substring matching
154
- const lowerQuery = query.toLowerCase();
155
- const topK = options?.topK ?? DEFAULT_TOP_K;
156
- recalled = facts
157
- .filter((fact) => fact.text.toLowerCase().includes(lowerQuery))
158
- .slice(0, topK)
159
- .map((fact) => ({ ...fact, score: 1 }));
160
- if (recalled.length > 0) {
161
- (0, runtime_1.emitNervesEvent)({
162
- level: "warn",
163
- component: "mind",
164
- event: "mind.associative_recall_fallback",
165
- message: "embeddings unavailable, used substring fallback",
166
- meta: { matchCount: recalled.length },
167
+ // Build combined result lines tagged by source
168
+ const resultLines = [];
169
+ let queryEmbedding;
170
+ // Search diary entries
171
+ if (facts.length > 0) {
172
+ let recalled;
173
+ try {
174
+ const provider = options?.provider ?? createDefaultProvider();
175
+ recalled = await recallFactsForQuery(query, facts, provider, options);
176
+ // Compute query embedding for journal search while provider is available
177
+ if (journalEntries.length > 0) {
178
+ const [qe] = await provider.embed([query.trim()]);
179
+ queryEmbedding = qe;
180
+ }
181
+ }
182
+ catch {
183
+ // Embeddings unavailable — fall back to substring matching
184
+ const lowerQuery = query.toLowerCase();
185
+ const topK = options?.topK ?? DEFAULT_TOP_K;
186
+ recalled = facts
187
+ .filter((fact) => fact.text.toLowerCase().includes(lowerQuery))
188
+ .slice(0, topK)
189
+ .map((fact) => ({ ...fact, score: 1 }));
190
+ if (recalled.length > 0) {
191
+ (0, runtime_1.emitNervesEvent)({
192
+ level: "warn",
193
+ component: "mind",
194
+ event: "mind.associative_recall_fallback",
195
+ message: "embeddings unavailable, used substring fallback",
196
+ meta: { matchCount: recalled.length },
197
+ });
198
+ }
199
+ }
200
+ for (const fact of recalled) {
201
+ let meta = `score=${fact.score.toFixed(3)} source=${fact.source}`;
202
+ if (fact.provenance) {
203
+ if (fact.provenance.channel)
204
+ meta += ` channel=${fact.provenance.channel}`;
205
+ if (fact.provenance.friendName)
206
+ meta += ` friend=${fact.provenance.friendName}`;
207
+ if (fact.provenance.trust)
208
+ meta += ` trust=${fact.provenance.trust}`;
209
+ }
210
+ const tag = (0, provenance_trust_1.classifyProvenanceTrust)(fact.provenance) === "external" ? "diary/external" : "diary";
211
+ resultLines.push({
212
+ text: `[${tag}] ${fact.text} [${meta}]`,
213
+ score: fact.score,
167
214
  });
168
215
  }
169
216
  }
170
- if (recalled.length === 0)
217
+ // Search journal entries (works whether diary had results or not)
218
+ if (journalEntries.length > 0) {
219
+ try {
220
+ if (!queryEmbedding) {
221
+ const provider = options?.provider ?? createDefaultProvider();
222
+ const [qe] = await provider.embed([query.trim()]);
223
+ queryEmbedding = qe;
224
+ }
225
+ if (queryEmbedding) {
226
+ const journalResults = searchJournalIndex(queryEmbedding, journalEntries, options);
227
+ for (const entry of journalResults) {
228
+ resultLines.push({
229
+ text: `[journal] ${entry.filename}: ${entry.preview} [score=${entry.score.toFixed(3)}]`,
230
+ score: entry.score,
231
+ });
232
+ }
233
+ }
234
+ }
235
+ catch {
236
+ // Embeddings unavailable — no journal fallback
237
+ }
238
+ }
239
+ if (resultLines.length === 0)
171
240
  return;
172
- const recallSection = recalled
173
- .map((fact, index) => `${index + 1}. ${fact.text} [score=${fact.score.toFixed(3)} source=${fact.source}]`)
241
+ // Sort all results by score descending
242
+ resultLines.sort((left, right) => right.score - left.score);
243
+ const recallSection = resultLines
244
+ .map((entry, index) => `${index + 1}. ${entry.text}`)
174
245
  .join("\n");
175
246
  messages[0] = {
176
247
  role: "system",
@@ -180,7 +251,7 @@ async function injectAssociativeRecall(messages, options) {
180
251
  component: "mind",
181
252
  event: "mind.associative_recall",
182
253
  message: "associative recall injected",
183
- meta: { count: recalled.length },
254
+ meta: { count: resultLines.length },
184
255
  });
185
256
  }
186
257
  catch (error) {
@@ -190,7 +261,7 @@ async function injectAssociativeRecall(messages, options) {
190
261
  event: "mind.associative_recall_error",
191
262
  message: "associative recall failed",
192
263
  meta: {
193
- reason: error instanceof Error ? error.message : String(error),
264
+ reason: error instanceof Error ? error.message : /* v8 ignore start -- defensive: non-Error catch branch @preserve */ String(error) /* v8 ignore stop */,
194
265
  },
195
266
  });
196
267
  }
@@ -52,7 +52,13 @@ exports.CANONICAL_BUNDLE_MANIFEST = [
52
52
  { path: "psyche/LORE.md", kind: "file" },
53
53
  { path: "psyche/TACIT.md", kind: "file" },
54
54
  { path: "psyche/ASPIRATIONS.md", kind: "file" },
55
- { path: "psyche/memory", kind: "dir" },
55
+ { path: "arc", kind: "dir" },
56
+ { path: "arc/episodes", kind: "dir" },
57
+ { path: "arc/obligations", kind: "dir" },
58
+ { path: "arc/cares", kind: "dir" },
59
+ { path: "arc/intentions", kind: "dir" },
60
+ { path: "diary", kind: "dir" },
61
+ { path: "journal", kind: "dir" },
56
62
  { path: "friends", kind: "dir" },
57
63
  { path: "state", kind: "dir" },
58
64
  { path: "tasks", kind: "dir" },
@@ -33,34 +33,39 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.validateSessionMessages = exports.repairSessionMessages = exports.migrateToolNames = void 0;
36
37
  exports.trimMessages = trimMessages;
37
- exports.validateSessionMessages = validateSessionMessages;
38
- exports.repairSessionMessages = repairSessionMessages;
39
38
  exports.saveSession = saveSession;
39
+ exports.appendSyntheticAssistantMessage = appendSyntheticAssistantMessage;
40
40
  exports.loadSession = loadSession;
41
41
  exports.postTurn = postTurn;
42
42
  exports.deleteSession = deleteSession;
43
43
  const config_1 = require("../heart/config");
44
+ const session_events_1 = require("../heart/session-events");
44
45
  const runtime_1 = require("../nerves/runtime");
45
46
  const fs = __importStar(require("fs"));
46
47
  const path = __importStar(require("path"));
47
48
  const token_estimate_1 = require("./token-estimate");
49
+ var session_events_2 = require("../heart/session-events");
50
+ Object.defineProperty(exports, "migrateToolNames", { enumerable: true, get: function () { return session_events_2.migrateToolNames; } });
51
+ Object.defineProperty(exports, "repairSessionMessages", { enumerable: true, get: function () { return session_events_2.repairSessionMessages; } });
52
+ Object.defineProperty(exports, "validateSessionMessages", { enumerable: true, get: function () { return session_events_2.validateSessionMessages; } });
48
53
  function buildTrimmableBlocks(messages) {
49
54
  const blocks = [];
50
55
  let i = 0;
51
56
  while (i < messages.length) {
52
57
  const msg = messages[i];
53
- if (msg?.role === "system") {
58
+ if (msg.role === "system") {
54
59
  i++;
55
60
  continue;
56
61
  }
57
62
  // Tool coherence block: assistant message with tool_calls + immediately following tool results
58
- if (msg?.role === "assistant" && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0) {
63
+ if (msg.role === "assistant" && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0) {
59
64
  const indices = [i];
60
65
  i++;
61
66
  while (i < messages.length) {
62
67
  const next = messages[i];
63
- if (next?.role !== "tool")
68
+ if (next.role !== "tool")
64
69
  break;
65
70
  indices.push(i);
66
71
  i++;
@@ -78,13 +83,13 @@ function buildTrimmableBlocks(messages) {
78
83
  function getSystemMessageIndices(messages) {
79
84
  const indices = [];
80
85
  for (let i = 0; i < messages.length; i++) {
81
- if (messages[i]?.role === "system")
86
+ if (messages[i].role === "system")
82
87
  indices.push(i);
83
88
  }
84
89
  return indices;
85
90
  }
86
91
  function buildTrimmedMessages(messages, kept) {
87
- return messages.filter((m, idx) => m?.role === "system" || kept.has(idx));
92
+ return messages.filter((m, idx) => m.role === "system" || kept.has(idx));
88
93
  }
89
94
  function trimMessages(messages, maxTokens, contextMargin, actualTokenCount) {
90
95
  const targetTokens = Math.floor(maxTokens * (1 - contextMargin / 100));
@@ -132,7 +137,7 @@ function trimMessages(messages, maxTokens, contextMargin, actualTokenCount) {
132
137
  let remaining = actualTokenCount;
133
138
  const kept = new Set();
134
139
  for (let i = 0; i < messages.length; i++) {
135
- if (messages[i]?.role !== "system")
140
+ if (messages[i].role !== "system")
136
141
  kept.add(i);
137
142
  }
138
143
  // Drop oldest blocks until we fall under target.
@@ -146,7 +151,7 @@ function trimMessages(messages, maxTokens, contextMargin, actualTokenCount) {
146
151
  let trimmed = buildTrimmedMessages(messages, kept);
147
152
  // If we're still above budget after dropping everything trimmable, preserve system only.
148
153
  if (remaining > targetTokens) {
149
- trimmed = messages.filter((m) => m?.role === "system");
154
+ trimmed = messages.filter((m) => m.role === "system");
150
155
  }
151
156
  const estimatedAfter = (0, token_estimate_1.estimateTokensForMessages)(trimmed);
152
157
  (0, runtime_1.emitNervesEvent)({
@@ -173,106 +178,80 @@ function trimMessages(messages, maxTokens, contextMargin, actualTokenCount) {
173
178
  * user → assistant (with optional tool calls/results) → user → assistant...
174
179
  * Never assistant → assistant without a user in between.
175
180
  */
176
- function validateSessionMessages(messages) {
177
- const violations = [];
178
- let prevNonToolRole = null;
179
- let prevAssistantHadToolCalls = false;
180
- let sawToolResultSincePrevAssistant = false;
181
- for (let i = 0; i < messages.length; i++) {
182
- const msg = messages[i];
183
- if (msg.role === "system")
184
- continue;
185
- if (msg.role === "tool") {
186
- sawToolResultSincePrevAssistant = true;
187
- continue;
188
- }
189
- if (msg.role === "assistant" && prevNonToolRole === "assistant") {
190
- // assistant → tool(s) → assistant is valid (tool call flow)
191
- if (!(prevAssistantHadToolCalls && sawToolResultSincePrevAssistant)) {
192
- violations.push(`back-to-back assistant at index ${i}`);
193
- }
194
- }
195
- prevAssistantHadToolCalls = msg.role === "assistant" && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0;
196
- sawToolResultSincePrevAssistant = false;
197
- prevNonToolRole = msg.role;
198
- }
199
- return violations;
181
+ function denormalizeContinuityState(state) {
182
+ if (!state.mustResolveBeforeHandoff && typeof state.lastFriendActivityAt !== "string")
183
+ return undefined;
184
+ return {
185
+ ...(state.mustResolveBeforeHandoff ? { mustResolveBeforeHandoff: true } : {}),
186
+ ...(typeof state.lastFriendActivityAt === "string" ? { lastFriendActivityAt: state.lastFriendActivityAt } : {}),
187
+ };
200
188
  }
201
- /**
202
- * Repairs session invariant violations by merging consecutive assistant messages.
203
- */
204
- function repairSessionMessages(messages) {
205
- const violations = validateSessionMessages(messages);
206
- if (violations.length === 0)
207
- return messages;
208
- const result = [];
209
- for (const msg of messages) {
210
- if (msg.role === "assistant" && result.length > 0) {
211
- const prev = result[result.length - 1];
212
- if (prev.role === "assistant" && !("tool_calls" in prev)) {
213
- const prevContent = typeof prev.content === "string" ? prev.content : "";
214
- const curContent = typeof msg.content === "string" ? msg.content : "";
215
- prev.content = `${prevContent}\n\n${curContent}`;
216
- continue;
217
- }
218
- }
219
- result.push(msg);
220
- }
221
- (0, runtime_1.emitNervesEvent)({
222
- level: "warn",
223
- event: "mind.session_invariant_repair",
224
- component: "mind",
225
- message: "repaired session invariant violations",
226
- meta: { violations },
189
+ function writeSessionEnvelope(filePath, envelope) {
190
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
191
+ fs.writeFileSync(filePath, JSON.stringify(envelope, null, 2));
192
+ }
193
+ function saveSession(filePath, messages, lastUsage, state) {
194
+ const existing = (0, session_events_1.loadSessionEnvelopeFile)(filePath);
195
+ const previousMessages = existing ? (0, session_events_1.projectProviderMessages)(existing) : [];
196
+ const sanitized = (0, session_events_1.sanitizeProviderMessages)(messages);
197
+ const envelope = (0, session_events_1.buildCanonicalSessionEnvelope)({
198
+ existing,
199
+ previousMessages,
200
+ currentMessages: sanitized,
201
+ trimmedMessages: sanitized,
202
+ recordedAt: new Date().toISOString(),
203
+ lastUsage: lastUsage ?? null,
204
+ state,
205
+ projectionBasis: {
206
+ maxTokens: null,
207
+ contextMargin: null,
208
+ inputTokens: lastUsage?.input_tokens ?? null,
209
+ },
227
210
  });
228
- return result;
211
+ writeSessionEnvelope(filePath, envelope);
229
212
  }
230
- function saveSession(filePath, messages, lastUsage) {
231
- const violations = validateSessionMessages(messages);
232
- if (violations.length > 0) {
213
+ function appendSyntheticAssistantMessage(filePath, content) {
214
+ try {
215
+ if (!fs.existsSync(filePath))
216
+ return false;
217
+ const envelope = (0, session_events_1.loadSessionEnvelopeFile)(filePath);
218
+ if (!envelope)
219
+ return false;
220
+ const updated = (0, session_events_1.appendSyntheticAssistantEvent)(envelope, content, new Date().toISOString());
221
+ writeSessionEnvelope(filePath, updated);
233
222
  (0, runtime_1.emitNervesEvent)({
234
- level: "warn",
235
- event: "mind.session_invariant_violation",
236
223
  component: "mind",
237
- message: "session invariant violated on save",
238
- meta: { path: filePath, violations },
224
+ event: "mind.session_synthetic_message_appended",
225
+ message: "appended synthetic assistant message to session",
226
+ meta: { path: filePath, contentLength: content.length },
239
227
  });
240
- messages = repairSessionMessages(messages);
228
+ return true;
229
+ }
230
+ catch {
231
+ return false;
241
232
  }
242
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
243
- const envelope = { version: 1, messages };
244
- if (lastUsage)
245
- envelope.lastUsage = lastUsage;
246
- fs.writeFileSync(filePath, JSON.stringify(envelope, null, 2));
247
233
  }
248
234
  function loadSession(filePath) {
249
235
  try {
250
- const raw = fs.readFileSync(filePath, "utf-8");
251
- const data = JSON.parse(raw);
252
- if (data.version !== 1)
236
+ const envelope = (0, session_events_1.loadSessionEnvelopeFile)(filePath);
237
+ if (!envelope)
253
238
  return null;
254
- let messages = data.messages;
255
- const violations = validateSessionMessages(messages);
256
- if (violations.length > 0) {
257
- (0, runtime_1.emitNervesEvent)({
258
- level: "warn",
259
- event: "mind.session_invariant_violation",
260
- component: "mind",
261
- message: "session invariant violated on load",
262
- meta: { path: filePath, violations },
263
- });
264
- messages = repairSessionMessages(messages);
265
- }
266
- return { messages, lastUsage: data.lastUsage };
239
+ return {
240
+ messages: (0, session_events_1.annotateMessageTimestamps)(envelope, (0, session_events_1.projectProviderMessages)(envelope)),
241
+ events: envelope.events,
242
+ lastUsage: envelope.lastUsage ?? undefined,
243
+ state: denormalizeContinuityState(envelope.state),
244
+ };
267
245
  }
268
246
  catch {
269
247
  return null;
270
248
  }
271
249
  }
272
- function postTurn(messages, sessPath, usage, hooks) {
250
+ function postTurn(messages, sessPath, usage, hooks, state) {
251
+ const preTrimMessages = [...messages];
273
252
  if (hooks?.beforeTrim) {
274
253
  try {
275
- hooks.beforeTrim([...messages]);
254
+ hooks.beforeTrim(preTrimMessages);
276
255
  }
277
256
  catch (error) {
278
257
  (0, runtime_1.emitNervesEvent)({
@@ -287,9 +266,26 @@ function postTurn(messages, sessPath, usage, hooks) {
287
266
  }
288
267
  }
289
268
  const { maxTokens, contextMargin } = (0, config_1.getContextConfig)();
290
- const trimmed = trimMessages(messages, maxTokens, contextMargin, usage?.input_tokens);
269
+ const currentMessages = (0, session_events_1.sanitizeProviderMessages)(messages);
270
+ const trimmed = trimMessages(currentMessages, maxTokens, contextMargin, usage?.input_tokens);
291
271
  messages.splice(0, messages.length, ...trimmed);
292
- saveSession(sessPath, messages, usage);
272
+ const existing = (0, session_events_1.loadSessionEnvelopeFile)(sessPath);
273
+ const previousMessages = existing ? (0, session_events_1.projectProviderMessages)(existing) : [];
274
+ const envelope = (0, session_events_1.buildCanonicalSessionEnvelope)({
275
+ existing,
276
+ previousMessages,
277
+ currentMessages,
278
+ trimmedMessages: trimmed,
279
+ recordedAt: new Date().toISOString(),
280
+ lastUsage: usage ?? null,
281
+ state,
282
+ projectionBasis: {
283
+ maxTokens,
284
+ contextMargin,
285
+ inputTokens: usage?.input_tokens ?? null,
286
+ },
287
+ });
288
+ writeSessionEnvelope(sessPath, envelope);
293
289
  }
294
290
  function deleteSession(filePath) {
295
291
  try {
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.detectSuspiciousContent = detectSuspiciousContent;
4
+ const PATTERN_CATEGORIES = [
5
+ {
6
+ name: "instruction_framing",
7
+ patterns: [
8
+ /\byou are (?:a|an) (?:ai|assistant|language model|helpful assistant)\b/i,
9
+ /\byour (?:new )?instructions are\b/i,
10
+ /\bsystem\s*:/i,
11
+ /\bignore (?:all |my )?previous instructions\b/i,
12
+ /\bdo not reveal\b/i,
13
+ ],
14
+ },
15
+ {
16
+ name: "override_language",
17
+ patterns: [
18
+ /\bdisregard\b/i,
19
+ /\bforget everything\b/i,
20
+ /\bnew instructions:/i,
21
+ /\boverride (?:all |any |previous )?instructions\b/i,
22
+ ],
23
+ },
24
+ {
25
+ name: "role_injection",
26
+ patterns: [
27
+ /\bas (?:a|an) (?:ai|language model)\b/i,
28
+ /\byou must always\b/i,
29
+ /\byou are now\b/i,
30
+ ],
31
+ },
32
+ {
33
+ name: "boundary_markers",
34
+ patterns: [
35
+ /```system/i,
36
+ /<<SYS>>/i,
37
+ /\[INST\]/i,
38
+ /<\/?system>/i,
39
+ /\[system\]/i,
40
+ ],
41
+ },
42
+ ];
43
+ function detectSuspiciousContent(text) {
44
+ if (!text) {
45
+ return { suspicious: false, patterns: [] };
46
+ }
47
+ const matched = new Set();
48
+ for (const category of PATTERN_CATEGORIES) {
49
+ for (const pattern of category.patterns) {
50
+ if (pattern.test(text)) {
51
+ matched.add(category.name);
52
+ break;
53
+ }
54
+ }
55
+ }
56
+ return {
57
+ suspicious: matched.size > 0,
58
+ patterns: [...matched],
59
+ };
60
+ }