@ouro.bot/cli 0.1.0-alpha.9 → 0.1.0-alpha.91

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 (128) 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 +147 -205
  5. package/assets/ouroboros.png +0 -0
  6. package/changelog.json +536 -0
  7. package/dist/heart/active-work.js +251 -0
  8. package/dist/heart/bridges/manager.js +358 -0
  9. package/dist/heart/bridges/state-machine.js +135 -0
  10. package/dist/heart/bridges/store.js +123 -0
  11. package/dist/heart/commitments.js +109 -0
  12. package/dist/heart/config.js +68 -23
  13. package/dist/heart/core.js +452 -93
  14. package/dist/heart/cross-chat-delivery.js +146 -0
  15. package/dist/heart/daemon/agent-discovery.js +81 -0
  16. package/dist/heart/daemon/auth-flow.js +430 -0
  17. package/dist/heart/daemon/daemon-cli.js +1738 -269
  18. package/dist/heart/daemon/daemon-entry.js +55 -6
  19. package/dist/heart/daemon/daemon-runtime-sync.js +212 -0
  20. package/dist/heart/daemon/daemon.js +216 -10
  21. package/dist/heart/daemon/hatch-animation.js +10 -3
  22. package/dist/heart/daemon/hatch-flow.js +7 -82
  23. package/dist/heart/daemon/hooks/bundle-meta.js +92 -0
  24. package/dist/heart/daemon/launchd.js +159 -0
  25. package/dist/heart/daemon/log-tailer.js +4 -3
  26. package/dist/heart/daemon/message-router.js +17 -8
  27. package/dist/heart/daemon/ouro-bot-entry.js +0 -0
  28. package/dist/heart/daemon/ouro-bot-global-installer.js +128 -0
  29. package/dist/heart/daemon/ouro-entry.js +0 -0
  30. package/dist/heart/daemon/ouro-path-installer.js +260 -0
  31. package/dist/heart/daemon/ouro-uti.js +11 -2
  32. package/dist/heart/daemon/ouro-version-manager.js +171 -0
  33. package/dist/heart/daemon/process-manager.js +14 -1
  34. package/dist/heart/daemon/run-hooks.js +37 -0
  35. package/dist/heart/daemon/runtime-logging.js +58 -15
  36. package/dist/heart/daemon/runtime-metadata.js +219 -0
  37. package/dist/heart/daemon/runtime-mode.js +67 -0
  38. package/dist/heart/daemon/sense-manager.js +307 -0
  39. package/dist/heart/daemon/skill-management-installer.js +94 -0
  40. package/dist/heart/daemon/socket-client.js +202 -0
  41. package/dist/heart/daemon/specialist-orchestrator.js +53 -84
  42. package/dist/heart/daemon/specialist-prompt.js +63 -11
  43. package/dist/heart/daemon/specialist-tools.js +211 -60
  44. package/dist/heart/daemon/staged-restart.js +114 -0
  45. package/dist/heart/daemon/thoughts.js +507 -0
  46. package/dist/heart/daemon/update-checker.js +111 -0
  47. package/dist/heart/daemon/update-hooks.js +138 -0
  48. package/dist/heart/daemon/wrapper-publish-guard.js +86 -0
  49. package/dist/heart/delegation.js +62 -0
  50. package/dist/heart/identity.js +126 -21
  51. package/dist/heart/kicks.js +1 -19
  52. package/dist/heart/model-capabilities.js +48 -0
  53. package/dist/heart/obligations.js +191 -0
  54. package/dist/heart/progress-story.js +42 -0
  55. package/dist/heart/providers/anthropic.js +74 -9
  56. package/dist/heart/providers/azure.js +86 -7
  57. package/dist/heart/providers/github-copilot.js +149 -0
  58. package/dist/heart/providers/minimax.js +4 -0
  59. package/dist/heart/providers/openai-codex.js +12 -3
  60. package/dist/heart/safe-workspace.js +362 -0
  61. package/dist/heart/sense-truth.js +61 -0
  62. package/dist/heart/session-activity.js +169 -0
  63. package/dist/heart/session-recall.js +116 -0
  64. package/dist/heart/streaming.js +100 -22
  65. package/dist/heart/target-resolution.js +123 -0
  66. package/dist/heart/turn-coordinator.js +28 -0
  67. package/dist/mind/associative-recall.js +14 -2
  68. package/dist/mind/bundle-manifest.js +70 -0
  69. package/dist/mind/context.js +57 -11
  70. package/dist/mind/first-impressions.js +16 -2
  71. package/dist/mind/friends/channel.js +35 -0
  72. package/dist/mind/friends/group-context.js +144 -0
  73. package/dist/mind/friends/store-file.js +19 -0
  74. package/dist/mind/friends/trust-explanation.js +74 -0
  75. package/dist/mind/friends/types.js +8 -0
  76. package/dist/mind/memory.js +27 -26
  77. package/dist/mind/obligation-steering.js +31 -0
  78. package/dist/mind/pending.js +76 -9
  79. package/dist/mind/phrases.js +1 -0
  80. package/dist/mind/prompt.js +467 -77
  81. package/dist/mind/token-estimate.js +8 -12
  82. package/dist/nerves/cli-logging.js +15 -2
  83. package/dist/nerves/coverage/run-artifacts.js +1 -1
  84. package/dist/nerves/index.js +12 -0
  85. package/dist/repertoire/ado-client.js +4 -2
  86. package/dist/repertoire/coding/feedback.js +180 -0
  87. package/dist/repertoire/coding/index.js +4 -1
  88. package/dist/repertoire/coding/manager.js +69 -4
  89. package/dist/repertoire/coding/spawner.js +21 -3
  90. package/dist/repertoire/coding/tools.js +105 -2
  91. package/dist/repertoire/data/ado-endpoints.json +188 -0
  92. package/dist/repertoire/guardrails.js +290 -0
  93. package/dist/repertoire/mcp-client.js +254 -0
  94. package/dist/repertoire/mcp-manager.js +195 -0
  95. package/dist/repertoire/skills.js +3 -26
  96. package/dist/repertoire/tasks/board.js +12 -0
  97. package/dist/repertoire/tasks/index.js +23 -9
  98. package/dist/repertoire/tasks/transitions.js +1 -2
  99. package/dist/repertoire/tools-base.js +714 -249
  100. package/dist/repertoire/tools-bluebubbles.js +93 -0
  101. package/dist/repertoire/tools-teams.js +58 -25
  102. package/dist/repertoire/tools.js +106 -53
  103. package/dist/senses/bluebubbles-client.js +210 -5
  104. package/dist/senses/bluebubbles-entry.js +2 -0
  105. package/dist/senses/bluebubbles-inbound-log.js +109 -0
  106. package/dist/senses/bluebubbles-media.js +339 -0
  107. package/dist/senses/bluebubbles-model.js +12 -4
  108. package/dist/senses/bluebubbles-mutation-log.js +45 -5
  109. package/dist/senses/bluebubbles-runtime-state.js +109 -0
  110. package/dist/senses/bluebubbles-session-cleanup.js +72 -0
  111. package/dist/senses/bluebubbles.js +894 -45
  112. package/dist/senses/cli-layout.js +187 -0
  113. package/dist/senses/cli.js +400 -164
  114. package/dist/senses/continuity.js +94 -0
  115. package/dist/senses/debug-activity.js +154 -0
  116. package/dist/senses/inner-dialog-worker.js +47 -18
  117. package/dist/senses/inner-dialog.js +377 -83
  118. package/dist/senses/pipeline.js +307 -0
  119. package/dist/senses/teams.js +573 -129
  120. package/dist/senses/trust-gate.js +112 -2
  121. package/package.json +14 -3
  122. package/subagents/README.md +4 -70
  123. package/dist/heart/daemon/specialist-session.js +0 -142
  124. package/dist/heart/daemon/subagent-installer.js +0 -125
  125. package/dist/inner-worker-entry.js +0 -4
  126. package/subagents/work-doer.md +0 -233
  127. package/subagents/work-merger.md +0 -624
  128. package/subagents/work-planner.md +0 -373
