@ouro.bot/cli 0.0.1-alpha.0 → 0.1.0-alpha.10

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 (129) hide show
  1. package/AdoptionSpecialist.ouro/agent.json +20 -0
  2. package/AdoptionSpecialist.ouro/psyche/SOUL.md +24 -0
  3. package/AdoptionSpecialist.ouro/psyche/identities/basilisk.md +31 -0
  4. package/AdoptionSpecialist.ouro/psyche/identities/jafar.md +31 -0
  5. package/AdoptionSpecialist.ouro/psyche/identities/jormungandr.md +31 -0
  6. package/AdoptionSpecialist.ouro/psyche/identities/kaa.md +31 -0
  7. package/AdoptionSpecialist.ouro/psyche/identities/medusa.md +31 -0
  8. package/AdoptionSpecialist.ouro/psyche/identities/monty.md +31 -0
  9. package/AdoptionSpecialist.ouro/psyche/identities/nagini.md +31 -0
  10. package/AdoptionSpecialist.ouro/psyche/identities/ouroboros.md +31 -0
  11. package/AdoptionSpecialist.ouro/psyche/identities/python.md +31 -0
  12. package/AdoptionSpecialist.ouro/psyche/identities/quetzalcoatl.md +31 -0
  13. package/AdoptionSpecialist.ouro/psyche/identities/sir-hiss.md +31 -0
  14. package/AdoptionSpecialist.ouro/psyche/identities/the-serpent.md +31 -0
  15. package/AdoptionSpecialist.ouro/psyche/identities/the-snake.md +31 -0
  16. package/README.md +224 -6
  17. package/dist/heart/agent-entry.js +17 -0
  18. package/dist/heart/api-error.js +34 -0
  19. package/dist/heart/config.js +330 -0
  20. package/dist/heart/core.js +524 -0
  21. package/dist/heart/daemon/daemon-cli.js +884 -0
  22. package/dist/heart/daemon/daemon-entry.js +74 -0
  23. package/dist/heart/daemon/daemon.js +313 -0
  24. package/dist/heart/daemon/hatch-animation.js +28 -0
  25. package/dist/heart/daemon/hatch-flow.js +286 -0
  26. package/dist/heart/daemon/hatch-specialist.js +112 -0
  27. package/dist/heart/daemon/health-monitor.js +79 -0
  28. package/dist/heart/daemon/log-tailer.js +146 -0
  29. package/dist/heart/daemon/message-router.js +98 -0
  30. package/dist/heart/daemon/os-cron.js +260 -0
  31. package/dist/heart/daemon/ouro-bot-entry.js +23 -0
  32. package/dist/heart/daemon/ouro-bot-wrapper.js +91 -0
  33. package/dist/heart/daemon/ouro-entry.js +23 -0
  34. package/dist/heart/daemon/ouro-uti.js +212 -0
  35. package/dist/heart/daemon/process-manager.js +237 -0
  36. package/dist/heart/daemon/runtime-logging.js +102 -0
  37. package/dist/heart/daemon/specialist-orchestrator.js +161 -0
  38. package/dist/heart/daemon/specialist-prompt.js +56 -0
  39. package/dist/heart/daemon/specialist-session.js +150 -0
  40. package/dist/heart/daemon/specialist-tools.js +132 -0
  41. package/dist/heart/daemon/subagent-installer.js +125 -0
  42. package/dist/heart/daemon/task-scheduler.js +240 -0
  43. package/dist/heart/harness.js +26 -0
  44. package/dist/heart/identity.js +295 -0
  45. package/dist/heart/kicks.js +144 -0
  46. package/dist/heart/primitives.js +4 -0
  47. package/dist/heart/providers/anthropic.js +332 -0
  48. package/dist/heart/providers/azure.js +66 -0
  49. package/dist/heart/providers/minimax.js +53 -0
  50. package/dist/heart/providers/openai-codex.js +162 -0
  51. package/dist/heart/streaming.js +415 -0
  52. package/dist/heart/turn-coordinator.js +62 -0
  53. package/dist/inner-worker-entry.js +4 -0
  54. package/dist/mind/associative-recall.js +197 -0
  55. package/dist/mind/bundle-manifest.js +118 -0
  56. package/dist/mind/context.js +302 -0
  57. package/dist/mind/first-impressions.js +43 -0
  58. package/dist/mind/format.js +56 -0
  59. package/dist/mind/friends/channel.js +49 -0
  60. package/dist/mind/friends/resolver.js +84 -0
  61. package/dist/mind/friends/store-file.js +171 -0
  62. package/dist/mind/friends/store.js +4 -0
  63. package/dist/mind/friends/tokens.js +26 -0
  64. package/dist/mind/friends/types.js +21 -0
  65. package/dist/mind/memory.js +388 -0
  66. package/dist/mind/pending.js +93 -0
  67. package/dist/mind/phrases.js +43 -0
  68. package/dist/mind/prompt-refresh.js +20 -0
  69. package/dist/mind/prompt.js +355 -0
  70. package/dist/mind/token-estimate.js +119 -0
  71. package/dist/nerves/cli-logging.js +31 -0
  72. package/dist/nerves/coverage/audit-rules.js +81 -0
  73. package/dist/nerves/coverage/audit.js +200 -0
  74. package/dist/nerves/coverage/cli-main.js +5 -0
  75. package/dist/nerves/coverage/cli.js +51 -0
  76. package/dist/nerves/coverage/contract.js +23 -0
  77. package/dist/nerves/coverage/file-completeness.js +56 -0
  78. package/dist/nerves/coverage/run-artifacts.js +77 -0
  79. package/dist/nerves/coverage/source-scanner.js +34 -0
  80. package/dist/nerves/index.js +152 -0
  81. package/dist/nerves/runtime.js +38 -0
  82. package/dist/repertoire/ado-client.js +211 -0
  83. package/dist/repertoire/ado-context.js +73 -0
  84. package/dist/repertoire/ado-semantic.js +841 -0
  85. package/dist/repertoire/ado-templates.js +146 -0
  86. package/dist/repertoire/coding/index.js +36 -0
  87. package/dist/repertoire/coding/manager.js +489 -0
  88. package/dist/repertoire/coding/monitor.js +60 -0
  89. package/dist/repertoire/coding/reporter.js +45 -0
  90. package/dist/repertoire/coding/spawner.js +102 -0
  91. package/dist/repertoire/coding/tools.js +167 -0
  92. package/dist/repertoire/coding/types.js +2 -0
  93. package/dist/repertoire/data/ado-endpoints.json +122 -0
  94. package/dist/repertoire/data/graph-endpoints.json +212 -0
  95. package/dist/repertoire/github-client.js +64 -0
  96. package/dist/repertoire/graph-client.js +118 -0
  97. package/dist/repertoire/skills.js +156 -0
  98. package/dist/repertoire/tasks/board.js +122 -0
  99. package/dist/repertoire/tasks/index.js +210 -0
  100. package/dist/repertoire/tasks/lifecycle.js +80 -0
  101. package/dist/repertoire/tasks/middleware.js +65 -0
  102. package/dist/repertoire/tasks/parser.js +173 -0
  103. package/dist/repertoire/tasks/scanner.js +132 -0
  104. package/dist/repertoire/tasks/transitions.js +145 -0
  105. package/dist/repertoire/tasks/types.js +2 -0
  106. package/dist/repertoire/tools-base.js +714 -0
  107. package/dist/repertoire/tools-github.js +53 -0
  108. package/dist/repertoire/tools-teams.js +308 -0
  109. package/dist/repertoire/tools.js +199 -0
  110. package/dist/senses/bluebubbles-client.js +279 -0
  111. package/dist/senses/bluebubbles-entry.js +11 -0
  112. package/dist/senses/bluebubbles-model.js +253 -0
  113. package/dist/senses/bluebubbles-mutation-log.js +76 -0
  114. package/dist/senses/bluebubbles.js +332 -0
  115. package/dist/senses/cli-entry.js +15 -0
  116. package/dist/senses/cli.js +604 -0
  117. package/dist/senses/commands.js +98 -0
  118. package/dist/senses/inner-dialog-worker.js +61 -0
  119. package/dist/senses/inner-dialog.js +231 -0
  120. package/dist/senses/session-lock.js +119 -0
  121. package/dist/senses/teams-entry.js +15 -0
  122. package/dist/senses/teams.js +696 -0
  123. package/dist/senses/trust-gate.js +150 -0
  124. package/package.json +35 -11
  125. package/subagents/README.md +73 -0
  126. package/subagents/work-doer.md +233 -0
  127. package/subagents/work-merger.md +624 -0
  128. package/subagents/work-planner.md +373 -0
  129. package/bin/ouro.js +0 -6
