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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (289) hide show
  1. package/README.md +188 -190
  2. package/SerpentGuide.ouro/agent.json +82 -0
  3. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +6 -3
  4. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +2 -2
  5. package/SerpentGuide.ouro/psyche/identities/python.md +31 -0
  6. package/assets/ouroboros.png +0 -0
  7. package/changelog.json +1888 -0
  8. package/dist/arc/attention-types.js +8 -0
  9. package/dist/arc/cares.js +140 -0
  10. package/dist/arc/episodes.js +117 -0
  11. package/dist/arc/intentions.js +133 -0
  12. package/dist/arc/json-store.js +117 -0
  13. package/dist/arc/obligations.js +237 -0
  14. package/dist/arc/packets.js +203 -0
  15. package/dist/arc/presence.js +185 -0
  16. package/dist/heart/active-work.js +832 -0
  17. package/dist/heart/agent-entry.js +37 -2
  18. package/dist/heart/attachments/image-normalize.js +194 -0
  19. package/dist/heart/attachments/materialize.js +230 -0
  20. package/dist/heart/attachments/render.js +29 -0
  21. package/dist/heart/attachments/store.js +103 -0
  22. package/dist/heart/attachments/types.js +138 -0
  23. package/dist/heart/auth/auth-flow.js +456 -0
  24. package/dist/heart/bridges/manager.js +358 -0
  25. package/dist/heart/bridges/state-machine.js +135 -0
  26. package/dist/heart/bridges/store.js +123 -0
  27. package/dist/heart/bundle-state.js +168 -0
  28. package/dist/heart/commitments.js +111 -0
  29. package/dist/heart/config-registry.js +304 -0
  30. package/dist/heart/config.js +123 -28
  31. package/dist/heart/core.js +738 -191
  32. package/dist/heart/cross-chat-delivery.js +131 -0
  33. package/dist/heart/daemon/agent-config-check.js +149 -0
  34. package/dist/heart/daemon/agent-discovery.js +157 -0
  35. package/dist/heart/daemon/agent-service.js +360 -0
  36. package/dist/heart/daemon/cadence.js +70 -0
  37. package/dist/heart/daemon/cli-defaults.js +574 -0
  38. package/dist/heart/daemon/cli-exec.js +1945 -0
  39. package/dist/heart/daemon/cli-parse.js +808 -0
  40. package/dist/heart/daemon/cli-render.js +503 -0
  41. package/dist/heart/daemon/cli-types.js +8 -0
  42. package/dist/heart/daemon/daemon-cli.js +29 -673
  43. package/dist/heart/daemon/daemon-entry.js +259 -8
  44. package/dist/heart/daemon/daemon-health.js +136 -0
  45. package/dist/heart/daemon/daemon-runtime-sync.js +231 -0
  46. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  47. package/dist/heart/daemon/daemon.js +745 -18
  48. package/dist/heart/daemon/health-monitor.js +38 -0
  49. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  50. package/dist/heart/daemon/hooks/bundle-meta.js +206 -0
  51. package/dist/heart/daemon/inner-status.js +89 -0
  52. package/dist/heart/daemon/launchd.js +171 -0
  53. package/dist/heart/daemon/log-tailer.js +82 -12
  54. package/dist/heart/daemon/logs-prune.js +105 -0
  55. package/dist/heart/daemon/message-router.js +17 -8
  56. package/dist/heart/daemon/os-cron-deps.js +134 -0
  57. package/dist/heart/daemon/ouro-bot-entry.js +1 -1
  58. package/dist/heart/daemon/process-manager.js +181 -1
  59. package/dist/heart/daemon/pulse.js +463 -0
  60. package/dist/heart/daemon/run-hooks.js +39 -0
  61. package/dist/heart/daemon/runtime-logging.js +70 -15
  62. package/dist/heart/daemon/runtime-metadata.js +219 -0
  63. package/dist/heart/daemon/runtime-mode.js +67 -0
  64. package/dist/heart/daemon/safe-mode.js +161 -0
  65. package/dist/heart/daemon/sense-manager.js +335 -0
  66. package/dist/heart/daemon/session-id-resolver.js +131 -0
  67. package/dist/heart/daemon/skill-management-installer.js +94 -0
  68. package/dist/heart/daemon/socket-client.js +307 -0
  69. package/dist/heart/daemon/task-scheduler.js +3 -25
  70. package/dist/heart/daemon/thoughts.js +510 -0
  71. package/dist/heart/delegation.js +62 -0
  72. package/dist/heart/habits/habit-migration.js +181 -0
  73. package/dist/heart/habits/habit-parser.js +140 -0
  74. package/dist/heart/habits/habit-scheduler.js +371 -0
  75. package/dist/heart/hatch/hatch-animation.js +35 -0
  76. package/dist/heart/{daemon → hatch}/hatch-flow.js +31 -130
  77. package/dist/heart/{daemon → hatch}/hatch-specialist.js +7 -2
  78. package/dist/heart/hatch/specialist-orchestrator.js +129 -0
  79. package/dist/heart/hatch/specialist-prompt.js +101 -0
  80. package/dist/heart/hatch/specialist-tools.js +283 -0
  81. package/dist/heart/identity.js +241 -54
  82. package/dist/heart/kicks.js +2 -20
  83. package/dist/heart/mcp/mcp-server.js +653 -0
  84. package/dist/heart/migrate-config.js +127 -0
  85. package/dist/heart/model-capabilities.js +59 -0
  86. package/dist/heart/outlook/outlook-http.js +439 -0
  87. package/dist/heart/outlook/outlook-read.js +1618 -0
  88. package/dist/heart/outlook/outlook-render.js +1032 -0
  89. package/dist/heart/outlook/outlook-types.js +7 -0
  90. package/dist/heart/outlook/outlook-view.js +194 -0
  91. package/dist/heart/progress-story.js +42 -0
  92. package/dist/heart/provider-failover.js +88 -0
  93. package/dist/heart/provider-ping.js +162 -0
  94. package/dist/heart/providers/anthropic-token.js +163 -0
  95. package/dist/heart/providers/anthropic.js +181 -41
  96. package/dist/heart/providers/azure.js +98 -11
  97. package/dist/heart/providers/error-classification.js +63 -0
  98. package/dist/heart/providers/github-copilot.js +136 -0
  99. package/dist/heart/providers/minimax-vlm.js +189 -0
  100. package/dist/heart/providers/minimax.js +23 -5
  101. package/dist/heart/providers/openai-codex.js +33 -22
  102. package/dist/heart/sense-truth.js +61 -0
  103. package/dist/heart/session-activity.js +172 -0
  104. package/dist/heart/session-recall.js +216 -0
  105. package/dist/heart/start-of-turn-packet.js +339 -0
  106. package/dist/heart/streaming.js +120 -33
  107. package/dist/heart/sync.js +332 -0
  108. package/dist/heart/target-resolution.js +127 -0
  109. package/dist/heart/tempo.js +93 -0
  110. package/dist/heart/temporal-view.js +41 -0
  111. package/dist/heart/tool-activity-callbacks.js +36 -0
  112. package/dist/heart/tool-description.js +135 -0
  113. package/dist/heart/tool-friction.js +55 -0
  114. package/dist/heart/tool-loop.js +200 -0
  115. package/dist/heart/turn-context.js +358 -0
  116. package/dist/heart/turn-coordinator.js +28 -0
  117. package/dist/heart/versioning/ouro-bot-global-installer.js +128 -0
  118. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +5 -4
  119. package/dist/heart/versioning/ouro-path-installer.js +221 -0
  120. package/dist/heart/{daemon → versioning}/ouro-uti.js +11 -2
  121. package/dist/heart/versioning/ouro-version-manager.js +295 -0
  122. package/dist/heart/versioning/staged-restart.js +146 -0
  123. package/dist/heart/versioning/update-checker.js +113 -0
  124. package/dist/heart/versioning/update-hooks.js +142 -0
  125. package/dist/heart/versioning/wrapper-publish-guard.js +86 -0
  126. package/dist/mind/associative-recall.js +135 -66
  127. package/dist/mind/bundle-manifest.js +77 -1
  128. package/dist/mind/context.js +125 -14
  129. package/dist/mind/diary-integrity.js +60 -0
  130. package/dist/mind/{memory.js → diary.js} +84 -96
  131. package/dist/mind/embedding-provider.js +60 -0
  132. package/dist/mind/file-state.js +179 -0
  133. package/dist/mind/first-impressions.js +16 -2
  134. package/dist/mind/friends/channel.js +64 -0
  135. package/dist/mind/friends/group-context.js +144 -0
  136. package/dist/mind/friends/resolver.js +37 -0
  137. package/dist/mind/friends/store-file.js +58 -3
  138. package/dist/mind/friends/trust-explanation.js +74 -0
  139. package/dist/mind/friends/types.js +9 -1
  140. package/dist/mind/journal-index.js +161 -0
  141. package/dist/mind/obligation-steering.js +221 -0
  142. package/dist/mind/pending.js +76 -9
  143. package/dist/mind/phrases.js +1 -0
  144. package/dist/mind/prompt.js +1011 -107
  145. package/dist/mind/scrutiny.js +173 -0
  146. package/dist/mind/token-estimate.js +8 -12
  147. package/dist/nerves/cli-logging.js +22 -3
  148. package/dist/nerves/coverage/audit.js +1 -1
  149. package/dist/nerves/coverage/file-completeness.js +59 -5
  150. package/dist/nerves/coverage/run-artifacts.js +1 -1
  151. package/dist/nerves/event-buffer.js +111 -0
  152. package/dist/nerves/index.js +224 -4
  153. package/dist/nerves/observation.js +20 -0
  154. package/dist/nerves/redact.js +79 -0
  155. package/dist/nerves/runtime.js +5 -1
  156. package/dist/outlook-ui/assets/index-Ck8agNeO.js +61 -0
  157. package/dist/outlook-ui/assets/index-LwChZTgL.css +1 -0
  158. package/dist/outlook-ui/index.html +15 -0
  159. package/dist/repertoire/ado-client.js +17 -56
  160. package/dist/repertoire/ado-semantic.js +11 -10
  161. package/dist/repertoire/api-client.js +97 -0
  162. package/dist/repertoire/bitwarden-store.js +319 -0
  163. package/dist/repertoire/bundle-templates.js +72 -0
  164. package/dist/repertoire/bw-installer.js +79 -0
  165. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  166. package/dist/repertoire/coding/context-pack.js +330 -0
  167. package/dist/repertoire/coding/feedback.js +301 -0
  168. package/dist/repertoire/coding/index.js +4 -1
  169. package/dist/repertoire/coding/manager.js +220 -13
  170. package/dist/repertoire/coding/spawner.js +58 -12
  171. package/dist/repertoire/coding/tools.js +209 -7
  172. package/dist/repertoire/commerce-errors.js +109 -0
  173. package/dist/repertoire/commerce-self-test.js +156 -0
  174. package/dist/repertoire/credential-access.js +527 -0
  175. package/dist/repertoire/data/ado-endpoints.json +188 -0
  176. package/dist/repertoire/duffel-client.js +185 -0
  177. package/dist/repertoire/github-client.js +14 -55
  178. package/dist/repertoire/graph-client.js +11 -52
  179. package/dist/repertoire/guardrails.js +375 -0
  180. package/dist/repertoire/mcp-client.js +255 -0
  181. package/dist/repertoire/mcp-manager.js +305 -0
  182. package/dist/repertoire/mcp-tools.js +63 -0
  183. package/dist/repertoire/shell-sessions.js +133 -0
  184. package/dist/repertoire/skills.js +14 -23
  185. package/dist/repertoire/stripe-client.js +131 -0
  186. package/dist/repertoire/tasks/board.js +43 -5
  187. package/dist/repertoire/tasks/fix.js +182 -0
  188. package/dist/repertoire/tasks/index.js +28 -10
  189. package/dist/repertoire/tasks/lifecycle.js +2 -2
  190. package/dist/repertoire/tasks/parser.js +3 -2
  191. package/dist/repertoire/tasks/scanner.js +194 -37
  192. package/dist/repertoire/tasks/transitions.js +11 -28
  193. package/dist/repertoire/tool-results.js +29 -0
  194. package/dist/repertoire/tools-attachments.js +316 -0
  195. package/dist/repertoire/tools-base.js +45 -707
  196. package/dist/repertoire/tools-bluebubbles.js +94 -0
  197. package/dist/repertoire/tools-bridge.js +141 -0
  198. package/dist/repertoire/tools-bundle.js +984 -0
  199. package/dist/repertoire/tools-config.js +185 -0
  200. package/dist/repertoire/tools-continuity.js +248 -0
  201. package/dist/repertoire/tools-credential.js +182 -0
  202. package/dist/repertoire/tools-files.js +342 -0
  203. package/dist/repertoire/tools-flight.js +224 -0
  204. package/dist/repertoire/tools-flow.js +105 -0
  205. package/dist/repertoire/tools-github.js +1 -7
  206. package/dist/repertoire/tools-memory.js +374 -0
  207. package/dist/repertoire/tools-session.js +739 -0
  208. package/dist/repertoire/tools-shell.js +120 -0
  209. package/dist/repertoire/tools-stripe.js +180 -0
  210. package/dist/repertoire/tools-surface.js +243 -0
  211. package/dist/repertoire/tools-teams.js +64 -61
  212. package/dist/repertoire/tools-travel.js +125 -0
  213. package/dist/repertoire/tools-user-profile.js +144 -0
  214. package/dist/repertoire/tools-vault.js +110 -0
  215. package/dist/repertoire/tools.js +149 -98
  216. package/dist/repertoire/travel-api-client.js +360 -0
  217. package/dist/repertoire/user-profile.js +118 -0
  218. package/dist/repertoire/vault-setup.js +241 -0
  219. package/dist/scripts/claude-code-hook.js +41 -0
  220. package/dist/scripts/claude-code-stop-hook.js +47 -0
  221. package/dist/senses/attention-queue.js +116 -0
  222. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  223. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  224. package/dist/senses/bluebubbles/client.js +568 -0
  225. package/dist/senses/bluebubbles/entry.js +13 -0
  226. package/dist/senses/bluebubbles/inbound-log.js +113 -0
  227. package/dist/senses/bluebubbles/index.js +1427 -0
  228. package/dist/senses/bluebubbles/media.js +390 -0
  229. package/dist/senses/bluebubbles/model.js +282 -0
  230. package/dist/senses/bluebubbles/mutation-log.js +116 -0
  231. package/dist/senses/bluebubbles/replay.js +129 -0
  232. package/dist/senses/bluebubbles/runtime-state.js +109 -0
  233. package/dist/senses/bluebubbles/session-cleanup.js +72 -0
  234. package/dist/senses/cli/bracketed-paste.js +82 -0
  235. package/dist/senses/cli/image-paste.js +287 -0
  236. package/dist/senses/cli/image-ref-navigation.js +75 -0
  237. package/dist/senses/cli/ink-app.js +156 -0
  238. package/dist/senses/cli/inline-diff.js +64 -0
  239. package/dist/senses/cli/input-keys.js +174 -0
  240. package/dist/senses/cli/kill-ring.js +86 -0
  241. package/dist/senses/cli/message-list.js +51 -0
  242. package/dist/senses/cli/ouro-tui.js +595 -0
  243. package/dist/senses/cli/spinner-imperative.js +135 -0
  244. package/dist/senses/cli/spinner.js +101 -0
  245. package/dist/senses/cli/status-line.js +60 -0
  246. package/dist/senses/cli/streaming-markdown.js +526 -0
  247. package/dist/senses/cli/tool-display.js +83 -0
  248. package/dist/senses/cli/tool-render.js +85 -0
  249. package/dist/senses/cli/tui-store.js +240 -0
  250. package/dist/senses/cli/virtual-list.js +35 -0
  251. package/dist/senses/cli-entry.js +1 -1
  252. package/dist/senses/cli-layout.js +187 -0
  253. package/dist/senses/cli.js +772 -264
  254. package/dist/senses/commands.js +65 -1
  255. package/dist/senses/continuity.js +94 -0
  256. package/dist/senses/habit-turn-message.js +108 -0
  257. package/dist/senses/inner-dialog-worker.js +112 -19
  258. package/dist/senses/inner-dialog.js +633 -86
  259. package/dist/senses/pipeline.js +560 -0
  260. package/dist/senses/shared-turn.js +195 -0
  261. package/dist/senses/surface-tool.js +68 -0
  262. package/dist/senses/teams.js +814 -196
  263. package/dist/senses/trust-gate.js +112 -2
  264. package/package.json +25 -9
  265. package/skills/agent-commerce.md +106 -0
  266. package/skills/browser-navigation.md +110 -0
  267. package/skills/commerce-setup-guide.md +116 -0
  268. package/skills/commerce-setup.md +84 -0
  269. package/skills/configure-dev-tools.md +81 -0
  270. package/skills/travel-planning.md +138 -0
  271. package/AdoptionSpecialist.ouro/agent.json +0 -20
  272. package/AdoptionSpecialist.ouro/psyche/identities/python.md +0 -1
  273. package/dist/heart/daemon/subagent-installer.js +0 -125
  274. package/dist/inner-worker-entry.js +0 -4
  275. package/subagents/README.md +0 -73
  276. package/subagents/work-doer.md +0 -233
  277. package/subagents/work-merger.md +0 -624
  278. package/subagents/work-planner.md +0 -373
  279. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  280. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  281. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  282. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  283. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  284. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  285. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  286. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  287. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  288. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +0 -0
  289. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
