@ouro.bot/cli 0.1.0-alpha.39 → 0.1.0-alpha.391

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 (332) hide show
  1. package/README.md +109 -14
  2. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +3 -2
  3. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +2 -2
  4. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
  5. package/changelog.json +2377 -4
  6. package/dist/arc/attention-types.js +8 -0
  7. package/dist/arc/cares.js +140 -0
  8. package/dist/arc/episodes.js +117 -0
  9. package/dist/arc/intentions.js +133 -0
  10. package/dist/arc/json-store.js +117 -0
  11. package/dist/arc/obligations.js +237 -0
  12. package/dist/arc/packets.js +193 -0
  13. package/dist/arc/presence.js +185 -0
  14. package/dist/arc/task-lifecycle.js +65 -0
  15. package/dist/heart/active-work.js +832 -0
  16. package/dist/heart/agent-entry.js +58 -3
  17. package/dist/heart/attachments/image-normalize.js +194 -0
  18. package/dist/heart/attachments/materialize.js +97 -0
  19. package/dist/heart/attachments/originals.js +88 -0
  20. package/dist/heart/attachments/render.js +29 -0
  21. package/dist/heart/attachments/sources/adapter.js +2 -0
  22. package/dist/heart/attachments/sources/bluebubbles.js +156 -0
  23. package/dist/heart/attachments/sources/cli-local-file.js +78 -0
  24. package/dist/heart/attachments/sources/index.js +16 -0
  25. package/dist/heart/attachments/store.js +103 -0
  26. package/dist/heart/attachments/types.js +93 -0
  27. package/dist/heart/auth/auth-flow.js +378 -0
  28. package/dist/heart/bridges/manager.js +358 -0
  29. package/dist/heart/bridges/state-machine.js +135 -0
  30. package/dist/heart/bridges/store.js +123 -0
  31. package/dist/heart/bundle-state.js +168 -0
  32. package/dist/heart/commitments.js +111 -0
  33. package/dist/heart/config-registry.js +304 -0
  34. package/dist/heart/config.js +111 -128
  35. package/dist/heart/core.js +803 -259
  36. package/dist/heart/cross-chat-delivery.js +131 -0
  37. package/dist/heart/daemon/agent-config-check.js +384 -0
  38. package/dist/heart/daemon/agent-discovery.js +79 -3
  39. package/dist/heart/daemon/agent-service.js +360 -0
  40. package/dist/heart/daemon/agentic-repair.js +205 -0
  41. package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
  42. package/dist/heart/daemon/cadence.js +70 -0
  43. package/dist/heart/daemon/cli-defaults.js +599 -0
  44. package/dist/heart/daemon/cli-exec.js +3384 -0
  45. package/dist/heart/daemon/cli-help.js +385 -0
  46. package/dist/heart/daemon/cli-parse.js +1097 -0
  47. package/dist/heart/daemon/cli-render-doctor.js +57 -0
  48. package/dist/heart/daemon/cli-render.js +560 -0
  49. package/dist/heart/daemon/cli-types.js +8 -0
  50. package/dist/heart/daemon/daemon-cli.js +28 -1582
  51. package/dist/heart/daemon/daemon-entry.js +356 -3
  52. package/dist/heart/daemon/daemon-health.js +141 -0
  53. package/dist/heart/daemon/daemon-runtime-sync.js +157 -12
  54. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  55. package/dist/heart/daemon/daemon.js +684 -58
  56. package/dist/heart/daemon/doctor-types.js +8 -0
  57. package/dist/heart/daemon/doctor.js +419 -0
  58. package/dist/heart/daemon/health-monitor.js +79 -1
  59. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  60. package/dist/heart/daemon/hooks/bundle-meta.js +115 -1
  61. package/dist/heart/daemon/http-health-probe.js +80 -0
  62. package/dist/heart/daemon/inner-status.js +89 -0
  63. package/dist/heart/daemon/interactive-repair.js +182 -0
  64. package/dist/heart/daemon/launchd.js +46 -9
  65. package/dist/heart/daemon/log-tailer.js +82 -12
  66. package/dist/heart/daemon/logs-prune.js +105 -0
  67. package/dist/heart/daemon/message-router.js +17 -8
  68. package/dist/heart/daemon/os-cron-deps.js +134 -0
  69. package/dist/heart/daemon/ouro-bot-entry.js +4 -2
  70. package/dist/heart/daemon/ouro-entry.js +3 -1
  71. package/dist/heart/daemon/process-manager.js +201 -0
  72. package/dist/heart/daemon/provider-discovery.js +137 -0
  73. package/dist/heart/daemon/pulse.js +475 -0
  74. package/dist/heart/daemon/run-hooks.js +2 -0
  75. package/dist/heart/daemon/runtime-logging.js +67 -16
  76. package/dist/heart/daemon/runtime-metadata.js +73 -0
  77. package/dist/heart/daemon/runtime-mode.js +67 -0
  78. package/dist/heart/daemon/safe-mode.js +161 -0
  79. package/dist/heart/daemon/sense-manager.js +119 -30
  80. package/dist/heart/daemon/session-id-resolver.js +131 -0
  81. package/dist/heart/daemon/skill-management-installer.js +94 -0
  82. package/dist/heart/daemon/socket-client.js +307 -0
  83. package/dist/heart/daemon/stale-bundle-prune.js +96 -0
  84. package/dist/heart/daemon/startup-tui.js +237 -0
  85. package/dist/heart/daemon/task-scheduler.js +3 -25
  86. package/dist/heart/daemon/thoughts.js +510 -0
  87. package/dist/heart/daemon/up-progress.js +135 -0
  88. package/dist/heart/delegation.js +62 -0
  89. package/dist/heart/habits/habit-migration.js +181 -0
  90. package/dist/heart/habits/habit-parser.js +140 -0
  91. package/dist/heart/habits/habit-scheduler.js +371 -0
  92. package/dist/heart/{daemon → hatch}/hatch-flow.js +55 -126
  93. package/dist/heart/{daemon → hatch}/hatch-specialist.js +3 -3
  94. package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
  95. package/dist/heart/{daemon → hatch}/specialist-tools.js +33 -12
  96. package/dist/heart/identity.js +153 -65
  97. package/dist/heart/kept-notes.js +357 -0
  98. package/dist/heart/kicks.js +2 -20
  99. package/dist/heart/machine-identity.js +161 -0
  100. package/dist/heart/mcp/mcp-server.js +653 -0
  101. package/dist/heart/migrate-config.js +100 -0
  102. package/dist/heart/model-capabilities.js +59 -0
  103. package/dist/heart/outlook/outlook-http-hooks.js +64 -0
  104. package/dist/heart/outlook/outlook-http-response.js +7 -0
  105. package/dist/heart/outlook/outlook-http-routes.js +232 -0
  106. package/dist/heart/outlook/outlook-http-static.js +99 -0
  107. package/dist/heart/outlook/outlook-http-transport.js +116 -0
  108. package/dist/heart/outlook/outlook-http.js +99 -0
  109. package/dist/heart/outlook/outlook-read.js +28 -0
  110. package/dist/heart/outlook/outlook-types.js +27 -0
  111. package/dist/heart/outlook/outlook-view.js +195 -0
  112. package/dist/heart/outlook/readers/agent-machine.js +359 -0
  113. package/dist/heart/outlook/readers/continuity-readers.js +332 -0
  114. package/dist/heart/outlook/readers/runtime-readers.js +660 -0
  115. package/dist/heart/outlook/readers/sessions.js +232 -0
  116. package/dist/heart/outlook/readers/shared.js +111 -0
  117. package/dist/heart/platform.js +81 -0
  118. package/dist/heart/progress-story.js +42 -0
  119. package/dist/heart/provider-attempt.js +133 -0
  120. package/dist/heart/provider-binding-resolver.js +239 -0
  121. package/dist/heart/provider-credentials.js +379 -0
  122. package/dist/heart/provider-failover.js +266 -0
  123. package/dist/heart/provider-models.js +81 -0
  124. package/dist/heart/provider-ping.js +237 -0
  125. package/dist/heart/provider-state.js +216 -0
  126. package/dist/heart/provider-visibility.js +186 -0
  127. package/dist/heart/providers/anthropic-token.js +131 -0
  128. package/dist/heart/providers/anthropic.js +193 -55
  129. package/dist/heart/providers/azure.js +103 -12
  130. package/dist/heart/providers/error-classification.js +63 -0
  131. package/dist/heart/providers/github-copilot.js +145 -0
  132. package/dist/heart/providers/minimax-vlm.js +189 -0
  133. package/dist/heart/providers/minimax.js +29 -7
  134. package/dist/heart/providers/openai-codex.js +39 -29
  135. package/dist/heart/runtime-credentials.js +181 -0
  136. package/dist/heart/session-activity.js +190 -0
  137. package/dist/heart/session-events.js +855 -0
  138. package/dist/heart/session-transcript.js +167 -0
  139. package/dist/heart/start-of-turn-packet.js +345 -0
  140. package/dist/heart/streaming.js +36 -27
  141. package/dist/heart/sync.js +332 -0
  142. package/dist/heart/target-resolution.js +127 -0
  143. package/dist/heart/tempo.js +93 -0
  144. package/dist/heart/temporal-view.js +41 -0
  145. package/dist/heart/tool-activity-callbacks.js +36 -0
  146. package/dist/heart/tool-description.js +135 -0
  147. package/dist/heart/tool-friction.js +55 -0
  148. package/dist/heart/tool-loop.js +200 -0
  149. package/dist/heart/turn-context.js +351 -0
  150. package/dist/heart/turn-coordinator.js +28 -0
  151. package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +1 -1
  152. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
  153. package/dist/heart/versioning/ouro-path-installer.js +301 -0
  154. package/dist/heart/versioning/ouro-version-manager.js +295 -0
  155. package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
  156. package/dist/heart/{daemon → versioning}/update-checker.js +12 -2
  157. package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
  158. package/dist/mind/bundle-manifest.js +7 -1
  159. package/dist/mind/context.js +141 -94
  160. package/dist/mind/diary-integrity.js +60 -0
  161. package/dist/mind/{memory.js → diary.js} +84 -96
  162. package/dist/mind/embedding-provider.js +60 -0
  163. package/dist/mind/file-state.js +179 -0
  164. package/dist/mind/first-impressions.js +14 -1
  165. package/dist/mind/friends/channel.js +21 -0
  166. package/dist/mind/friends/group-context.js +144 -0
  167. package/dist/mind/friends/resolver.js +38 -1
  168. package/dist/mind/friends/store-file.js +39 -3
  169. package/dist/mind/friends/trust-explanation.js +74 -0
  170. package/dist/mind/friends/types.js +1 -1
  171. package/dist/mind/journal-index.js +161 -0
  172. package/dist/mind/note-search.js +268 -0
  173. package/dist/mind/obligation-steering.js +221 -0
  174. package/dist/mind/pending.js +66 -7
  175. package/dist/mind/prompt-refresh.js +3 -2
  176. package/dist/mind/prompt.js +946 -167
  177. package/dist/mind/provenance-trust.js +26 -0
  178. package/dist/mind/scrutiny.js +173 -0
  179. package/dist/mind/token-estimate.js +8 -12
  180. package/dist/nerves/cli-logging.js +7 -1
  181. package/dist/nerves/coverage/audit-rules.js +15 -6
  182. package/dist/nerves/coverage/audit.js +28 -2
  183. package/dist/nerves/coverage/cli.js +1 -1
  184. package/dist/nerves/coverage/file-completeness.js +83 -5
  185. package/dist/nerves/coverage/run-artifacts.js +1 -1
  186. package/dist/nerves/event-buffer.js +111 -0
  187. package/dist/nerves/index.js +224 -4
  188. package/dist/nerves/observation.js +20 -0
  189. package/dist/nerves/redact.js +79 -0
  190. package/dist/nerves/runtime.js +5 -1
  191. package/dist/outlook-ui/assets/index-BAcU08c-.css +1 -0
  192. package/dist/outlook-ui/assets/index-D7l3l4vY.js +61 -0
  193. package/dist/outlook-ui/index.html +15 -0
  194. package/dist/repertoire/ado-client.js +15 -56
  195. package/dist/repertoire/ado-semantic.js +11 -10
  196. package/dist/repertoire/api-client.js +97 -0
  197. package/dist/repertoire/bitwarden-store.js +365 -0
  198. package/dist/repertoire/bundle-templates.js +72 -0
  199. package/dist/repertoire/bw-installer.js +79 -0
  200. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  201. package/dist/repertoire/coding/context-pack.js +330 -0
  202. package/dist/repertoire/coding/feedback.js +197 -30
  203. package/dist/repertoire/coding/manager.js +158 -9
  204. package/dist/repertoire/coding/spawner.js +55 -9
  205. package/dist/repertoire/coding/tools.js +170 -7
  206. package/dist/repertoire/commerce-errors.js +109 -0
  207. package/dist/repertoire/commerce-self-test.js +156 -0
  208. package/dist/repertoire/credential-access.js +107 -0
  209. package/dist/repertoire/duffel-client.js +185 -0
  210. package/dist/repertoire/github-client.js +14 -55
  211. package/dist/repertoire/graph-client.js +11 -52
  212. package/dist/repertoire/guardrails.js +371 -0
  213. package/dist/repertoire/mcp-client.js +255 -0
  214. package/dist/repertoire/mcp-manager.js +305 -0
  215. package/dist/repertoire/mcp-tools.js +63 -0
  216. package/dist/repertoire/shell-sessions.js +133 -0
  217. package/dist/repertoire/skills.js +15 -24
  218. package/dist/repertoire/stripe-client.js +131 -0
  219. package/dist/repertoire/tasks/board.js +43 -5
  220. package/dist/repertoire/tasks/fix.js +182 -0
  221. package/dist/repertoire/tasks/index.js +28 -10
  222. package/dist/repertoire/tasks/lifecycle.js +2 -2
  223. package/dist/repertoire/tasks/parser.js +3 -2
  224. package/dist/repertoire/tasks/scanner.js +194 -37
  225. package/dist/repertoire/tasks/transitions.js +16 -79
  226. package/dist/repertoire/tool-results.js +29 -0
  227. package/dist/repertoire/tools-attachments.js +317 -0
  228. package/dist/repertoire/tools-base.js +42 -690
  229. package/dist/repertoire/tools-bluebubbles.js +1 -0
  230. package/dist/repertoire/tools-bridge.js +141 -0
  231. package/dist/repertoire/tools-bundle.js +984 -0
  232. package/dist/repertoire/tools-config.js +185 -0
  233. package/dist/repertoire/tools-continuity.js +248 -0
  234. package/dist/repertoire/tools-credential.js +182 -0
  235. package/dist/repertoire/tools-files.js +342 -0
  236. package/dist/repertoire/tools-flight.js +224 -0
  237. package/dist/repertoire/tools-flow.js +105 -0
  238. package/dist/repertoire/tools-github.js +1 -7
  239. package/dist/repertoire/tools-notes.js +376 -0
  240. package/dist/repertoire/tools-session.js +739 -0
  241. package/dist/repertoire/tools-shell.js +120 -0
  242. package/dist/repertoire/tools-stripe.js +180 -0
  243. package/dist/repertoire/tools-surface.js +243 -0
  244. package/dist/repertoire/tools-teams.js +12 -62
  245. package/dist/repertoire/tools-travel.js +125 -0
  246. package/dist/repertoire/tools-user-profile.js +144 -0
  247. package/dist/repertoire/tools-vault.js +40 -0
  248. package/dist/repertoire/tools.js +144 -115
  249. package/dist/repertoire/travel-api-client.js +360 -0
  250. package/dist/repertoire/user-profile.js +118 -0
  251. package/dist/repertoire/vault-setup.js +246 -0
  252. package/dist/repertoire/vault-unlock.js +366 -0
  253. package/dist/scripts/claude-code-hook.js +41 -0
  254. package/dist/scripts/claude-code-stop-hook.js +47 -0
  255. package/dist/senses/attention-queue.js +116 -0
  256. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  257. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  258. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +260 -9
  259. package/dist/senses/bluebubbles/entry.js +70 -0
  260. package/dist/senses/bluebubbles/inbound-log.js +113 -0
  261. package/dist/senses/bluebubbles/index.js +1620 -0
  262. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -70
  263. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +33 -12
  264. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +46 -6
  265. package/dist/senses/bluebubbles/replay.js +129 -0
  266. package/dist/senses/bluebubbles/runtime-state.js +109 -0
  267. package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
  268. package/dist/senses/cli/bracketed-paste.js +82 -0
  269. package/dist/senses/cli/image-paste.js +287 -0
  270. package/dist/senses/cli/image-ref-navigation.js +75 -0
  271. package/dist/senses/cli/ink-app.js +156 -0
  272. package/dist/senses/cli/inline-diff.js +64 -0
  273. package/dist/senses/cli/input-keys.js +174 -0
  274. package/dist/senses/cli/kill-ring.js +86 -0
  275. package/dist/senses/cli/message-list.js +51 -0
  276. package/dist/senses/cli/ouro-tui.js +605 -0
  277. package/dist/senses/cli/spinner-imperative.js +135 -0
  278. package/dist/senses/cli/spinner.js +101 -0
  279. package/dist/senses/cli/status-line.js +60 -0
  280. package/dist/senses/cli/streaming-markdown.js +526 -0
  281. package/dist/senses/cli/tool-display.js +83 -0
  282. package/dist/senses/cli/tool-render.js +85 -0
  283. package/dist/senses/cli/tui-store.js +240 -0
  284. package/dist/senses/cli/virtual-list.js +35 -0
  285. package/dist/senses/cli-entry.js +60 -8
  286. package/dist/senses/cli-layout.js +187 -0
  287. package/dist/senses/cli.js +526 -211
  288. package/dist/senses/commands.js +66 -3
  289. package/dist/senses/continuity.js +94 -0
  290. package/dist/senses/habit-turn-message.js +108 -0
  291. package/dist/senses/inner-dialog-worker.js +112 -19
  292. package/dist/senses/inner-dialog.js +600 -95
  293. package/dist/senses/pipeline.js +539 -61
  294. package/dist/senses/proactive-content-guard.js +51 -0
  295. package/dist/senses/shared-turn.js +205 -0
  296. package/dist/senses/surface-tool.js +68 -0
  297. package/dist/senses/teams-entry.js +60 -8
  298. package/dist/senses/teams.js +569 -237
  299. package/dist/senses/trust-gate.js +6 -7
  300. package/package.json +28 -7
  301. package/skills/agent-commerce.md +106 -0
  302. package/skills/browser-navigation.md +110 -0
  303. package/skills/commerce-setup-guide.md +116 -0
  304. package/skills/commerce-setup.md +84 -0
  305. package/skills/configure-dev-tools.md +101 -0
  306. package/skills/travel-planning.md +134 -0
  307. package/dist/heart/daemon/ouro-path-installer.js +0 -178
  308. package/dist/heart/daemon/subagent-installer.js +0 -134
  309. package/dist/mind/associative-recall.js +0 -197
  310. package/dist/senses/bluebubbles-entry.js +0 -11
  311. package/dist/senses/bluebubbles.js +0 -832
  312. package/dist/senses/debug-activity.js +0 -127
  313. package/subagents/README.md +0 -60
  314. package/subagents/work-doer.md +0 -235
  315. package/subagents/work-merger.md +0 -618
  316. package/subagents/work-planner.md +0 -382
  317. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  318. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  319. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  320. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  321. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  322. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  323. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  324. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  325. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  326. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  327. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  328. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  329. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  330. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  331. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  332. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -0,0 +1,246 @@
