@ouro.bot/cli 0.1.0-alpha.1 → 0.1.0-alpha.100

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 (132) 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 +596 -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 +102 -23
  13. package/dist/heart/core.js +512 -94
  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 +1935 -185
  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 +218 -9
  21. package/dist/heart/daemon/hatch-animation.js +35 -0
  22. package/dist/heart/daemon/hatch-flow.js +10 -83
  23. package/dist/heart/daemon/hatch-specialist.js +6 -1
  24. package/dist/heart/daemon/hooks/bundle-meta.js +92 -0
  25. package/dist/heart/daemon/launchd.js +159 -0
  26. package/dist/heart/daemon/log-tailer.js +147 -0
  27. package/dist/heart/daemon/message-router.js +17 -8
  28. package/dist/heart/daemon/os-cron.js +260 -0
  29. package/dist/heart/daemon/ouro-bot-global-installer.js +128 -0
  30. package/dist/heart/daemon/ouro-bot-wrapper.js +4 -3
  31. package/dist/heart/daemon/ouro-path-installer.js +260 -0
  32. package/dist/heart/daemon/ouro-uti.js +11 -2
  33. package/dist/heart/daemon/ouro-version-manager.js +171 -0
  34. package/dist/heart/daemon/process-manager.js +32 -2
  35. package/dist/heart/daemon/run-hooks.js +37 -0
  36. package/dist/heart/daemon/runtime-logging.js +61 -14
  37. package/dist/heart/daemon/runtime-metadata.js +219 -0
  38. package/dist/heart/daemon/runtime-mode.js +67 -0
  39. package/dist/heart/daemon/sense-manager.js +307 -0
  40. package/dist/heart/daemon/skill-management-installer.js +94 -0
  41. package/dist/heart/daemon/socket-client.js +202 -0
  42. package/dist/heart/daemon/specialist-orchestrator.js +129 -0
  43. package/dist/heart/daemon/specialist-prompt.js +99 -0
  44. package/dist/heart/daemon/specialist-tools.js +283 -0
  45. package/dist/heart/daemon/staged-restart.js +114 -0
  46. package/dist/heart/daemon/task-scheduler.js +4 -1
  47. package/dist/heart/daemon/thoughts.js +507 -0
  48. package/dist/heart/daemon/update-checker.js +111 -0
  49. package/dist/heart/daemon/update-hooks.js +138 -0
  50. package/dist/heart/daemon/wrapper-publish-guard.js +86 -0
  51. package/dist/heart/delegation.js +62 -0
  52. package/dist/heart/identity.js +153 -23
  53. package/dist/heart/kicks.js +1 -19
  54. package/dist/heart/model-capabilities.js +48 -0
  55. package/dist/heart/obligations.js +191 -0
  56. package/dist/heart/progress-story.js +42 -0
  57. package/dist/heart/providers/anthropic.js +77 -9
  58. package/dist/heart/providers/azure.js +86 -7
  59. package/dist/heart/providers/github-copilot.js +149 -0
  60. package/dist/heart/providers/minimax.js +4 -0
  61. package/dist/heart/providers/openai-codex.js +12 -3
  62. package/dist/heart/safe-workspace.js +381 -0
  63. package/dist/heart/sense-truth.js +61 -0
  64. package/dist/heart/session-activity.js +169 -0
  65. package/dist/heart/session-recall.js +116 -0
  66. package/dist/heart/streaming.js +103 -22
  67. package/dist/heart/target-resolution.js +123 -0
  68. package/dist/heart/turn-coordinator.js +28 -0
  69. package/dist/mind/associative-recall.js +37 -4
  70. package/dist/mind/bundle-manifest.js +70 -0
  71. package/dist/mind/context.js +141 -11
  72. package/dist/mind/first-impressions.js +16 -2
  73. package/dist/mind/friends/channel.js +43 -0
  74. package/dist/mind/friends/group-context.js +144 -0
  75. package/dist/mind/friends/store-file.js +19 -0
  76. package/dist/mind/friends/trust-explanation.js +74 -0
  77. package/dist/mind/friends/types.js +9 -1
  78. package/dist/mind/memory.js +89 -26
  79. package/dist/mind/obligation-steering.js +31 -0
  80. package/dist/mind/pending.js +160 -0
  81. package/dist/mind/phrases.js +1 -0
  82. package/dist/mind/prompt-refresh.js +20 -0
  83. package/dist/mind/prompt.js +499 -8
  84. package/dist/mind/token-estimate.js +8 -12
  85. package/dist/nerves/cli-logging.js +15 -2
  86. package/dist/nerves/coverage/file-completeness.js +14 -4
  87. package/dist/nerves/coverage/run-artifacts.js +1 -1
  88. package/dist/nerves/index.js +12 -0
  89. package/dist/repertoire/ado-client.js +4 -2
  90. package/dist/repertoire/coding/feedback.js +210 -0
  91. package/dist/repertoire/coding/index.js +4 -1
  92. package/dist/repertoire/coding/manager.js +69 -4
  93. package/dist/repertoire/coding/spawner.js +21 -3
  94. package/dist/repertoire/coding/tools.js +105 -2
  95. package/dist/repertoire/data/ado-endpoints.json +188 -0
  96. package/dist/repertoire/guardrails.js +290 -0
  97. package/dist/repertoire/mcp-client.js +254 -0
  98. package/dist/repertoire/mcp-manager.js +195 -0
  99. package/dist/repertoire/skills.js +3 -26
  100. package/dist/repertoire/tasks/board.js +12 -0
  101. package/dist/repertoire/tasks/index.js +23 -9
  102. package/dist/repertoire/tasks/transitions.js +1 -2
  103. package/dist/repertoire/tools-base.js +770 -213
  104. package/dist/repertoire/tools-bluebubbles.js +93 -0
  105. package/dist/repertoire/tools-teams.js +58 -25
  106. package/dist/repertoire/tools.js +106 -53
  107. package/dist/senses/bluebubbles-client.js +484 -0
  108. package/dist/senses/bluebubbles-entry.js +13 -0
  109. package/dist/senses/bluebubbles-inbound-log.js +109 -0
  110. package/dist/senses/bluebubbles-media.js +339 -0
  111. package/dist/senses/bluebubbles-model.js +261 -0
  112. package/dist/senses/bluebubbles-mutation-log.js +116 -0
  113. package/dist/senses/bluebubbles-runtime-state.js +109 -0
  114. package/dist/senses/bluebubbles-session-cleanup.js +72 -0
  115. package/dist/senses/bluebubbles.js +1181 -0
  116. package/dist/senses/cli-layout.js +187 -0
  117. package/dist/senses/cli.js +452 -99
  118. package/dist/senses/continuity.js +94 -0
  119. package/dist/senses/debug-activity.js +154 -0
  120. package/dist/senses/inner-dialog-worker.js +47 -18
  121. package/dist/senses/inner-dialog.js +387 -70
  122. package/dist/senses/pipeline.js +307 -0
  123. package/dist/senses/session-lock.js +119 -0
  124. package/dist/senses/teams.js +574 -129
  125. package/dist/senses/trust-gate.js +112 -2
  126. package/package.json +16 -4
  127. package/subagents/README.md +4 -68
  128. package/dist/heart/daemon/subagent-installer.js +0 -125
  129. package/dist/inner-worker-entry.js +0 -4
  130. package/subagents/work-doer.md +0 -233
  131. package/subagents/work-merger.md +0 -593
  132. package/subagents/work-planner.md +0 -373
