@ouro.bot/cli 0.1.0-alpha.33 → 0.1.0-alpha.330

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 (315) 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 +1976 -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 +149 -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 +2277 -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 +29 -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 +69 -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-render.js +1032 -0
  107. package/dist/heart/outlook/outlook-types.js +27 -0
  108. package/dist/heart/outlook/outlook-view.js +194 -0
  109. package/dist/heart/outlook/readers/agent-machine.js +355 -0
  110. package/dist/heart/outlook/readers/continuity-readers.js +332 -0
  111. package/dist/heart/outlook/readers/runtime-readers.js +660 -0
  112. package/dist/heart/outlook/readers/sessions.js +231 -0
  113. package/dist/heart/outlook/readers/shared.js +111 -0
  114. package/dist/heart/progress-story.js +42 -0
  115. package/dist/heart/provider-failover.js +135 -0
  116. package/dist/heart/provider-models.js +81 -0
  117. package/dist/heart/provider-ping.js +162 -0
  118. package/dist/heart/providers/anthropic-token.js +163 -0
  119. package/dist/heart/providers/anthropic.js +169 -46
  120. package/dist/heart/providers/azure.js +98 -11
  121. package/dist/heart/providers/error-classification.js +63 -0
  122. package/dist/heart/providers/github-copilot.js +136 -0
  123. package/dist/heart/providers/minimax-vlm.js +189 -0
  124. package/dist/heart/providers/minimax.js +23 -5
  125. package/dist/heart/providers/openai-codex.js +33 -22
  126. package/dist/heart/session-activity.js +190 -0
  127. package/dist/heart/session-events.js +726 -0
  128. package/dist/heart/session-recall.js +162 -0
  129. package/dist/heart/start-of-turn-packet.js +341 -0
  130. package/dist/heart/streaming.js +36 -27
  131. package/dist/heart/sync.js +332 -0
  132. package/dist/heart/target-resolution.js +127 -0
  133. package/dist/heart/tempo.js +93 -0
  134. package/dist/heart/temporal-view.js +41 -0
  135. package/dist/heart/tool-activity-callbacks.js +36 -0
  136. package/dist/heart/tool-description.js +135 -0
  137. package/dist/heart/tool-friction.js +55 -0
  138. package/dist/heart/tool-loop.js +200 -0
  139. package/dist/heart/turn-context.js +358 -0
  140. package/dist/heart/turn-coordinator.js +28 -0
  141. package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +1 -1
  142. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
  143. package/dist/heart/{daemon → versioning}/ouro-path-installer.js +78 -35
  144. package/dist/heart/versioning/ouro-version-manager.js +295 -0
  145. package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
  146. package/dist/heart/{daemon → versioning}/update-checker.js +12 -2
  147. package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
  148. package/dist/mind/associative-recall.js +137 -66
  149. package/dist/mind/bundle-manifest.js +7 -1
  150. package/dist/mind/context.js +89 -93
  151. package/dist/mind/diary-integrity.js +60 -0
  152. package/dist/mind/{memory.js → diary.js} +84 -96
  153. package/dist/mind/embedding-provider.js +60 -0
  154. package/dist/mind/file-state.js +179 -0
  155. package/dist/mind/first-impressions.js +14 -1
  156. package/dist/mind/friends/channel.js +56 -0
  157. package/dist/mind/friends/group-context.js +144 -0
  158. package/dist/mind/friends/resolver.js +37 -0
  159. package/dist/mind/friends/store-file.js +58 -3
  160. package/dist/mind/friends/trust-explanation.js +74 -0
  161. package/dist/mind/friends/types.js +8 -0
  162. package/dist/mind/journal-index.js +161 -0
  163. package/dist/mind/obligation-steering.js +221 -0
  164. package/dist/mind/pending.js +74 -7
  165. package/dist/mind/prompt.js +949 -111
  166. package/dist/mind/provenance-trust.js +26 -0
  167. package/dist/mind/scrutiny.js +173 -0
  168. package/dist/mind/token-estimate.js +8 -12
  169. package/dist/nerves/cli-logging.js +7 -1
  170. package/dist/nerves/coverage/audit.js +1 -1
  171. package/dist/nerves/coverage/file-completeness.js +83 -5
  172. package/dist/nerves/coverage/run-artifacts.js +1 -1
  173. package/dist/nerves/event-buffer.js +111 -0
  174. package/dist/nerves/index.js +224 -4
  175. package/dist/nerves/observation.js +20 -0
  176. package/dist/nerves/redact.js +79 -0
  177. package/dist/nerves/runtime.js +5 -1
  178. package/dist/outlook-ui/assets/index-IuR4F6y6.js +61 -0
  179. package/dist/outlook-ui/assets/index-LwChZTgL.css +1 -0
  180. package/dist/outlook-ui/index.html +15 -0
  181. package/dist/repertoire/ado-client.js +15 -56
  182. package/dist/repertoire/ado-semantic.js +11 -10
  183. package/dist/repertoire/api-client.js +97 -0
  184. package/dist/repertoire/bitwarden-store.js +319 -0
  185. package/dist/repertoire/bundle-templates.js +72 -0
  186. package/dist/repertoire/bw-installer.js +79 -0
  187. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  188. package/dist/repertoire/coding/context-pack.js +330 -0
  189. package/dist/repertoire/coding/feedback.js +197 -30
  190. package/dist/repertoire/coding/manager.js +158 -9
  191. package/dist/repertoire/coding/spawner.js +55 -9
  192. package/dist/repertoire/coding/tools.js +170 -7
  193. package/dist/repertoire/commerce-errors.js +109 -0
  194. package/dist/repertoire/commerce-self-test.js +156 -0
  195. package/dist/repertoire/credential-access.js +527 -0
  196. package/dist/repertoire/duffel-client.js +185 -0
  197. package/dist/repertoire/github-client.js +14 -55
  198. package/dist/repertoire/graph-client.js +11 -52
  199. package/dist/repertoire/guardrails.js +375 -0
  200. package/dist/repertoire/mcp-client.js +255 -0
  201. package/dist/repertoire/mcp-manager.js +305 -0
  202. package/dist/repertoire/mcp-tools.js +63 -0
  203. package/dist/repertoire/shell-sessions.js +133 -0
  204. package/dist/repertoire/skills.js +14 -23
  205. package/dist/repertoire/stripe-client.js +131 -0
  206. package/dist/repertoire/tasks/board.js +43 -5
  207. package/dist/repertoire/tasks/fix.js +182 -0
  208. package/dist/repertoire/tasks/index.js +28 -10
  209. package/dist/repertoire/tasks/lifecycle.js +2 -2
  210. package/dist/repertoire/tasks/parser.js +3 -2
  211. package/dist/repertoire/tasks/scanner.js +194 -37
  212. package/dist/repertoire/tasks/transitions.js +16 -79
  213. package/dist/repertoire/tool-results.js +29 -0
  214. package/dist/repertoire/tools-attachments.js +316 -0
  215. package/dist/repertoire/tools-base.js +45 -771
  216. package/dist/repertoire/tools-bluebubbles.js +1 -0
  217. package/dist/repertoire/tools-bridge.js +141 -0
  218. package/dist/repertoire/tools-bundle.js +984 -0
  219. package/dist/repertoire/tools-config.js +185 -0
  220. package/dist/repertoire/tools-continuity.js +248 -0
  221. package/dist/repertoire/tools-credential.js +182 -0
  222. package/dist/repertoire/tools-files.js +342 -0
  223. package/dist/repertoire/tools-flight.js +224 -0
  224. package/dist/repertoire/tools-flow.js +105 -0
  225. package/dist/repertoire/tools-github.js +1 -7
  226. package/dist/repertoire/tools-memory.js +376 -0
  227. package/dist/repertoire/tools-session.js +739 -0
  228. package/dist/repertoire/tools-shell.js +120 -0
  229. package/dist/repertoire/tools-stripe.js +180 -0
  230. package/dist/repertoire/tools-surface.js +243 -0
  231. package/dist/repertoire/tools-teams.js +12 -62
  232. package/dist/repertoire/tools-travel.js +125 -0
  233. package/dist/repertoire/tools-user-profile.js +144 -0
  234. package/dist/repertoire/tools-vault.js +110 -0
  235. package/dist/repertoire/tools.js +144 -138
  236. package/dist/repertoire/travel-api-client.js +360 -0
  237. package/dist/repertoire/user-profile.js +118 -0
  238. package/dist/repertoire/vault-setup.js +241 -0
  239. package/dist/scripts/claude-code-hook.js +41 -0
  240. package/dist/scripts/claude-code-stop-hook.js +47 -0
  241. package/dist/senses/attention-queue.js +116 -0
  242. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  243. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  244. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +225 -9
  245. package/dist/senses/bluebubbles/entry.js +13 -0
  246. package/dist/senses/bluebubbles/inbound-log.js +113 -0
  247. package/dist/senses/bluebubbles/index.js +1590 -0
  248. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -70
  249. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +43 -12
  250. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +46 -6
  251. package/dist/senses/bluebubbles/replay.js +129 -0
  252. package/dist/senses/bluebubbles/runtime-state.js +109 -0
  253. package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
  254. package/dist/senses/cli/bracketed-paste.js +82 -0
  255. package/dist/senses/cli/image-paste.js +287 -0
  256. package/dist/senses/cli/image-ref-navigation.js +75 -0
  257. package/dist/senses/cli/ink-app.js +156 -0
  258. package/dist/senses/cli/inline-diff.js +64 -0
  259. package/dist/senses/cli/input-keys.js +174 -0
  260. package/dist/senses/cli/kill-ring.js +86 -0
  261. package/dist/senses/cli/message-list.js +51 -0
  262. package/dist/senses/cli/ouro-tui.js +605 -0
  263. package/dist/senses/cli/spinner-imperative.js +135 -0
  264. package/dist/senses/cli/spinner.js +101 -0
  265. package/dist/senses/cli/status-line.js +60 -0
  266. package/dist/senses/cli/streaming-markdown.js +526 -0
  267. package/dist/senses/cli/tool-display.js +83 -0
  268. package/dist/senses/cli/tool-render.js +85 -0
  269. package/dist/senses/cli/tui-store.js +240 -0
  270. package/dist/senses/cli/virtual-list.js +35 -0
  271. package/dist/senses/cli-entry.js +1 -1
  272. package/dist/senses/cli-layout.js +187 -0
  273. package/dist/senses/cli.js +595 -246
  274. package/dist/senses/commands.js +65 -1
  275. package/dist/senses/continuity.js +94 -0
  276. package/dist/senses/habit-turn-message.js +108 -0
  277. package/dist/senses/inner-dialog-worker.js +112 -19
  278. package/dist/senses/inner-dialog.js +633 -86
  279. package/dist/senses/pipeline.js +567 -0
  280. package/dist/senses/shared-turn.js +199 -0
  281. package/dist/senses/surface-tool.js +68 -0
  282. package/dist/senses/teams.js +665 -160
  283. package/dist/senses/trust-gate.js +112 -2
  284. package/package.json +28 -7
  285. package/skills/agent-commerce.md +106 -0
  286. package/skills/browser-navigation.md +110 -0
  287. package/skills/commerce-setup-guide.md +116 -0
  288. package/skills/commerce-setup.md +84 -0
  289. package/skills/configure-dev-tools.md +81 -0
  290. package/skills/travel-planning.md +138 -0
  291. package/dist/heart/daemon/subagent-installer.js +0 -134
  292. package/dist/senses/bluebubbles-entry.js +0 -11
  293. package/dist/senses/bluebubbles.js +0 -544
  294. package/dist/senses/debug-activity.js +0 -108
  295. package/subagents/README.md +0 -73
  296. package/subagents/work-doer.md +0 -235
  297. package/subagents/work-merger.md +0 -618
  298. package/subagents/work-planner.md +0 -382
  299. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  300. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  301. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  302. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  303. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  304. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  305. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  306. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  307. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  308. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  309. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  310. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +0 -0
  311. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  312. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  313. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  314. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  315. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -0,0 +1,319 @@