@@ -39,13 +39,18 @@ const fs = __importStar(require("fs"));
39
39
  const os = __importStar(require("os"));
40
40
  const path = __importStar(require("path"));
41
41
  const identity_1 = require("../identity");
42
+ const config_1 = require("../config");
42
43
  const runtime_1 = require("../../nerves/runtime");
44
+ const auth_flow_1 = require("./auth-flow");
43
45
  const hatch_specialist_1 = require("./hatch-specialist");
44
46
  function requiredCredentialKeys(provider) {
45
47
  if (provider === "anthropic")
46
48
  return ["setupToken"];
47
49
  if (provider === "openai-codex")
48
50
  return ["oauthAccessToken"];
51
+ /* v8 ignore next -- branch tested via requiredCredentialKeys unit test @preserve */
52
+ if (provider === "github-copilot")
53
+ return ["githubToken"];
49
54
  if (provider === "minimax")
50
55
  return ["apiKey"];
51
56
  return ["apiKey", "endpoint", "deployment"];
@@ -66,70 +71,8 @@ function validateCredentials(provider, credentials) {
66
71
  throw new Error(`Missing required credentials for ${provider}: ${missing.join(", ")}`);
67
72
  }
68
73
  }
69
- function buildSecretsTemplate() {
70
- return {
71
- providers: {
72
- azure: {
73
- modelName: "gpt-4o-mini",
74
- apiKey: "",
75
- endpoint: "",
76
- deployment: "",
77
- apiVersion: "2025-04-01-preview",
78
- },
79
- minimax: {
80
- model: "minimax-text-01",
81
- apiKey: "",
82
- },
83
- anthropic: {
84
- model: "claude-opus-4-6",
85
- setupToken: "",
86
- },
87
- "openai-codex": {
88
- model: "gpt-5.2",
89
- oauthAccessToken: "",
90
- },
91
- },
92
- teams: {
93
- clientId: "",
94
- clientSecret: "",
95
- tenantId: "",
96
- },
97
- oauth: {
98
- graphConnectionName: "graph",
99
- adoConnectionName: "ado",
100
- githubConnectionName: "",
101
- },
102
- teamsChannel: {
103
- skipConfirmation: true,
104
- port: 3978,
105
- },
106
- integrations: {
107
- perplexityApiKey: "",
108
- openaiEmbeddingsApiKey: "",
109
- },
110
- };
111
- }
112
74
  function writeSecretsFile(agentName, provider, credentials, secretsRoot) {
113
- const secrets = buildSecretsTemplate();
114
- if (provider === "anthropic") {
115
- secrets.providers.anthropic.setupToken = credentials.setupToken.trim();
116
- }
117
- else if (provider === "openai-codex") {
118
- secrets.providers["openai-codex"].oauthAccessToken = credentials.oauthAccessToken.trim();
119
- }
120
- else if (provider === "minimax") {
121
- secrets.providers.minimax.apiKey = credentials.apiKey.trim();
122
- }
123
- else {
124
- secrets.providers.azure.apiKey = credentials.apiKey.trim();
125
- secrets.providers.azure.endpoint = credentials.endpoint.trim();
126
- secrets.providers.azure.deployment = credentials.deployment.trim();
127
- }
128
- const secretsDir = path.join(secretsRoot, agentName);
129
- fs.mkdirSync(secretsDir, { recursive: true });
130
- const secretsPath = path.join(secretsDir, "secrets.json");
131
- fs.writeFileSync(secretsPath, `${JSON.stringify(secrets, null, 2)}\n`, "utf-8");
132
- return secretsPath;
75
+ return (0, auth_flow_1.writeProviderCredentials)(agentName, provider, credentials, { secretsRoot }).secretsPath;
133
76
  }