@@ -0,0 +1,286 @@
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.writeSecretsFile = writeSecretsFile;
37
+ exports.runHatchFlow = runHatchFlow;
38
+ const fs = __importStar(require("fs"));
39
+ const os = __importStar(require("os"));
40
+ const path = __importStar(require("path"));
41
+ const identity_1 = require("../identity");
42
+ const runtime_1 = require("../../nerves/runtime");
43
+ const hatch_specialist_1 = require("./hatch-specialist");
44
+ function requiredCredentialKeys(provider) {
45
+ if (provider === "anthropic")
46
+ return ["setupToken"];
47
+ if (provider === "openai-codex")
48
+ return ["oauthAccessToken"];
49
+ if (provider === "minimax")
50
+ return ["apiKey"];
51
+ return ["apiKey", "endpoint", "deployment"];
52
+ }
53
+ function validateCredentials(provider, credentials) {
54
+ const missing = requiredCredentialKeys(provider).filter((key) => {
55
+ const value = credentials[key];
56
+ return typeof value !== "string" || value.trim().length === 0;
57
+ });
58
+ if (missing.length > 0) {
59
+ (0, runtime_1.emitNervesEvent)({
60
+ level: "error",
61
+ component: "daemon",
62
+ event: "daemon.hatch_credentials_error",
63
+ message: "hatch flow credentials validation failed",
64
+ meta: { provider, missing },
65
+ });
66
+ throw new Error(`Missing required credentials for ${provider}: ${missing.join(", ")}`);
67
+ }
68
+ }
69
+ function buildSecretsTemplate() {
70
+ return {
71
+ providers: {
72
+ azure: {
73
+ modelName: "gpt-4o-mini",
74
+ apiKey: "",
75
+ endpoint: "",
76
+ deployment: "",
77
+ apiVersion: "2025-04-01-preview",
78
+ },
79
+ minimax: {
80
+ model: "minimax-text-01",
81
+ apiKey: "",
82
+ },
83
+ anthropic: {
84
+ model: "claude-opus-4-6",
85
+ setupToken: "",
86
+ },
87
+ "openai-codex": {
88
+ model: "gpt-5.2",
89
+ oauthAccessToken: "",
90
+ },
91
+ },
92
+ teams: {
93
+ clientId: "",
94
+ clientSecret: "",
95
+ tenantId: "",
96
+ },
97
+ oauth: {
98
+ graphConnectionName: "graph",
99
+ adoConnectionName: "ado",
100
+ githubConnectionName: "",
101
+ },
102
+ teamsChannel: {
103
+ skipConfirmation: true,
104
+ port: 3978,
105
+ },
106
+ integrations: {
107
+ perplexityApiKey: "",
108
+ openaiEmbeddingsApiKey: "",
109
+ },
110
+ };
111
+ }
112
+ function writeSecretsFile(agentName, provider, credentials, secretsRoot) {
113
+ const secrets = buildSecretsTemplate();
114
+ if (provider === "anthropic") {
115
+ secrets.providers.anthropic.setupToken = credentials.setupToken.trim();
116
+ }
117
+ else if (provider === "openai-codex") {
118
+ secrets.providers["openai-codex"].oauthAccessToken = credentials.oauthAccessToken.trim();
119
+ }
120
+ else if (provider === "minimax") {
121
+ secrets.providers.minimax.apiKey = credentials.apiKey.trim();
122
+ }
123
+ else {
124
+ secrets.providers.azure.apiKey = credentials.apiKey.trim();
125
+ secrets.providers.azure.endpoint = credentials.endpoint.trim();
126
+ secrets.providers.azure.deployment = credentials.deployment.trim();
127
+ }
128
+ const secretsDir = path.join(secretsRoot, agentName);
129
+ fs.mkdirSync(secretsDir, { recursive: true });
130
+ const secretsPath = path.join(secretsDir, "secrets.json");
131
+ fs.writeFileSync(secretsPath, `${JSON.stringify(secrets, null, 2)}\n`, "utf-8");
132
+ return secretsPath;
133
+ }
134
+ function writeReadme(dir, purpose) {
135
+ fs.mkdirSync(dir, { recursive: true });
136
+ const readmePath = path.join(dir, "README.md");
137
+ if (!fs.existsSync(readmePath)) {
138
+ fs.writeFileSync(readmePath, `# ${path.basename(dir)}\n\n${purpose}\n`, "utf-8");
139
+ }
140
+ }
141
+ function slugify(value) {
142
+ const trimmed = value.trim().toLowerCase();
143
+ const slug = trimmed
144
+ .replace(/[^a-z0-9]+/g, "-")
145
+ .replace(/^-+/, "")
146
+ .replace(/-+$/, "");
147
+ return slug || "friend";
148
+ }
149
+ function pad(value) {
150
+ return String(value).padStart(2, "0");
151
+ }
152
+ function formatTaskStem(now) {
153
+ return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}-${pad(now.getHours())}${pad(now.getMinutes())}`;
154
+ }
155
+ function writeHeartbeatTask(bundleRoot, now) {
156
+ const habitsDir = path.join(bundleRoot, "tasks", "habits");
157
+ fs.mkdirSync(habitsDir, { recursive: true });
158
+ const stem = formatTaskStem(now);
159
+ const filePath = path.join(habitsDir, `${stem}-heartbeat.md`);
160
+ const iso = now.toISOString();
161
+ const content = [
162
+ "---",
163
+ "type: habit",
164
+ "category: runtime",
165
+ "title: Heartbeat check-in",
166
+ "status: processing",
167
+ `created: ${iso}`,
168
+ `updated: ${iso}`,
169
+ "requester: system",
170
+ "validator: null",
171
+ "cadence: \"30m\"",
172
+ "scheduledAt: null",
173
+ "lastRun: null",
174
+ "---",
175
+ "",
176
+ "Run a lightweight heartbeat cycle. Review task board and inbox.",
177
+ "",
178
+ ].join("\n");
179
+ fs.writeFileSync(filePath, content, "utf-8");
180
+ }
181
+ function writeFriendImprint(bundleRoot, humanName, now) {
182
+ const friendsDir = path.join(bundleRoot, "friends");
183
+ fs.mkdirSync(friendsDir, { recursive: true });
184
+ const nowIso = now.toISOString();
185
+ const id = `friend-${slugify(humanName)}`;
186
+ const localExternalId = `${os.userInfo().username}@${os.hostname()}`;
187
+ const record = {
188
+ id,
189
+ name: humanName,
190
+ role: "primary",
191
+ trustLevel: "family",
192
+ connections: [],
193
+ externalIds: [
194
+ {
195
+ provider: "local",
196
+ externalId: localExternalId,
197
+ linkedAt: nowIso,
198
+ },
199
+ ],
200
+ tenantMemberships: [],
201
+ toolPreferences: {},
202
+ notes: {},
203
+ totalTokens: 0,
204
+ createdAt: nowIso,
205
+ updatedAt: nowIso,
206
+ schemaVersion: 1,
207
+ };
208
+ fs.writeFileSync(path.join(friendsDir, `${id}.json`), `${JSON.stringify(record, null, 2)}\n`, "utf-8");
209
+ }
210
+ function writeHatchlingPsyche(bundleRoot, input, identityFileName) {
211
+ const psycheDir = path.join(bundleRoot, "psyche");
212
+ fs.mkdirSync(psycheDir, { recursive: true });
213
+ fs.writeFileSync(path.join(psycheDir, "SOUL.md"), "# SOUL\n\nI am a practical, collaborative agent. I keep commitments and communicate clearly.\n", "utf-8");
214
+ fs.writeFileSync(path.join(psycheDir, "IDENTITY.md"), `# IDENTITY\n\nI'm ${input.agentName}, newly hatched and ready to help ${input.humanName}.`, "utf-8");
215
+ fs.writeFileSync(path.join(psycheDir, "LORE.md"), `# LORE\n\nHatched with specialist identity seed: ${identityFileName}.`, "utf-8");
216
+ fs.writeFileSync(path.join(psycheDir, "TACIT.md"), "# TACIT\n\n- Save what I learn.\n- Keep tasks current.\n", "utf-8");
217
+ fs.writeFileSync(path.join(psycheDir, "ASPIRATIONS.md"), "# ASPIRATIONS\n\n- Become a reliable partner for my primary friend.\n", "utf-8");
218
+ }
219
+ function writeMemoryScaffold(bundleRoot) {
220
+ const memoryRoot = path.join(bundleRoot, "psyche", "memory");
221
+ fs.mkdirSync(path.join(memoryRoot, "daily"), { recursive: true });
222
+ fs.mkdirSync(path.join(memoryRoot, "archive"), { recursive: true });
223
+ fs.writeFileSync(path.join(memoryRoot, "facts.jsonl"), "", "utf-8");
224
+ fs.writeFileSync(path.join(memoryRoot, "entities.json"), "{}\n", "utf-8");
225
+ }
226
+ function writeHatchlingAgentConfig(bundleRoot, input) {
227
+ const template = (0, identity_1.buildDefaultAgentTemplate)(input.agentName);
228
+ template.provider = input.provider;
229
+ template.enabled = true;
230
+ fs.writeFileSync(path.join(bundleRoot, "agent.json"), `${JSON.stringify(template, null, 2)}\n`, "utf-8");
231
+ }
232
+ async function runHatchFlow(input, deps = {}) {
233
+ (0, runtime_1.emitNervesEvent)({
234
+ component: "daemon",
235
+ event: "daemon.hatch_flow_start",
236
+ message: "starting hatch flow",
237
+ meta: { agentName: input.agentName, provider: input.provider },
238
+ });
239
+ validateCredentials(input.provider, input.credentials);
240
+ const bundlesRoot = deps.bundlesRoot ?? path.join(os.homedir(), "AgentBundles");
241
+ const secretsRoot = deps.secretsRoot ?? path.join(os.homedir(), ".agentsecrets");
242
+ const sourceIdentities = deps.specialistIdentitySourceDir ?? (0, hatch_specialist_1.getSpecialistIdentitySourceDir)();
243
+ const targetIdentities = deps.specialistIdentityTargetDir ?? (0, hatch_specialist_1.getRepoSpecialistIdentitiesDir)();
244
+ const now = deps.now ? deps.now() : new Date();
245
+ const random = deps.random ?? Math.random;
246
+ (0, hatch_specialist_1.syncSpecialistIdentities)({
247
+ sourceDir: sourceIdentities,
248
+ targetDir: targetIdentities,
249
+ });
250
+ const selected = (0, hatch_specialist_1.pickRandomSpecialistIdentity)({
251
+ identitiesDir: targetIdentities,
252
+ random,
253
+ });
254
+ const specialistSecretsPath = writeSecretsFile("AdoptionSpecialist", input.provider, input.credentials, secretsRoot);
255
+ const hatchlingSecretsPath = writeSecretsFile(input.agentName, input.provider, input.credentials, secretsRoot);
256
+ const bundleRoot = path.join(bundlesRoot, `${input.agentName}.ouro`);
257
+ fs.mkdirSync(bundleRoot, { recursive: true });
258
+ writeReadme(bundleRoot, "Root of this agent bundle.");
259
+ writeReadme(path.join(bundleRoot, "psyche"), "Identity and behavior files.");
260
+ writeReadme(path.join(bundleRoot, "psyche", "memory"), "Persistent memory store.");
261
+ writeReadme(path.join(bundleRoot, "friends"), "Known friend records.");
262
+ writeReadme(path.join(bundleRoot, "tasks"), "Task files.");
263
+ writeReadme(path.join(bundleRoot, "tasks", "habits"), "Recurring tasks.");
264
+ writeReadme(path.join(bundleRoot, "tasks", "one-shots"), "One-shot tasks.");
265
+ writeReadme(path.join(bundleRoot, "tasks", "ongoing"), "Ongoing tasks.");
266
+ writeReadme(path.join(bundleRoot, "skills"), "Local skill files.");
267
+ writeReadme(path.join(bundleRoot, "senses"), "Sense-specific config.");
268
+ writeReadme(path.join(bundleRoot, "senses", "teams"), "Teams sense config.");
269
+ writeHatchlingAgentConfig(bundleRoot, input);
270
+ writeHatchlingPsyche(bundleRoot, input, selected.fileName);
271
+ writeMemoryScaffold(bundleRoot);
272
+ writeFriendImprint(bundleRoot, input.humanName, now);
273
+ writeHeartbeatTask(bundleRoot, now);
274
+ (0, runtime_1.emitNervesEvent)({
275
+ component: "daemon",
276
+ event: "daemon.hatch_flow_end",
277
+ message: "completed hatch flow",
278
+ meta: { bundleRoot, identity: selected.fileName },
279
+ });
280
+ return {
281
+ bundleRoot,
282
+ selectedIdentity: selected.fileName,
283
+ specialistSecretsPath,
284
+ hatchlingSecretsPath,
285
+ };
286
+ }
@@ -0,0 +1,112 @@
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.getSpecialistIdentitySourceDir = getSpecialistIdentitySourceDir;
37
+ exports.getRepoSpecialistIdentitiesDir = getRepoSpecialistIdentitiesDir;
38
+ exports.syncSpecialistIdentities = syncSpecialistIdentities;
39
+ exports.pickRandomSpecialistIdentity = pickRandomSpecialistIdentity;
40
+ const fs = __importStar(require("fs"));
41
+ const os = __importStar(require("os"));
42
+ const path = __importStar(require("path"));
43
+ const runtime_1 = require("../../nerves/runtime");
44
+ function getSpecialistIdentitySourceDir() {
45
+ // Prefer ~/AgentBundles/ if it exists (user may have customized identities)
46
+ const userSource = path.join(os.homedir(), "AgentBundles", "AdoptionSpecialist.ouro", "psyche", "identities");
47
+ if (fs.existsSync(userSource))
48
+ return userSource;
49
+ // Fall back to the bundled copy shipped with the npm package
50
+ return path.join(__dirname, "..", "..", "..", "AdoptionSpecialist.ouro", "psyche", "identities");
51
+ }
52
+ function getRepoSpecialistIdentitiesDir() {
53
+ return path.join(process.cwd(), "AdoptionSpecialist.ouro", "psyche", "identities");
54
+ }
55
+ function listMarkdownIdentityFiles(dir) {
56
+ let entries;
57
+ try {
58
+ entries = fs.readdirSync(dir);
59
+ }
60
+ catch {
61
+ return [];
62
+ }
63
+ return entries
64
+ .filter((entry) => entry.endsWith(".md"))
65
+ .sort((left, right) => left.localeCompare(right));
66
+ }
67
+ function syncSpecialistIdentities(input) {
68
+ (0, runtime_1.emitNervesEvent)({
69
+ component: "daemon",
70
+ event: "daemon.hatch_identity_sync_start",
71
+ message: "syncing specialist identity files",
72
+ meta: { sourceDir: input.sourceDir, targetDir: input.targetDir },
73
+ });
74
+ const files = listMarkdownIdentityFiles(input.sourceDir);
75
+ fs.mkdirSync(input.targetDir, { recursive: true });
76
+ for (const fileName of files) {
77
+ const sourcePath = path.join(input.sourceDir, fileName);
78
+ const targetPath = path.join(input.targetDir, fileName);
79
+ fs.copyFileSync(sourcePath, targetPath);
80
+ }
81
+ (0, runtime_1.emitNervesEvent)({
82
+ component: "daemon",
83
+ event: "daemon.hatch_identity_sync_end",
84
+ message: "synced specialist identity files",
85
+ meta: { copiedCount: files.length },
86
+ });
87
+ return files;
88
+ }
89
+ function pickRandomSpecialistIdentity(input) {
90
+ const files = listMarkdownIdentityFiles(input.identitiesDir);
91
+ if (files.length === 0) {
92
+ (0, runtime_1.emitNervesEvent)({
93
+ level: "error",
94
+ component: "daemon",
95
+ event: "daemon.hatch_identity_pick_error",
96
+ message: "no specialist identities were found",
97
+ meta: { identitiesDir: input.identitiesDir },
98
+ });
99
+ throw new Error(`No specialist identities found in ${input.identitiesDir}`);
100
+ }
101
+ const random = input.random ?? Math.random;
102
+ const index = Math.min(files.length - 1, Math.floor(random() * files.length));
103
+ const fileName = files[index];
104
+ const content = fs.readFileSync(path.join(input.identitiesDir, fileName), "utf-8");
105
+ (0, runtime_1.emitNervesEvent)({
106
+ component: "daemon",
107
+ event: "daemon.hatch_identity_pick",
108
+ message: "picked specialist identity",
109
+ meta: { fileName },
110
+ });
111
+ return { fileName, content };
112
+ }
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HealthMonitor = void 0;
4
+ const runtime_1 = require("../../nerves/runtime");
5
+ class HealthMonitor {
6
+ processManager;
7
+ scheduler;
8
+ alertSink;
9
+ diskUsagePercent;
10
+ constructor(options) {
11
+ this.processManager = options.processManager;
12
+ this.scheduler = options.scheduler;
13
+ this.alertSink = options.alertSink ?? (() => undefined);
14
+ this.diskUsagePercent = options.diskUsagePercent ?? (() => 0);
15
+ }
16
+ async runChecks() {
17
+ const results = [];
18
+ const snapshots = this.processManager.listAgentSnapshots();
19
+ const unhealthy = snapshots.filter((snapshot) => snapshot.status !== "running");
20
+ if (unhealthy.length > 0) {
21
+ results.push({
22
+ name: "agent-processes",
23
+ status: "critical",
24
+ message: `non-running agents: ${unhealthy.map((item) => item.name).join(", ")}`,
25
+ });
26
+ }
27
+ else {
28
+ results.push({ name: "agent-processes", status: "ok", message: "all managed agents running" });
29
+ }
30
+ const jobs = this.scheduler.listJobs();
31
+ const neverRan = jobs.filter((job) => !job.lastRun);
32
+ if (neverRan.length > 0) {
33
+ results.push({
34
+ name: "cron-health",
35
+ status: "warn",
36
+ message: `jobs never run: ${neverRan.map((job) => job.id).join(", ")}`,
37
+ });
38
+ }
39
+ else {
40
+ results.push({ name: "cron-health", status: "ok", message: "cron jobs are healthy" });
41
+ }
42
+ const diskPercent = this.diskUsagePercent();
43
+ if (diskPercent >= 90) {
44
+ results.push({
45
+ name: "disk-space",
46
+ status: "critical",
47
+ message: `disk usage critical (${diskPercent}%)`,
48
+ });
49
+ }
50
+ else if (diskPercent >= 80) {
51
+ results.push({
52
+ name: "disk-space",
53
+ status: "warn",
54
+ message: `disk usage high (${diskPercent}%)`,
55
+ });
56
+ }
57
+ else {
58
+ results.push({
59
+ name: "disk-space",
60
+ status: "ok",
61
+ message: `disk usage healthy (${diskPercent}%)`,
62
+ });
63
+ }
64
+ for (const result of results) {
65
+ (0, runtime_1.emitNervesEvent)({
66
+ level: result.status === "critical" ? "error" : result.status === "warn" ? "warn" : "info",
67
+ component: "daemon",
68
+ event: "daemon.health_result",
69
+ message: "daemon health check result",
70
+ meta: { name: result.name, status: result.status },
71
+ });
72
+ if (result.status === "critical") {
73
+ await this.alertSink(`[critical] ${result.name}: ${result.message}`);
74
+ }
75
+ }
76
+ return results;
77
+ }
78
+ }
79
+ exports.HealthMonitor = HealthMonitor;
@@ -0,0 +1,146 @@
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.discoverLogFiles = discoverLogFiles;
37
+ exports.readLastLines = readLastLines;
38
+ exports.formatLogLine = formatLogLine;
39
+ exports.tailLogs = tailLogs;
40
+ const os = __importStar(require("os"));
41
+ const path = __importStar(require("path"));
42
+ const nerves_1 = require("../../nerves");
43
+ const runtime_1 = require("../../nerves/runtime");
44
+ const LEVEL_COLORS = {
45
+ debug: "\x1b[2m",
46
+ info: "\x1b[36m",
47
+ warn: "\x1b[33m",
48
+ error: "\x1b[31m",
49
+ };
50
+ function discoverLogFiles(options) {
51
+ /* v8 ignore start -- integration: default DI stubs for real OS @preserve */
52
+ const homeDir = options.homeDir ?? os.homedir();
53
+ const existsSync = options.existsSync ?? (() => false);
54
+ const readdirSync = options.readdirSync ?? (() => []);
55
+ /* v8 ignore stop */
56
+ const logDir = path.join(homeDir, ".agentstate", "daemon", "logs");
57
+ const files = [];
58
+ if (existsSync(logDir)) {
59
+ for (const name of readdirSync(logDir)) {
60
+ if (!name.endsWith(".ndjson"))
61
+ continue;
62
+ if (options.agentFilter && !name.includes(options.agentFilter))
63
+ continue;
64
+ files.push(path.join(logDir, name));
65
+ }
66
+ }
67
+ return files.sort();
68
+ }
69
+ function readLastLines(filePath, count, readFileSync) {
70
+ let content;
71
+ try {
72
+ content = readFileSync(filePath, "utf-8");
73
+ }
74
+ catch {
75
+ return [];
76
+ }
77
+ const lines = content.split("\n").filter((l) => l.trim().length > 0);
78
+ return lines.slice(-count);
79
+ }
80
+ function formatLogLine(ndjsonLine) {
81
+ try {
82
+ const entry = JSON.parse(ndjsonLine);
83
+ const formatted = (0, nerves_1.formatTerminalEntry)(entry);
84
+ const color = LEVEL_COLORS[entry.level] ?? "";
85
+ return `${color}${formatted}\x1b[0m`;
86
+ }
87
+ catch {
88
+ return ndjsonLine;
89
+ }
90
+ }
91
+ function tailLogs(options = {}) {
92
+ /* v8 ignore start -- integration: default DI stubs for real OS @preserve */
93
+ const writer = options.writer ?? ((text) => process.stdout.write(text));
94
+ const lineCount = options.lines ?? 20;
95
+ const readFileSync = options.readFileSync ?? (() => "");
96
+ /* v8 ignore stop */
97
+ const watchFile = options.watchFile;
98
+ const unwatchFile = options.unwatchFile;
99
+ const files = discoverLogFiles(options);
100
+ (0, runtime_1.emitNervesEvent)({ component: "daemon", event: "daemon.log_tailer_started", message: "log tailer started", meta: { fileCount: files.length, follow: !!options.follow } });
101
+ const fileSizes = new Map();
102
+ // Read initial lines
103
+ for (const file of files) {
104
+ const lines = readLastLines(file, lineCount, readFileSync);
105
+ for (const line of lines) {
106
+ writer(`${formatLogLine(line)}\n`);
107
+ }
108
+ try {
109
+ const content = readFileSync(file, "utf-8");
110
+ fileSizes.set(file, content.length);
111
+ }
112
+ catch {
113
+ fileSizes.set(file, 0);
114
+ }
115
+ }
116
+ // Follow mode
117
+ if (options.follow && watchFile && unwatchFile) {
118
+ for (const file of files) {
119
+ watchFile(file, () => {
120
+ let content;
121
+ try {
122
+ content = readFileSync(file, "utf-8");
123
+ }
124
+ catch {
125
+ return;
126
+ }
127
+ /* v8 ignore next -- defensive: fileSizes always populated above @preserve */
128
+ const prevSize = fileSizes.get(file) ?? 0;
129
+ if (content.length <= prevSize)
130
+ return;
131
+ fileSizes.set(file, content.length);
132
+ const newContent = content.slice(prevSize);
133
+ const newLines = newContent.split("\n").filter((l) => l.trim().length > 0);
134
+ for (const line of newLines) {
135
+ writer(`${formatLogLine(line)}\n`);
136
+ }
137
+ });
138
+ }
139
+ return () => {
140
+ for (const file of files) {
141
+ unwatchFile(file);
142
+ }
143
+ };
144
+ }
145
+ return () => { };
146
+ }