1
+ "use strict";
2
+ /**
3
+ * Bitwarden CLI credential store — wraps `bw` CLI for the agent's own vault.
4
+ *
5
+ * Unlike AacCredentialStore (which accesses someone else's vault via approval),
6
+ * this store authenticates directly as the agent using its own master password.
7
+ * The agent owns the vault, so no human-in-the-loop is needed.
8
+ *
9
+ * Requires the `bw` CLI to be installed. Session tokens are cached in-memory.
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.BitwardenCredentialStore = void 0;
13
+ const node_child_process_1 = require("node:child_process");
14
+ const runtime_1 = require("../nerves/runtime");
15
+ const bw_installer_1 = require("./bw-installer");
16
+ // ---------------------------------------------------------------------------
17
+ // bw CLI wrapper
18
+ // ---------------------------------------------------------------------------
19
+ function execBw(args, sessionToken) {
20
+ const env = sessionToken
21
+ ? { ...process.env, BW_SESSION: sessionToken }
22
+ : process.env;
23
+ return new Promise((resolve, reject) => {
24
+ (0, node_child_process_1.execFile)("bw", args, { timeout: 30_000, env }, (err, stdout) => {
25
+ if (err) {
26
+ if (isBwNotInstalled(err)) {
27
+ reject(new Error("bw CLI not found. Install from https://bitwarden.com/help/cli/"));
28
+ return;
29
+ }
30
+ reject(new Error(`bw CLI error: ${err.message}`));
31
+ return;
32
+ }
33
+ resolve(stdout);
34
+ });
35
+ });
36
+ }
37
+ /** Check if the error indicates the bw CLI binary is not installed. */
38
+ function isBwNotInstalled(err) {
39
+ const msg = err.message.toLowerCase();
40
+ const code = err.code;
41
+ return code === "ENOENT" || msg.includes("enoent") || msg.includes("not found") || msg.includes("command not found");
42
+ }
43
+ /** Check if the error is transient (network/timeout) and worth retrying. */
44
+ function isTransientError(err) {
45
+ const msg = err.message.toLowerCase();
46
+ return (msg.includes("econnrefused") ||
47
+ msg.includes("etimedout") ||
48
+ msg.includes("enotfound") ||
49
+ msg.includes("socket hang up") ||
50
+ msg.includes("503") ||
51
+ msg.includes("server unavailable"));
52
+ }
53
+ const MAX_RETRIES = 3;
54
+ const BASE_BACKOFF_MS = 1000;
55
+ function delay(ms) {
56
+ return new Promise((resolve) => setTimeout(resolve, ms));
57
+ }
58
+ // ---------------------------------------------------------------------------
59
+ // BitwardenCredentialStore
60
+ // ---------------------------------------------------------------------------
61
+ class BitwardenCredentialStore {
62
+ serverUrl;
63
+ email;
64
+ masterPassword;
65
+ sessionToken = null;
66
+ constructor(serverUrl, email, masterPassword) {
67
+ this.serverUrl = serverUrl;
68
+ this.email = email;
69
+ this.masterPassword = masterPassword;
70
+ }
71
+ isReady() {
72
+ return true;
73
+ }
74
+ /**
75
+ * Ensure the bw CLI is authenticated and unlocked.
76
+ * Handles three states: logged out → login, locked → unlock, already unlocked → no-op.
77
+ * Retries transient failures (network/timeout) up to MAX_RETRIES with exponential backoff.
78
+ */
79
+ async login() {
80
+ // Ensure bw CLI is installed before any bw commands
81
+ await (0, bw_installer_1.ensureBwCli)();
82
+ let lastError;
83
+ for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
84
+ try {
85
+ await this.loginAttempt();
86
+ return;
87
+ }
88
+ catch (err) {
89
+ /* v8 ignore next -- defensive: loginAttempt always throws Error instances @preserve */
90
+ lastError = err instanceof Error ? err : new Error(String(err));
91
+ // Don't retry non-transient errors (auth failures, bw not installed)
92
+ if (!isTransientError(lastError)) {
93
+ throw lastError;
94
+ }
95
+ // Don't retry after final attempt
96
+ if (attempt === MAX_RETRIES - 1)
97
+ break;
98
+ const backoffMs = BASE_BACKOFF_MS * Math.pow(2, attempt);
99
+ (0, runtime_1.emitNervesEvent)({
100
+ event: "repertoire.bw_login_retry",
101
+ component: "repertoire",
102
+ message: `bw login attempt ${attempt + 1} failed, retrying in ${backoffMs}ms`,
103
+ meta: { attempt: attempt + 1, backoffMs, reason: lastError.message },
104
+ });
105
+ await delay(backoffMs);
106
+ }
107
+ }
108
+ throw lastError;
109
+ }
110
+ /** Single login attempt — called by login() retry loop. */
111
+ async loginAttempt() {
112
+ // Check current status
113
+ let status = {};
114
+ try {
115
+ const raw = await execBw(["status"]);
116
+ status = JSON.parse(raw);
117
+ }
118
+ catch (err) {
119
+ // If bw CLI is not installed or a transient error, propagate it for retry
120
+ if (err instanceof Error && (isBwNotInstalled(err) || isTransientError(err))) {
121
+ throw err;
122
+ }
123
+ // CLI not configured or broken — proceed with full setup
124
+ }
125
+ // Configure server URL if needed (only works when logged out)
126
+ if (status.status === "unauthenticated" || !status.serverUrl) {
127
+ try {
128
+ await execBw(["config", "server", this.serverUrl]);
129
+ }
130
+ catch {
131
+ // "Logout required" means already logged in — that's fine, skip config
132
+ }
133
+ }
134
+ if (status.status === "locked") {
135
+ // Already logged in, just needs unlock
136
+ const unlockOutput = await execBw(["unlock", this.masterPassword, "--raw"]);
137
+ this.sessionToken = unlockOutput.trim();
138
+ }
139
+ else if (status.status === "unauthenticated" || !status.status) {
140
+ // Not logged in — full login
141
+ const loginOutput = await execBw(["login", this.email, this.masterPassword, "--raw"]);
142
+ try {
143
+ const parsed = JSON.parse(loginOutput);
144
+ this.sessionToken = parsed.access_token ?? loginOutput.trim();
145
+ }
146
+ catch {
147
+ this.sessionToken = loginOutput.trim();
148
+ }
149
+ }
150
+ else {
151
+ // Status is "unlocked" — already good, just need the session token
152
+ const unlockOutput = await execBw(["unlock", this.masterPassword, "--raw"]);
153
+ this.sessionToken = unlockOutput.trim();
154
+ }
155
+ }
156
+ async ensureSession() {
157
+ if (!this.sessionToken) {
158
+ await this.login();
159
+ }
160
+ /* v8 ignore next -- defensive: login() always sets sessionToken on success @preserve */
161
+ return this.sessionToken ?? undefined;
162
+ }
163
+ async get(domain) {
164
+ (0, runtime_1.emitNervesEvent)({
165
+ event: "repertoire.bw_credential_get_start",
166
+ component: "repertoire",
167
+ message: `getting credential via bw for ${domain}`,
168
+ meta: { domain, backend: "bitwarden" },
169
+ });
170
+ const session = await this.ensureSession();
171
+ const item = await this.findItemByDomain(domain, session);
172
+ if (!item) {
173
+ (0, runtime_1.emitNervesEvent)({
174
+ event: "repertoire.bw_credential_get_end",
175
+ component: "repertoire",
176
+ message: `no bw credential for ${domain}`,
177
+ meta: { domain, found: false, backend: "bitwarden" },
178
+ });
179
+ return null;
180
+ }
181
+ (0, runtime_1.emitNervesEvent)({
182
+ event: "repertoire.bw_credential_get_end",
183
+ component: "repertoire",
184
+ message: `bw credential found for ${domain}`,
185
+ meta: { domain, found: true, backend: "bitwarden" },
186
+ });
187
+ return {
188
+ domain: item.name,
189
+ username: item.login?.username,
190
+ notes: item.notes ?? undefined,
191
+ createdAt: item.revisionDate ?? new Date().toISOString(),
192
+ };
193
+ }
194
+ async getRawSecret(domain, field) {
195
+ const session = await this.ensureSession();
196
+ const item = await this.findItemByDomain(domain, session);
197
+ if (!item) {
198
+ throw new Error(`no credential found for domain "${domain}"`);
199
+ }
200
+ // Map common field names to bw item structure
201
+ let value;
202
+ if (field === "password") {
203
+ value = item.login?.password;
204
+ }
205
+ else if (field === "username") {
206
+ value = item.login?.username;
207
+ }
208
+ else {
209
+ value = item[field];
210
+ }
211
+ if (value === undefined || value === null) {
212
+ throw new Error(`field "${field}" not found for domain "${domain}"`);
213
+ }
214
+ return String(value);
215
+ }
216
+ async store(domain, data) {
217
+ (0, runtime_1.emitNervesEvent)({
218
+ event: "repertoire.bw_credential_store_start",
219
+ component: "repertoire",
220
+ message: `storing credential via bw for ${domain}`,
221
+ meta: { domain, backend: "bitwarden" },
222
+ });
223
+ const session = await this.ensureSession();
224
+ // Create a new login item
225
+ const item = {
226
+ type: 1, // Login type
227
+ name: domain,
228
+ login: {
229
+ username: data.username ?? "",
230
+ password: data.password,
231
+ uris: [{ match: null, uri: `https://${domain}` }],
232
+ },
233
+ notes: data.notes ?? null,
234
+ };
235
+ const encoded = Buffer.from(JSON.stringify(item)).toString("base64");
236
+ await execBw(["create", "item", encoded], session);
237
+ (0, runtime_1.emitNervesEvent)({
238
+ event: "repertoire.bw_credential_store_end",
239
+ component: "repertoire",
240
+ message: `credential stored via bw for ${domain}`,
241
+ meta: { domain, backend: "bitwarden" },
242
+ });
243
+ }
244
+ async list() {
245
+ (0, runtime_1.emitNervesEvent)({
246
+ event: "repertoire.bw_credential_list_start",
247
+ component: "repertoire",
248
+ message: "listing bw credentials",
249
+ meta: { backend: "bitwarden" },
250
+ });
251
+ const session = await this.ensureSession();
252
+ try {
253
+ const stdout = await execBw(["list", "items"], session);
254
+ const items = JSON.parse(stdout);
255
+ const results = items.map((item) => ({
256
+ domain: item.name,
257
+ username: item.login?.username,
258
+ notes: item.notes ?? undefined,
259
+ createdAt: item.revisionDate ?? new Date().toISOString(),
260
+ }));
261
+ (0, runtime_1.emitNervesEvent)({
262
+ event: "repertoire.bw_credential_list_end",
263
+ component: "repertoire",
264
+ message: "bw credentials listed",
265
+ meta: { backend: "bitwarden", count: results.length },
266
+ });
267
+ return results;
268
+ }
269
+ catch {
270
+ (0, runtime_1.emitNervesEvent)({
271
+ event: "repertoire.bw_credential_list_end",
272
+ component: "repertoire",
273
+ message: "bw credential list failed",
274
+ meta: { backend: "bitwarden", count: 0 },
275
+ });
276
+ return [];
277
+ }
278
+ }
279
+ async delete(domain) {
280
+ (0, runtime_1.emitNervesEvent)({
281
+ event: "repertoire.bw_credential_delete_start",
282
+ component: "repertoire",
283
+ message: `deleting credential via bw for ${domain}`,
284
+ meta: { domain, backend: "bitwarden" },
285
+ });
286
+ const session = await this.ensureSession();
287
+ const item = await this.findItemByDomain(domain, session);
288
+ if (!item) {
289
+ (0, runtime_1.emitNervesEvent)({
290
+ event: "repertoire.bw_credential_delete_end",
291
+ component: "repertoire",
292
+ message: `no bw credential to delete for ${domain}`,
293
+ meta: { domain, deleted: false, backend: "bitwarden" },
294
+ });
295
+ return false;
296
+ }
297
+ await execBw(["delete", "item", item.id], session);
298
+ (0, runtime_1.emitNervesEvent)({
299
+ event: "repertoire.bw_credential_delete_end",
300
+ component: "repertoire",
301
+ message: `credential deleted via bw for ${domain}`,
302
+ meta: { domain, deleted: true, backend: "bitwarden" },
303
+ });
304
+ return true;
305
+ }
306
+ // --- Private ---
307
+ async findItemByDomain(domain, session) {
308
+ try {
309
+ const stdout = await execBw(["list", "items", "--search", domain], session);
310
+ const items = JSON.parse(stdout);
311
+ // Find exact match by name
312
+ return items.find((item) => item.name === domain) ?? items[0] ?? null;
313
+ }
314
+ catch {
315
+ return null;
316
+ }
317
+ }
318
+ }
319
+ exports.BitwardenCredentialStore = BitwardenCredentialStore;
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ /**
3
+ * Templates for agent bundle scaffolding.
4
+ *
5
+ * ## .gitignore design philosophy
6
+ *
7
+ * The bundle .gitignore handles FUNCTIONAL "shouldn't track" cases only:
8
+ *
9
+ * - Runtime state (sessions, logs, runtime files) — stale data with no
10
+ * value for review or history.
11
+ * - Credentials — real secrets live in `~/.agentsecrets`, but defense
12
+ * in depth in case anything leaks into the bundle.
13
+ * - Editor / OS noise (.DS_Store, .idea/, etc.).
14
+ * - Build artifacts (rare in bundles, but possible).
15
+ *
16
+ * It DOES NOT handle PII. The bundle is inherently full of PII — `friends/`,
17
+ * `diary/`, `journal/`, `psyche/`, `arc/`, `facts/`, `family/`, `travel/`
18
+ * etc. That's the point of the bundle; blocking those via .gitignore would
19
+ * defeat the purpose.
20
+ *
21
+ * PII is handled at first-push time by `bundle_first_push_review`, which
22
+ * enumerates PII-bearing directories, shows the agent counts, probes the
23
+ * remote URL for GitHub visibility, and hard-pauses until the human
24
+ * confirms. See Directive D in the planning doc.
25
+ *
26
+ * No content-pattern blocks (no `**\/sk-ant-*` or similar). Content-review
27
+ * failures are a different safety layer — credential scanning at commit
28
+ * time would be a follow-up feature.
29
+ */
30
+ Object.defineProperty(exports, "__esModule", { value: true });
31
+ exports.PII_BUNDLE_DIRECTORIES = exports.BUNDLE_GITIGNORE_TEMPLATE = void 0;
32
+ exports.BUNDLE_GITIGNORE_TEMPLATE = `# Runtime state — sessions, logs, runtime files, never tracked
33
+ state/
34
+
35
+ # Credentials — never tracked. Real secrets live in ~/.agentsecrets, but
36
+ # defense in depth in case anything leaks into the bundle.
37
+ .env
38
+ .env.*
39
+ secrets/
40
+ **/*.key
41
+ **/*.pem
42
+ **/*.credentials
43
+ **/*.pfx
44
+
45
+ # Editor and OS noise
46
+ .DS_Store
47
+ .idea/
48
+ .vscode/
49
+ *.swp
50
+ *.swo
51
+
52
+ # Build artifacts (rare in bundles, but possible if a workspace lands here)
53
+ node_modules/
54
+ dist/
55
+ `;
56
+ /**
57
+ * PII-sensitive top-level directories. Enumerated here so `bundle_first_push_review`
58
+ * can categorize and count. Adding a new PII bucket to the bundle means adding
59
+ * it here so the first-push warning includes it.
60
+ */
61
+ exports.PII_BUNDLE_DIRECTORIES = [
62
+ "friends",
63
+ "diary",
64
+ "journal",
65
+ "psyche",
66
+ "arc",
67
+ "facts",
68
+ "family",
69
+ "travel",
70
+ "memory",
71
+ "sessions",
72
+ ];
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ /**
3
+ * Lazy bw CLI installer — auto-installs the Bitwarden CLI when not present.
4
+ *
5
+ * Mirrors the whisper-cpp pattern in senses/bluebubbles/media.ts:
6
+ * check PATH first, install via npm if missing, emit nerves event.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.ensureBwCli = ensureBwCli;
10
+ const node_child_process_1 = require("node:child_process");
11
+ const runtime_1 = require("../nerves/runtime");
12
+ const INSTALL_TIMEOUT_MS = 120_000;
13
+ const WHICH_TIMEOUT_MS = 5_000;
14
+ function execFileAsync(cmd, args, timeout) {
15
+ return new Promise((resolve, reject) => {
16
+ (0, node_child_process_1.execFile)(cmd, args, { timeout }, (err, stdout) => {
17
+ if (err) {
18
+ reject(err);
19
+ return;
20
+ }
21
+ resolve(stdout);
22
+ });
23
+ });
24
+ }
25
+ /**
26
+ * Ensure the `bw` CLI is available, installing it via npm if needed.
27
+ * Returns the path to the `bw` binary.
28
+ */
29
+ async function ensureBwCli() {
30
+ // 1. Check if bw is already in PATH
31
+ try {
32
+ const existing = (await execFileAsync("which", ["bw"], WHICH_TIMEOUT_MS)).trim();
33
+ if (existing) {
34
+ return existing;
35
+ }
36
+ }
37
+ catch {
38
+ // Not found — fall through to install
39
+ }
40
+ // 2. Install via npm
41
+ (0, runtime_1.emitNervesEvent)({
42
+ event: "repertoire.bw_cli_install_start",
43
+ component: "repertoire",
44
+ message: "bw CLI not found, installing via npm",
45
+ meta: {},
46
+ });
47
+ try {
48
+ await execFileAsync("npm", ["install", "-g", "@bitwarden/cli"], INSTALL_TIMEOUT_MS);
49
+ }
50
+ catch (err) {
51
+ /* v8 ignore next -- execFileCb always throws Error instances @preserve */
52
+ const reason = err instanceof Error ? err.message : String(err);
53
+ (0, runtime_1.emitNervesEvent)({
54
+ level: "error",
55
+ event: "repertoire.bw_cli_install_fail",
56
+ component: "repertoire",
57
+ message: "failed to install bw CLI via npm",
58
+ meta: { reason },
59
+ });
60
+ throw new Error(`failed to install bw CLI via npm: ${reason}`);
61
+ }
62
+ // 3. Verify installation and return path
63
+ try {
64
+ const installed = (await execFileAsync("which", ["bw"], WHICH_TIMEOUT_MS)).trim();
65
+ if (installed) {
66
+ (0, runtime_1.emitNervesEvent)({
67
+ event: "repertoire.bw_cli_install_end",
68
+ component: "repertoire",
69
+ message: "bw CLI installed successfully",
70
+ meta: { path: installed },
71
+ });
72
+ return installed;
73
+ }
74
+ }
75
+ catch {
76
+ // Fall through to error
77
+ }
78
+ throw new Error("bw CLI installed via npm but binary not found in PATH");
79
+ }
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ /**
3
+ * Codex JSONL event parser.
4
+ * Parses typed events from Codex --json output:
5
+ * thread.started, turn.started, turn.completed, item.completed.
6
+ * Maps events to coding session status transitions.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.parseCodexJsonlEvent = parseCodexJsonlEvent;
10
+ const runtime_1 = require("../../nerves/runtime");
11
+ const KNOWN_TYPES = new Set(["thread.started", "turn.started", "turn.completed", "item.completed"]);
12
+ /**
13
+ * Parse a single JSONL line from Codex --json output.
14
+ * Returns null for invalid JSON, empty strings, or unknown event types.
15
+ */
16
+ function parseCodexJsonlEvent(line) {
17
+ const trimmed = line.trim();
18
+ if (trimmed.length === 0)
19
+ return null;
20
+ let parsed;
21
+ try {
22
+ parsed = JSON.parse(trimmed);
23
+ }
24
+ catch {
25
+ (0, runtime_1.emitNervesEvent)({
26
+ component: "repertoire",
27
+ event: "repertoire.codex_jsonl_parse_error",
28
+ message: "failed to parse codex JSONL line",
29
+ meta: { line: trimmed.slice(0, 100) },
30
+ });
31
+ return null;
32
+ }
33
+ const type = parsed.type;
34
+ if (!type || !KNOWN_TYPES.has(type))
35
+ return null;
36
+ const event = {
37
+ type: type,
38
+ threadId: typeof parsed.thread_id === "string" ? parsed.thread_id : undefined,
39
+ turnId: typeof parsed.turn_id === "string" ? parsed.turn_id : undefined,
40
+ item: typeof parsed.item === "object" && parsed.item !== null ? parsed.item : undefined,
41
+ raw: parsed,
42
+ statusHint: mapStatusHint(type),
43
+ };
44
+ (0, runtime_1.emitNervesEvent)({
45
+ component: "repertoire",
46
+ event: "repertoire.codex_jsonl_event",
47
+ message: "parsed codex JSONL event",
48
+ meta: { type, threadId: event.threadId ?? null },
49
+ });
50
+ return event;
51
+ }
52
+ function mapStatusHint(type) {
53
+ switch (type) {
54
+ case "thread.started":
55
+ case "turn.started":
56
+ return "running";
57
+ case "turn.completed":
58
+ case "item.completed":
59
+ return null; // No automatic status change for completion events
60
+ /* v8 ignore next -- defensive default for unknown event types */
61
+ default:
62
+ return null;
63
+ }
64
+ }