@ouro.bot/cli 0.1.0-alpha.15 → 0.1.0-alpha.150
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.
- package/AdoptionSpecialist.ouro/psyche/SOUL.md +2 -2
- package/AdoptionSpecialist.ouro/psyche/identities/monty.md +2 -2
- package/README.md +151 -205
- package/changelog.json +985 -0
- package/dist/heart/active-work.js +633 -0
- package/dist/heart/bridges/manager.js +358 -0
- package/dist/heart/bridges/state-machine.js +135 -0
- package/dist/heart/bridges/store.js +123 -0
- package/dist/heart/commitments.js +105 -0
- package/dist/heart/config.js +66 -21
- package/dist/heart/core.js +645 -112
- package/dist/heart/cross-chat-delivery.js +146 -0
- package/dist/heart/daemon/agent-discovery.js +81 -0
- package/dist/heart/daemon/agent-service.js +360 -0
- package/dist/heart/daemon/auth-flow.js +457 -0
- package/dist/heart/daemon/cadence.js +70 -0
- package/dist/heart/daemon/daemon-cli.js +2301 -205
- package/dist/heart/daemon/daemon-entry.js +131 -4
- package/dist/heart/daemon/daemon-runtime-sync.js +212 -0
- package/dist/heart/daemon/daemon-tombstone.js +106 -0
- package/dist/heart/daemon/daemon.js +372 -3
- package/dist/heart/daemon/habit-migration.js +181 -0
- package/dist/heart/daemon/habit-parser.js +119 -0
- package/dist/heart/daemon/habit-scheduler.js +252 -0
- package/dist/heart/daemon/hatch-animation.js +10 -3
- package/dist/heart/daemon/hatch-flow.js +28 -111
- package/dist/heart/daemon/hooks/bundle-meta.js +92 -0
- package/dist/heart/daemon/inner-status.js +89 -0
- package/dist/heart/daemon/launchd.js +159 -0
- package/dist/heart/daemon/log-tailer.js +4 -3
- package/dist/heart/daemon/mcp-server.js +591 -0
- package/dist/heart/daemon/message-router.js +17 -8
- package/dist/heart/daemon/os-cron-deps.js +134 -0
- package/dist/heart/daemon/ouro-bot-global-installer.js +128 -0
- package/dist/heart/daemon/ouro-path-installer.js +78 -34
- package/dist/heart/daemon/ouro-version-manager.js +171 -0
- package/dist/heart/daemon/process-manager.js +75 -0
- package/dist/heart/daemon/run-hooks.js +37 -0
- package/dist/heart/daemon/runtime-logging.js +58 -15
- package/dist/heart/daemon/runtime-metadata.js +219 -0
- package/dist/heart/daemon/runtime-mode.js +67 -0
- package/dist/heart/daemon/sense-manager.js +50 -2
- package/dist/heart/daemon/session-id-resolver.js +131 -0
- package/dist/heart/daemon/skill-management-installer.js +94 -0
- package/dist/heart/daemon/socket-client.js +202 -0
- package/dist/heart/daemon/specialist-orchestrator.js +2 -2
- package/dist/heart/daemon/specialist-prompt.js +10 -7
- package/dist/heart/daemon/specialist-tools.js +53 -4
- package/dist/heart/daemon/staged-restart.js +114 -0
- package/dist/heart/daemon/task-scheduler.js +3 -25
- package/dist/heart/daemon/thoughts.js +507 -0
- package/dist/heart/daemon/update-checker.js +111 -0
- package/dist/heart/daemon/update-hooks.js +138 -0
- package/dist/heart/daemon/wrapper-publish-guard.js +86 -0
- package/dist/heart/delegation.js +62 -0
- package/dist/heart/identity.js +64 -21
- package/dist/heart/kicks.js +2 -20
- package/dist/heart/model-capabilities.js +48 -0
- package/dist/heart/obligations.js +197 -0
- package/dist/heart/progress-story.js +42 -0
- package/dist/heart/provider-failover.js +88 -0
- package/dist/heart/provider-ping.js +159 -0
- package/dist/heart/providers/anthropic-token.js +163 -0
- package/dist/heart/providers/anthropic.js +195 -34
- package/dist/heart/providers/azure.js +115 -9
- package/dist/heart/providers/github-copilot.js +157 -0
- package/dist/heart/providers/minimax.js +33 -3
- package/dist/heart/providers/openai-codex.js +49 -14
- package/dist/heart/session-activity.js +173 -0
- package/dist/heart/session-recall.js +216 -0
- package/dist/heart/streaming.js +117 -33
- package/dist/heart/target-resolution.js +127 -0
- package/dist/heart/tool-loop.js +200 -0
- package/dist/heart/turn-coordinator.js +28 -0
- package/dist/mind/associative-recall.js +122 -32
- package/dist/mind/bundle-manifest.js +14 -0
- package/dist/mind/context.js +125 -14
- package/dist/mind/{memory.js → diary.js} +70 -56
- package/dist/mind/first-impressions.js +16 -2
- package/dist/mind/friends/channel.js +44 -0
- package/dist/mind/friends/group-context.js +144 -0
- package/dist/mind/friends/store-file.js +19 -0
- package/dist/mind/friends/trust-explanation.js +74 -0
- package/dist/mind/friends/types.js +8 -0
- package/dist/mind/journal-index.js +161 -0
- package/dist/mind/obligation-steering.js +221 -0
- package/dist/mind/obligations.js +134 -0
- package/dist/mind/pending.js +76 -9
- package/dist/mind/phrases.js +1 -0
- package/dist/mind/prompt.js +607 -88
- package/dist/mind/token-estimate.js +8 -12
- package/dist/nerves/cli-logging.js +15 -2
- package/dist/nerves/coverage/run-artifacts.js +1 -1
- package/dist/nerves/index.js +59 -2
- package/dist/nerves/runtime.js +5 -1
- package/dist/repertoire/ado-client.js +4 -2
- package/dist/repertoire/ado-semantic.js +6 -0
- package/dist/repertoire/coding/codex-jsonl.js +64 -0
- package/dist/repertoire/coding/context-pack.js +254 -0
- package/dist/repertoire/coding/feedback.js +301 -0
- package/dist/repertoire/coding/index.js +4 -1
- package/dist/repertoire/coding/manager.js +210 -4
- package/dist/repertoire/coding/spawner.js +58 -12
- package/dist/repertoire/coding/tools.js +176 -4
- package/dist/repertoire/data/ado-endpoints.json +188 -0
- package/dist/repertoire/guardrails.js +290 -0
- package/dist/repertoire/mcp-client.js +254 -0
- package/dist/repertoire/mcp-manager.js +198 -0
- package/dist/repertoire/skills.js +14 -23
- package/dist/repertoire/tasks/board.js +12 -0
- package/dist/repertoire/tasks/index.js +23 -9
- package/dist/repertoire/tasks/parser.js +0 -2
- package/dist/repertoire/tasks/transitions.js +1 -20
- package/dist/repertoire/tools-base.js +990 -273
- package/dist/repertoire/tools-bluebubbles.js +94 -0
- package/dist/repertoire/tools-github.js +1 -6
- package/dist/repertoire/tools-teams.js +65 -59
- package/dist/repertoire/tools.js +281 -91
- package/dist/scripts/claude-code-hook.js +41 -0
- package/dist/scripts/claude-code-stop-hook.js +47 -0
- package/dist/senses/attention-queue.js +97 -0
- package/dist/senses/bluebubbles-client.js +258 -5
- package/dist/senses/bluebubbles-entry.js +2 -0
- package/dist/senses/bluebubbles-inbound-log.js +109 -0
- package/dist/senses/bluebubbles-media.js +339 -0
- package/dist/senses/bluebubbles-model.js +12 -4
- package/dist/senses/bluebubbles-mutation-log.js +45 -5
- package/dist/senses/bluebubbles-runtime-state.js +109 -0
- package/dist/senses/bluebubbles-session-cleanup.js +72 -0
- package/dist/senses/bluebubbles.js +981 -45
- package/dist/senses/cli-entry.js +1 -1
- package/dist/senses/cli-layout.js +187 -0
- package/dist/senses/cli.js +374 -131
- package/dist/senses/contextual-heartbeat.js +106 -0
- package/dist/senses/continuity.js +94 -0
- package/dist/senses/debug-activity.js +154 -0
- package/dist/senses/inner-dialog-worker.js +112 -19
- package/dist/senses/inner-dialog.js +621 -84
- package/dist/senses/pipeline.js +463 -0
- package/dist/senses/shared-turn.js +196 -0
- package/dist/senses/surface-tool.js +95 -0
- package/dist/senses/teams.js +796 -141
- package/dist/senses/trust-gate.js +112 -2
- package/package.json +12 -4
- package/skills/configure-dev-tools.md +81 -0
- package/subagents/README.md +4 -70
- package/dist/heart/daemon/subagent-installer.js +0 -134
- package/subagents/work-doer.md +0 -233
- package/subagents/work-merger.md +0 -624
- package/subagents/work-planner.md +0 -373
|
@@ -51,15 +51,21 @@ class DaemonProcessManager {
|
|
|
51
51
|
now;
|
|
52
52
|
setTimeoutFn;
|
|
53
53
|
clearTimeoutFn;
|
|
54
|
+
cooldownRecoveryMs;
|
|
55
|
+
maxCooldownRetries;
|
|
56
|
+
existsSyncFn;
|
|
54
57
|
constructor(options) {
|
|
55
58
|
this.maxRestartsPerHour = options.maxRestartsPerHour ?? 10;
|
|
56
59
|
this.stabilityThresholdMs = options.stabilityThresholdMs ?? 60_000;
|
|
57
60
|
this.initialBackoffMs = options.initialBackoffMs ?? 1_000;
|
|
58
61
|
this.maxBackoffMs = options.maxBackoffMs ?? 60_000;
|
|
62
|
+
this.cooldownRecoveryMs = options.cooldownRecoveryMs ?? 5 * 60 * 1_000;
|
|
63
|
+
this.maxCooldownRetries = options.maxCooldownRetries ?? 3;
|
|
59
64
|
this.spawnFn = options.spawn ?? ((command, args, spawnOptions) => (0, child_process_1.spawn)(command, args, spawnOptions));
|
|
60
65
|
this.now = options.now ?? (() => Date.now());
|
|
61
66
|
this.setTimeoutFn = options.setTimeoutFn ?? ((cb, delay) => setTimeout(cb, delay));
|
|
62
67
|
this.clearTimeoutFn = options.clearTimeoutFn ?? ((timer) => clearTimeout(timer));
|
|
68
|
+
this.existsSyncFn = options.existsSync ?? null;
|
|
63
69
|
for (const agent of options.agents) {
|
|
64
70
|
this.agents.set(agent.name, {
|
|
65
71
|
config: agent,
|
|
@@ -67,6 +73,8 @@ class DaemonProcessManager {
|
|
|
67
73
|
restartTimer: null,
|
|
68
74
|
crashTimestamps: [],
|
|
69
75
|
stopRequested: false,
|
|
76
|
+
cooldownTimer: null,
|
|
77
|
+
cooldownRetryCount: 0,
|
|
70
78
|
snapshot: {
|
|
71
79
|
name: agent.name,
|
|
72
80
|
channel: agent.channel,
|
|
@@ -76,6 +84,8 @@ class DaemonProcessManager {
|
|
|
76
84
|
startedAt: null,
|
|
77
85
|
lastCrashAt: null,
|
|
78
86
|
backoffMs: this.initialBackoffMs,
|
|
87
|
+
lastExitCode: null,
|
|
88
|
+
lastSignal: null,
|
|
79
89
|
},
|
|
80
90
|
});
|
|
81
91
|
}
|
|
@@ -96,6 +106,17 @@ class DaemonProcessManager {
|
|
|
96
106
|
state.snapshot.status = "starting";
|
|
97
107
|
const runCwd = (0, identity_1.getRepoRoot)();
|
|
98
108
|
const entryScript = path.join((0, identity_1.getRepoRoot)(), "dist", state.config.entry);
|
|
109
|
+
if (this.existsSyncFn && !this.existsSyncFn(entryScript)) {
|
|
110
|
+
state.snapshot.status = "crashed";
|
|
111
|
+
(0, runtime_1.emitNervesEvent)({
|
|
112
|
+
level: "error",
|
|
113
|
+
component: "daemon",
|
|
114
|
+
event: "daemon.agent_entry_missing",
|
|
115
|
+
message: "agent entry script does not exist — cannot spawn. Run 'ouro daemon install' from the correct location.",
|
|
116
|
+
meta: { agent, entryScript },
|
|
117
|
+
});
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
99
120
|
const args = [entryScript, "--agent", state.config.agentArg ?? agent, ...(state.config.args ?? [])];
|
|
100
121
|
const child = this.spawnFn("node", args, {
|
|
101
122
|
cwd: runCwd,
|
|
@@ -112,6 +133,17 @@ class DaemonProcessManager {
|
|
|
112
133
|
message: "daemon started managed agent process",
|
|
113
134
|
meta: { agent, pid: child.pid ?? null, cwd: runCwd },
|
|
114
135
|
});
|
|
136
|
+
/* v8 ignore start — child process error handler; requires real spawn to trigger */
|
|
137
|
+
child.on("error", (err) => {
|
|
138
|
+
(0, runtime_1.emitNervesEvent)({
|
|
139
|
+
level: "warn",
|
|
140
|
+
component: "daemon",
|
|
141
|
+
event: "daemon.agent_process_error",
|
|
142
|
+
message: "managed agent process emitted error",
|
|
143
|
+
meta: { agent, error: err.message },
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
/* v8 ignore stop */
|
|
115
147
|
child.once("exit", (code, signal) => {
|
|
116
148
|
this.onExit(state, code, signal);
|
|
117
149
|
});
|
|
@@ -119,6 +151,7 @@ class DaemonProcessManager {
|
|
|
119
151
|
async stopAgent(agent) {
|
|
120
152
|
const state = this.requireAgent(agent);
|
|
121
153
|
this.clearRestartTimer(state);
|
|
154
|
+
this.clearCooldownTimer(state);
|
|
122
155
|
state.stopRequested = true;
|
|
123
156
|
if (!state.process) {
|
|
124
157
|
state.snapshot.status = "stopped";
|
|
@@ -179,6 +212,8 @@ class DaemonProcessManager {
|
|
|
179
212
|
return;
|
|
180
213
|
state.process = null;
|
|
181
214
|
state.snapshot.pid = null;
|
|
215
|
+
state.snapshot.lastExitCode = code;
|
|
216
|
+
state.snapshot.lastSignal = signal;
|
|
182
217
|
const crashed = !state.stopRequested && code !== 0;
|
|
183
218
|
const now = this.now();
|
|
184
219
|
const startedAt = state.snapshot.startedAt ? Date.parse(state.snapshot.startedAt) : now;
|
|
@@ -209,6 +244,7 @@ class DaemonProcessManager {
|
|
|
209
244
|
message: "managed agent exceeded restart limit and is marked crashed",
|
|
210
245
|
meta: { agent: state.config.name, maxRestartsPerHour: this.maxRestartsPerHour },
|
|
211
246
|
});
|
|
247
|
+
this.scheduleCooldownRecovery(state);
|
|
212
248
|
return;
|
|
213
249
|
}
|
|
214
250
|
state.snapshot.status = "starting";
|
|
@@ -226,6 +262,45 @@ class DaemonProcessManager {
|
|
|
226
262
|
this.clearTimeoutFn(state.restartTimer);
|
|
227
263
|
state.restartTimer = null;
|
|
228
264
|
}
|
|
265
|
+
scheduleCooldownRecovery(state) {
|
|
266
|
+
if (state.cooldownRetryCount >= this.maxCooldownRetries) {
|
|
267
|
+
(0, runtime_1.emitNervesEvent)({
|
|
268
|
+
level: "error",
|
|
269
|
+
component: "daemon",
|
|
270
|
+
event: "daemon.agent_permanent_failure",
|
|
271
|
+
message: "managed agent exhausted all cooldown retries — permanently stopped",
|
|
272
|
+
meta: { agent: state.config.name, cooldownRetryCount: state.cooldownRetryCount, maxCooldownRetries: this.maxCooldownRetries },
|
|
273
|
+
});
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
this.clearCooldownTimer(state);
|
|
277
|
+
state.cooldownTimer = this.setTimeoutFn(() => {
|
|
278
|
+
state.cooldownRetryCount += 1;
|
|
279
|
+
state.crashTimestamps = [];
|
|
280
|
+
state.snapshot.backoffMs = this.initialBackoffMs;
|
|
281
|
+
state.snapshot.status = "starting";
|
|
282
|
+
state.snapshot.restartCount += 1;
|
|
283
|
+
(0, runtime_1.emitNervesEvent)({
|
|
284
|
+
component: "daemon",
|
|
285
|
+
event: "daemon.agent_cooldown_recovery",
|
|
286
|
+
message: "attempting cooldown recovery for managed agent",
|
|
287
|
+
meta: { agent: state.config.name, cooldownRetryCount: state.cooldownRetryCount },
|
|
288
|
+
});
|
|
289
|
+
void this.startAgent(state.config.name);
|
|
290
|
+
}, this.cooldownRecoveryMs);
|
|
291
|
+
(0, runtime_1.emitNervesEvent)({
|
|
292
|
+
component: "daemon",
|
|
293
|
+
event: "daemon.agent_cooldown_scheduled",
|
|
294
|
+
message: `scheduled cooldown recovery in ${this.cooldownRecoveryMs}ms`,
|
|
295
|
+
meta: { agent: state.config.name, cooldownRecoveryMs: this.cooldownRecoveryMs, cooldownRetryCount: state.cooldownRetryCount },
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
clearCooldownTimer(state) {
|
|
299
|
+
if (state.cooldownTimer === null)
|
|
300
|
+
return;
|
|
301
|
+
this.clearTimeoutFn(state.cooldownTimer);
|
|
302
|
+
state.cooldownTimer = null;
|
|
303
|
+
}
|
|
229
304
|
requireAgent(agent) {
|
|
230
305
|
const state = this.agents.get(agent);
|
|
231
306
|
if (!state) {
|
|
@@ -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
|
|
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
|
|
47
|
-
|
|
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
|
|
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 { ...
|
|
85
|
+
return { ...processDefault };
|
|
61
86
|
}
|
|
62
87
|
if (!parsed || typeof parsed !== "object") {
|
|
63
|
-
return { ...
|
|
88
|
+
return { ...processDefault };
|
|
64
89
|
}
|
|
65
90
|
const candidate = parsed;
|
|
66
|
-
const level = isLogLevel(candidate.level) ? candidate.level :
|
|
67
|
-
const sinks =
|
|
68
|
-
|
|
69
|
-
|
|
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
|
|
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
|
|
77
|
-
const configPath = options.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));
|
|
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(
|
|
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)({
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
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.detectRuntimeMode = detectRuntimeMode;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
40
|
+
function detectRuntimeMode(rootPath, deps = {}) {
|
|
41
|
+
const checkExists = deps.existsSync ?? fs.existsSync;
|
|
42
|
+
// 1. Production: installed via npm
|
|
43
|
+
if (rootPath.includes("node_modules/@ouro.bot/cli") ||
|
|
44
|
+
rootPath.includes("node_modules/ouro.bot")) {
|
|
45
|
+
(0, runtime_1.emitNervesEvent)({
|
|
46
|
+
component: "daemon",
|
|
47
|
+
event: "daemon.runtime_mode_detected",
|
|
48
|
+
message: "detected runtime mode",
|
|
49
|
+
meta: { rootPath, mode: "production" },
|
|
50
|
+
});
|
|
51
|
+
return "production";
|
|
52
|
+
}
|
|
53
|
+
// 2-4. Everything else is dev: worktrees, git repos, unknown paths
|
|
54
|
+
// (conservative default: assume dev unless proven production)
|
|
55
|
+
const reason = rootPath.includes(".claude/worktrees/")
|
|
56
|
+
? "worktree"
|
|
57
|
+
: checkExists(path.join(rootPath, ".git"))
|
|
58
|
+
? "git-repo"
|
|
59
|
+
: "unknown";
|
|
60
|
+
(0, runtime_1.emitNervesEvent)({
|
|
61
|
+
component: "daemon",
|
|
62
|
+
event: "daemon.runtime_mode_detected",
|
|
63
|
+
message: "detected runtime mode",
|
|
64
|
+
meta: { rootPath, mode: "dev", reason },
|
|
65
|
+
});
|
|
66
|
+
return "dev";
|
|
67
|
+
}
|
|
@@ -38,12 +38,14 @@ const fs = __importStar(require("fs"));
|
|
|
38
38
|
const os = __importStar(require("os"));
|
|
39
39
|
const path = __importStar(require("path"));
|
|
40
40
|
const runtime_1 = require("../../nerves/runtime");
|
|
41
|
+
const bluebubbles_runtime_state_1 = require("../../senses/bluebubbles-runtime-state");
|
|
41
42
|
const identity_1 = require("../identity");
|
|
42
43
|
const sense_truth_1 = require("../sense-truth");
|
|
43
44
|
const process_manager_1 = require("./process-manager");
|
|
44
45
|
const DEFAULT_TEAMS_PORT = 3978;
|
|
45
46
|
const DEFAULT_BLUEBUBBLES_PORT = 18790;
|
|
46
47
|
const DEFAULT_BLUEBUBBLES_WEBHOOK_PATH = "/bluebubbles-webhook";
|
|
48
|
+
const BLUEBUBBLES_RUNTIME_FRESHNESS_WINDOW_MS = 90_000;
|
|
47
49
|
function defaultSenses() {
|
|
48
50
|
return {
|
|
49
51
|
cli: { ...identity_1.DEFAULT_AGENT_SENSES.cli },
|
|
@@ -175,12 +177,45 @@ function runtimeInfoFor(status) {
|
|
|
175
177
|
return { runtime: "running" };
|
|
176
178
|
return { runtime: "error" };
|
|
177
179
|
}
|
|
180
|
+
function blueBubblesRuntimeStateIsFresh(lastCheckedAt, now = Date.now()) {
|
|
181
|
+
if (!lastCheckedAt) {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
const checkedAt = Date.parse(lastCheckedAt);
|
|
185
|
+
if (!Number.isFinite(checkedAt)) {
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
return checkedAt >= now - BLUEBUBBLES_RUNTIME_FRESHNESS_WINDOW_MS;
|
|
189
|
+
}
|
|
190
|
+
function readBlueBubblesRuntimeFacts(agent, bundlesRoot, snapshot) {
|
|
191
|
+
const agentRoot = path.join(bundlesRoot, `${agent}.ouro`);
|
|
192
|
+
const runtimePath = path.join(agentRoot, "state", "senses", "bluebubbles", "runtime.json");
|
|
193
|
+
if (!fs.existsSync(runtimePath)) {
|
|
194
|
+
return { runtime: snapshot?.runtime };
|
|
195
|
+
}
|
|
196
|
+
const state = (0, bluebubbles_runtime_state_1.readBlueBubblesRuntimeState)(agent, agentRoot);
|
|
197
|
+
if (!blueBubblesRuntimeStateIsFresh(state.lastCheckedAt)) {
|
|
198
|
+
return { runtime: snapshot?.runtime };
|
|
199
|
+
}
|
|
200
|
+
if (state.upstreamStatus === "error") {
|
|
201
|
+
return {
|
|
202
|
+
runtime: "error",
|
|
203
|
+
detail: state.detail,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
if (state.upstreamStatus === "ok") {
|
|
207
|
+
return { runtime: "running" };
|
|
208
|
+
}
|
|
209
|
+
return { runtime: snapshot?.runtime };
|
|
210
|
+
}
|
|
178
211
|
class DaemonSenseManager {
|
|
179
212
|
processManager;
|
|
180
213
|
contexts;
|
|
214
|
+
bundlesRoot;
|
|
181
215
|
constructor(options) {
|
|
182
216
|
const bundlesRoot = options.bundlesRoot ?? path.join(os.homedir(), "AgentBundles");
|
|
183
217
|
const secretsRoot = options.secretsRoot ?? path.join(os.homedir(), ".agentsecrets");
|
|
218
|
+
this.bundlesRoot = bundlesRoot;
|
|
184
219
|
this.contexts = new Map(options.agents.map((agent) => {
|
|
185
220
|
const senses = readAgentSenses(path.join(bundlesRoot, `${agent}.ouro`, "agent.json"));
|
|
186
221
|
const facts = senseFactsFromSecrets(agent, senses, path.join(secretsRoot, agent, "secrets.json"));
|
|
@@ -216,6 +251,13 @@ class DaemonSenseManager {
|
|
|
216
251
|
async stopAll() {
|
|
217
252
|
await this.processManager.stopAll();
|
|
218
253
|
}
|
|
254
|
+
/* v8 ignore start -- pid collection for orphan cleanup pidfile @preserve */
|
|
255
|
+
listManagedPids() {
|
|
256
|
+
return this.processManager.listAgentSnapshots()
|
|
257
|
+
.map((s) => s.pid)
|
|
258
|
+
.filter((pid) => pid !== null && pid !== undefined);
|
|
259
|
+
}
|
|
260
|
+
/* v8 ignore stop */
|
|
219
261
|
listSenseRows() {
|
|
220
262
|
const runtime = new Map();
|
|
221
263
|
for (const snapshot of this.processManager.listAgentSnapshots()) {
|
|
@@ -227,6 +269,7 @@ class DaemonSenseManager {
|
|
|
227
269
|
runtime.set(parsed.agent, current);
|
|
228
270
|
}
|
|
229
271
|
const rows = [...this.contexts.entries()].flatMap(([agent, context]) => {
|
|
272
|
+
const blueBubblesRuntimeFacts = readBlueBubblesRuntimeFacts(agent, this.bundlesRoot, runtime.get(agent)?.bluebubbles);
|
|
230
273
|
const runtimeInfo = {
|
|
231
274
|
cli: { configured: true },
|
|
232
275
|
teams: {
|
|
@@ -235,7 +278,7 @@ class DaemonSenseManager {
|
|
|
235
278
|
},
|
|
236
279
|
bluebubbles: {
|
|
237
280
|
configured: context.facts.bluebubbles.configured,
|
|
238
|
-
...
|
|
281
|
+
...blueBubblesRuntimeFacts,
|
|
239
282
|
},
|
|
240
283
|
};
|
|
241
284
|
const inventory = (0, sense_truth_1.getSenseInventory)({ senses: context.senses }, runtimeInfo);
|
|
@@ -245,7 +288,12 @@ class DaemonSenseManager {
|
|
|
245
288
|
label: entry.label,
|
|
246
289
|
enabled: entry.enabled,
|
|
247
290
|
status: entry.status,
|
|
248
|
-
detail: entry.enabled
|
|
291
|
+
detail: entry.enabled
|
|
292
|
+
? entry.sense === "bluebubbles"
|
|
293
|
+
? blueBubblesRuntimeFacts.detail
|
|
294
|
+
?? context.facts[entry.sense].detail
|
|
295
|
+
: context.facts[entry.sense].detail
|
|
296
|
+
: "not enabled in agent.json",
|
|
249
297
|
}));
|
|
250
298
|
});
|
|
251
299
|
(0, runtime_1.emitNervesEvent)({
|