@ouro.bot/cli 0.1.0-alpha.4 → 0.1.0-alpha.41

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 (84) hide show
  1. package/AdoptionSpecialist.ouro/agent.json +70 -9
  2. package/AdoptionSpecialist.ouro/psyche/SOUL.md +5 -2
  3. package/AdoptionSpecialist.ouro/psyche/identities/monty.md +2 -2
  4. package/README.md +117 -188
  5. package/assets/ouroboros.png +0 -0
  6. package/changelog.json +170 -0
  7. package/dist/heart/config.js +81 -8
  8. package/dist/heart/core.js +78 -45
  9. package/dist/heart/daemon/agent-discovery.js +81 -0
  10. package/dist/heart/daemon/daemon-cli.js +987 -77
  11. package/dist/heart/daemon/daemon-entry.js +14 -5
  12. package/dist/heart/daemon/daemon-runtime-sync.js +90 -0
  13. package/dist/heart/daemon/daemon.js +177 -9
  14. package/dist/heart/daemon/hatch-animation.js +35 -0
  15. package/dist/heart/daemon/hatch-flow.js +4 -20
  16. package/dist/heart/daemon/hooks/bundle-meta.js +92 -0
  17. package/dist/heart/daemon/launchd.js +134 -0
  18. package/dist/heart/daemon/message-router.js +15 -6
  19. package/dist/heart/daemon/ouro-bot-entry.js +0 -0
  20. package/dist/heart/daemon/ouro-bot-global-installer.js +128 -0
  21. package/dist/heart/daemon/ouro-entry.js +0 -0
  22. package/dist/heart/daemon/ouro-path-installer.js +178 -0
  23. package/dist/heart/daemon/ouro-uti.js +11 -2
  24. package/dist/heart/daemon/process-manager.js +1 -1
  25. package/dist/heart/daemon/run-hooks.js +37 -0
  26. package/dist/heart/daemon/runtime-metadata.js +118 -0
  27. package/dist/heart/daemon/sense-manager.js +266 -0
  28. package/dist/heart/daemon/specialist-orchestrator.js +129 -0
  29. package/dist/heart/daemon/specialist-prompt.js +99 -0
  30. package/dist/heart/daemon/specialist-tools.js +283 -0
  31. package/dist/heart/daemon/staged-restart.js +114 -0
  32. package/dist/heart/daemon/subagent-installer.js +10 -1
  33. package/dist/heart/daemon/update-checker.js +111 -0
  34. package/dist/heart/daemon/update-hooks.js +138 -0
  35. package/dist/heart/daemon/wrapper-publish-guard.js +86 -0
  36. package/dist/heart/identity.js +96 -4
  37. package/dist/heart/kicks.js +1 -19
  38. package/dist/heart/providers/anthropic.js +16 -2
  39. package/dist/heart/sense-truth.js +61 -0
  40. package/dist/heart/streaming.js +96 -21
  41. package/dist/mind/bundle-manifest.js +70 -0
  42. package/dist/mind/context.js +7 -7
  43. package/dist/mind/first-impressions.js +2 -1
  44. package/dist/mind/friends/channel.js +43 -0
  45. package/dist/mind/friends/store-file.js +19 -0
  46. package/dist/mind/friends/types.js +9 -1
  47. package/dist/mind/memory.js +10 -3
  48. package/dist/mind/pending.js +10 -2
  49. package/dist/mind/phrases.js +1 -0
  50. package/dist/mind/prompt.js +222 -7
  51. package/dist/mind/token-estimate.js +8 -12
  52. package/dist/nerves/cli-logging.js +15 -2
  53. package/dist/repertoire/ado-client.js +4 -2
  54. package/dist/repertoire/coding/feedback.js +134 -0
  55. package/dist/repertoire/coding/index.js +4 -1
  56. package/dist/repertoire/coding/manager.js +62 -4
  57. package/dist/repertoire/coding/spawner.js +3 -3
  58. package/dist/repertoire/coding/tools.js +41 -2
  59. package/dist/repertoire/data/ado-endpoints.json +188 -0
  60. package/dist/repertoire/tasks/index.js +2 -9
  61. package/dist/repertoire/tasks/transitions.js +1 -2
  62. package/dist/repertoire/tools-base.js +202 -219
  63. package/dist/repertoire/tools-bluebubbles.js +93 -0
  64. package/dist/repertoire/tools-teams.js +58 -25
  65. package/dist/repertoire/tools.js +55 -35
  66. package/dist/senses/bluebubbles-client.js +434 -0
  67. package/dist/senses/bluebubbles-entry.js +11 -0
  68. package/dist/senses/bluebubbles-media.js +338 -0
  69. package/dist/senses/bluebubbles-model.js +261 -0
  70. package/dist/senses/bluebubbles-mutation-log.js +74 -0
  71. package/dist/senses/bluebubbles-session-cleanup.js +72 -0
  72. package/dist/senses/bluebubbles.js +832 -0
  73. package/dist/senses/cli.js +327 -138
  74. package/dist/senses/debug-activity.js +127 -0
  75. package/dist/senses/inner-dialog.js +103 -55
  76. package/dist/senses/pipeline.js +124 -0
  77. package/dist/senses/teams.js +427 -112
  78. package/dist/senses/trust-gate.js +112 -2
  79. package/package.json +14 -3
  80. package/subagents/README.md +40 -53
  81. package/subagents/work-doer.md +26 -24
  82. package/subagents/work-merger.md +24 -30
  83. package/subagents/work-planner.md +34 -25
  84. package/dist/inner-worker-entry.js +0 -4
