@ouro.bot/cli 0.1.0-alpha.14 → 0.1.0-alpha.141

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 (138) hide show
  1. package/AdoptionSpecialist.ouro/psyche/SOUL.md +2 -2
  2. package/AdoptionSpecialist.ouro/psyche/identities/monty.md +2 -2
  3. package/README.md +151 -205
  4. package/changelog.json +913 -0
  5. package/dist/heart/active-work.js +633 -0
  6. package/dist/heart/bridges/manager.js +358 -0
  7. package/dist/heart/bridges/state-machine.js +135 -0
  8. package/dist/heart/bridges/store.js +123 -0
  9. package/dist/heart/commitments.js +105 -0
  10. package/dist/heart/config.js +66 -21
  11. package/dist/heart/core.js +645 -112
  12. package/dist/heart/cross-chat-delivery.js +146 -0
  13. package/dist/heart/daemon/agent-discovery.js +81 -0
  14. package/dist/heart/daemon/agent-service.js +467 -0
  15. package/dist/heart/daemon/auth-flow.js +457 -0
  16. package/dist/heart/daemon/daemon-cli.js +1840 -196
  17. package/dist/heart/daemon/daemon-entry.js +80 -3
  18. package/dist/heart/daemon/daemon-runtime-sync.js +212 -0
  19. package/dist/heart/daemon/daemon.js +301 -1
  20. package/dist/heart/daemon/hatch-animation.js +10 -3
  21. package/dist/heart/daemon/hatch-flow.js +15 -80
  22. package/dist/heart/daemon/heartbeat-timer.js +131 -0
  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/mcp-server.js +464 -0
  27. package/dist/heart/daemon/message-router.js +17 -8
  28. package/dist/heart/daemon/ouro-bot-global-installer.js +128 -0
  29. package/dist/heart/daemon/ouro-path-installer.js +67 -34
  30. package/dist/heart/daemon/ouro-version-manager.js +171 -0
  31. package/dist/heart/daemon/process-manager.js +13 -0
  32. package/dist/heart/daemon/run-hooks.js +37 -0
  33. package/dist/heart/daemon/runtime-logging.js +58 -15
  34. package/dist/heart/daemon/runtime-metadata.js +219 -0
  35. package/dist/heart/daemon/runtime-mode.js +67 -0
  36. package/dist/heart/daemon/sense-manager.js +50 -2
  37. package/dist/heart/daemon/skill-management-installer.js +94 -0
  38. package/dist/heart/daemon/socket-client.js +202 -0
  39. package/dist/heart/daemon/specialist-orchestrator.js +2 -2
  40. package/dist/heart/daemon/specialist-prompt.js +10 -7
  41. package/dist/heart/daemon/specialist-tools.js +52 -3
  42. package/dist/heart/daemon/staged-restart.js +114 -0
  43. package/dist/heart/daemon/thoughts.js +507 -0
  44. package/dist/heart/daemon/update-checker.js +111 -0
  45. package/dist/heart/daemon/update-hooks.js +138 -0
  46. package/dist/heart/daemon/wrapper-publish-guard.js +86 -0
  47. package/dist/heart/delegation.js +62 -0
  48. package/dist/heart/identity.js +64 -21
  49. package/dist/heart/kicks.js +2 -20
  50. package/dist/heart/model-capabilities.js +48 -0
  51. package/dist/heart/obligations.js +197 -0
  52. package/dist/heart/progress-story.js +42 -0
  53. package/dist/heart/provider-failover.js +88 -0
  54. package/dist/heart/provider-ping.js +159 -0
  55. package/dist/heart/providers/anthropic-token.js +163 -0
  56. package/dist/heart/providers/anthropic.js +195 -34
  57. package/dist/heart/providers/azure.js +115 -9
  58. package/dist/heart/providers/github-copilot.js +157 -0
  59. package/dist/heart/providers/minimax.js +33 -3
  60. package/dist/heart/providers/openai-codex.js +49 -14
  61. package/dist/heart/session-activity.js +173 -0
  62. package/dist/heart/session-recall.js +216 -0
  63. package/dist/heart/streaming.js +117 -33
  64. package/dist/heart/target-resolution.js +123 -0
  65. package/dist/heart/tool-loop.js +200 -0
  66. package/dist/heart/turn-coordinator.js +28 -0
  67. package/dist/mind/associative-recall.js +122 -32
  68. package/dist/mind/bundle-manifest.js +14 -0
  69. package/dist/mind/context.js +125 -14
  70. package/dist/mind/{memory.js → diary.js} +70 -56
  71. package/dist/mind/first-impressions.js +16 -2
  72. package/dist/mind/friends/channel.js +35 -0
  73. package/dist/mind/friends/group-context.js +144 -0
  74. package/dist/mind/friends/store-file.js +19 -0
  75. package/dist/mind/friends/trust-explanation.js +74 -0
  76. package/dist/mind/friends/types.js +8 -0
  77. package/dist/mind/journal-index.js +161 -0
  78. package/dist/mind/obligation-steering.js +221 -0
  79. package/dist/mind/obligations.js +134 -0
  80. package/dist/mind/pending.js +76 -9
  81. package/dist/mind/phrases.js +1 -0
  82. package/dist/mind/prompt.js +554 -88
  83. package/dist/mind/token-estimate.js +8 -12
  84. package/dist/nerves/cli-logging.js +15 -2
  85. package/dist/nerves/coverage/run-artifacts.js +1 -1
  86. package/dist/nerves/index.js +12 -0
  87. package/dist/nerves/runtime.js +5 -1
  88. package/dist/repertoire/ado-client.js +4 -2
  89. package/dist/repertoire/ado-semantic.js +6 -0
  90. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  91. package/dist/repertoire/coding/context-pack.js +254 -0
  92. package/dist/repertoire/coding/feedback.js +301 -0
  93. package/dist/repertoire/coding/index.js +4 -1
  94. package/dist/repertoire/coding/manager.js +210 -4
  95. package/dist/repertoire/coding/spawner.js +59 -12
  96. package/dist/repertoire/coding/tools.js +176 -4
  97. package/dist/repertoire/data/ado-endpoints.json +188 -0
  98. package/dist/repertoire/guardrails.js +290 -0
  99. package/dist/repertoire/mcp-client.js +254 -0
  100. package/dist/repertoire/mcp-manager.js +198 -0
  101. package/dist/repertoire/skills.js +14 -23
  102. package/dist/repertoire/tasks/board.js +12 -0
  103. package/dist/repertoire/tasks/index.js +23 -9
  104. package/dist/repertoire/tasks/transitions.js +1 -2
  105. package/dist/repertoire/tools-base.js +980 -271
  106. package/dist/repertoire/tools-bluebubbles.js +94 -0
  107. package/dist/repertoire/tools-github.js +1 -6
  108. package/dist/repertoire/tools-teams.js +65 -59
  109. package/dist/repertoire/tools.js +266 -91
  110. package/dist/senses/attention-queue.js +97 -0
  111. package/dist/senses/bluebubbles-client.js +210 -5
  112. package/dist/senses/bluebubbles-entry.js +2 -0
  113. package/dist/senses/bluebubbles-inbound-log.js +109 -0
  114. package/dist/senses/bluebubbles-media.js +339 -0
  115. package/dist/senses/bluebubbles-model.js +12 -4
  116. package/dist/senses/bluebubbles-mutation-log.js +45 -5
  117. package/dist/senses/bluebubbles-runtime-state.js +109 -0
  118. package/dist/senses/bluebubbles-session-cleanup.js +72 -0
  119. package/dist/senses/bluebubbles.js +944 -45
  120. package/dist/senses/cli-entry.js +1 -1
  121. package/dist/senses/cli-layout.js +187 -0
  122. package/dist/senses/cli.js +374 -131
  123. package/dist/senses/contextual-heartbeat.js +102 -0
  124. package/dist/senses/continuity.js +94 -0
  125. package/dist/senses/debug-activity.js +154 -0
  126. package/dist/senses/inner-dialog-worker.js +47 -18
  127. package/dist/senses/inner-dialog.js +500 -84
  128. package/dist/senses/pipeline.js +454 -0
  129. package/dist/senses/surface-tool.js +82 -0
  130. package/dist/senses/teams.js +607 -129
  131. package/dist/senses/trust-gate.js +112 -2
  132. package/package.json +12 -4
  133. package/skills/configure-dev-tools.md +109 -0
  134. package/subagents/README.md +4 -70
  135. package/dist/heart/daemon/subagent-installer.js +0 -134
  136. package/subagents/work-doer.md +0 -233
  137. package/subagents/work-merger.md +0 -624
  138. package/subagents/work-planner.md +0 -373