134
77
  function writeReadme(dir, purpose) {
135
78
  fs.mkdirSync(dir, { recursive: true });
@@ -138,14 +81,6 @@ function writeReadme(dir, purpose) {
138
81
  fs.writeFileSync(readmePath, `# ${path.basename(dir)}\n\n${purpose}\n`, "utf-8");
139
82
  }
140
83
  }
141
- function slugify(value) {
142
- const trimmed = value.trim().toLowerCase();
143
- const slug = trimmed
144
- .replace(/[^a-z0-9]+/g, "-")
145
- .replace(/^-+/, "")
146
- .replace(/-+$/, "");
147
- return slug || "friend";
148
- }
149
84
  function pad(value) {
150
85
  return String(value).padStart(2, "0");
151
86
  }
@@ -182,7 +117,7 @@ function writeFriendImprint(bundleRoot, humanName, now) {
182
117
  const friendsDir = path.join(bundleRoot, "friends");
183
118
  fs.mkdirSync(friendsDir, { recursive: true });
184
119
  const nowIso = now.toISOString();
185
- const id = `friend-${slugify(humanName)}`;
120
+ const id = `friend-${(0, config_1.slugify)(humanName) || "friend"}`;
186
121
  const localExternalId = `${os.userInfo().username}@${os.hostname()}`;
187
122
  const record = {
188
123
  id,
@@ -207,15 +142,6 @@ function writeFriendImprint(bundleRoot, humanName, now) {
207
142
  };
208
143
  fs.writeFileSync(path.join(friendsDir, `${id}.json`), `${JSON.stringify(record, null, 2)}\n`, "utf-8");
209
144
  }
210
- function writeHatchlingPsyche(bundleRoot, input, identityFileName) {
211
- const psycheDir = path.join(bundleRoot, "psyche");
212
- fs.mkdirSync(psycheDir, { recursive: true });
213
- fs.writeFileSync(path.join(psycheDir, "SOUL.md"), "# SOUL\n\nI am a practical, collaborative agent. I keep commitments and communicate clearly.\n", "utf-8");
214
- fs.writeFileSync(path.join(psycheDir, "IDENTITY.md"), `# IDENTITY\n\nI'm ${input.agentName}, newly hatched and ready to help ${input.humanName}.`, "utf-8");
215
- fs.writeFileSync(path.join(psycheDir, "LORE.md"), `# LORE\n\nHatched with specialist identity seed: ${identityFileName}.`, "utf-8");
216
- fs.writeFileSync(path.join(psycheDir, "TACIT.md"), "# TACIT\n\n- Save what I learn.\n- Keep tasks current.\n", "utf-8");
217
- fs.writeFileSync(path.join(psycheDir, "ASPIRATIONS.md"), "# ASPIRATIONS\n\n- Become a reliable partner for my primary friend.\n", "utf-8");
218
- }
219
145
  function writeMemoryScaffold(bundleRoot) {
220
146
  const memoryRoot = path.join(bundleRoot, "psyche", "memory");
221
147
  fs.mkdirSync(path.join(memoryRoot, "daily"), { recursive: true });
@@ -267,7 +193,6 @@ async function runHatchFlow(input, deps = {}) {
267
193
  writeReadme(path.join(bundleRoot, "senses"), "Sense-specific config.");
268
194
  writeReadme(path.join(bundleRoot, "senses", "teams"), "Teams sense config.");
269
195
  writeHatchlingAgentConfig(bundleRoot, input);
270
- writeHatchlingPsyche(bundleRoot, input, selected.fileName);
271
196
  writeMemoryScaffold(bundleRoot);
272
197
  writeFriendImprint(bundleRoot, input.humanName, now);
273
198
  writeHeartbeatTask(bundleRoot, now);
@@ -0,0 +1,92 @@
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.bundleMetaHook = bundleMetaHook;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const runtime_1 = require("../../../nerves/runtime");
40
+ async function bundleMetaHook(ctx) {
41
+ (0, runtime_1.emitNervesEvent)({
42
+ component: "daemon",
43
+ event: "daemon.bundle_meta_hook_start",
44
+ message: "running bundle-meta update hook",
45
+ meta: { agentRoot: ctx.agentRoot, currentVersion: ctx.currentVersion },
46
+ });
47
+ const metaPath = path.join(ctx.agentRoot, "bundle-meta.json");
48
+ let existing;
49
+ try {
50
+ if (fs.existsSync(metaPath)) {
51
+ const raw = fs.readFileSync(metaPath, "utf-8");
52
+ existing = JSON.parse(raw);
53
+ }
54
+ }
55
+ catch {
56
+ // Malformed JSON -- treat as missing, will overwrite with fresh
57
+ existing = undefined;
58
+ }
59
+ const updated = {
60
+ runtimeVersion: ctx.currentVersion,
61
+ bundleSchemaVersion: existing?.bundleSchemaVersion ?? 1,
62
+ lastUpdated: new Date().toISOString(),
63
+ };
64
+ // Save old runtimeVersion as previousRuntimeVersion (if there was one)
65
+ if (existing?.runtimeVersion) {
66
+ updated.previousRuntimeVersion = existing.runtimeVersion;
67
+ }
68
+ try {
69
+ fs.writeFileSync(metaPath, JSON.stringify(updated, null, 2) + "\n", "utf-8");
70
+ }
71
+ catch (err) {
72
+ const errorMessage = err instanceof Error ? err.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(err);
73
+ (0, runtime_1.emitNervesEvent)({
74
+ component: "daemon",
75
+ event: "daemon.bundle_meta_hook_error",
76
+ message: "bundle-meta hook write failed",
77
+ meta: { agentRoot: ctx.agentRoot, error: errorMessage },
78
+ });
79
+ return { ok: false, error: errorMessage };
80
+ }
81
+ (0, runtime_1.emitNervesEvent)({
82
+ component: "daemon",
83
+ event: "daemon.bundle_meta_hook_end",
84
+ message: "bundle-meta updated",
85
+ meta: {
86
+ agentRoot: ctx.agentRoot,
87
+ runtimeVersion: updated.runtimeVersion,
88
+ previousRuntimeVersion: updated.previousRuntimeVersion,
89
+ },
90
+ });
91
+ return { ok: true };
92
+ }
@@ -0,0 +1,159 @@
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.writeLaunchAgentPlist = writeLaunchAgentPlist;
39
+ exports.installLaunchAgent = installLaunchAgent;
40
+ exports.uninstallLaunchAgent = uninstallLaunchAgent;
41
+ exports.isDaemonInstalled = isDaemonInstalled;
42
+ const path = __importStar(require("path"));
43
+ const runtime_1 = require("../../nerves/runtime");
44
+ exports.DAEMON_PLIST_LABEL = "bot.ouro.daemon";
45
+ function plistFilePath(homeDir) {
46
+ return path.join(homeDir, "Library", "LaunchAgents", `${exports.DAEMON_PLIST_LABEL}.plist`);
47
+ }
48
+ function userLaunchDomain(userUid) {
49
+ return `gui/${userUid}`;
50
+ }
51
+ function generateDaemonPlist(options) {
52
+ (0, runtime_1.emitNervesEvent)({
53
+ component: "daemon",
54
+ event: "daemon.launchd_generate_plist",
55
+ message: "generating daemon plist",
56
+ meta: { entryPath: options.entryPath, socketPath: options.socketPath },
57
+ });
58
+ const lines = [
59
+ `<?xml version="1.0" encoding="UTF-8"?>`,
60
+ `<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">`,
61
+ `<plist version="1.0">`,
62
+ `<dict>`,
63
+ ` <key>Label</key>`,
64
+ ` <string>${exports.DAEMON_PLIST_LABEL}</string>`,
65
+ ` <key>ProgramArguments</key>`,
66
+ ` <array>`,
67
+ ` <string>${options.nodePath}</string>`,
68
+ ` <string>${options.entryPath}</string>`,
69
+ ` <string>--socket</string>`,
70
+ ` <string>${options.socketPath}</string>`,
71
+ ` </array>`,
72
+ ` <key>RunAtLoad</key>`,
73
+ ` <true/>`,
74
+ ` <key>KeepAlive</key>`,
75
+ ` <true/>`,
76
+ ];
77
+ if (options.envPath) {
78
+ lines.push(` <key>EnvironmentVariables</key>`, ` <dict>`, ` <key>PATH</key>`, ` <string>${options.envPath}</string>`, ` </dict>`);
79
+ }
80
+ if (options.logDir) {
81
+ 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>`);
82
+ }
83
+ lines.push(`</dict>`, `</plist>`, ``);
84
+ return lines.join("\n");
85
+ }
86
+ function writeLaunchAgentPlist(deps, options) {
87
+ const launchAgentsDir = path.join(deps.homeDir, "Library", "LaunchAgents");
88
+ deps.mkdirp(launchAgentsDir);
89
+ if (options.logDir) {
90
+ deps.mkdirp(options.logDir);
91
+ }
92
+ const fullPath = plistFilePath(deps.homeDir);
93
+ const xml = generateDaemonPlist(options);
94
+ deps.writeFile(fullPath, xml);
95
+ (0, runtime_1.emitNervesEvent)({
96
+ component: "daemon",
97
+ event: "daemon.launchd_plist_written",
98
+ message: "daemon launch agent plist written",
99
+ meta: { plistPath: fullPath, entryPath: options.entryPath, socketPath: options.socketPath },
100
+ });
101
+ return fullPath;
102
+ }
103
+ function installLaunchAgent(deps, options) {
104
+ (0, runtime_1.emitNervesEvent)({
105
+ component: "daemon",
106
+ event: "daemon.launchd_install",
107
+ message: "installing launch agent",
108
+ meta: { entryPath: options.entryPath, socketPath: options.socketPath },
109
+ });
110
+ const fullPath = plistFilePath(deps.homeDir);
111
+ const domain = userLaunchDomain(deps.userUid);
112
+ // Unload existing (best effort) for idempotent re-install
113
+ if (deps.existsFile(fullPath)) {
114
+ try {
115
+ deps.exec(`launchctl bootout ${domain} "${fullPath}"`);
116
+ }
117
+ catch { /* best effort */ }
118
+ }
119
+ writeLaunchAgentPlist(deps, options);
120
+ deps.exec(`launchctl bootstrap ${domain} "${fullPath}"`);
121
+ (0, runtime_1.emitNervesEvent)({
122
+ component: "daemon",
123
+ event: "daemon.launchd_installed",
124
+ message: "launch agent installed",
125
+ meta: { plistPath: fullPath },
126
+ });
127
+ }
128
+ function uninstallLaunchAgent(deps) {
129
+ (0, runtime_1.emitNervesEvent)({
130
+ component: "daemon",
131
+ event: "daemon.launchd_uninstall",
132
+ message: "uninstalling launch agent",
133
+ meta: {},
134
+ });
135
+ const fullPath = plistFilePath(deps.homeDir);
136
+ const domain = userLaunchDomain(deps.userUid);
137
+ if (deps.existsFile(fullPath)) {
138
+ try {
139
+ deps.exec(`launchctl bootout ${domain} "${fullPath}"`);
140
+ }
141
+ catch { /* best effort */ }
142
+ deps.removeFile(fullPath);
143
+ }
144
+ (0, runtime_1.emitNervesEvent)({
145
+ component: "daemon",
146
+ event: "daemon.launchd_uninstalled",
147
+ message: "launch agent uninstalled",
148
+ meta: { plistPath: fullPath },
149
+ });
150
+ }
151
+ function isDaemonInstalled(deps) {
152
+ (0, runtime_1.emitNervesEvent)({
153
+ component: "daemon",
154
+ event: "daemon.launchd_check_installed",
155
+ message: "checking if daemon is installed",
156
+ meta: {},
157
+ });
158
+ return deps.existsFile(plistFilePath(deps.homeDir));
159
+ }
@@ -37,10 +37,10 @@ exports.discoverLogFiles = discoverLogFiles;
37
37
  exports.readLastLines = readLastLines;
38
38
  exports.formatLogLine = formatLogLine;
39
39
  exports.tailLogs = tailLogs;
40
- const os = __importStar(require("os"));
41
40
  const path = __importStar(require("path"));
42
41
  const nerves_1 = require("../../nerves");
43
42
  const runtime_1 = require("../../nerves/runtime");
43
+ const identity_1 = require("../identity");
44
44
  const LEVEL_COLORS = {
45
45
  debug: "\x1b[2m",
46
46
  info: "\x1b[36m",
@@ -49,11 +49,12 @@ const LEVEL_COLORS = {
49
49
  };
50
50
  function discoverLogFiles(options) {
51
51
  /* v8 ignore start -- integration: default DI stubs for real OS @preserve */
52
- const homeDir = options.homeDir ?? os.homedir();
53
52
  const existsSync = options.existsSync ?? (() => false);
54
53
  const readdirSync = options.readdirSync ?? (() => []);
55
54
  /* v8 ignore stop */
56
- const logDir = path.join(homeDir, ".agentstate", "daemon", "logs");
55
+ const logDir = options.homeDir
56
+ ? path.join(options.homeDir, "AgentBundles", `${options.agentName ?? "slugger"}.ouro`, "state", "daemon", "logs")
57
+ : (0, identity_1.getAgentDaemonLogsDir)(options.agentName);
57
58
  const files = [];
58
59
  if (existsSync(logDir)) {
59
60
  for (const name of readdirSync(logDir)) {
@@ -35,9 +35,9 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.FileMessageRouter = void 0;
37
37
  const fs = __importStar(require("fs"));
38
- const os = __importStar(require("os"));
39
38
  const path = __importStar(require("path"));
40
39
  const runtime_1 = require("../../nerves/runtime");
40
+ const identity_1 = require("../identity");
41
41
  function messageId(nowIso) {
42
42
  return `msg-${nowIso.replace(/[^0-9]/g, "")}`;
43
43
  }
@@ -45,7 +45,7 @@ class FileMessageRouter {
45
45
  baseDir;
46
46
  now;
47
47
  constructor(options = {}) {
48
- this.baseDir = options.baseDir ?? path.join(os.homedir(), ".agentstate", "messages");
48
+ this.baseDir = options.baseDir ?? (0, identity_1.getAgentMessagesRoot)();
49
49
  this.now = options.now ?? (() => new Date().toISOString());
50
50
  fs.mkdirSync(this.baseDir, { recursive: true });
51
51
  }
@@ -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