@ouro.bot/cli 0.1.0-alpha.20 → 0.1.0-alpha.200
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/README.md +187 -191
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +3 -2
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +1 -1
- package/changelog.json +1248 -0
- package/dist/heart/active-work.js +832 -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/cares.js +179 -0
- package/dist/heart/commitments.js +111 -0
- package/dist/heart/config.js +54 -30
- package/dist/heart/core.js +620 -124
- package/dist/heart/cross-chat-delivery.js +146 -0
- package/dist/heart/daemon/agent-config-check.js +149 -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 +477 -0
- package/dist/heart/daemon/cadence.js +70 -0
- package/dist/heart/daemon/daemon-cli.js +2443 -217
- package/dist/heart/daemon/daemon-entry.js +182 -4
- package/dist/heart/daemon/daemon-health.js +136 -0
- package/dist/heart/daemon/daemon-runtime-sync.js +231 -0
- package/dist/heart/daemon/daemon-tombstone.js +123 -0
- package/dist/heart/daemon/daemon.js +460 -18
- 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 +369 -0
- package/dist/heart/daemon/hatch-flow.js +31 -112
- package/dist/heart/daemon/hatch-specialist.js +3 -3
- package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
- package/dist/heart/daemon/hooks/bundle-meta.js +206 -0
- package/dist/heart/daemon/inner-status.js +89 -0
- package/dist/heart/daemon/launchd.js +165 -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/outlook-http.js +439 -0
- package/dist/heart/daemon/outlook-read.js +1618 -0
- package/dist/heart/daemon/outlook-render.js +1032 -0
- package/dist/heart/daemon/outlook-types.js +7 -0
- package/dist/heart/daemon/outlook-view.js +194 -0
- package/dist/heart/daemon/process-manager.js +93 -0
- package/dist/heart/daemon/run-hooks.js +39 -0
- package/dist/heart/daemon/runtime-logging.js +58 -15
- package/dist/heart/daemon/runtime-metadata.js +101 -0
- package/dist/heart/daemon/runtime-mode.js +67 -0
- package/dist/heart/daemon/safe-mode.js +161 -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-prompt.js +10 -7
- package/dist/heart/daemon/specialist-tools.js +49 -3
- package/dist/heart/daemon/staged-restart.js +138 -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 +147 -55
- package/dist/heart/intentions.js +173 -0
- package/dist/heart/kicks.js +2 -20
- package/dist/heart/migrate-config.js +127 -0
- package/dist/heart/model-capabilities.js +48 -0
- package/dist/heart/obligations.js +225 -0
- package/dist/heart/presence.js +185 -0
- package/dist/heart/progress-story.js +42 -0
- package/dist/heart/provider-failover.js +88 -0
- package/dist/heart/provider-ping.js +178 -0
- package/dist/heart/providers/anthropic-token.js +163 -0
- package/dist/heart/providers/anthropic.js +187 -41
- package/dist/heart/providers/azure.js +116 -10
- package/dist/heart/providers/github-copilot.js +157 -0
- package/dist/heart/providers/minimax.js +33 -3
- package/dist/heart/providers/openai-codex.js +51 -16
- package/dist/heart/session-activity.js +172 -0
- package/dist/heart/session-recall.js +216 -0
- package/dist/heart/start-of-turn-packet.js +232 -0
- package/dist/heart/streaming.js +36 -27
- package/dist/heart/sync.js +217 -0
- package/dist/heart/target-resolution.js +127 -0
- package/dist/heart/tempo.js +93 -0
- package/dist/heart/temporal-view.js +41 -0
- package/dist/heart/tool-activity-callbacks.js +36 -0
- package/dist/heart/tool-description.js +135 -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 +19 -1
- package/dist/mind/context.js +125 -14
- package/dist/mind/{memory.js → diary.js} +69 -56
- package/dist/mind/episodes.js +119 -0
- package/dist/mind/file-state.js +179 -0
- package/dist/mind/first-impressions.js +16 -2
- package/dist/mind/friends/channel.js +56 -0
- package/dist/mind/friends/group-context.js +144 -0
- package/dist/mind/friends/store-file.js +36 -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 +138 -0
- package/dist/mind/pending.js +76 -9
- package/dist/mind/phrases.js +1 -0
- package/dist/mind/prompt.js +785 -103
- package/dist/mind/scrutiny.js +173 -0
- package/dist/mind/token-estimate.js +8 -12
- package/dist/nerves/coverage/audit.js +1 -1
- package/dist/nerves/coverage/run-artifacts.js +1 -1
- package/dist/nerves/event-buffer.js +111 -0
- package/dist/nerves/index.js +63 -3
- package/dist/nerves/observation.js +20 -0
- package/dist/nerves/runtime.js +5 -1
- package/dist/outlook-ui/assets/index-Ck8agNeO.js +61 -0
- package/dist/outlook-ui/assets/index-LwChZTgL.css +1 -0
- package/dist/outlook-ui/index.html +15 -0
- package/dist/repertoire/ado-semantic.js +11 -5
- package/dist/repertoire/coding/codex-jsonl.js +64 -0
- package/dist/repertoire/coding/context-pack.js +330 -0
- package/dist/repertoire/coding/feedback.js +197 -30
- package/dist/repertoire/coding/manager.js +149 -2
- package/dist/repertoire/coding/spawner.js +55 -9
- package/dist/repertoire/coding/tools.js +170 -7
- package/dist/repertoire/guardrails.js +291 -0
- package/dist/repertoire/mcp-client.js +254 -0
- package/dist/repertoire/mcp-manager.js +251 -0
- package/dist/repertoire/shell-sessions.js +133 -0
- package/dist/repertoire/skills.js +14 -23
- package/dist/repertoire/tasks/board.js +43 -5
- package/dist/repertoire/tasks/fix.js +182 -0
- package/dist/repertoire/tasks/index.js +28 -10
- package/dist/repertoire/tasks/lifecycle.js +2 -2
- package/dist/repertoire/tasks/parser.js +3 -2
- package/dist/repertoire/tasks/scanner.js +194 -37
- package/dist/repertoire/tasks/transitions.js +11 -28
- package/dist/repertoire/tools-base.js +1345 -320
- package/dist/repertoire/tools-bluebubbles.js +94 -0
- package/dist/repertoire/tools-github.js +1 -6
- package/dist/repertoire/tools-teams.js +12 -59
- package/dist/repertoire/tools.js +318 -124
- 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 +102 -3
- package/dist/senses/bluebubbles-entry.js +2 -0
- package/dist/senses/bluebubbles-inbound-log.js +109 -0
- package/dist/senses/bluebubbles-media.js +118 -23
- 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 +1008 -102
- package/dist/senses/cli/adapter.js +274 -0
- package/dist/senses/cli/ink-app.js +156 -0
- package/dist/senses/cli/inline-diff.js +64 -0
- package/dist/senses/cli/message-list.js +51 -0
- package/dist/senses/cli/ouro-tui.js +349 -0
- package/dist/senses/cli/spinner-imperative.js +135 -0
- package/dist/senses/cli/spinner.js +101 -0
- package/dist/senses/cli/status-line.js +60 -0
- package/dist/senses/cli/streaming-markdown.js +526 -0
- package/dist/senses/cli/tool-display.js +83 -0
- package/dist/senses/cli/tool-render.js +85 -0
- package/dist/senses/cli/tui-store.js +198 -0
- package/dist/senses/cli/virtual-list.js +35 -0
- package/dist/senses/cli-entry.js +1 -1
- package/dist/senses/cli-layout.js +187 -0
- package/dist/senses/cli.js +508 -243
- package/dist/senses/commands.js +65 -1
- package/dist/senses/continuity.js +94 -0
- package/dist/senses/habit-turn-message.js +108 -0
- package/dist/senses/inner-dialog-worker.js +112 -19
- package/dist/senses/inner-dialog.js +592 -84
- package/dist/senses/pipeline.js +693 -0
- package/dist/senses/shared-turn.js +196 -0
- package/dist/senses/surface-tool.js +95 -0
- package/dist/senses/teams.js +667 -120
- package/dist/senses/trust-gate.js +112 -2
- package/package.json +16 -6
- package/skills/configure-dev-tools.md +81 -0
- package/subagents/README.md +4 -70
- package/dist/heart/daemon/subagent-installer.js +0 -134
- package/dist/senses/debug-activity.js +0 -107
- package/subagents/work-doer.md +0 -235
- package/subagents/work-merger.md +0 -618
- package/subagents/work-planner.md +0 -382
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OUTLOOK_DEFAULT_PORT = exports.OUTLOOK_DEFAULT_INNER_VISIBILITY = exports.OUTLOOK_RELEASE_INTERACTION_MODEL = exports.OUTLOOK_PRODUCT_NAME = void 0;
|
|
4
|
+
exports.OUTLOOK_PRODUCT_NAME = "Ouro Outlook";
|
|
5
|
+
exports.OUTLOOK_RELEASE_INTERACTION_MODEL = "read-only";
|
|
6
|
+
exports.OUTLOOK_DEFAULT_INNER_VISIBILITY = "summary";
|
|
7
|
+
exports.OUTLOOK_DEFAULT_PORT = 6876;
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildOutlookMachineView = buildOutlookMachineView;
|
|
4
|
+
exports.buildOutlookAgentView = buildOutlookAgentView;
|
|
5
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
6
|
+
const outlook_types_1 = require("./outlook-types");
|
|
7
|
+
function deriveAttention(agent) {
|
|
8
|
+
if (agent.degraded.status === "degraded") {
|
|
9
|
+
return { level: "degraded", label: "Degraded" };
|
|
10
|
+
}
|
|
11
|
+
if (agent.freshness.status === "stale") {
|
|
12
|
+
return { level: "stale", label: "Stale" };
|
|
13
|
+
}
|
|
14
|
+
if (agent.tasks.blockedCount > 0 || agent.coding.blockedCount > 0) {
|
|
15
|
+
return { level: "blocked", label: "Blocked" };
|
|
16
|
+
}
|
|
17
|
+
if (agent.tasks.liveCount > 0 || agent.coding.activeCount > 0 || agent.obligations.openCount > 0) {
|
|
18
|
+
return { level: "active", label: "Active" };
|
|
19
|
+
}
|
|
20
|
+
return { level: "idle", label: "Idle" };
|
|
21
|
+
}
|
|
22
|
+
function deriveAgentAttention(agent) {
|
|
23
|
+
return deriveAttention({
|
|
24
|
+
agentName: agent.agentName,
|
|
25
|
+
enabled: agent.enabled,
|
|
26
|
+
freshness: agent.freshness,
|
|
27
|
+
degraded: agent.degraded,
|
|
28
|
+
tasks: {
|
|
29
|
+
liveCount: agent.tasks.liveCount,
|
|
30
|
+
blockedCount: agent.tasks.blockedCount,
|
|
31
|
+
},
|
|
32
|
+
obligations: {
|
|
33
|
+
openCount: agent.obligations.openCount,
|
|
34
|
+
},
|
|
35
|
+
coding: {
|
|
36
|
+
activeCount: agent.coding.activeCount,
|
|
37
|
+
blockedCount: agent.coding.blockedCount,
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function buildTotals(machine) {
|
|
42
|
+
return machine.agents.reduce((totals, agent) => ({
|
|
43
|
+
agents: totals.agents + 1,
|
|
44
|
+
enabledAgents: totals.enabledAgents + (agent.enabled ? 1 : 0),
|
|
45
|
+
degradedAgents: totals.degradedAgents + (agent.degraded.status === "degraded" ? 1 : 0),
|
|
46
|
+
staleAgents: totals.staleAgents + (agent.freshness.status === "stale" ? 1 : 0),
|
|
47
|
+
liveTasks: totals.liveTasks + agent.tasks.liveCount,
|
|
48
|
+
blockedTasks: totals.blockedTasks + agent.tasks.blockedCount,
|
|
49
|
+
openObligations: totals.openObligations + agent.obligations.openCount,
|
|
50
|
+
activeCodingAgents: totals.activeCodingAgents + (agent.coding.activeCount > 0 ? 1 : 0),
|
|
51
|
+
blockedCodingAgents: totals.blockedCodingAgents + (agent.coding.blockedCount > 0 ? 1 : 0),
|
|
52
|
+
}), {
|
|
53
|
+
agents: 0,
|
|
54
|
+
enabledAgents: 0,
|
|
55
|
+
degradedAgents: 0,
|
|
56
|
+
staleAgents: 0,
|
|
57
|
+
liveTasks: 0,
|
|
58
|
+
blockedTasks: 0,
|
|
59
|
+
openObligations: 0,
|
|
60
|
+
activeCodingAgents: 0,
|
|
61
|
+
blockedCodingAgents: 0,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
function deriveMood(machine, daemon) {
|
|
65
|
+
if (machine.degraded.status === "degraded" || daemon.health === "warn") {
|
|
66
|
+
return "strained";
|
|
67
|
+
}
|
|
68
|
+
if (machine.freshness.status === "stale") {
|
|
69
|
+
return "watchful";
|
|
70
|
+
}
|
|
71
|
+
return "calm";
|
|
72
|
+
}
|
|
73
|
+
function buildOutlookMachineView(input) {
|
|
74
|
+
const totals = buildTotals(input.machine);
|
|
75
|
+
const agents = input.machine.agents
|
|
76
|
+
.map((agent) => ({
|
|
77
|
+
...agent,
|
|
78
|
+
attention: deriveAttention(agent),
|
|
79
|
+
}))
|
|
80
|
+
.sort((left, right) => {
|
|
81
|
+
const leftAt = left.freshness.latestActivityAt ?? "";
|
|
82
|
+
const rightAt = right.freshness.latestActivityAt ?? "";
|
|
83
|
+
return rightAt.localeCompare(leftAt);
|
|
84
|
+
});
|
|
85
|
+
return {
|
|
86
|
+
overview: {
|
|
87
|
+
productName: outlook_types_1.OUTLOOK_PRODUCT_NAME,
|
|
88
|
+
observedAt: input.machine.observedAt,
|
|
89
|
+
primaryEntryPoint: input.daemon.outlookUrl,
|
|
90
|
+
daemon: input.daemon,
|
|
91
|
+
runtime: input.machine.runtime,
|
|
92
|
+
freshness: input.machine.freshness,
|
|
93
|
+
degraded: input.machine.degraded,
|
|
94
|
+
totals,
|
|
95
|
+
mood: deriveMood(input.machine, input.daemon),
|
|
96
|
+
entrypoints: [
|
|
97
|
+
{ kind: "web", label: "Open Outlook", target: input.daemon.outlookUrl },
|
|
98
|
+
{ kind: "cli", label: "CLI JSON", target: "ouro outlook --json" },
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
agents,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function normalizeViewer(viewer) {
|
|
105
|
+
return {
|
|
106
|
+
kind: viewer?.kind ?? "human",
|
|
107
|
+
agentName: viewer?.agentName,
|
|
108
|
+
innerDetail: viewer?.innerDetail ?? "summary",
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
function buildInnerView(inner, viewer) {
|
|
112
|
+
if (viewer.innerDetail === "deep") {
|
|
113
|
+
return {
|
|
114
|
+
mode: "deep",
|
|
115
|
+
status: inner.status,
|
|
116
|
+
summary: inner.surfacedSummary,
|
|
117
|
+
hasPending: inner.hasPending,
|
|
118
|
+
origin: inner.origin,
|
|
119
|
+
obligationStatus: inner.obligationStatus,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
mode: "summary",
|
|
124
|
+
status: inner.status,
|
|
125
|
+
summary: inner.surfacedSummary,
|
|
126
|
+
hasPending: inner.hasPending,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function buildRecentActivity(agent) {
|
|
130
|
+
const items = [
|
|
131
|
+
...agent.coding.items.map((item) => ({
|
|
132
|
+
kind: "coding",
|
|
133
|
+
at: item.lastActivityAt,
|
|
134
|
+
label: item.checkpoint ?? `${item.runner} ${item.status}`,
|
|
135
|
+
detail: item.workdir,
|
|
136
|
+
})),
|
|
137
|
+
...agent.sessions.items.map((item) => ({
|
|
138
|
+
kind: "session",
|
|
139
|
+
at: item.lastActivityAt,
|
|
140
|
+
label: `${item.friendName} via ${item.channel}`,
|
|
141
|
+
detail: item.key,
|
|
142
|
+
})),
|
|
143
|
+
...agent.obligations.items.map((item) => ({
|
|
144
|
+
kind: "obligation",
|
|
145
|
+
at: item.updatedAt,
|
|
146
|
+
label: item.content,
|
|
147
|
+
detail: item.nextAction ?? item.status,
|
|
148
|
+
})),
|
|
149
|
+
];
|
|
150
|
+
if (agent.inner.latestActivityAt) {
|
|
151
|
+
items.push({
|
|
152
|
+
kind: "inner",
|
|
153
|
+
at: agent.inner.latestActivityAt,
|
|
154
|
+
label: agent.inner.surfacedSummary ?? agent.inner.status,
|
|
155
|
+
detail: agent.inner.hasPending ? "pending inner work" : agent.inner.obligationStatus ?? "no linked obligation",
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
return items
|
|
159
|
+
.filter((item) => Number.isFinite(Date.parse(item.at)))
|
|
160
|
+
.sort((left, right) => right.at.localeCompare(left.at))
|
|
161
|
+
.slice(0, 4);
|
|
162
|
+
}
|
|
163
|
+
function buildOutlookAgentView(input) {
|
|
164
|
+
/* v8 ignore next */
|
|
165
|
+
(0, runtime_1.emitNervesEvent)({ component: "daemon", event: "daemon.outlook_view_agent", message: `building outlook view for ${input.agent.agentName}`, meta: { agent: input.agent.agentName } });
|
|
166
|
+
const viewer = normalizeViewer(input.viewer);
|
|
167
|
+
return {
|
|
168
|
+
productName: outlook_types_1.OUTLOOK_PRODUCT_NAME,
|
|
169
|
+
interactionModel: outlook_types_1.OUTLOOK_RELEASE_INTERACTION_MODEL,
|
|
170
|
+
viewer,
|
|
171
|
+
agent: {
|
|
172
|
+
agentName: input.agent.agentName,
|
|
173
|
+
agentRoot: input.agent.agentRoot,
|
|
174
|
+
enabled: input.agent.enabled,
|
|
175
|
+
provider: input.agent.provider,
|
|
176
|
+
senses: input.agent.senses,
|
|
177
|
+
freshness: input.agent.freshness,
|
|
178
|
+
degraded: input.agent.degraded,
|
|
179
|
+
attention: deriveAgentAttention(input.agent),
|
|
180
|
+
},
|
|
181
|
+
work: {
|
|
182
|
+
tasks: input.agent.tasks,
|
|
183
|
+
obligations: input.agent.obligations,
|
|
184
|
+
sessions: input.agent.sessions,
|
|
185
|
+
coding: input.agent.coding,
|
|
186
|
+
bridges: input.agent.tasks.activeBridges,
|
|
187
|
+
},
|
|
188
|
+
inner: buildInnerView(input.agent.inner, viewer),
|
|
189
|
+
activity: {
|
|
190
|
+
freshness: input.agent.freshness,
|
|
191
|
+
recent: buildRecentActivity(input.agent),
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
}
|
|
@@ -51,15 +51,23 @@ class DaemonProcessManager {
|
|
|
51
51
|
now;
|
|
52
52
|
setTimeoutFn;
|
|
53
53
|
clearTimeoutFn;
|
|
54
|
+
cooldownRecoveryMs;
|
|
55
|
+
maxCooldownRetries;
|
|
56
|
+
existsSyncFn;
|
|
57
|
+
configCheckFn;
|
|
54
58
|
constructor(options) {
|
|
55
59
|
this.maxRestartsPerHour = options.maxRestartsPerHour ?? 10;
|
|
56
60
|
this.stabilityThresholdMs = options.stabilityThresholdMs ?? 60_000;
|
|
57
61
|
this.initialBackoffMs = options.initialBackoffMs ?? 1_000;
|
|
58
62
|
this.maxBackoffMs = options.maxBackoffMs ?? 60_000;
|
|
63
|
+
this.cooldownRecoveryMs = options.cooldownRecoveryMs ?? 5 * 60 * 1_000;
|
|
64
|
+
this.maxCooldownRetries = options.maxCooldownRetries ?? 3;
|
|
59
65
|
this.spawnFn = options.spawn ?? ((command, args, spawnOptions) => (0, child_process_1.spawn)(command, args, spawnOptions));
|
|
60
66
|
this.now = options.now ?? (() => Date.now());
|
|
61
67
|
this.setTimeoutFn = options.setTimeoutFn ?? ((cb, delay) => setTimeout(cb, delay));
|
|
62
68
|
this.clearTimeoutFn = options.clearTimeoutFn ?? ((timer) => clearTimeout(timer));
|
|
69
|
+
this.existsSyncFn = options.existsSync ?? null;
|
|
70
|
+
this.configCheckFn = options.configCheck ?? null;
|
|
63
71
|
for (const agent of options.agents) {
|
|
64
72
|
this.agents.set(agent.name, {
|
|
65
73
|
config: agent,
|
|
@@ -67,6 +75,8 @@ class DaemonProcessManager {
|
|
|
67
75
|
restartTimer: null,
|
|
68
76
|
crashTimestamps: [],
|
|
69
77
|
stopRequested: false,
|
|
78
|
+
cooldownTimer: null,
|
|
79
|
+
cooldownRetryCount: 0,
|
|
70
80
|
snapshot: {
|
|
71
81
|
name: agent.name,
|
|
72
82
|
channel: agent.channel,
|
|
@@ -76,6 +86,8 @@ class DaemonProcessManager {
|
|
|
76
86
|
startedAt: null,
|
|
77
87
|
lastCrashAt: null,
|
|
78
88
|
backoffMs: this.initialBackoffMs,
|
|
89
|
+
lastExitCode: null,
|
|
90
|
+
lastSignal: null,
|
|
79
91
|
},
|
|
80
92
|
});
|
|
81
93
|
}
|
|
@@ -94,8 +106,35 @@ class DaemonProcessManager {
|
|
|
94
106
|
this.clearRestartTimer(state);
|
|
95
107
|
state.stopRequested = false;
|
|
96
108
|
state.snapshot.status = "starting";
|
|
109
|
+
if (this.configCheckFn) {
|
|
110
|
+
const result = this.configCheckFn(agent);
|
|
111
|
+
if (!result.ok) {
|
|
112
|
+
state.snapshot.status = "crashed";
|
|
113
|
+
(0, runtime_1.emitNervesEvent)({
|
|
114
|
+
level: "error",
|
|
115
|
+
component: "daemon",
|
|
116
|
+
event: "daemon.agent_config_invalid",
|
|
117
|
+
message: result.error ?? "agent config validation failed",
|
|
118
|
+
meta: { agent, fix: result.fix ?? null },
|
|
119
|
+
});
|
|
120
|
+
process.stderr.write(`[daemon] ${agent}: ${result.error}\n` +
|
|
121
|
+
(result.fix ? ` Fix: ${result.fix}\n` : ""));
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
97
125
|
const runCwd = (0, identity_1.getRepoRoot)();
|
|
98
126
|
const entryScript = path.join((0, identity_1.getRepoRoot)(), "dist", state.config.entry);
|
|
127
|
+
if (this.existsSyncFn && !this.existsSyncFn(entryScript)) {
|
|
128
|
+
state.snapshot.status = "crashed";
|
|
129
|
+
(0, runtime_1.emitNervesEvent)({
|
|
130
|
+
level: "error",
|
|
131
|
+
component: "daemon",
|
|
132
|
+
event: "daemon.agent_entry_missing",
|
|
133
|
+
message: "agent entry script does not exist — cannot spawn. Run 'ouro daemon install' from the correct location.",
|
|
134
|
+
meta: { agent, entryScript },
|
|
135
|
+
});
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
99
138
|
const args = [entryScript, "--agent", state.config.agentArg ?? agent, ...(state.config.args ?? [])];
|
|
100
139
|
const child = this.spawnFn("node", args, {
|
|
101
140
|
cwd: runCwd,
|
|
@@ -112,6 +151,17 @@ class DaemonProcessManager {
|
|
|
112
151
|
message: "daemon started managed agent process",
|
|
113
152
|
meta: { agent, pid: child.pid ?? null, cwd: runCwd },
|
|
114
153
|
});
|
|
154
|
+
/* v8 ignore start — child process error handler; requires real spawn to trigger */
|
|
155
|
+
child.on("error", (err) => {
|
|
156
|
+
(0, runtime_1.emitNervesEvent)({
|
|
157
|
+
level: "warn",
|
|
158
|
+
component: "daemon",
|
|
159
|
+
event: "daemon.agent_process_error",
|
|
160
|
+
message: "managed agent process emitted error",
|
|
161
|
+
meta: { agent, error: err.message },
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
/* v8 ignore stop */
|
|
115
165
|
child.once("exit", (code, signal) => {
|
|
116
166
|
this.onExit(state, code, signal);
|
|
117
167
|
});
|
|
@@ -119,6 +169,7 @@ class DaemonProcessManager {
|
|
|
119
169
|
async stopAgent(agent) {
|
|
120
170
|
const state = this.requireAgent(agent);
|
|
121
171
|
this.clearRestartTimer(state);
|
|
172
|
+
this.clearCooldownTimer(state);
|
|
122
173
|
state.stopRequested = true;
|
|
123
174
|
if (!state.process) {
|
|
124
175
|
state.snapshot.status = "stopped";
|
|
@@ -179,6 +230,8 @@ class DaemonProcessManager {
|
|
|
179
230
|
return;
|
|
180
231
|
state.process = null;
|
|
181
232
|
state.snapshot.pid = null;
|
|
233
|
+
state.snapshot.lastExitCode = code;
|
|
234
|
+
state.snapshot.lastSignal = signal;
|
|
182
235
|
const crashed = !state.stopRequested && code !== 0;
|
|
183
236
|
const now = this.now();
|
|
184
237
|
const startedAt = state.snapshot.startedAt ? Date.parse(state.snapshot.startedAt) : now;
|
|
@@ -209,6 +262,7 @@ class DaemonProcessManager {
|
|
|
209
262
|
message: "managed agent exceeded restart limit and is marked crashed",
|
|
210
263
|
meta: { agent: state.config.name, maxRestartsPerHour: this.maxRestartsPerHour },
|
|
211
264
|
});
|
|
265
|
+
this.scheduleCooldownRecovery(state);
|
|
212
266
|
return;
|
|
213
267
|
}
|
|
214
268
|
state.snapshot.status = "starting";
|
|
@@ -226,6 +280,45 @@ class DaemonProcessManager {
|
|
|
226
280
|
this.clearTimeoutFn(state.restartTimer);
|
|
227
281
|
state.restartTimer = null;
|
|
228
282
|
}
|
|
283
|
+
scheduleCooldownRecovery(state) {
|
|
284
|
+
if (state.cooldownRetryCount >= this.maxCooldownRetries) {
|
|
285
|
+
(0, runtime_1.emitNervesEvent)({
|
|
286
|
+
level: "error",
|
|
287
|
+
component: "daemon",
|
|
288
|
+
event: "daemon.agent_permanent_failure",
|
|
289
|
+
message: "managed agent exhausted all cooldown retries — permanently stopped",
|
|
290
|
+
meta: { agent: state.config.name, cooldownRetryCount: state.cooldownRetryCount, maxCooldownRetries: this.maxCooldownRetries },
|
|
291
|
+
});
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
this.clearCooldownTimer(state);
|
|
295
|
+
state.cooldownTimer = this.setTimeoutFn(() => {
|
|
296
|
+
state.cooldownRetryCount += 1;
|
|
297
|
+
state.crashTimestamps = [];
|
|
298
|
+
state.snapshot.backoffMs = this.initialBackoffMs;
|
|
299
|
+
state.snapshot.status = "starting";
|
|
300
|
+
state.snapshot.restartCount += 1;
|
|
301
|
+
(0, runtime_1.emitNervesEvent)({
|
|
302
|
+
component: "daemon",
|
|
303
|
+
event: "daemon.agent_cooldown_recovery",
|
|
304
|
+
message: "attempting cooldown recovery for managed agent",
|
|
305
|
+
meta: { agent: state.config.name, cooldownRetryCount: state.cooldownRetryCount },
|
|
306
|
+
});
|
|
307
|
+
void this.startAgent(state.config.name);
|
|
308
|
+
}, this.cooldownRecoveryMs);
|
|
309
|
+
(0, runtime_1.emitNervesEvent)({
|
|
310
|
+
component: "daemon",
|
|
311
|
+
event: "daemon.agent_cooldown_scheduled",
|
|
312
|
+
message: `scheduled cooldown recovery in ${this.cooldownRecoveryMs}ms`,
|
|
313
|
+
meta: { agent: state.config.name, cooldownRecoveryMs: this.cooldownRecoveryMs, cooldownRetryCount: state.cooldownRetryCount },
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
clearCooldownTimer(state) {
|
|
317
|
+
if (state.cooldownTimer === null)
|
|
318
|
+
return;
|
|
319
|
+
this.clearTimeoutFn(state.cooldownTimer);
|
|
320
|
+
state.cooldownTimer = null;
|
|
321
|
+
}
|
|
229
322
|
requireAgent(agent) {
|
|
230
323
|
const state = this.agents.get(agent);
|
|
231
324
|
if (!state) {
|
|
@@ -0,0 +1,39 @@
|
|
|
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
|
+
const agent_config_v2_1 = require("./hooks/agent-config-v2");
|
|
7
|
+
async function runHooks(deps) {
|
|
8
|
+
(0, runtime_1.emitNervesEvent)({
|
|
9
|
+
component: "daemon",
|
|
10
|
+
event: "daemon.run_hooks_start",
|
|
11
|
+
message: "running update hooks",
|
|
12
|
+
meta: { bundlesRoot: deps.bundlesRoot },
|
|
13
|
+
});
|
|
14
|
+
try {
|
|
15
|
+
deps.registerUpdateHook(bundle_meta_1.bundleMetaHook);
|
|
16
|
+
deps.registerUpdateHook(agent_config_v2_1.agentConfigV2Hook);
|
|
17
|
+
const currentVersion = deps.getPackageVersion();
|
|
18
|
+
await deps.applyPendingUpdates(deps.bundlesRoot, currentVersion);
|
|
19
|
+
(0, runtime_1.emitNervesEvent)({
|
|
20
|
+
component: "daemon",
|
|
21
|
+
event: "daemon.run_hooks_success",
|
|
22
|
+
message: "update hooks completed successfully",
|
|
23
|
+
meta: { bundlesRoot: deps.bundlesRoot },
|
|
24
|
+
});
|
|
25
|
+
return 0;
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
(0, runtime_1.emitNervesEvent)({
|
|
29
|
+
component: "daemon",
|
|
30
|
+
event: "daemon.run_hooks_error",
|
|
31
|
+
message: "update hooks failed",
|
|
32
|
+
meta: {
|
|
33
|
+
bundlesRoot: deps.bundlesRoot,
|
|
34
|
+
error: err instanceof Error ? err.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(err),
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
return 1;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -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)({
|
|
@@ -34,7 +34,9 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.getRuntimeMetadata = getRuntimeMetadata;
|
|
37
|
+
const crypto_1 = require("crypto");
|
|
37
38
|
const fs = __importStar(require("fs"));
|
|
39
|
+
const os = __importStar(require("os"));
|
|
38
40
|
const path = __importStar(require("path"));
|
|
39
41
|
const childProcess = __importStar(require("child_process"));
|
|
40
42
|
const identity_1 = require("../identity");
|
|
@@ -85,10 +87,98 @@ function readLastUpdated(repoRoot, packageJsonPath, statSyncImpl, execFileSyncIm
|
|
|
85
87
|
return { value: UNKNOWN_METADATA, source: "unknown" };
|
|
86
88
|
}
|
|
87
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
|
+
}
|
|
88
172
|
function getRuntimeMetadata(deps = {}) {
|
|
89
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)();
|
|
90
178
|
const readFileSyncImpl = deps.readFileSync ?? optionalFunction(fs, "readFileSync")?.bind(fs) ?? null;
|
|
91
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;
|
|
92
182
|
const execFileSyncImpl = deps.execFileSync
|
|
93
183
|
?? optionalFunction(childProcess, "execFileSync")?.bind(childProcess)
|
|
94
184
|
?? null;
|
|
@@ -101,6 +191,8 @@ function getRuntimeMetadata(deps = {}) {
|
|
|
101
191
|
throw new Error("git unavailable");
|
|
102
192
|
}))
|
|
103
193
|
: { value: UNKNOWN_METADATA, source: "unknown" };
|
|
194
|
+
const configTargets = listConfigTargets(bundlesRoot, secretsRoot, daemonLoggingPath, readdirSyncImpl);
|
|
195
|
+
const configFingerprint = readConfigFingerprint(configTargets, readFileSyncImpl, existsSyncImpl);
|
|
104
196
|
(0, runtime_1.emitNervesEvent)({
|
|
105
197
|
component: "daemon",
|
|
106
198
|
event: "daemon.runtime_metadata_read",
|
|
@@ -109,10 +201,19 @@ function getRuntimeMetadata(deps = {}) {
|
|
|
109
201
|
version,
|
|
110
202
|
lastUpdated: lastUpdated.value,
|
|
111
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,
|
|
112
211
|
},
|
|
113
212
|
});
|
|
114
213
|
return {
|
|
115
214
|
version,
|
|
116
215
|
lastUpdated: lastUpdated.value,
|
|
216
|
+
repoRoot,
|
|
217
|
+
configFingerprint: configFingerprint.value,
|
|
117
218
|
};
|
|
118
219
|
}
|