@@ -39,8 +39,18 @@ const os = __importStar(require("os"));
39
39
  const path = __importStar(require("path"));
40
40
  const runtime_1 = require("../../nerves/runtime");
41
41
  const WRAPPER_SCRIPT = `#!/bin/sh
42
- exec npx --yes ouro.bot "$@"
42
+ ENTRY="$HOME/.ouro-cli/CurrentVersion/node_modules/@ouro.bot/cli/dist/heart/daemon/ouro-entry.js"
43
+ if [ ! -e "$ENTRY" ]; then
44
+ echo "ouro not installed. Run: npx ouro.bot" >&2
45
+ exit 1
46
+ fi
47
+ exec node "$ENTRY" "$@"
43
48
  `;
49
+ function writeWrapperScript(scriptPath, mkdirSync, writeFileSync, chmodSync) {
50
+ mkdirSync(path.dirname(scriptPath), { recursive: true });
51
+ writeFileSync(scriptPath, WRAPPER_SCRIPT, { mode: 0o755 });
52
+ chmodSync(scriptPath, 0o755);
53
+ }
44
54
  function detectShellProfile(homeDir, shell) {
45
55
  if (!shell)
46
56
  return null;
@@ -66,6 +76,16 @@ function buildPathExportLine(binDir, shell) {
66
76
  }
67
77
  return `\n# Added by ouro\nexport PATH="${binDir}:$PATH"\n`;
68
78
  }