@@ -0,0 +1,221 @@
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.installOuroCommand = installOuroCommand;
37
+ const fs = __importStar(require("fs"));
38
+ const os = __importStar(require("os"));
39
+ const path = __importStar(require("path"));
40
+ const runtime_1 = require("../../nerves/runtime");
41
+ const WRAPPER_SCRIPT = `#!/bin/sh
42
+ # Check for dev mode — if dev-config.json exists, dispatch to the dev repo
43
+ # Skip dev dispatch for "up" command (explicitly returns to production)
44
+ DEV_CONFIG="$HOME/.ouro-cli/dev-config.json"
45
+ if [ -f "$DEV_CONFIG" ] && [ "$1" != "up" ]; then
46
+ DEV_REPO=$(node -e "try{console.log(JSON.parse(require('fs').readFileSync('$DEV_CONFIG','utf-8')).repoPath)}catch{}" 2>/dev/null)
47
+ DEV_ENTRY="$DEV_REPO/dist/heart/daemon/ouro-entry.js"
48
+ if [ -n "$DEV_REPO" ] && [ -e "$DEV_ENTRY" ]; then
49
+ exec node "$DEV_ENTRY" "$@"
50
+ fi
51
+ fi
52
+ # Fall back to installed version
53
+ ENTRY="$HOME/.ouro-cli/CurrentVersion/node_modules/@ouro.bot/cli/dist/heart/daemon/ouro-entry.js"
54
+ if [ ! -e "$ENTRY" ]; then
55
+ echo "ouro not installed. Run: npx ouro.bot" >&2
56
+ exit 1
57
+ fi
58
+ exec node "$ENTRY" "$@"
59
+ `;
60
+ function writeWrapperScript(scriptPath, mkdirSync, writeFileSync, chmodSync) {
61
+ mkdirSync(path.dirname(scriptPath), { recursive: true });
62
+ writeFileSync(scriptPath, WRAPPER_SCRIPT, { mode: 0o755 });
63
+ chmodSync(scriptPath, 0o755);
64
+ }
65
+ function detectShellProfile(homeDir, shell) {
66
+ if (!shell)
67
+ return null;
68
+ const base = path.basename(shell);
69
+ if (base === "zsh")
70
+ return path.join(homeDir, ".zshrc");
71
+ if (base === "bash") {
72
+ // macOS uses .bash_profile, Linux uses .bashrc
73
+ const profilePath = path.join(homeDir, ".bash_profile");
74
+ return profilePath;
75
+ }
76
+ if (base === "fish")
77
+ return path.join(homeDir, ".config", "fish", "config.fish");
78
+ return null;
79
+ }
80
+ function isBinDirInPath(binDir, envPath) {
81
+ return envPath.split(path.delimiter).some((p) => p === binDir);
82
+ }
83
+ function buildPathExportLine(binDir, shell) {
84
+ const base = shell ? path.basename(shell) : /* v8 ignore next -- unreachable: only called when detectShellProfile returns non-null, which requires shell @preserve */ "";
85
+ if (base === "fish") {
86
+ return `\n# Added by ouro\nset -gx PATH ${binDir} $PATH\n`;
87
+ }
88
+ return `\n# Added by ouro\nexport PATH="${binDir}:$PATH"\n`;
89
+ }
90
+ function isWrapperCurrent(scriptPath, existsSync, readFileSync) {
91
+ if (!existsSync(scriptPath))
92
+ return false;
93
+ try {
94
+ return readFileSync(scriptPath, "utf-8") === WRAPPER_SCRIPT;
95
+ }
96
+ catch {
97
+ return false;
98
+ }
99
+ }
100
+ function installOuroCommand(deps = {}) {
101
+ /* v8 ignore start -- dep defaults: only used in real runtime, tests always inject @preserve */
102
+ const platform = deps.platform ?? process.platform;
103
+ const homeDir = deps.homeDir ?? os.homedir();
104
+ const existsSync = deps.existsSync ?? fs.existsSync;
105
+ const mkdirSync = deps.mkdirSync ?? fs.mkdirSync;
106
+ const writeFileSync = deps.writeFileSync ?? fs.writeFileSync;
107
+ const readFileSync = deps.readFileSync ?? ((p, enc) => fs.readFileSync(p, enc));
108
+ const appendFileSync = deps.appendFileSync ?? fs.appendFileSync;
109
+ const chmodSync = deps.chmodSync ?? fs.chmodSync;
110
+ const envPath = deps.envPath ?? process.env.PATH ?? "";
111
+ const shell = deps.shell ?? process.env.SHELL;
112
+ /* v8 ignore stop */
113
+ if (platform === "win32") {
114
+ (0, runtime_1.emitNervesEvent)({
115
+ component: "daemon",
116
+ event: "daemon.ouro_path_install_skip",
117
+ message: "skipped ouro PATH install on Windows",
118
+ meta: { platform },
119
+ });
120
+ return { installed: false, scriptPath: null, pathReady: false, shellProfileUpdated: null, skippedReason: "windows", repairedOldLauncher: false };
121
+ }
122
+ // Ensure ~/.ouro-cli/ directory layout exists
123
+ if (deps.ensureCliLayout) {
124
+ deps.ensureCliLayout();
125
+ }
126
+ const binDir = path.join(homeDir, ".ouro-cli", "bin");
127
+ const scriptPath = path.join(binDir, "ouro");
128
+ const oldScriptPath = path.join(homeDir, ".local", "bin", "ouro");
129
+ const modernCurrent = isWrapperCurrent(scriptPath, existsSync, readFileSync);
130
+ const oldExists = existsSync(oldScriptPath);
131
+ const oldCurrent = oldExists && isWrapperCurrent(oldScriptPath, existsSync, readFileSync);
132
+ // ── Repair old ~/.local/bin/ouro launcher ──
133
+ // If the old launcher exists with stale content it can shadow the modern
134
+ // path and cause the wrong CLI version to run. Overwrite it with the
135
+ // current wrapper so both paths resolve to ~/.ouro-cli/CurrentVersion.
136
+ let repairedOldLauncher = false;
137
+ if (oldExists && !oldCurrent) {
138
+ (0, runtime_1.emitNervesEvent)({
139
+ component: "daemon",
140
+ event: "daemon.ouro_path_repair_old",
141
+ message: "repairing stale old launcher at ~/.local/bin/ouro",
142
+ meta: { oldScriptPath },
143
+ });
144
+ try {
145
+ writeFileSync(oldScriptPath, WRAPPER_SCRIPT, { mode: 0o755 });
146
+ chmodSync(oldScriptPath, 0o755);
147
+ repairedOldLauncher = true;
148
+ }
149
+ catch {
150
+ // Best effort — old launcher repair failure must not block modern install
151
+ }
152
+ }
153
+ // ── Fast-path: modern wrapper already current ──
154
+ if (modernCurrent) {
155
+ (0, runtime_1.emitNervesEvent)({
156
+ component: "daemon",
157
+ event: "daemon.ouro_path_install_skip",
158
+ message: "ouro command already installed",
159
+ meta: { scriptPath },
160
+ });
161
+ return { installed: false, scriptPath, pathReady: isBinDirInPath(binDir, envPath), shellProfileUpdated: null, skippedReason: "already-installed", repairedOldLauncher };
162
+ }
163
+ (0, runtime_1.emitNervesEvent)({
164
+ component: "daemon",
165
+ event: "daemon.ouro_path_install_start",
166
+ message: existsSync(scriptPath) ? "repairing stale ouro wrapper script" : "installing ouro command to PATH",
167
+ meta: { scriptPath, binDir },
168
+ });
169
+ try {
170
+ if (!modernCurrent) {
171
+ writeWrapperScript(scriptPath, mkdirSync, writeFileSync, chmodSync);
172
+ }
173
+ }
174
+ catch (error) {
175
+ (0, runtime_1.emitNervesEvent)({
176
+ level: "warn",
177
+ component: "daemon",
178
+ event: "daemon.ouro_path_install_error",
179
+ message: "failed to install ouro command",
180
+ meta: { error: error instanceof Error ? error.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(error) },
181
+ });
182
+ return { installed: false, scriptPath: null, pathReady: false, shellProfileUpdated: null, skippedReason: error instanceof Error ? error.message : /* v8 ignore next -- defensive @preserve */ String(error), repairedOldLauncher };
183
+ }
184
+ // Check if ~/.ouro-cli/bin is already in PATH
185
+ const pathReady = isBinDirInPath(binDir, envPath);
186
+ let shellProfileUpdated = null;
187
+ if (!pathReady) {
188
+ const profilePath = detectShellProfile(homeDir, shell);
189
+ if (profilePath) {
190
+ try {
191
+ let existing = "";
192
+ try {
193
+ existing = readFileSync(profilePath, "utf-8");
194
+ }
195
+ catch {
196
+ // Profile doesn't exist yet — that's fine, we'll create it
197
+ }
198
+ if (!existing.includes(binDir)) {
199
+ appendFileSync(profilePath, buildPathExportLine(binDir, shell));
200
+ shellProfileUpdated = profilePath;
201
+ }
202
+ }
203
+ catch (error) {
204
+ (0, runtime_1.emitNervesEvent)({
205
+ level: "warn",
206
+ component: "daemon",
207
+ event: "daemon.ouro_path_profile_error",
208
+ message: "failed to update shell profile for PATH",
209
+ meta: { profilePath, error: error instanceof Error ? error.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(error) },
210
+ });
211
+ }
212
+ }
213
+ }
214
+ (0, runtime_1.emitNervesEvent)({
215
+ component: "daemon",
216
+ event: "daemon.ouro_path_install_end",
217
+ message: "ouro command installed",
218
+ meta: { scriptPath, pathReady, shellProfileUpdated, oldScriptPath: oldExists ? oldScriptPath : null },
219
+ });
220
+ return { installed: true, scriptPath, pathReady, shellProfileUpdated, repairedOldLauncher };
221
+ }
@@ -42,7 +42,13 @@ const identity_1 = require("../identity");
42
42
  const runtime_1 = require("../../nerves/runtime");