1
+ "use strict";
2
+ /**
3
+ * Vault setup module — Bitwarden/Vaultwarden account creation.
4
+ *
5
+ * Implements the Bitwarden registration protocol using Node.js crypto:
6
+ * - PBKDF2-SHA256 for master key derivation
7
+ * - HKDF-SHA256 for key stretching
8
+ * - AES-256-CBC for symmetric key protection
9
+ * - RSA-2048 keypair for asymmetric encryption
10
+ *
11
+ * All crypto follows the Bitwarden security whitepaper:
12
+ * https://bitwarden.com/help/bitwarden-security-white-paper/
13
+ */
14
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ var desc = Object.getOwnPropertyDescriptor(m, k);
17
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
18
+ desc = { enumerable: true, get: function() { return m[k]; } };
19
+ }
20
+ Object.defineProperty(o, k2, desc);
21
+ }) : (function(o, m, k, k2) {
22
+ if (k2 === undefined) k2 = k;
23
+ o[k2] = m[k];
24
+ }));
25
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
26
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
27
+ }) : function(o, v) {
28
+ o["default"] = v;
29
+ });
30
+ var __importStar = (this && this.__importStar) || (function () {
31
+ var ownKeys = function(o) {
32
+ ownKeys = Object.getOwnPropertyNames || function (o) {
33
+ var ar = [];
34
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
35
+ return ar;
36
+ };
37
+ return ownKeys(o);
38
+ };
39
+ return function (mod) {
40
+ if (mod && mod.__esModule) return mod;
41
+ var result = {};
42
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
43
+ __setModuleDefault(result, mod);
44
+ return result;
45
+ };
46
+ })();
47
+ Object.defineProperty(exports, "__esModule", { value: true });
48
+ exports.deriveMasterKey = deriveMasterKey;
49
+ exports.deriveMasterPasswordHash = deriveMasterPasswordHash;
50
+ exports.deriveStretchedMasterKey = deriveStretchedMasterKey;
51
+ exports.makeProtectedSymmetricKey = makeProtectedSymmetricKey;
52
+ exports.createVaultAccount = createVaultAccount;
53
+ const crypto = __importStar(require("node:crypto"));
54
+ const runtime_1 = require("../nerves/runtime");
55
+ // ---------------------------------------------------------------------------
56
+ // Crypto primitives
57
+ // ---------------------------------------------------------------------------
58
+ /**
59
+ * Derive the master key from password and email using PBKDF2-SHA256.
60
+ * Email is lowercased and used as the salt per Bitwarden spec.
61
+ */
62
+ function deriveMasterKey(password, email, iterations) {
63
+ return new Promise((resolve, reject) => {
64
+ crypto.pbkdf2(password, email.toLowerCase(), iterations, 32, "sha256", (err, key) => {
65
+ /* v8 ignore next -- defensive: pbkdf2 rejects on invalid input @preserve */
66
+ if (err)
67
+ reject(err);
68
+ else
69
+ resolve(key);
70
+ });
71
+ });
72
+ }
73
+ /**
74
+ * Derive the master password hash: PBKDF2-SHA256(masterKey, password, 1 iteration).
75
+ * This hash is sent to the server for authentication — it never sees the master key.
76
+ */
77
+ function deriveMasterPasswordHash(masterKey, password) {
78
+ return new Promise((resolve, reject) => {
79
+ crypto.pbkdf2(masterKey, password, 1, 32, "sha256", (err, hash) => {
80
+ /* v8 ignore next -- defensive: pbkdf2 rejects on invalid input @preserve */
81
+ if (err)
82
+ reject(err);
83
+ else
84
+ resolve(hash.toString("base64"));
85
+ });
86
+ });
87
+ }
88
+ /**
89
+ * Stretch the master key using HKDF-Expand-only (RFC 5869 §2.3) to produce a 64-byte key.
90
+ * First 32 bytes = encryption key, last 32 bytes = MAC key.
91
+ *
92
+ * CRITICAL: Bitwarden uses HKDF-Expand ONLY (no Extract step).
93
+ * Node.js crypto.hkdfSync() does Extract+Expand which produces DIFFERENT output.
94
+ * Reference: https://github.com/bitwarden/sdk-internal/blob/main/crates/bitwarden-crypto/src/util.rs
95
+ * Bitwarden calls Hkdf::<Sha256>::from_prk(masterKey).expand(info, output) — Expand only.
96
+ */
97
+ function deriveStretchedMasterKey(masterKey) {
98
+ const encKey = hkdfExpandOnly(masterKey, "enc", 32);
99
+ const macKey = hkdfExpandOnly(masterKey, "mac", 32);
100
+ return Buffer.concat([encKey, macKey]);
101
+ }
102
+ /**
103
+ * HKDF-Expand only (RFC 5869 §2.3) — no Extract step.
104
+ * Matches Bitwarden's Hkdf::from_prk(prk).expand(info).
105
+ */
106
+ function hkdfExpandOnly(prk, info, length) {
107
+ const hashLen = 32; // SHA-256
108
+ const n = Math.ceil(length / hashLen);
109
+ let okm = Buffer.alloc(0);
110
+ let t = Buffer.alloc(0);
111
+ for (let i = 1; i <= n; i++) {
112
+ t = crypto.createHmac("sha256", prk)
113
+ .update(Buffer.concat([t, Buffer.from(info, "utf8"), Buffer.from([i])]))
114
+ .digest();
115
+ okm = Buffer.concat([okm, t]);
116
+ }
117
+ return okm.subarray(0, length);
118
+ }
119
+ /**
120
+ * Encrypt data with AES-256-CBC and HMAC-SHA256 MAC.
121
+ * Returns a Bitwarden "type 2" cipherstring: "2.<iv>|<ct>|<mac>"
122
+ */
123
+ function encryptWithStretchedKey(data, stretchedKey) {
124
+ const encKey = stretchedKey.subarray(0, 32);
125
+ const macKey = stretchedKey.subarray(32, 64);
126
+ const iv = crypto.randomBytes(16);
127
+ const cipher = crypto.createCipheriv("aes-256-cbc", encKey, iv);
128
+ const ct = Buffer.concat([cipher.update(data), cipher.final()]);
129
+ // MAC covers iv + ct
130
+ const mac = crypto.createHmac("sha256", macKey)
131
+ .update(iv)
132
+ .update(ct)
133
+ .digest();
134
+ return `2.${iv.toString("base64")}|${ct.toString("base64")}|${mac.toString("base64")}`;
135
+ }
136
+ /**
137
+ * Generate a 64-byte symmetric key, encrypt it with the stretched master key.
138
+ * Returns the "protected symmetric key" cipherstring.
139
+ */
140
+ function makeProtectedSymmetricKey(stretchedMasterKey) {
141
+ const symKey = crypto.randomBytes(64);
142
+ return encryptWithStretchedKey(symKey, stretchedMasterKey);
143
+ }
144
+ /**
145
+ * Generate an RSA-2048 keypair.
146
+ * Returns { publicKey: base64-DER, privateKeyDer: Buffer }.
147
+ */
148
+ function generateRsaKeypair() {
149
+ const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", {
150
+ modulusLength: 2048,
151
+ publicKeyEncoding: { type: "spki", format: "der" },
152
+ privateKeyEncoding: { type: "pkcs8", format: "der" },
153
+ });
154
+ return {
155
+ publicKeyB64: publicKey.toString("base64"),
156
+ privateKeyDer: privateKey,
157
+ };
158
+ }
159
+ // ---------------------------------------------------------------------------
160
+ // Registration
161
+ // ---------------------------------------------------------------------------
162
+ const KDF_PBKDF2 = 0;
163
+ const KDF_ITERATIONS = 600000;
164
+ const REGISTER_ACCOUNT_PATH = "/identity/accounts/register";
165
+ /**
166
+ * Create a Bitwarden account on the configured Vaultwarden server.
167
+ * Uses the Bitwarden registration API with standard KDF implementation.
168
+ */
169
+ async function createVaultAccount(agentName, serverUrl, email, masterPassword) {
170
+ (0, runtime_1.emitNervesEvent)({
171
+ event: "repertoire.vault_setup_start",
172
+ component: "repertoire",
173
+ message: `creating vault account for ${agentName}`,
174
+ meta: { agentName, serverUrl, email },
175
+ });
176
+ try {
177
+ // Step 1: Derive keys
178
+ const masterKey = await deriveMasterKey(masterPassword, email, KDF_ITERATIONS);
179
+ const masterPasswordHash = await deriveMasterPasswordHash(masterKey, masterPassword);
180
+ const stretchedKey = deriveStretchedMasterKey(masterKey);
181
+ // Step 2: Generate symmetric key (64 bytes = 32 enc + 32 mac), encrypt with stretched key
182
+ const symKey = crypto.randomBytes(64);
183
+ const protectedSymKey = encryptWithStretchedKey(symKey, stretchedKey);
184
+ // Step 3: Generate RSA keypair, encrypt private key with the symmetric key
185
+ const { publicKeyB64, privateKeyDer } = generateRsaKeypair();
186
+ const encryptedPrivateKey = encryptWithStretchedKey(privateKeyDer, symKey);
187
+ // Step 4: POST registration
188
+ const registrationUrl = `${serverUrl}${REGISTER_ACCOUNT_PATH}`;
189
+ const res = await fetch(registrationUrl, {
190
+ method: "POST",
191
+ headers: { "Content-Type": "application/json" },
192
+ body: JSON.stringify({
193
+ name: agentName,
194
+ email,
195
+ masterPasswordHash,
196
+ masterPasswordHint: null,
197
+ key: protectedSymKey,
198
+ kdf: KDF_PBKDF2,
199
+ kdfIterations: KDF_ITERATIONS,
200
+ keys: {
201
+ publicKey: publicKeyB64,
202
+ encryptedPrivateKey,
203
+ },
204
+ }),
205
+ });
206
+ if (!res.ok) {
207
+ let errorDetail;
208
+ try {
209
+ const body = await res.json();
210
+ errorDetail = body.message ?? `HTTP ${res.status} ${res.statusText}`;
211
+ }
212
+ catch {
213
+ errorDetail = `HTTP ${res.status} ${res.statusText}`;
214
+ }
215
+ const endpointAwareError = `${errorDetail} from ${registrationUrl}. Check --server; Ouro expects a Bitwarden/Vaultwarden identity API.`;
216
+ (0, runtime_1.emitNervesEvent)({
217
+ level: "error",
218
+ event: "repertoire.vault_setup_error",
219
+ component: "repertoire",
220
+ message: `vault registration failed: ${endpointAwareError}`,
221
+ meta: { agentName, serverUrl, email, registrationUrl, reason: endpointAwareError },
222
+ });
223
+ return { success: false, email, serverUrl, error: endpointAwareError };
224
+ }
225
+ (0, runtime_1.emitNervesEvent)({
226
+ event: "repertoire.vault_setup_end",
227
+ component: "repertoire",
228
+ message: `vault account created for ${agentName}`,
229
+ meta: { agentName, serverUrl, email },
230
+ });
231
+ return { success: true, email, serverUrl };
232
+ }
233
+ catch (err) {
234
+ const reason = err instanceof Error ? err.message : String(err);
235
+ const registrationUrl = `${serverUrl}${REGISTER_ACCOUNT_PATH}`;
236
+ const endpointAwareError = `cannot reach vault registration endpoint ${registrationUrl}: ${reason}. Check network, DNS/TLS, and --server.`;
237
+ (0, runtime_1.emitNervesEvent)({
238
+ level: "error",
239
+ event: "repertoire.vault_setup_error",
240
+ component: "repertoire",
241
+ message: `vault setup failed: ${endpointAwareError}`,
242
+ meta: { agentName, serverUrl, email, registrationUrl, reason: endpointAwareError },
243
+ });
244
+ return { success: false, email, serverUrl, error: endpointAwareError };
245
+ }
246
+ }
@@ -0,0 +1,366 @@
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.resolveVaultUnlockStore = resolveVaultUnlockStore;
37
+ exports.readVaultUnlockSecret = readVaultUnlockSecret;
38
+ exports.storeVaultUnlockSecret = storeVaultUnlockSecret;
39
+ exports.getVaultUnlockStatus = getVaultUnlockStatus;
40
+ const node_child_process_1 = require("node:child_process");
41
+ const crypto = __importStar(require("node:crypto"));
42
+ const fs = __importStar(require("node:fs"));
43
+ const os = __importStar(require("node:os"));
44
+ const path = __importStar(require("node:path"));
45
+ const runtime_1 = require("../nerves/runtime");
46
+ const VAULT_UNLOCK_SERVICE = "ouro.vault";
47
+ const PLAINTEXT_UNLOCK_DIR = path.join(".ouro-cli", "vault-unlock");
48
+ const WINDOWS_DPAPI_UNLOCK_DIR = path.join(".ouro-cli", "vault-unlock-dpapi");
49
+ const SUPPORTED_STORES = ["auto", "macos-keychain", "windows-dpapi", "linux-secret-service", "plaintext-file"];
50
+ function platform(deps) {
51
+ return deps.platform ?? process.platform;
52
+ }
53
+ function spawnSync(deps) {
54
+ return deps.spawnSync ?? node_child_process_1.spawnSync;
55
+ }
56
+ function homeDir(deps) {
57
+ return deps.homeDir ?? os.homedir();
58
+ }
59
+ function vaultKey(config) {
60
+ return `${config.serverUrl}:${config.email}`;
61
+ }
62
+ function vaultLabel(config) {
63
+ return `${config.email} at ${config.serverUrl}`;
64
+ }
65
+ function plaintextUnlockPath(config, deps) {
66
+ const digest = crypto.createHash("sha256").update(vaultKey(config)).digest("hex").slice(0, 24);
67
+ return path.join(homeDir(deps), PLAINTEXT_UNLOCK_DIR, `${digest}.secret`);
68
+ }
69
+ function windowsDpapiUnlockPath(config, deps) {
70
+ const digest = crypto.createHash("sha256").update(vaultKey(config)).digest("hex").slice(0, 24);
71
+ const localAppData = process.env.LOCALAPPDATA;
72
+ const baseDir = localAppData && platform(deps) === "win32"
73
+ ? path.join(localAppData, "Ouro")
74
+ : path.join(homeDir(deps), WINDOWS_DPAPI_UNLOCK_DIR);
75
+ return path.join(baseDir, "vault-unlock", `${digest}.dpapi`);
76
+ }
77
+ function commandExists(command, deps) {
78
+ const result = spawnSync(deps)(command, ["--version"], { encoding: "utf8" });
79
+ const code = result.error?.code;
80
+ return code !== "ENOENT";
81
+ }
82
+ function missingSecureStoreMessage(config) {
83
+ const agentPart = config.agentName ? ` for ${config.agentName}` : "";
84
+ return [
85
+ `No supported secure local secret store was found on this machine${agentPart}.`,
86
+ "",
87
+ `Ouro knows the credential vault is ${vaultLabel(config)}, but it cannot cache the vault unlock secret here yet.`,
88
+ "",
89
+ "On macOS, Ouro uses Keychain automatically.",
90
+ "On Windows, Ouro uses a CurrentUser DPAPI-encrypted local file automatically.",
91
+ "On Linux/WSL, install and configure Secret Service/libsecret, or choose the explicit plaintext fallback on a trusted machine.",
92
+ "",
93
+ config.agentName
94
+ ? `Run \`ouro vault unlock --agent ${config.agentName} --store plaintext-file\` to store the vault unlock secret in a chmod 0600 local file.`
95
+ : "Run `ouro vault unlock --store plaintext-file` to store the vault unlock secret in a chmod 0600 local file.",
96
+ ].join("\n");
97
+ }
98
+ function lockedMessage(config, store) {
99
+ const agentPart = config.agentName ? ` for ${config.agentName}` : "";
100
+ const command = config.agentName
101
+ ? `ouro vault unlock --agent ${config.agentName}${store.kind === "plaintext-file" ? " --store plaintext-file" : ""}`
102
+ : `ouro vault unlock${store.kind === "plaintext-file" ? " --store plaintext-file" : ""}`;
103
+ return [
104
+ `Ouro credential vault is locked on this machine${agentPart}.`,
105
+ "",
106
+ `Vault: ${vaultLabel(config)}`,
107
+ `Local unlock store: ${store.kind} (${store.location})`,
108
+ "",
109
+ "Provider credentials are still stored in the agent vault.",
110
+ "This computer does not currently have usable local unlock material for that vault.",
111
+ "This can happen on a new computer, after a local profile or hostname migration, or if the local unlock entry was removed.",
112
+ "",
113
+ `Run \`${command}\` and enter the saved agent vault unlock secret from the human/operator who controls that vault.`,
114
+ config.agentName
115
+ ? `If nobody saved that unlock secret, run \`ouro vault recover --agent ${config.agentName} --from <json>\` with a local credential export, or create a replacement vault and re-enter credentials.`
116
+ : "If nobody saved that unlock secret, run `ouro vault recover --agent <agent> --from <json>` with a local credential export, or create a replacement vault and re-enter credentials.",
117
+ ].join("\n");
118
+ }
119
+ function validateStoreKind(store) {
120
+ const requested = store ?? "auto";
121
+ if (!SUPPORTED_STORES.includes(requested)) {
122
+ throw new Error(`unknown vault unlock store '${requested}'. Use auto|macos-keychain|windows-dpapi|linux-secret-service|plaintext-file.`);
123
+ }
124
+ return requested;
125
+ }
126
+ function resolveVaultUnlockStore(config, deps = {}) {
127
+ const requested = validateStoreKind(deps.store);
128
+ const currentPlatform = platform(deps);
129
+ if (requested === "macos-keychain") {
130
+ if (currentPlatform !== "darwin") {
131
+ throw new Error(`macos-keychain unlock store is only available on macOS; this machine is ${currentPlatform}.`);
132
+ }
133
+ return { kind: "macos-keychain", secure: true, location: "macOS Keychain" };
134
+ }
135
+ if (requested === "linux-secret-service") {
136
+ if (currentPlatform !== "linux") {
137
+ throw new Error(`linux-secret-service unlock store is only available on Linux/WSL; this machine is ${currentPlatform}.`);
138
+ }
139
+ if (!commandExists("secret-tool", deps)) {
140
+ throw new Error("linux-secret-service unlock store requires the `secret-tool` command from libsecret.");
141
+ }
142
+ return { kind: "linux-secret-service", secure: true, location: "Secret Service via secret-tool" };
143
+ }
144
+ if (requested === "windows-dpapi") {
145
+ if (currentPlatform !== "win32") {
146
+ throw new Error(`windows-dpapi unlock store is only available on Windows; this machine is ${currentPlatform}.`);
147
+ }
148
+ return { kind: "windows-dpapi", secure: true, location: windowsDpapiUnlockPath(config, deps) };
149
+ }
150
+ if (requested === "plaintext-file") {
151
+ return { kind: "plaintext-file", secure: false, location: plaintextUnlockPath(config, deps) };
152
+ }
153
+ if (currentPlatform === "darwin") {
154
+ return { kind: "macos-keychain", secure: true, location: "macOS Keychain" };
155
+ }
156
+ if (currentPlatform === "win32") {
157
+ return { kind: "windows-dpapi", secure: true, location: windowsDpapiUnlockPath(config, deps) };
158
+ }
159
+ if (currentPlatform === "linux" && commandExists("secret-tool", deps)) {
160
+ return { kind: "linux-secret-service", secure: true, location: "Secret Service via secret-tool" };
161
+ }
162
+ throw new Error(missingSecureStoreMessage(config));
163
+ }
164
+ function readFromMacosKeychain(config, deps) {
165
+ const result = spawnSync(deps)("security", [
166
+ "find-generic-password",
167
+ "-s",
168
+ VAULT_UNLOCK_SERVICE,
169
+ "-a",
170
+ vaultKey(config),
171
+ "-w",
172
+ ], { encoding: "utf8" });
173
+ const secret = typeof result.stdout === "string" ? result.stdout.trim() : "";
174
+ return result.status === 0 && secret ? secret : null;
175
+ }
176
+ function writeToMacosKeychain(config, secret, deps) {
177
+ const result = spawnSync(deps)("security", [
178
+ "add-generic-password",
179
+ "-U",
180
+ "-s",
181
+ VAULT_UNLOCK_SERVICE,
182
+ "-a",
183
+ vaultKey(config),
184
+ "-w",
185
+ secret,
186
+ ], { encoding: "utf8" });
187
+ if (result.status !== 0) {
188
+ const stderr = typeof result.stderr === "string" ? result.stderr.trim() : "";
189
+ throw new Error(`failed to store vault unlock secret in macOS Keychain${stderr ? `: ${stderr}` : ""}`);
190
+ }
191
+ }
192
+ function readFromLinuxSecretService(config, deps) {
193
+ const result = spawnSync(deps)("secret-tool", [
194
+ "lookup",
195
+ "service",
196
+ VAULT_UNLOCK_SERVICE,
197
+ "account",
198
+ vaultKey(config),
199
+ ], { encoding: "utf8" });
200
+ const secret = typeof result.stdout === "string" ? result.stdout.trim() : "";
201
+ return result.status === 0 && secret ? secret : null;
202
+ }
203
+ function writeToLinuxSecretService(config, secret, deps) {
204
+ const result = spawnSync(deps)("secret-tool", [
205
+ "store",
206
+ "--label",
207
+ `Ouro credential vault ${vaultLabel(config)}`,
208
+ "service",
209
+ VAULT_UNLOCK_SERVICE,
210
+ "account",
211
+ vaultKey(config),
212
+ ], { encoding: "utf8", input: secret });
213
+ if (result.status !== 0) {
214
+ const stderr = typeof result.stderr === "string" ? result.stderr.trim() : "";
215
+ throw new Error(`failed to store vault unlock secret in Linux Secret Service${stderr ? `: ${stderr}` : ""}`);
216
+ }
217
+ }
218
+ function runWindowsDpapi(mode, payload, deps) {
219
+ const script = `
220
+ $ErrorActionPreference = "Stop"
221
+ $inputJson = [Console]::In.ReadToEnd()
222
+ $payload = $inputJson | ConvertFrom-Json
223
+ Add-Type -AssemblyName System.Security
224
+ if ($payload.mode -eq "protect") {
225
+ $bytes = [Text.Encoding]::UTF8.GetBytes([string]$payload.secret)
226
+ $protected = [Security.Cryptography.ProtectedData]::Protect($bytes, $null, [Security.Cryptography.DataProtectionScope]::CurrentUser)
227
+ [Console]::Out.Write([Convert]::ToBase64String($protected))
228
+ } elseif ($payload.mode -eq "unprotect") {
229
+ $protected = [Convert]::FromBase64String([string]$payload.ciphertext)
230
+ $bytes = [Security.Cryptography.ProtectedData]::Unprotect($protected, $null, [Security.Cryptography.DataProtectionScope]::CurrentUser)
231
+ [Console]::Out.Write([Text.Encoding]::UTF8.GetString($bytes))
232
+ } else {
233
+ throw "unknown DPAPI mode"
234
+ }
235
+ `;
236
+ const result = spawnSync(deps)("powershell.exe", [
237
+ "-NoProfile",
238
+ "-NonInteractive",
239
+ "-ExecutionPolicy",
240
+ "Bypass",
241
+ "-Command",
242
+ script,
243
+ ], {
244
+ encoding: "utf8",
245
+ input: JSON.stringify({ mode, ...payload }),
246
+ });
247
+ if (result.status !== 0) {
248
+ const stderr = typeof result.stderr === "string" ? result.stderr.trim() : "";
249
+ const error = result.error instanceof Error ? result.error.message : stderr;
250
+ throw new Error(`Windows DPAPI ${mode} failed${error ? `: ${error}` : ""}`);
251
+ }
252
+ return typeof result.stdout === "string" ? result.stdout : "";
253
+ }
254
+ function readFromWindowsDpapi(config, deps) {
255
+ const filePath = windowsDpapiUnlockPath(config, deps);
256
+ if (!fs.existsSync(filePath))
257
+ return null;
258
+ const ciphertext = fs.readFileSync(filePath, "utf8").trim();
259
+ if (!ciphertext)
260
+ return null;
261
+ const secret = runWindowsDpapi("unprotect", { ciphertext }, deps).trim();
262
+ return secret || null;
263
+ }
264
+ function writeToWindowsDpapi(config, secret, deps) {
265
+ const filePath = windowsDpapiUnlockPath(config, deps);
266
+ const ciphertext = runWindowsDpapi("protect", { secret }, deps).trim();
267
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
268
+ fs.writeFileSync(filePath, `${ciphertext}\n`, "utf8");
269
+ }
270
+ function readFromPlaintextFile(config, deps) {
271
+ const filePath = plaintextUnlockPath(config, deps);
272
+ if (!fs.existsSync(filePath))
273
+ return null;
274
+ if (platform(deps) !== "win32") {
275
+ const mode = fs.statSync(filePath).mode & 0o777;
276
+ if ((mode & 0o077) !== 0) {
277
+ throw new Error(`refusing to read plaintext vault unlock file at ${filePath} because permissions are too broad; run chmod 600 ${filePath}`);
278
+ }
279
+ }
280
+ const secret = fs.readFileSync(filePath, "utf8").trim();
281
+ return secret || null;
282
+ }
283
+ function writeToPlaintextFile(config, secret, deps) {
284
+ const filePath = plaintextUnlockPath(config, deps);
285
+ fs.mkdirSync(path.dirname(filePath), { recursive: true, mode: 0o700 });
286
+ fs.writeFileSync(filePath, secret, { encoding: "utf8", mode: 0o600 });
287
+ if (platform(deps) !== "win32") {
288
+ fs.chmodSync(path.dirname(filePath), 0o700);
289
+ fs.chmodSync(filePath, 0o600);
290
+ }
291
+ }
292
+ function readFromStore(config, store, deps) {
293
+ if (store.kind === "macos-keychain")
294
+ return readFromMacosKeychain(config, deps);
295
+ if (store.kind === "windows-dpapi")
296
+ return readFromWindowsDpapi(config, deps);
297
+ if (store.kind === "linux-secret-service")
298
+ return readFromLinuxSecretService(config, deps);
299
+ return readFromPlaintextFile(config, deps);
300
+ }
301
+ function writeToStore(config, store, secret, deps) {
302
+ if (store.kind === "macos-keychain") {
303
+ writeToMacosKeychain(config, secret, deps);
304
+ return;
305
+ }
306
+ if (store.kind === "linux-secret-service") {
307
+ writeToLinuxSecretService(config, secret, deps);
308
+ return;
309
+ }
310
+ if (store.kind === "windows-dpapi") {
311
+ writeToWindowsDpapi(config, secret, deps);
312
+ return;
313
+ }
314
+ writeToPlaintextFile(config, secret, deps);
315
+ }
316
+ function readVaultUnlockSecret(config, deps = {}) {
317
+ const store = resolveVaultUnlockStore(config, deps);
318
+ const secret = readFromStore(config, store, deps);
319
+ if (!secret) {
320
+ throw new Error(lockedMessage(config, store));
321
+ }
322
+ (0, runtime_1.emitNervesEvent)({
323
+ component: "repertoire",
324
+ event: "repertoire.vault_unlock_loaded",
325
+ message: "loaded vault unlock material from local store",
326
+ meta: { store: store.kind, secure: store.secure, hasAgentName: !!config.agentName },
327
+ });
328
+ return { secret, store };
329
+ }
330
+ function storeVaultUnlockSecret(config, secret, deps = {}) {
331
+ const trimmed = secret.trim();
332
+ if (!trimmed) {
333
+ throw new Error("vault unlock secret is required");
334
+ }
335
+ const store = resolveVaultUnlockStore(config, deps);
336
+ writeToStore(config, store, trimmed, deps);
337
+ (0, runtime_1.emitNervesEvent)({
338
+ component: "repertoire",
339
+ event: "repertoire.vault_unlock_stored",
340
+ message: "stored vault unlock material in local store",
341
+ meta: { store: store.kind, secure: store.secure, hasAgentName: !!config.agentName },
342
+ });
343
+ return store;
344
+ }
345
+ function getVaultUnlockStatus(config, deps = {}) {
346
+ try {
347
+ const store = resolveVaultUnlockStore(config, deps);
348
+ const stored = !!readFromStore(config, store, deps);
349
+ return {
350
+ configured: true,
351
+ stored,
352
+ store,
353
+ fix: stored
354
+ ? "Vault unlock secret is available on this machine."
355
+ : lockedMessage(config, store),
356
+ };
357
+ }
358
+ catch (error) {
359
+ return {
360
+ configured: false,
361
+ stored: false,
362
+ error: error instanceof Error ? error.message : String(error),
363
+ fix: error instanceof Error ? error.message : String(error),
364
+ };
365
+ }
366
+ }
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ // Claude Code lifecycle hook handler.
3
+ // Receives events from Claude Code's hooks system (SessionStart, Stop, PostToolUse)
4
+ // and forwards them to the Ouroboros daemon for agent awareness.
5
+ //
6
+ // This module exports handleHookEvent for testability.
7
+ // The actual hook scripts (scripts/claude-code-hook.js) read stdin and call this.
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.handleHookEvent = handleHookEvent;
10
+ const socket_client_1 = require("../heart/daemon/socket-client");
11
+ const runtime_1 = require("../nerves/runtime");
12
+ /**
13
+ * Handle a Claude Code lifecycle hook event.
14
+ * Sends the event to the daemon and always exits 0 (hooks must not block the IDE).
15
+ */
16
+ async function handleHookEvent(hookEvent) {
17
+ (0, runtime_1.emitNervesEvent)({
18
+ component: "daemon",
19
+ event: "daemon.hook_event_received",
20
+ message: "claude code hook event received",
21
+ meta: { hookEvent: hookEvent.event, sessionId: hookEvent.sessionId },
22
+ });
23
+ try {
24
+ await (0, socket_client_1.sendDaemonCommand)(socket_client_1.DEFAULT_DAEMON_SOCKET_PATH, {
25
+ kind: "hook.event",
26
+ event: hookEvent.event,
27
+ sessionId: hookEvent.sessionId,
28
+ toolName: hookEvent.toolName,
29
+ });
30
+ }
31
+ catch {
32
+ // Daemon unavailable — silently ignore. Hooks must not block.
33
+ (0, runtime_1.emitNervesEvent)({
34
+ component: "daemon",
35
+ event: "daemon.hook_event_daemon_unavailable",
36
+ message: "daemon unavailable for hook event",
37
+ meta: { hookEvent: hookEvent.event },
38
+ });
39
+ }
40
+ return { exitCode: 0 };
41
+ }