@@ -0,0 +1,134 @@
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.DAEMON_PLIST_LABEL = void 0;
37
+ exports.generateDaemonPlist = generateDaemonPlist;
38
+ exports.installLaunchAgent = installLaunchAgent;
39
+ exports.uninstallLaunchAgent = uninstallLaunchAgent;
40
+ exports.isDaemonInstalled = isDaemonInstalled;
41
+ const path = __importStar(require("path"));
42
+ const runtime_1 = require("../../nerves/runtime");
43
+ exports.DAEMON_PLIST_LABEL = "bot.ouro.daemon";
44
+ function plistFilePath(homeDir) {
45
+ return path.join(homeDir, "Library", "LaunchAgents", `${exports.DAEMON_PLIST_LABEL}.plist`);
46
+ }
47
+ function generateDaemonPlist(options) {
48
+ (0, runtime_1.emitNervesEvent)({
49
+ component: "daemon",
50
+ event: "daemon.launchd_generate_plist",
51
+ message: "generating daemon plist",
52
+ meta: { entryPath: options.entryPath, socketPath: options.socketPath },
53
+ });
54
+ const lines = [
55
+ `<?xml version="1.0" encoding="UTF-8"?>`,
56
+ `<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">`,
57
+ `<plist version="1.0">`,
58
+ `<dict>`,
59
+ ` <key>Label</key>`,
60
+ ` <string>${exports.DAEMON_PLIST_LABEL}</string>`,
61
+ ` <key>ProgramArguments</key>`,
62
+ ` <array>`,
63
+ ` <string>${options.nodePath}</string>`,
64
+ ` <string>${options.entryPath}</string>`,
65
+ ` <string>--socket</string>`,
66
+ ` <string>${options.socketPath}</string>`,
67
+ ` </array>`,
68
+ ` <key>KeepAlive</key>`,
69
+ ` <true/>`,
70
+ ];
71
+ if (options.logDir) {
72
+ lines.push(` <key>StandardOutPath</key>`, ` <string>${path.join(options.logDir, "ouro-daemon-stdout.log")}</string>`, ` <key>StandardErrorPath</key>`, ` <string>${path.join(options.logDir, "ouro-daemon-stderr.log")}</string>`);
73
+ }
74
+ lines.push(`</dict>`, `</plist>`, ``);
75
+ return lines.join("\n");
76
+ }
77
+ function installLaunchAgent(deps, options) {
78
+ (0, runtime_1.emitNervesEvent)({
79
+ component: "daemon",
80
+ event: "daemon.launchd_install",
81
+ message: "installing launch agent",
82
+ meta: { entryPath: options.entryPath, socketPath: options.socketPath },
83
+ });
84
+ const launchAgentsDir = path.join(deps.homeDir, "Library", "LaunchAgents");
85
+ deps.mkdirp(launchAgentsDir);
86
+ const fullPath = plistFilePath(deps.homeDir);
87
+ // Unload existing (best effort) for idempotent re-install
88
+ if (deps.existsFile(fullPath)) {
89
+ try {
90
+ deps.exec(`launchctl unload "${fullPath}"`);
91
+ }
92
+ catch { /* best effort */ }
93
+ }
94
+ const xml = generateDaemonPlist(options);
95
+ deps.writeFile(fullPath, xml);
96
+ deps.exec(`launchctl load "${fullPath}"`);
97
+ (0, runtime_1.emitNervesEvent)({
98
+ component: "daemon",
99
+ event: "daemon.launchd_installed",
100
+ message: "launch agent installed",
101
+ meta: { plistPath: fullPath },
102
+ });
103
+ }
104
+ function uninstallLaunchAgent(deps) {
105
+ (0, runtime_1.emitNervesEvent)({
106
+ component: "daemon",
107
+ event: "daemon.launchd_uninstall",
108
+ message: "uninstalling launch agent",
109
+ meta: {},
110
+ });
111
+ const fullPath = plistFilePath(deps.homeDir);
112
+ if (deps.existsFile(fullPath)) {
113
+ try {
114
+ deps.exec(`launchctl unload "${fullPath}"`);
115
+ }
116
+ catch { /* best effort */ }
117
+ deps.removeFile(fullPath);
118
+ }
119
+ (0, runtime_1.emitNervesEvent)({
120
+ component: "daemon",
121
+ event: "daemon.launchd_uninstalled",
122
+ message: "launch agent uninstalled",
123
+ meta: { plistPath: fullPath },
124
+ });
125
+ }
126
+ function isDaemonInstalled(deps) {
127
+ (0, runtime_1.emitNervesEvent)({
128
+ component: "daemon",
129
+ event: "daemon.launchd_check_installed",
130
+ message: "checking if daemon is installed",
131
+ meta: {},
132
+ });
133
+ return deps.existsFile(plistFilePath(deps.homeDir));
134
+ }
@@ -77,12 +77,21 @@ class FileMessageRouter {
77
77
  if (!fs.existsSync(inboxPath))
78
78
  return [];
79
79
  const raw = fs.readFileSync(inboxPath, "utf-8");
80
- fs.writeFileSync(inboxPath, "", "utf-8");
81
- const messages = raw
82
- .split("\n")
83
- .map((line) => line.trim())
84
- .filter((line) => line.length > 0)
85
- .map((line) => JSON.parse(line));
80
+ const messages = [];
81
+ const unparsed = [];
82
+ for (const line of raw.split("\n")) {
83
+ const trimmed = line.trim();
84
+ if (!trimmed)
85
+ continue;
86
+ try {
87
+ messages.push(JSON.parse(trimmed));
88
+ }
89
+ catch {
90
+ unparsed.push(trimmed);
91
+ }
92
+ }
93
+ // Only clear inbox after parsing; preserve lines that failed to parse.
94
+ fs.writeFileSync(inboxPath, unparsed.length > 0 ? unparsed.map((l) => `${l}\n`).join("") : "", "utf-8");
86
95
  (0, runtime_1.emitNervesEvent)({
87
96
  component: "daemon",
88
97
  event: "daemon.message_polled",
File without changes
@@ -0,0 +1,128 @@
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.syncGlobalOuroBotWrapper = syncGlobalOuroBotWrapper;
37
+ const child_process_1 = require("child_process");
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const runtime_1 = require("../../nerves/runtime");
41
+ const runtime_metadata_1 = require("./runtime-metadata");
42
+ function normalizeOutput(output) {
43
+ return (typeof output === "string" ? output : output.toString("utf-8")).trim();
44
+ }
45
+ function resolveGlobalPrefix(execFileSyncImpl) {
46
+ return normalizeOutput(execFileSyncImpl("npm", ["prefix", "-g"], { encoding: "utf-8" }));
47
+ }
48
+ function resolveGlobalRoot(execFileSyncImpl) {
49
+ return normalizeOutput(execFileSyncImpl("npm", ["root", "-g"], { encoding: "utf-8" }));
50
+ }
51
+ function readInstalledWrapperVersion(globalRoot, existsSyncImpl, readFileSyncImpl) {
52
+ const packageJsonPath = path.join(globalRoot, "ouro.bot", "package.json");
53
+ if (!existsSyncImpl(packageJsonPath))
54
+ return null;
55
+ try {
56
+ const parsed = JSON.parse(readFileSyncImpl(packageJsonPath, "utf-8"));
57
+ return typeof parsed.version === "string" && parsed.version.trim().length > 0 ? parsed.version.trim() : null;
58
+ }
59
+ catch {
60
+ return null;
61
+ }
62
+ }
63
+ function resolveExecutableOwner(globalPrefix, platform, existsSyncImpl, realpathSyncImpl) {
64
+ const binName = platform === "win32" ? "ouro.bot.cmd" : "ouro.bot";
65
+ const binPath = platform === "win32"
66
+ ? path.join(globalPrefix, binName)
67
+ : path.join(globalPrefix, "bin", binName);
68
+ if (!existsSyncImpl(binPath))
69
+ return null;
70
+ try {
71
+ const resolved = realpathSyncImpl(binPath);
72
+ if (resolved.includes(`${path.sep}node_modules${path.sep}ouro.bot${path.sep}`))
73
+ return "wrapper";
74
+ if (resolved.includes(`${path.sep}node_modules${path.sep}@ouro.bot${path.sep}cli${path.sep}`))
75
+ return "cli";
76
+ return "other";
77
+ }
78
+ catch {
79
+ return "unknown";
80
+ }
81
+ }
82
+ function syncGlobalOuroBotWrapper(deps = {}) {
83
+ /* v8 ignore start -- dependency-injection defaults are only exercised in the live runtime */
84
+ const execFileSyncImpl = deps.execFileSync ?? child_process_1.execFileSync;
85
+ const existsSyncImpl = deps.existsSync ?? fs.existsSync;
86
+ const readFileSyncImpl = deps.readFileSync ?? fs.readFileSync;
87
+ const realpathSyncImpl = deps.realpathSync ?? fs.realpathSync;
88
+ const runtimeVersion = deps.runtimeVersion ?? (0, runtime_metadata_1.getRuntimeMetadata)().version;
89
+ const platform = deps.platform ?? process.platform;
90
+ /* v8 ignore stop */
91
+ (0, runtime_1.emitNervesEvent)({
92
+ component: "daemon",
93
+ event: "daemon.ouro_bot_global_sync_start",
94
+ message: "checking global ouro.bot wrapper",
95
+ meta: { version: runtimeVersion },
96
+ });
97
+ const globalPrefix = resolveGlobalPrefix(execFileSyncImpl);
98
+ const globalRoot = resolveGlobalRoot(execFileSyncImpl);
99
+ const installedVersion = readInstalledWrapperVersion(globalRoot, existsSyncImpl, readFileSyncImpl);
100
+ const executableOwner = resolveExecutableOwner(globalPrefix, platform, existsSyncImpl, realpathSyncImpl);
101
+ if (executableOwner === "wrapper") {
102
+ (0, runtime_1.emitNervesEvent)({
103
+ component: "daemon",
104
+ event: "daemon.ouro_bot_global_sync_end",
105
+ message: "global ouro.bot wrapper already current",
106
+ meta: { version: runtimeVersion, installedVersion, executableOwner, installed: false },
107
+ });
108
+ return {
109
+ installed: false,
110
+ version: runtimeVersion,
111
+ installedVersion,
112
+ executableOwner,
113
+ };
114
+ }
115
+ execFileSyncImpl("npm", ["install", "-g", "--force", "ouro.bot@latest"], { stdio: "pipe", encoding: "utf-8" });
116
+ (0, runtime_1.emitNervesEvent)({
117
+ component: "daemon",
118
+ event: "daemon.ouro_bot_global_sync_end",
119
+ message: "global ouro.bot wrapper synced",
120
+ meta: { version: runtimeVersion, installedVersion, executableOwner, installed: true },
121
+ });
122
+ return {
123
+ installed: true,
124
+ version: runtimeVersion,
125
+ installedVersion,
126
+ executableOwner,
127
+ };
128
+ }
File without changes
@@ -0,0 +1,178 @@
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 CLI_PACKAGE_SPECIFIER = "@ouro.bot/cli@alpha";
42
+ const WRAPPER_SCRIPT = `#!/bin/sh
43
+ exec npx --yes ${CLI_PACKAGE_SPECIFIER} "$@"
44
+ `;
45
+ function detectShellProfile(homeDir, shell) {
46
+ if (!shell)
47
+ return null;
48
+ const base = path.basename(shell);
49
+ if (base === "zsh")
50
+ return path.join(homeDir, ".zshrc");
51
+ if (base === "bash") {
52
+ // macOS uses .bash_profile, Linux uses .bashrc
53
+ const profilePath = path.join(homeDir, ".bash_profile");
54
+ return profilePath;
55
+ }
56
+ if (base === "fish")
57
+ return path.join(homeDir, ".config", "fish", "config.fish");
58
+ return null;
59
+ }
60
+ function isBinDirInPath(binDir, envPath) {
61
+ return envPath.split(path.delimiter).some((p) => p === binDir);
62
+ }
63
+ function buildPathExportLine(binDir, shell) {
64
+ const base = shell ? path.basename(shell) : /* v8 ignore next -- unreachable: only called when detectShellProfile returns non-null, which requires shell @preserve */ "";
65
+ if (base === "fish") {
66
+ return `\n# Added by ouro\nset -gx PATH ${binDir} $PATH\n`;
67
+ }
68
+ return `\n# Added by ouro\nexport PATH="${binDir}:$PATH"\n`;
69
+ }
70
+ function installOuroCommand(deps = {}) {
71
+ /* v8 ignore start -- dep defaults: only used in real runtime, tests always inject @preserve */
72
+ const platform = deps.platform ?? process.platform;
73
+ const homeDir = deps.homeDir ?? os.homedir();
74
+ const existsSync = deps.existsSync ?? fs.existsSync;
75
+ const mkdirSync = deps.mkdirSync ?? fs.mkdirSync;
76
+ const writeFileSync = deps.writeFileSync ?? fs.writeFileSync;
77
+ const readFileSync = deps.readFileSync ?? ((p, enc) => fs.readFileSync(p, enc));
78
+ const appendFileSync = deps.appendFileSync ?? fs.appendFileSync;
79
+ const chmodSync = deps.chmodSync ?? fs.chmodSync;
80
+ const envPath = deps.envPath ?? process.env.PATH ?? "";
81
+ const shell = deps.shell ?? process.env.SHELL;
82
+ /* v8 ignore stop */
83
+ if (platform === "win32") {
84
+ (0, runtime_1.emitNervesEvent)({
85
+ component: "daemon",
86
+ event: "daemon.ouro_path_install_skip",
87
+ message: "skipped ouro PATH install on Windows",
88
+ meta: { platform },
89
+ });
90
+ return { installed: false, scriptPath: null, pathReady: false, shellProfileUpdated: null, skippedReason: "windows" };
91
+ }
92
+ const binDir = path.join(homeDir, ".local", "bin");
93
+ const scriptPath = path.join(binDir, "ouro");
94
+ (0, runtime_1.emitNervesEvent)({
95
+ component: "daemon",
96
+ event: "daemon.ouro_path_install_start",
97
+ message: "installing ouro command to PATH",
98
+ meta: { scriptPath, binDir },
99
+ });
100
+ // If ouro already exists, check content and repair if stale
101
+ if (existsSync(scriptPath)) {
102
+ let existingContent = "";
103
+ try {
104
+ existingContent = readFileSync(scriptPath, "utf-8");
105
+ }
106
+ catch {
107
+ // Can't read — treat as stale, will overwrite below
108
+ }
109
+ if (existingContent === WRAPPER_SCRIPT) {
110
+ (0, runtime_1.emitNervesEvent)({
111
+ component: "daemon",
112
+ event: "daemon.ouro_path_install_skip",
113
+ message: "ouro command already installed",
114
+ meta: { scriptPath },
115
+ });
116
+ return { installed: false, scriptPath, pathReady: isBinDirInPath(binDir, envPath), shellProfileUpdated: null, skippedReason: "already-installed" };
117
+ }
118
+ // Content is stale — repair by overwriting
119
+ (0, runtime_1.emitNervesEvent)({
120
+ component: "daemon",
121
+ event: "daemon.ouro_path_install_repair",
122
+ message: "repairing stale ouro wrapper script",
123
+ meta: { scriptPath },
124
+ });
125
+ }
126
+ try {
127
+ mkdirSync(binDir, { recursive: true });
128
+ writeFileSync(scriptPath, WRAPPER_SCRIPT, { mode: 0o755 });
129
+ chmodSync(scriptPath, 0o755);
130
+ }
131
+ catch (error) {
132
+ (0, runtime_1.emitNervesEvent)({
133
+ level: "warn",
134
+ component: "daemon",
135
+ event: "daemon.ouro_path_install_error",
136
+ message: "failed to install ouro command",
137
+ meta: { error: error instanceof Error ? error.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(error) },
138
+ });
139
+ return { installed: false, scriptPath: null, pathReady: false, shellProfileUpdated: null, skippedReason: error instanceof Error ? error.message : /* v8 ignore next -- defensive @preserve */ String(error) };
140
+ }
141
+ // Check if ~/.local/bin is already in PATH
142
+ let shellProfileUpdated = null;
143
+ const pathReady = isBinDirInPath(binDir, envPath);
144
+ if (!pathReady) {
145
+ const profilePath = detectShellProfile(homeDir, shell);
146
+ if (profilePath) {
147
+ try {
148
+ let existing = "";
149
+ try {
150
+ existing = readFileSync(profilePath, "utf-8");
151
+ }
152
+ catch {
153
+ // Profile doesn't exist yet — that's fine, we'll create it
154
+ }
155
+ if (!existing.includes(binDir)) {
156
+ appendFileSync(profilePath, buildPathExportLine(binDir, shell));
157
+ shellProfileUpdated = profilePath;
158
+ }
159
+ }
160
+ catch (error) {
161
+ (0, runtime_1.emitNervesEvent)({
162
+ level: "warn",
163
+ component: "daemon",
164
+ event: "daemon.ouro_path_profile_error",
165
+ message: "failed to update shell profile for PATH",
166
+ meta: { profilePath, error: error instanceof Error ? error.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(error) },
167
+ });
168
+ }
169
+ }
170
+ }
171
+ (0, runtime_1.emitNervesEvent)({
172
+ component: "daemon",
173
+ event: "daemon.ouro_path_install_end",
174
+ message: "ouro command installed",
175
+ meta: { scriptPath, pathReady, shellProfileUpdated },
176
+ });
177
+ return { installed: true, scriptPath, pathReady, shellProfileUpdated };
178
+ }
@@ -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",
@@ -96,7 +96,7 @@ class DaemonProcessManager {
96
96
  state.snapshot.status = "starting";
97
97
  const runCwd = (0, identity_1.getRepoRoot)();
98
98
  const entryScript = path.join((0, identity_1.getRepoRoot)(), "dist", state.config.entry);
99
- const args = [entryScript, "--agent", agent, ...(state.config.args ?? [])];
99
+ const args = [entryScript, "--agent", state.config.agentArg ?? agent, ...(state.config.args ?? [])];
100
100
  const child = this.spawnFn("node", args, {
101
101
  cwd: runCwd,
102
102
  env: state.config.env ? { ...process.env, ...state.config.env } : process.env,
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runHooks = runHooks;
4
+ const runtime_1 = require("../../nerves/runtime");
5
+ const bundle_meta_1 = require("./hooks/bundle-meta");
6
+ async function runHooks(deps) {
7
+ (0, runtime_1.emitNervesEvent)({
8
+ component: "daemon",
9
+ event: "daemon.run_hooks_start",
10
+ message: "running update hooks",
11
+ meta: { bundlesRoot: deps.bundlesRoot },
12
+ });
13
+ try {
14
+ deps.registerUpdateHook(bundle_meta_1.bundleMetaHook);
15
+ const currentVersion = deps.getPackageVersion();
16
+ await deps.applyPendingUpdates(deps.bundlesRoot, currentVersion);
17
+ (0, runtime_1.emitNervesEvent)({
18
+ component: "daemon",
19
+ event: "daemon.run_hooks_success",
20
+ message: "update hooks completed successfully",
21
+ meta: { bundlesRoot: deps.bundlesRoot },
22
+ });
23
+ return 0;
24
+ }
25
+ catch (err) {
26
+ (0, runtime_1.emitNervesEvent)({
27
+ component: "daemon",
28
+ event: "daemon.run_hooks_error",
29
+ message: "update hooks failed",
30
+ meta: {
31
+ bundlesRoot: deps.bundlesRoot,
32
+ error: err instanceof Error ? err.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(err),
33
+ },
34
+ });
35
+ return 1;
36
+ }
37
+ }
@@ -0,0 +1,118 @@
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.getRuntimeMetadata = getRuntimeMetadata;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const childProcess = __importStar(require("child_process"));
40
+ const identity_1 = require("../identity");
41
+ const runtime_1 = require("../../nerves/runtime");
42
+ const UNKNOWN_METADATA = "unknown";
43
+ function optionalFunction(target, key) {
44
+ try {
45
+ const candidate = target[key];
46
+ return typeof candidate === "function" ? candidate : null;
47
+ }
48
+ catch {
49
+ return null;
50
+ }
51
+ }
52
+ function readVersion(packageJsonPath, readFileSyncImpl) {
53
+ try {
54
+ const parsed = JSON.parse(readFileSyncImpl(packageJsonPath, "utf-8"));
55
+ return typeof parsed.version === "string" && parsed.version.trim().length > 0
56
+ ? parsed.version.trim()
57
+ : UNKNOWN_METADATA;
58
+ }
59
+ catch {
60
+ return UNKNOWN_METADATA;
61
+ }
62
+ }
63
+ function readLastUpdated(repoRoot, packageJsonPath, statSyncImpl, execFileSyncImpl) {
64
+ try {
65
+ const raw = execFileSyncImpl("git", ["log", "-1", "--format=%cI"], {
66
+ cwd: repoRoot,
67
+ encoding: "utf-8",
68
+ stdio: ["ignore", "pipe", "ignore"],
69
+ }).trim();
70
+ if (raw.length > 0) {
71
+ return { value: raw, source: "git" };
72
+ }
73
+ }
74
+ catch {
75
+ // fall through to mtime fallback
76
+ }
77
+ try {
78
+ const stats = statSyncImpl(packageJsonPath);
79
+ return {
80
+ value: stats.mtime.toISOString(),
81
+ source: "package-json-mtime",
82
+ };
83
+ }
84
+ catch {
85
+ return { value: UNKNOWN_METADATA, source: "unknown" };
86
+ }
87
+ }
88
+ function getRuntimeMetadata(deps = {}) {
89
+ const repoRoot = deps.repoRoot ?? (0, identity_1.getRepoRoot)();
90
+ const readFileSyncImpl = deps.readFileSync ?? optionalFunction(fs, "readFileSync")?.bind(fs) ?? null;
91
+ const statSyncImpl = deps.statSync ?? optionalFunction(fs, "statSync")?.bind(fs) ?? null;
92
+ const execFileSyncImpl = deps.execFileSync
93
+ ?? optionalFunction(childProcess, "execFileSync")?.bind(childProcess)
94
+ ?? null;
95
+ const packageJsonPath = path.join(repoRoot, "package.json");
96
+ const version = readFileSyncImpl
97
+ ? readVersion(packageJsonPath, readFileSyncImpl)
98
+ : UNKNOWN_METADATA;
99
+ const lastUpdated = statSyncImpl
100
+ ? readLastUpdated(repoRoot, packageJsonPath, statSyncImpl, execFileSyncImpl ?? (() => {
101
+ throw new Error("git unavailable");
102
+ }))
103
+ : { value: UNKNOWN_METADATA, source: "unknown" };
104
+ (0, runtime_1.emitNervesEvent)({
105
+ component: "daemon",
106
+ event: "daemon.runtime_metadata_read",
107
+ message: "read runtime metadata",
108
+ meta: {
109
+ version,
110
+ lastUpdated: lastUpdated.value,
111
+ lastUpdatedSource: lastUpdated.source,
112
+ },
113
+ });
114
+ return {
115
+ version,
116
+ lastUpdated: lastUpdated.value,
117
+ };
118
+ }