79
+ function isWrapperCurrent(scriptPath, existsSync, readFileSync) {
80
+ if (!existsSync(scriptPath))
81
+ return false;
82
+ try {
83
+ return readFileSync(scriptPath, "utf-8") === WRAPPER_SCRIPT;
84
+ }
85
+ catch {
86
+ return false;
87
+ }
88
+ }
69
89
  function installOuroCommand(deps = {}) {
70
90
  /* v8 ignore start -- dep defaults: only used in real runtime, tests always inject @preserve */
71
91
  const platform = deps.platform ?? process.platform;
@@ -86,46 +106,59 @@ function installOuroCommand(deps = {}) {
86
106
  message: "skipped ouro PATH install on Windows",
87
107
  meta: { platform },
88
108
  });
89
- return { installed: false, scriptPath: null, pathReady: false, shellProfileUpdated: null, skippedReason: "windows" };
109
+ return { installed: false, scriptPath: null, pathReady: false, shellProfileUpdated: null, skippedReason: "windows", repairedOldLauncher: false };
110
+ }
111
+ // Ensure ~/.ouro-cli/ directory layout exists
112
+ if (deps.ensureCliLayout) {
113
+ deps.ensureCliLayout();
90
114
  }
91
- const binDir = path.join(homeDir, ".local", "bin");
115
+ const binDir = path.join(homeDir, ".ouro-cli", "bin");
92
116
  const scriptPath = path.join(binDir, "ouro");