@@ -42,7 +42,13 @@ const identity_1 = require("../identity");
42
42
  const runtime_1 = require("../../nerves/runtime");
43
43
  const LSREGISTER_PATH = "/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister";
44
44
  const ICON_SIZES = [16, 32, 128, 256, 512];
45
- function resolveIconSourcePath(repoRoot) {
45
+ function resolveIconSourcePath(repoRoot, existsSync) {
46
+ // Prefer bundled asset (shipped with npm package)
47
+ const bundledPath = path.resolve(repoRoot, "assets", "ouroboros.png");
48
+ if (existsSync(bundledPath)) {
49
+ return bundledPath;
50
+ }
51
+ // Fall back to adjacent repo path (dev environment)
46
52
  return path.resolve(repoRoot, "..", "ouroboros-website", "public", "images", "ouroboros.png");
47
53
  }
48
54
  function buildIconAsset(iconSourcePath, icnsPath, iconsetDir, deps) {
@@ -91,6 +97,7 @@ function buildInfoPlist(iconInstalled) {
91
97
  " <key>UTTypeConformsTo</key>",
92
98
  " <array>",
93
99
  " <string>public.folder</string>",
100
+ " <string>com.apple.package</string>",
94
101
  " </array>",
95
102
  " <key>UTTypeTagSpecification</key>",
96
103
  " <dict>",
@@ -112,6 +119,8 @@ function buildInfoPlist(iconInstalled) {
112
119
  " </array>",
113
120
  " <key>CFBundleTypeRole</key>",
114
121
  " <string>Editor</string>",
122
+ " <key>LSTypeIsPackage</key>",
123
+ " <true/>",
115
124
  ` ${iconTag.trim()}`,
116
125
  " </dict>",
117
126
  " </array>",
@@ -152,7 +161,7 @@ function registerOuroBundleUti(deps = {}) {
152
161
  const plistPath = path.join(contentsDir, "Info.plist");
153
162
  const icnsPath = path.join(resourcesDir, "ouro.icns");
154
163
  const iconsetDir = path.join(supportRoot, "ouro.iconset");
155
- const iconSourcePath = resolveIconSourcePath(repoRoot);
164
+ const iconSourcePath = resolveIconSourcePath(repoRoot, existsSync);
156
165
  (0, runtime_1.emitNervesEvent)({
157
166
  component: "daemon",
158
167
  event: "daemon.ouro_uti_register_start",
@@ -0,0 +1,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,11 +98,22 @@ 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);
99
- const args = [entryScript, "--agent", agent, ...(state.config.args ?? [])];
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
+ }
112
+ const args = [entryScript, "--agent", state.config.agentArg ?? agent, ...(state.config.args ?? [])];
100
113
  const child = this.spawnFn("node", args, {
101
114
  cwd: runCwd,
102
115
  env: state.config.env ? { ...process.env, ...state.config.env } : process.env,
103
- stdio: ["ignore", "ignore", "ignore"],
116
+ stdio: ["ignore", "ignore", "ignore", "ipc"],
104
117
  });
105
118
  state.process = child;
106
119
  state.snapshot.status = "running";
@@ -151,6 +164,23 @@ class DaemonProcessManager {
151
164
  await this.stopAgent(state.config.name);
152
165
  }
153
166
  }
167
+ sendToAgent(agent, message) {
168
+ const state = this.requireAgent(agent);
169
+ if (!state.process)
170
+ return;
171
+ try {
172
+ state.process.send(message);
173
+ }
174
+ catch {
175
+ (0, runtime_1.emitNervesEvent)({
176
+ level: "warn",
177
+ component: "daemon",
178
+ event: "daemon.agent_ipc_send_error",
179
+ message: "failed to send IPC message to managed agent",
180
+ meta: { agent },
181
+ });
182
+ }
183
+ }
154
184
  getAgentSnapshot(agent) {
155
185
  return this.agents.get(agent)?.snapshot;
156
186
  }
@@ -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,48 +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 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 };
60
+ }
46
61
  function isLogLevel(value) {
47
62
  return value === "debug" || value === "info" || value === "warn" || value === "error";
48
63
  }
49
- function resolveRuntimeLoggingConfig(configPath) {
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
+ }
77
+ function resolveRuntimeLoggingConfig(configPath, processName) {
78
+ const processDefault = defaultLoggingForProcess(processName);
50
79
  let parsed = null;
51
80
  try {
52
81
  const raw = fs.readFileSync(configPath, "utf-8");
53
82
  parsed = JSON.parse(raw);
54
83
  }
55
84
  catch {
56
- return { ...DEFAULT_RUNTIME_LOGGING };
85
+ return { ...processDefault };
57
86
  }
58
87
  if (!parsed || typeof parsed !== "object") {
59
- return { ...DEFAULT_RUNTIME_LOGGING };
88
+ return { ...processDefault };
60
89
  }
61
90
  const candidate = parsed;
62
- const level = isLogLevel(candidate.level) ? candidate.level : DEFAULT_RUNTIME_LOGGING.level;
63
- const sinks = Array.isArray(candidate.sinks)
64
- ? candidate.sinks.filter((entry) => entry === "terminal" || entry === "ndjson")
65
- : 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
+ }
66
97
  return {
67
98
  level,
68
- sinks: sinks.length > 0 ? [...new Set(sinks)] : [...DEFAULT_RUNTIME_LOGGING.sinks],
99
+ sinks,
69
100
  };
70
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
+ }
71
112
  function configureDaemonRuntimeLogger(processName, options = {}) {
72
- const homeDir = options.homeDir ?? os.homedir();
73
- const configPath = options.configPath ?? path.join(homeDir, ".agentstate", "daemon", "logging.json");
74
- const config = resolveRuntimeLoggingConfig(configPath);
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));
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);
75
122
  const sinks = config.sinks.map((sinkName) => {
76
123
  if (sinkName === "terminal") {
77
124
  return (0, nerves_1.createTerminalSink)();
78
125
  }
79
- const ndjsonPath = path.join(homeDir, ".agentstate", "daemon", "logs", `${processName}.ndjson`);
126
+ const ndjsonPath = path.join(logsDir, `${processName}.ndjson`);
80
127
  return (0, nerves_1.createNdjsonFileSink)(ndjsonPath);
81
128
  });