43
43
  const LSREGISTER_PATH = "/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister";
44
44
  const ICON_SIZES = [16, 32, 128, 256, 512];
45
- function resolveIconSourcePath(repoRoot) {
45
+ function resolveIconSourcePath(repoRoot, existsSync) {
46
+ // Prefer bundled asset (shipped with npm package)
47
+ const bundledPath = path.resolve(repoRoot, "assets", "ouroboros.png");
48
+ if (existsSync(bundledPath)) {
49
+ return bundledPath;
50
+ }
51
+ // Fall back to adjacent repo path (dev environment)
46
52
  return path.resolve(repoRoot, "..", "ouroboros-website", "public", "images", "ouroboros.png");
47
53
  }
48
54
  function buildIconAsset(iconSourcePath, icnsPath, iconsetDir, deps) {
@@ -91,6 +97,7 @@ function buildInfoPlist(iconInstalled) {
91
97
  " <key>UTTypeConformsTo</key>",
92
98
  " <array>",
93
99
  " <string>public.folder</string>",
100
+ " <string>com.apple.package</string>",
94
101
  " </array>",
95
102
  " <key>UTTypeTagSpecification</key>",
96
103
  " <dict>",
@@ -112,6 +119,8 @@ function buildInfoPlist(iconInstalled) {
112
119
  " </array>",
113
120
  " <key>CFBundleTypeRole</key>",
114
121
  " <string>Editor</string>",
122
+ " <key>LSTypeIsPackage</key>",
123
+ " <true/>",
115
124
  ` ${iconTag.trim()}`,
116
125
  " </dict>",
117
126
  " </array>",
@@ -152,7 +161,7 @@ function registerOuroBundleUti(deps = {}) {
152
161
  const plistPath = path.join(contentsDir, "Info.plist");
153
162
  const icnsPath = path.join(resourcesDir, "ouro.icns");
154
163
  const iconsetDir = path.join(supportRoot, "ouro.iconset");
155
- const iconSourcePath = resolveIconSourcePath(repoRoot);
164
+ const iconSourcePath = resolveIconSourcePath(repoRoot, existsSync);
156
165
  (0, runtime_1.emitNervesEvent)({
157
166
  component: "daemon",
158
167
  event: "daemon.ouro_uti_register_start",
@@ -0,0 +1,295 @@
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.DEFAULT_RETAIN_VERSIONS = void 0;
37
+ exports.getOuroCliHome = getOuroCliHome;
38
+ exports.getCurrentVersion = getCurrentVersion;
39
+ exports.getPreviousVersion = getPreviousVersion;
40
+ exports.buildChangelogCommand = buildChangelogCommand;
41
+ exports.listInstalledVersions = listInstalledVersions;
42
+ exports.installVersion = installVersion;
43
+ exports.activateVersion = activateVersion;
44
+ exports.compareCliVersions = compareCliVersions;
45
+ exports.selectVersionsToPrune = selectVersionsToPrune;
46
+ exports.pruneOldVersions = pruneOldVersions;
47
+ exports.ensureLayout = ensureLayout;
48
+ const fs = __importStar(require("fs"));
49
+ const os = __importStar(require("os"));
50
+ const path = __importStar(require("path"));
51
+ const runtime_1 = require("../../nerves/runtime");
52
+ /** Maximum number of installed CLI versions to retain after pruning. */
53
+ exports.DEFAULT_RETAIN_VERSIONS = 5;
54
+ function getOuroCliHome(homeDir) {
55
+ /* v8 ignore next -- dep default: tests always inject @preserve */
56
+ const home = homeDir ?? os.homedir();
57
+ return path.join(home, ".ouro-cli");
58
+ }
59
+ function getCurrentVersion(deps) {
60
+ const cliHome = getOuroCliHome(deps.homeDir);
61
+ /* v8 ignore next -- dep default: tests always inject @preserve */
62
+ const readlinkSync = deps.readlinkSync ?? fs.readlinkSync;
63
+ try {
64
+ const target = readlinkSync(path.join(cliHome, "CurrentVersion"));
65
+ return path.basename(target);
66
+ }
67
+ catch {
68
+ return null;
69
+ }
70
+ }
71
+ function getPreviousVersion(deps) {
72
+ const cliHome = getOuroCliHome(deps.homeDir);
73
+ /* v8 ignore next -- dep default: tests always inject @preserve */
74
+ const readlinkSync = deps.readlinkSync ?? fs.readlinkSync;
75
+ try {
76
+ const target = readlinkSync(path.join(cliHome, "previous"));
77
+ return path.basename(target);
78
+ }
79
+ catch {
80
+ return null;
81
+ }
82
+ }
83
+ function buildChangelogCommand(previousVersion, currentVersion) {
84
+ if (!previousVersion || !currentVersion || previousVersion === currentVersion) {
85
+ return null;
86
+ }
87
+ return `ouro changelog --from ${previousVersion}`;
88
+ }
89
+ function listInstalledVersions(deps) {
90
+ const cliHome = getOuroCliHome(deps.homeDir);
91
+ /* v8 ignore next -- dep default: tests always inject @preserve */
92
+ const readdirSync = deps.readdirSync ?? ((p, opts) => fs.readdirSync(p, opts));
93
+ try {
94
+ const entries = readdirSync(path.join(cliHome, "versions"), { withFileTypes: true });
95
+ return entries.filter((e) => e.isDirectory()).map((e) => e.name);
96
+ }
97
+ catch {
98
+ return [];
99
+ }
100
+ }
101
+ function installVersion(version, deps) {
102
+ const cliHome = getOuroCliHome(deps.homeDir);
103
+ /* v8 ignore start -- dep defaults: tests always inject @preserve */
104
+ const mkdirSync = deps.mkdirSync ?? fs.mkdirSync;
105
+ const execSync = deps.execSync ?? ((cmd, opts) => require("child_process").execSync(cmd, opts));
106
+ /* v8 ignore stop */
107
+ const versionDir = path.join(cliHome, "versions", version);
108
+ (0, runtime_1.emitNervesEvent)({
109
+ component: "daemon",
110
+ event: "daemon.cli_version_install_start",
111
+ message: "installing CLI version",
112
+ meta: { version, versionDir },
113
+ });
114
+ mkdirSync(versionDir, { recursive: true });
115
+ execSync(`npm install --prefix ${versionDir} @ouro.bot/cli@${version}`, { stdio: "pipe" });
116
+ (0, runtime_1.emitNervesEvent)({
117
+ component: "daemon",
118
+ event: "daemon.cli_version_install_end",
119
+ message: "CLI version installed",
120
+ meta: { version, versionDir },
121
+ });
122
+ }
123
+ function activateVersion(version, deps) {
124
+ const cliHome = getOuroCliHome(deps.homeDir);
125
+ /* v8 ignore start -- dep defaults: tests always inject @preserve */
126
+ const readlinkSync = deps.readlinkSync ?? fs.readlinkSync;
127
+ const unlinkSync = deps.unlinkSync ?? fs.unlinkSync;
128
+ const symlinkSync = deps.symlinkSync ?? fs.symlinkSync;
129
+ const existsSync = deps.existsSync ?? fs.existsSync;
130
+ /* v8 ignore stop */
131
+ const currentVersionPath = path.join(cliHome, "CurrentVersion");
132
+ const previousPath = path.join(cliHome, "previous");
133
+ const newTarget = path.join(cliHome, "versions", version);
134
+ (0, runtime_1.emitNervesEvent)({
135
+ component: "daemon",
136
+ event: "daemon.cli_version_activate",
137
+ message: "activating CLI version",
138
+ meta: { version },
139
+ });
140
+ // Read old CurrentVersion target (may not exist)
141
+ let oldTarget = null;
142
+ try {
143
+ oldTarget = readlinkSync(currentVersionPath);
144
+ }
145
+ catch {
146
+ // No current version — first install
147
+ }
148
+ // Update previous symlink to point to old current
149
+ if (oldTarget) {
150
+ try {
151
+ unlinkSync(previousPath);
152
+ }
153
+ catch {
154
+ // previous symlink may not exist yet
155
+ }
156
+ symlinkSync(oldTarget, previousPath);
157
+ }
158
+ // Update CurrentVersion symlink
159
+ if (existsSync(currentVersionPath)) {
160
+ unlinkSync(currentVersionPath);
161
+ }
162
+ symlinkSync(newTarget, currentVersionPath);
163
+ }
164
+ /**
165
+ * Compare two version strings of the form `0.1.0-alpha.{n}`. Returns
166
+ * positive when `a` is newer, negative when `b` is newer, 0 when equal.
167
+ *
168
+ * The harness only ships `0.1.0-alpha.{n}` versions today; this comparator
169
+ * extracts the numeric tail and falls back to a lexicographic compare for
170
+ * any version that doesn't match the pattern (so unexpected version
171
+ * formats sort consistently rather than throwing).
172
+ */
173
+ function compareCliVersions(a, b) {
174
+ const aMatch = /alpha\.(\d+)/.exec(a);
175
+ const bMatch = /alpha\.(\d+)/.exec(b);
176
+ if (aMatch && bMatch) {
177
+ const aN = parseInt(aMatch[1], 10);
178
+ const bN = parseInt(bMatch[1], 10);
179
+ return aN - bN;
180
+ }
181
+ // Fallback: lexicographic. Both-mismatched and one-mismatched cases land
182
+ // here. Predictable, even if not strictly semver-correct.
183
+ if (a < b)
184
+ return -1;
185
+ if (a > b)
186
+ return 1;
187
+ return 0;
188
+ }
189
+ /**
190
+ * Identify which installed CLI versions can be safely deleted, given a
191
+ * retention policy. Pure: takes the full version list and the protected
192
+ * (current/previous) versions, returns the versions to delete.
193
+ *
194
+ * Retention rules:
195
+ * - Always keep the N most recent versions (default 5).
196
+ * - Always keep the currently-active version (CurrentVersion symlink target).
197
+ * - Always keep the previous version (previous symlink target) so rollback
198
+ * stays one command away.
199
+ * - Delete everything else.
200
+ *
201
+ * Exported so tests can pin the policy without shelling out to a real fs.
202
+ */
203
+ function selectVersionsToPrune(installedVersions, protectedVersions, retain = exports.DEFAULT_RETAIN_VERSIONS) {
204
+ if (installedVersions.length <= retain)
205
+ return [];
206
+ const sorted = [...installedVersions].sort(compareCliVersions).reverse();
207
+ const keepers = new Set(sorted.slice(0, retain));
208
+ if (protectedVersions.current)
209
+ keepers.add(protectedVersions.current);
210
+ if (protectedVersions.previous)
211
+ keepers.add(protectedVersions.previous);
212
+ return installedVersions.filter((v) => !keepers.has(v));
213
+ }
214
+ /**
215
+ * Prune installed CLI versions according to the retention policy. Removes
216
+ * `~/.ouro-cli/versions/{version}/` directories for versions outside the
217
+ * retention window. Best-effort: per-version delete failures are logged
218
+ * via nerves but don't propagate.
219
+ *
220
+ * Called from the activate path (cli-defaults.ts) so that every successful
221
+ * `ouro up` self-prunes. The user observed `~/.ouro-cli/versions/` going
222
+ * back to alpha.85 from March 20 — every CLI version they'd ever installed
223
+ * was still on disk because nothing ever GCed.
224
+ */
225
+ function pruneOldVersions(retain = exports.DEFAULT_RETAIN_VERSIONS, deps = {}) {
226
+ const cliHome = getOuroCliHome(deps.homeDir);
227
+ /* v8 ignore start -- dep defaults: tests always inject @preserve */
228
+ const readdirSync = deps.readdirSync ?? ((p, opts) => fs.readdirSync(p, opts));
229
+ const readlinkSync = deps.readlinkSync ?? fs.readlinkSync;
230
+ const rmSync = deps.rmSync ?? fs.rmSync;
231
+ /* v8 ignore stop */
232
+ const versionsDir = path.join(cliHome, "versions");
233
+ let installed;
234
+ try {
235
+ installed = readdirSync(versionsDir, { withFileTypes: true })
236
+ .filter((e) => e.isDirectory())
237
+ .map((e) => e.name);
238
+ }
239
+ catch {
240
+ return { kept: [], deleted: [], failed: [] };
241
+ }
242
+ const current = (() => {
243
+ try {
244
+ return path.basename(readlinkSync(path.join(cliHome, "CurrentVersion")));
245
+ }
246
+ catch {
247
+ return null;
248
+ }
249
+ })();
250
+ const previous = (() => {
251
+ try {
252
+ return path.basename(readlinkSync(path.join(cliHome, "previous")));
253
+ }
254
+ catch {
255
+ return null;
256
+ }
257
+ })();
258
+ const toDelete = selectVersionsToPrune(installed, { current, previous }, retain);
259
+ const deleted = [];
260
+ const failed = [];
261
+ for (const version of toDelete) {
262
+ const versionDir = path.join(versionsDir, version);
263
+ try {
264
+ rmSync(versionDir, { recursive: true, force: true });
265
+ deleted.push(version);
266
+ }
267
+ catch (error) {
268
+ failed.push({
269
+ version,
270
+ error: error instanceof Error ? error.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(error),
271
+ });
272
+ }
273
+ }
274
+ (0, runtime_1.emitNervesEvent)({
275
+ component: "daemon",
276
+ event: "daemon.cli_versions_pruned",
277
+ message: `pruned ${deleted.length} old CLI versions`,
278
+ meta: { retain, deleted, failed: failed.length, kept: installed.filter((v) => !deleted.includes(v)) },
279
+ });
280
+ return { kept: installed.filter((v) => !deleted.includes(v)), deleted, failed };
281
+ }
282
+ function ensureLayout(deps) {
283
+ const cliHome = getOuroCliHome(deps.homeDir);
284
+ /* v8 ignore next -- dep default: tests always inject @preserve */
285
+ const mkdirSync = deps.mkdirSync ?? fs.mkdirSync;
286
+ mkdirSync(cliHome, { recursive: true });
287
+ mkdirSync(path.join(cliHome, "bin"), { recursive: true });
288
+ mkdirSync(path.join(cliHome, "versions"), { recursive: true });
289
+ (0, runtime_1.emitNervesEvent)({
290
+ component: "daemon",
291
+ event: "daemon.cli_layout_ensured",
292
+ message: "CLI directory layout ensured",
293
+ meta: { cliHome },
294
+ });
295
+ }