93
- (0, runtime_1.emitNervesEvent)({
94
- component: "daemon",
95
- event: "daemon.ouro_path_install_start",
96
- message: "installing ouro command to PATH",
97
- meta: { scriptPath, binDir },
98
- });
99
- // If ouro already exists, check content and repair if stale
100
- if (existsSync(scriptPath)) {
101
- let existingContent = "";
117
+ const oldScriptPath = path.join(homeDir, ".local", "bin", "ouro");
118
+ const modernCurrent = isWrapperCurrent(scriptPath, existsSync, readFileSync);
119
+ const oldExists = existsSync(oldScriptPath);
120
+ const oldCurrent = oldExists && isWrapperCurrent(oldScriptPath, existsSync, readFileSync);
121
+ // ── Repair old ~/.local/bin/ouro launcher ──
122
+ // If the old launcher exists with stale content it can shadow the modern
123
+ // path and cause the wrong CLI version to run. Overwrite it with the
124
+ // current wrapper so both paths resolve to ~/.ouro-cli/CurrentVersion.
125
+ let repairedOldLauncher = false;
126
+ if (oldExists && !oldCurrent) {
127
+ (0, runtime_1.emitNervesEvent)({
128
+ component: "daemon",
129
+ event: "daemon.ouro_path_repair_old",
130
+ message: "repairing stale old launcher at ~/.local/bin/ouro",
131
+ meta: { oldScriptPath },
132
+ });
102
133
  try {
103
- existingContent = readFileSync(scriptPath, "utf-8");
134
+ writeFileSync(oldScriptPath, WRAPPER_SCRIPT, { mode: 0o755 });
135
+ chmodSync(oldScriptPath, 0o755);
136
+ repairedOldLauncher = true;
104
137
  }
105
138
  catch {
106
- // Can't read — treat as stale, will overwrite below
107
- }
108
- if (existingContent === WRAPPER_SCRIPT) {
109
- (0, runtime_1.emitNervesEvent)({
110
- component: "daemon",
111
- event: "daemon.ouro_path_install_skip",
112
- message: "ouro command already installed",
113
- meta: { scriptPath },
114
- });
115
- return { installed: false, scriptPath, pathReady: isBinDirInPath(binDir, envPath), shellProfileUpdated: null, skippedReason: "already-installed" };
139
+ // Best effort — old launcher repair failure must not block modern install
116
140
  }
117
- // Content is stale — repair by overwriting
141
+ }
142
+ // ── Fast-path: modern wrapper already current ──
143
+ if (modernCurrent) {
118
144
  (0, runtime_1.emitNervesEvent)({
119
145
  component: "daemon",
120
- event: "daemon.ouro_path_install_repair",
121
- message: "repairing stale ouro wrapper script",
146
+ event: "daemon.ouro_path_install_skip",
147
+ message: "ouro command already installed",
122
148
  meta: { scriptPath },
123
149
  });
150
+ return { installed: false, scriptPath, pathReady: isBinDirInPath(binDir, envPath), shellProfileUpdated: null, skippedReason: "already-installed", repairedOldLauncher };
124
151
  }
152
+ (0, runtime_1.emitNervesEvent)({
153
+ component: "daemon",
154
+ event: "daemon.ouro_path_install_start",
155
+ message: existsSync(scriptPath) ? "repairing stale ouro wrapper script" : "installing ouro command to PATH",
156
+ meta: { scriptPath, binDir },
157
+ });
125
158
  try {
126
- mkdirSync(binDir, { recursive: true });
127
- writeFileSync(scriptPath, WRAPPER_SCRIPT, { mode: 0o755 });
128
- chmodSync(scriptPath, 0o755);
159
+ if (!modernCurrent) {
160
+ writeWrapperScript(scriptPath, mkdirSync, writeFileSync, chmodSync);
161
+ }
129
162
  }
130
163
  catch (error) {
131
164
  (0, runtime_1.emitNervesEvent)({
@@ -135,11 +168,11 @@ function installOuroCommand(deps = {}) {
135
168
  message: "failed to install ouro command",
136
169
  meta: { error: error instanceof Error ? error.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(error) },
137
170
  });
138
- return { installed: false, scriptPath: null, pathReady: false, shellProfileUpdated: null, skippedReason: error instanceof Error ? error.message : /* v8 ignore next -- defensive @preserve */ String(error) };
171
+ return { installed: false, scriptPath: null, pathReady: false, shellProfileUpdated: null, skippedReason: error instanceof Error ? error.message : /* v8 ignore next -- defensive @preserve */ String(error), repairedOldLauncher };
139
172
  }
140
- // Check if ~/.local/bin is already in PATH
141
- let shellProfileUpdated = null;
173
+ // Check if ~/.ouro-cli/bin is already in PATH
142
174
  const pathReady = isBinDirInPath(binDir, envPath);
175
+ let shellProfileUpdated = null;
143
176
  if (!pathReady) {
144
177
  const profilePath = detectShellProfile(homeDir, shell);
145
178
  if (profilePath) {
@@ -171,7 +204,7 @@ function installOuroCommand(deps = {}) {
171
204
  component: "daemon",
172
205
  event: "daemon.ouro_path_install_end",
173
206
  message: "ouro command installed",
174
- meta: { scriptPath, pathReady, shellProfileUpdated },
207
+ meta: { scriptPath, pathReady, shellProfileUpdated, oldScriptPath: oldExists ? oldScriptPath : null },
175
208
  });
176
- return { installed: true, scriptPath, pathReady, shellProfileUpdated };
209
+ return { installed: true, scriptPath, pathReady, shellProfileUpdated, repairedOldLauncher };
177
210
  }
@@ -0,0 +1,171 @@
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.getOuroCliHome = getOuroCliHome;
37
+ exports.getCurrentVersion = getCurrentVersion;
38
+ exports.getPreviousVersion = getPreviousVersion;
39
+ exports.buildChangelogCommand = buildChangelogCommand;
40
+ exports.listInstalledVersions = listInstalledVersions;
41
+ exports.installVersion = installVersion;
42
+ exports.activateVersion = activateVersion;
43
+ exports.ensureLayout = ensureLayout;
44
+ const fs = __importStar(require("fs"));
45
+ const os = __importStar(require("os"));
46
+ const path = __importStar(require("path"));
47
+ const runtime_1 = require("../../nerves/runtime");
48
+ function getOuroCliHome(homeDir) {
49
+ /* v8 ignore next -- dep default: tests always inject @preserve */
50
+ const home = homeDir ?? os.homedir();
51
+ return path.join(home, ".ouro-cli");
52
+ }
53
+ function getCurrentVersion(deps) {
54
+ const cliHome = getOuroCliHome(deps.homeDir);
55
+ /* v8 ignore next -- dep default: tests always inject @preserve */
56
+ const readlinkSync = deps.readlinkSync ?? fs.readlinkSync;
57
+ try {
58
+ const target = readlinkSync(path.join(cliHome, "CurrentVersion"));
59
+ return path.basename(target);
60
+ }
61
+ catch {
62
+ return null;
63
+ }
64
+ }
65
+ function getPreviousVersion(deps) {
66
+ const cliHome = getOuroCliHome(deps.homeDir);
67
+ /* v8 ignore next -- dep default: tests always inject @preserve */
68
+ const readlinkSync = deps.readlinkSync ?? fs.readlinkSync;
69
+ try {
70
+ const target = readlinkSync(path.join(cliHome, "previous"));
71
+ return path.basename(target);
72
+ }
73
+ catch {
74
+ return null;
75
+ }
76
+ }
77
+ function buildChangelogCommand(previousVersion, currentVersion) {
78
+ if (!previousVersion || !currentVersion || previousVersion === currentVersion) {
79
+ return null;
80
+ }
81
+ return `ouro changelog --from ${previousVersion}`;
82
+ }
83
+ function listInstalledVersions(deps) {
84
+ const cliHome = getOuroCliHome(deps.homeDir);
85
+ /* v8 ignore next -- dep default: tests always inject @preserve */
86
+ const readdirSync = deps.readdirSync ?? ((p, opts) => fs.readdirSync(p, opts));
87
+ try {
88
+ const entries = readdirSync(path.join(cliHome, "versions"), { withFileTypes: true });
89
+ return entries.filter((e) => e.isDirectory()).map((e) => e.name);
90
+ }
91
+ catch {
92
+ return [];
93
+ }
94
+ }
95
+ function installVersion(version, deps) {
96
+ const cliHome = getOuroCliHome(deps.homeDir);
97
+ /* v8 ignore start -- dep defaults: tests always inject @preserve */
98
+ const mkdirSync = deps.mkdirSync ?? fs.mkdirSync;
99
+ const execSync = deps.execSync ?? ((cmd, opts) => require("child_process").execSync(cmd, opts));
100
+ /* v8 ignore stop */
101
+ const versionDir = path.join(cliHome, "versions", version);
102
+ (0, runtime_1.emitNervesEvent)({
103
+ component: "daemon",
104
+ event: "daemon.cli_version_install_start",
105
+ message: "installing CLI version",
106
+ meta: { version, versionDir },
107
+ });
108
+ mkdirSync(versionDir, { recursive: true });
109
+ execSync(`npm install --prefix ${versionDir} @ouro.bot/cli@${version}`, { stdio: "pipe" });
110
+ (0, runtime_1.emitNervesEvent)({
111
+ component: "daemon",
112
+ event: "daemon.cli_version_install_end",
113
+ message: "CLI version installed",
114
+ meta: { version, versionDir },
115
+ });
116
+ }
117
+ function activateVersion(version, deps) {
118
+ const cliHome = getOuroCliHome(deps.homeDir);
119
+ /* v8 ignore start -- dep defaults: tests always inject @preserve */
120
+ const readlinkSync = deps.readlinkSync ?? fs.readlinkSync;
121
+ const unlinkSync = deps.unlinkSync ?? fs.unlinkSync;
122
+ const symlinkSync = deps.symlinkSync ?? fs.symlinkSync;
123
+ const existsSync = deps.existsSync ?? fs.existsSync;
124
+ /* v8 ignore stop */
125
+ const currentVersionPath = path.join(cliHome, "CurrentVersion");
126
+ const previousPath = path.join(cliHome, "previous");
127
+ const newTarget = path.join(cliHome, "versions", version);
128
+ (0, runtime_1.emitNervesEvent)({
129
+ component: "daemon",
130
+ event: "daemon.cli_version_activate",
131
+ message: "activating CLI version",
132
+ meta: { version },
133
+ });
134
+ // Read old CurrentVersion target (may not exist)
135
+ let oldTarget = null;
136
+ try {
137
+ oldTarget = readlinkSync(currentVersionPath);
138
+ }
139
+ catch {
140
+ // No current version — first install
141
+ }
142
+ // Update previous symlink to point to old current
143
+ if (oldTarget) {
144
+ try {
145
+ unlinkSync(previousPath);
146
+ }
147
+ catch {
148
+ // previous symlink may not exist yet
149
+ }
150
+ symlinkSync(oldTarget, previousPath);
151
+ }
152
+ // Update CurrentVersion symlink
153
+ if (existsSync(currentVersionPath)) {
154
+ unlinkSync(currentVersionPath);
155
+ }
156
+ symlinkSync(newTarget, currentVersionPath);
157
+ }
158
+ function ensureLayout(deps) {
159
+ const cliHome = getOuroCliHome(deps.homeDir);
160
+ /* v8 ignore next -- dep default: tests always inject @preserve */
161
+ const mkdirSync = deps.mkdirSync ?? fs.mkdirSync;
162
+ mkdirSync(cliHome, { recursive: true });
163
+ mkdirSync(path.join(cliHome, "bin"), { recursive: true });
164
+ mkdirSync(path.join(cliHome, "versions"), { recursive: true });
165
+ (0, runtime_1.emitNervesEvent)({
166
+ component: "daemon",
167
+ event: "daemon.cli_layout_ensured",
168
+ message: "CLI directory layout ensured",
169
+ meta: { cliHome },
170
+ });
171
+ }
@@ -51,6 +51,7 @@ class DaemonProcessManager {
51
51
  now;
52
52
  setTimeoutFn;
53
53
  clearTimeoutFn;
54
+ existsSyncFn;
54
55
  constructor(options) {
55
56
  this.maxRestartsPerHour = options.maxRestartsPerHour ?? 10;
56
57
  this.stabilityThresholdMs = options.stabilityThresholdMs ?? 60_000;
@@ -60,6 +61,7 @@ class DaemonProcessManager {
60
61
  this.now = options.now ?? (() => Date.now());
61
62
  this.setTimeoutFn = options.setTimeoutFn ?? ((cb, delay) => setTimeout(cb, delay));
62
63
  this.clearTimeoutFn = options.clearTimeoutFn ?? ((timer) => clearTimeout(timer));
64
+ this.existsSyncFn = options.existsSync ?? null;
63
65
  for (const agent of options.agents) {
64
66
  this.agents.set(agent.name, {
65
67
  config: agent,
@@ -96,6 +98,17 @@ class DaemonProcessManager {
96
98
  state.snapshot.status = "starting";
97
99
  const runCwd = (0, identity_1.getRepoRoot)();
98
100
  const entryScript = path.join((0, identity_1.getRepoRoot)(), "dist", state.config.entry);
101
+ if (this.existsSyncFn && !this.existsSyncFn(entryScript)) {
102
+ state.snapshot.status = "crashed";
103
+ (0, runtime_1.emitNervesEvent)({
104
+ level: "error",
105
+ component: "daemon",
106
+ event: "daemon.agent_entry_missing",
107
+ message: "agent entry script does not exist — cannot spawn. Run 'ouro daemon install' from the correct location.",
108
+ meta: { agent, entryScript },
109
+ });
110
+ return;
111
+ }
99
112
  const args = [entryScript, "--agent", state.config.agentArg ?? agent, ...(state.config.args ?? [])];
100
113
  const child = this.spawnFn("node", args, {
101
114
  cwd: runCwd,
@@ -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
+ }
@@ -35,52 +35,95 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.configureDaemonRuntimeLogger = configureDaemonRuntimeLogger;
37
37
  const fs = __importStar(require("fs"));
38
- const os = __importStar(require("os"));
39
38
  const path = __importStar(require("path"));
40
39
  const nerves_1 = require("../../nerves");
41
40
  const runtime_1 = require("../../nerves/runtime");
42
- const DEFAULT_RUNTIME_LOGGING = {
41
+ const identity_1 = require("../identity");
42
+ const LEGACY_SHARED_RUNTIME_LOGGING = {
43
43
  level: "info",
44
44
  sinks: ["terminal", "ndjson"],
45
45
  };
46
- function defaultLevelForProcess(processName) {
47
- return processName === "daemon" ? "info" : "warn";
46
+ function defaultLoggingForProcess(processName) {
47
+ if (processName === "ouro" || processName === "ouro-bot") {
48
+ return {
49
+ level: "info",
50
+ sinks: ["ndjson"],
51
+ };
52
+ }
53
+ if (processName === "bluebubbles") {
54
+ return {
55
+ level: "warn",
56
+ sinks: ["terminal", "ndjson"],
57
+ };
58
+ }
59
+ return { ...LEGACY_SHARED_RUNTIME_LOGGING };
48
60
  }
49
61
  function isLogLevel(value) {
50
62
  return value === "debug" || value === "info" || value === "warn" || value === "error";
51
63
  }
64
+ function normalizeSinks(value, fallback) {
65
+ if (!Array.isArray(value)) {
66
+ return [...fallback];
67
+ }
68
+ const sinks = value.filter((entry) => entry === "terminal" || entry === "ndjson");
69
+ return sinks.length > 0 ? [...new Set(sinks)] : [...fallback];
70
+ }
71
+ function isLegacySharedDefaultConfig(candidate, normalizedLevel, normalizedSinks) {
72
+ return normalizedLevel === LEGACY_SHARED_RUNTIME_LOGGING.level
73
+ && normalizedSinks.length === LEGACY_SHARED_RUNTIME_LOGGING.sinks.length
74
+ && LEGACY_SHARED_RUNTIME_LOGGING.sinks.every((sink) => normalizedSinks.includes(sink))
75
+ && Object.keys(candidate).every((key) => key === "level" || key === "sinks");
76
+ }
52
77
  function resolveRuntimeLoggingConfig(configPath, processName) {
53
- const defaultLevel = defaultLevelForProcess(processName);
78
+ const processDefault = defaultLoggingForProcess(processName);
54
79
  let parsed = null;
55
80
  try {
56
81
  const raw = fs.readFileSync(configPath, "utf-8");
57
82
  parsed = JSON.parse(raw);
58
83
  }
59
84
  catch {
60
- return { ...DEFAULT_RUNTIME_LOGGING, level: defaultLevel };
85
+ return { ...processDefault };
61
86
  }
62
87
  if (!parsed || typeof parsed !== "object") {
63
- return { ...DEFAULT_RUNTIME_LOGGING, level: defaultLevel };
88
+ return { ...processDefault };
64
89
  }
65
90
  const candidate = parsed;
66
- const level = isLogLevel(candidate.level) ? candidate.level : defaultLevel;
67
- const sinks = Array.isArray(candidate.sinks)
68
- ? candidate.sinks.filter((entry) => entry === "terminal" || entry === "ndjson")
69
- : DEFAULT_RUNTIME_LOGGING.sinks;
91
+ const level = isLogLevel(candidate.level) ? candidate.level : processDefault.level;
92
+ const sinks = normalizeSinks(candidate.sinks, processDefault.sinks);
93
+ if ((processName === "ouro" || processName === "ouro-bot")
94
+ && isLegacySharedDefaultConfig(candidate, level, sinks)) {
95
+ return { ...processDefault };
96
+ }
70
97
  return {
71
98
  level,
72
- sinks: sinks.length > 0 ? [...new Set(sinks)] : [...DEFAULT_RUNTIME_LOGGING.sinks],
99
+ sinks,
73
100
  };
74
101
  }
102
+ function resolveAgentNameForPaths(explicit) {
103
+ if (explicit && explicit.trim().length > 0)
104
+ return explicit.trim();
105
+ try {
106
+ return (0, identity_1.getAgentName)();
107
+ }
108
+ catch {
109
+ return "slugger";
110
+ }
111
+ }
75
112
  function configureDaemonRuntimeLogger(processName, options = {}) {
76
- const homeDir = options.homeDir ?? os.homedir();
77
- const configPath = options.configPath ?? path.join(homeDir, ".agentstate", "daemon", "logging.json");
113
+ const agentName = resolveAgentNameForPaths(options.agentName);
114
+ const configPath = options.configPath
115
+ ?? (options.homeDir
116
+ ? path.join(options.homeDir, "AgentBundles", `${agentName}.ouro`, "state", "daemon", "logging.json")
117
+ : (0, identity_1.getAgentDaemonLoggingConfigPath)(agentName));
78
118
  const config = resolveRuntimeLoggingConfig(configPath, processName);
119
+ const logsDir = options.homeDir
120
+ ? path.join(options.homeDir, "AgentBundles", `${agentName}.ouro`, "state", "daemon", "logs")
121
+ : (0, identity_1.getAgentDaemonLogsDir)(agentName);
79
122
  const sinks = config.sinks.map((sinkName) => {
80
123
  if (sinkName === "terminal") {
81
124
  return (0, nerves_1.createTerminalSink)();
82
125
  }
83
- const ndjsonPath = path.join(homeDir, ".agentstate", "daemon", "logs", `${processName}.ndjson`);
126
+ const ndjsonPath = path.join(logsDir, `${processName}.ndjson`);
84
127
  return (0, nerves_1.createNdjsonFileSink)(ndjsonPath);
85
128
  });
86
129
  const logger = (0, nerves_1.createLogger)({