82
129
  const logger = (0, nerves_1.createLogger)({
@@ -0,0 +1,219 @@
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 crypto_1 = require("crypto");
38
+ const fs = __importStar(require("fs"));
39
+ const os = __importStar(require("os"));
40
+ const path = __importStar(require("path"));
41
+ const childProcess = __importStar(require("child_process"));
42
+ const identity_1 = require("../identity");
43
+ const runtime_1 = require("../../nerves/runtime");
44
+ const UNKNOWN_METADATA = "unknown";
45
+ function optionalFunction(target, key) {
46
+ try {
47
+ const candidate = target[key];
48
+ return typeof candidate === "function" ? candidate : null;
49
+ }
50
+ catch {
51
+ return null;
52
+ }
53
+ }
54
+ function readVersion(packageJsonPath, readFileSyncImpl) {
55
+ try {
56
+ const parsed = JSON.parse(readFileSyncImpl(packageJsonPath, "utf-8"));
57
+ return typeof parsed.version === "string" && parsed.version.trim().length > 0
58
+ ? parsed.version.trim()
59
+ : UNKNOWN_METADATA;
60
+ }
61
+ catch {
62
+ return UNKNOWN_METADATA;
63
+ }
64
+ }
65
+ function readLastUpdated(repoRoot, packageJsonPath, statSyncImpl, execFileSyncImpl) {
66
+ try {
67
+ const raw = execFileSyncImpl("git", ["log", "-1", "--format=%cI"], {
68
+ cwd: repoRoot,
69
+ encoding: "utf-8",
70
+ stdio: ["ignore", "pipe", "ignore"],
71
+ }).trim();
72
+ if (raw.length > 0) {
73
+ return { value: raw, source: "git" };
74
+ }
75
+ }
76
+ catch {
77
+ // fall through to mtime fallback
78
+ }
79
+ try {
80
+ const stats = statSyncImpl(packageJsonPath);
81
+ return {
82
+ value: stats.mtime.toISOString(),
83
+ source: "package-json-mtime",
84
+ };
85
+ }
86
+ catch {
87
+ return { value: UNKNOWN_METADATA, source: "unknown" };
88
+ }
89
+ }
90
+ function readHomeDir() {
91
+ const homedirImpl = optionalFunction(os, "homedir");
92
+ if (!homedirImpl) {
93
+ return null;
94
+ }
95
+ try {
96
+ return homedirImpl.call(os);
97
+ }
98
+ catch {
99
+ return null;
100
+ }
101
+ }
102
+ function listConfigTargets(bundlesRoot, secretsRoot, daemonLoggingPath, readdirSyncImpl) {
103
+ if (!readdirSyncImpl)
104
+ return [];
105
+ const targets = new Set();
106
+ if (daemonLoggingPath) {
107
+ targets.add(daemonLoggingPath);
108
+ }
109
+ try {
110
+ const bundleEntries = readdirSyncImpl(bundlesRoot, { withFileTypes: true });
111
+ for (const entry of bundleEntries) {
112
+ if (!entry.isDirectory() || !entry.name.endsWith(".ouro"))
113
+ continue;
114
+ targets.add(path.join(bundlesRoot, entry.name, "agent.json"));
115
+ }
116
+ }
117
+ catch {
118
+ // ignore unreadable bundle roots
119
+ }
120
+ if (secretsRoot) {
121
+ try {
122
+ const secretEntries = readdirSyncImpl(secretsRoot, { withFileTypes: true });
123
+ for (const entry of secretEntries) {
124
+ if (!entry.isDirectory())
125
+ continue;
126
+ targets.add(path.join(secretsRoot, entry.name, "secrets.json"));
127
+ }
128
+ }
129
+ catch {
130
+ // ignore unreadable secrets roots
131
+ }
132
+ }
133
+ return [...targets].sort();
134
+ }
135
+ function readConfigFingerprint(targets, readFileSyncImpl, existsSyncImpl) {
136
+ if (!readFileSyncImpl || !existsSyncImpl) {
137
+ return {
138
+ value: UNKNOWN_METADATA,
139
+ source: "unknown",
140
+ trackedFiles: targets.length,
141
+ presentFiles: 0,
142
+ };
143
+ }
144
+ const hash = (0, crypto_1.createHash)("sha256");
145
+ let presentFiles = 0;
146
+ for (const target of targets) {
147
+ hash.update(target);
148
+ hash.update("\0");
149
+ if (!existsSyncImpl(target)) {
150
+ hash.update("missing");
151
+ hash.update("\0");
152
+ continue;
153
+ }
154
+ presentFiles += 1;
155
+ hash.update("present");
156
+ hash.update("\0");
157
+ try {
158
+ hash.update(readFileSyncImpl(target, "utf-8"));
159
+ }
160
+ catch {
161
+ hash.update("unreadable");
162
+ }
163
+ hash.update("\0");
164
+ }
165
+ return {
166
+ value: hash.digest("hex"),
167
+ source: "content-hash",
168
+ trackedFiles: targets.length,
169
+ presentFiles,
170
+ };
171
+ }
172
+ function getRuntimeMetadata(deps = {}) {
173
+ const repoRoot = deps.repoRoot ?? (0, identity_1.getRepoRoot)();
174
+ const bundlesRoot = deps.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
175
+ const homeDir = readHomeDir();
176
+ const secretsRoot = deps.secretsRoot ?? (homeDir ? path.join(homeDir, ".agentsecrets") : null);
177
+ const daemonLoggingPath = deps.daemonLoggingPath ?? (0, identity_1.getAgentDaemonLoggingConfigPath)();
178
+ const readFileSyncImpl = deps.readFileSync ?? optionalFunction(fs, "readFileSync")?.bind(fs) ?? null;
179
+ const statSyncImpl = deps.statSync ?? optionalFunction(fs, "statSync")?.bind(fs) ?? null;
180
+ const readdirSyncImpl = deps.readdirSync ?? optionalFunction(fs, "readdirSync")?.bind(fs) ?? null;
181
+ const existsSyncImpl = deps.existsSync ?? optionalFunction(fs, "existsSync")?.bind(fs) ?? null;
182
+ const execFileSyncImpl = deps.execFileSync
183
+ ?? optionalFunction(childProcess, "execFileSync")?.bind(childProcess)
184
+ ?? null;
185
+ const packageJsonPath = path.join(repoRoot, "package.json");
186
+ const version = readFileSyncImpl
187
+ ? readVersion(packageJsonPath, readFileSyncImpl)
188
+ : UNKNOWN_METADATA;
189
+ const lastUpdated = statSyncImpl
190
+ ? readLastUpdated(repoRoot, packageJsonPath, statSyncImpl, execFileSyncImpl ?? (() => {
191
+ throw new Error("git unavailable");
192
+ }))
193
+ : { value: UNKNOWN_METADATA, source: "unknown" };
194
+ const configTargets = listConfigTargets(bundlesRoot, secretsRoot, daemonLoggingPath, readdirSyncImpl);
195
+ const configFingerprint = readConfigFingerprint(configTargets, readFileSyncImpl, existsSyncImpl);
196
+ (0, runtime_1.emitNervesEvent)({
197
+ component: "daemon",
198
+ event: "daemon.runtime_metadata_read",
199
+ message: "read runtime metadata",
200
+ meta: {
201
+ version,
202
+ lastUpdated: lastUpdated.value,
203
+ lastUpdatedSource: lastUpdated.source,
204
+ repoRoot,
205
+ configFingerprint: configFingerprint.value === UNKNOWN_METADATA
206
+ ? UNKNOWN_METADATA
207
+ : configFingerprint.value.slice(0, 12),
208
+ configFingerprintSource: configFingerprint.source,
209
+ configTrackedFiles: configFingerprint.trackedFiles,
210
+ configPresentFiles: configFingerprint.presentFiles,
211
+ },
212
+ });
213
+ return {
214
+ version,
215
+ lastUpdated: lastUpdated.value,
216
+ repoRoot,
217
+ configFingerprint: configFingerprint.value,
218
+ };
219
+ }