@ouro.bot/cli 0.0.1-alpha.0 → 0.1.0-alpha.1
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/agent.json +20 -0
- package/AdoptionSpecialist.ouro/psyche/SOUL.md +22 -0
- package/AdoptionSpecialist.ouro/psyche/identities/basilisk.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/jafar.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/jormungandr.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/kaa.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/medusa.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/monty.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/nagini.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/ouroboros.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/python.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/quetzalcoatl.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/sir-hiss.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/the-serpent.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/the-snake.md +31 -0
- package/README.md +224 -6
- package/dist/heart/agent-entry.js +17 -0
- package/dist/heart/api-error.js +34 -0
- package/dist/heart/config.js +296 -0
- package/dist/heart/core.js +485 -0
- package/dist/heart/daemon/daemon-cli.js +626 -0
- package/dist/heart/daemon/daemon-entry.js +74 -0
- package/dist/heart/daemon/daemon.js +310 -0
- package/dist/heart/daemon/hatch-flow.js +284 -0
- package/dist/heart/daemon/hatch-specialist.js +107 -0
- package/dist/heart/daemon/health-monitor.js +79 -0
- package/dist/heart/daemon/message-router.js +98 -0
- package/dist/heart/daemon/ouro-bot-entry.js +23 -0
- package/dist/heart/daemon/ouro-bot-wrapper.js +90 -0
- package/dist/heart/daemon/ouro-entry.js +23 -0
- package/dist/heart/daemon/ouro-uti.js +212 -0
- package/dist/heart/daemon/process-manager.js +220 -0
- package/dist/heart/daemon/runtime-logging.js +98 -0
- package/dist/heart/daemon/subagent-installer.js +125 -0
- package/dist/heart/daemon/task-scheduler.js +237 -0
- package/dist/heart/harness.js +26 -0
- package/dist/heart/identity.js +270 -0
- package/dist/heart/kicks.js +144 -0
- package/dist/heart/primitives.js +4 -0
- package/dist/heart/providers/anthropic.js +329 -0
- package/dist/heart/providers/azure.js +66 -0
- package/dist/heart/providers/minimax.js +53 -0
- package/dist/heart/providers/openai-codex.js +162 -0
- package/dist/heart/streaming.js +412 -0
- package/dist/heart/turn-coordinator.js +62 -0
- package/dist/inner-worker-entry.js +4 -0
- package/dist/mind/associative-recall.js +176 -0
- package/dist/mind/bundle-manifest.js +118 -0
- package/dist/mind/context.js +218 -0
- package/dist/mind/first-impressions.js +43 -0
- package/dist/mind/format.js +56 -0
- package/dist/mind/friends/channel.js +41 -0
- package/dist/mind/friends/resolver.js +84 -0
- package/dist/mind/friends/store-file.js +171 -0
- package/dist/mind/friends/store.js +4 -0
- package/dist/mind/friends/tokens.js +26 -0
- package/dist/mind/friends/types.js +21 -0
- package/dist/mind/memory.js +326 -0
- package/dist/mind/phrases.js +43 -0
- package/dist/mind/prompt.js +254 -0
- package/dist/mind/token-estimate.js +119 -0
- package/dist/nerves/cli-logging.js +31 -0
- package/dist/nerves/coverage/audit-rules.js +81 -0
- package/dist/nerves/coverage/audit.js +200 -0
- package/dist/nerves/coverage/cli-main.js +5 -0
- package/dist/nerves/coverage/cli.js +51 -0
- package/dist/nerves/coverage/contract.js +23 -0
- package/dist/nerves/coverage/file-completeness.js +46 -0
- package/dist/nerves/coverage/run-artifacts.js +77 -0
- package/dist/nerves/coverage/source-scanner.js +34 -0
- package/dist/nerves/index.js +152 -0
- package/dist/nerves/runtime.js +38 -0
- package/dist/repertoire/ado-client.js +211 -0
- package/dist/repertoire/ado-context.js +73 -0
- package/dist/repertoire/ado-semantic.js +841 -0
- package/dist/repertoire/ado-templates.js +146 -0
- package/dist/repertoire/coding/index.js +36 -0
- package/dist/repertoire/coding/manager.js +489 -0
- package/dist/repertoire/coding/monitor.js +60 -0
- package/dist/repertoire/coding/reporter.js +45 -0
- package/dist/repertoire/coding/spawner.js +102 -0
- package/dist/repertoire/coding/tools.js +167 -0
- package/dist/repertoire/coding/types.js +2 -0
- package/dist/repertoire/data/ado-endpoints.json +122 -0
- package/dist/repertoire/data/graph-endpoints.json +212 -0
- package/dist/repertoire/github-client.js +64 -0
- package/dist/repertoire/graph-client.js +118 -0
- package/dist/repertoire/skills.js +156 -0
- package/dist/repertoire/tasks/board.js +122 -0
- package/dist/repertoire/tasks/index.js +210 -0
- package/dist/repertoire/tasks/lifecycle.js +80 -0
- package/dist/repertoire/tasks/middleware.js +65 -0
- package/dist/repertoire/tasks/parser.js +173 -0
- package/dist/repertoire/tasks/scanner.js +132 -0
- package/dist/repertoire/tasks/transitions.js +145 -0
- package/dist/repertoire/tasks/types.js +2 -0
- package/dist/repertoire/tools-base.js +622 -0
- package/dist/repertoire/tools-github.js +53 -0
- package/dist/repertoire/tools-teams.js +308 -0
- package/dist/repertoire/tools.js +199 -0
- package/dist/senses/cli-entry.js +15 -0
- package/dist/senses/cli.js +523 -0
- package/dist/senses/commands.js +98 -0
- package/dist/senses/inner-dialog-worker.js +61 -0
- package/dist/senses/inner-dialog.js +216 -0
- package/dist/senses/teams-entry.js +15 -0
- package/dist/senses/teams.js +695 -0
- package/dist/senses/trust-gate.js +150 -0
- package/package.json +34 -11
- package/subagents/README.md +71 -0
- package/subagents/work-doer.md +233 -0
- package/subagents/work-merger.md +593 -0
- package/subagents/work-planner.md +373 -0
- package/bin/ouro.js +0 -6
|
@@ -0,0 +1,626 @@
|
|
|
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.parseOuroCommand = parseOuroCommand;
|
|
37
|
+
exports.createDefaultOuroCliDeps = createDefaultOuroCliDeps;
|
|
38
|
+
exports.runOuroCli = runOuroCli;
|
|
39
|
+
const child_process_1 = require("child_process");
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const net = __importStar(require("net"));
|
|
42
|
+
const os = __importStar(require("os"));
|
|
43
|
+
const path = __importStar(require("path"));
|
|
44
|
+
const identity_1 = require("../identity");
|
|
45
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
46
|
+
const store_file_1 = require("../../mind/friends/store-file");
|
|
47
|
+
const types_1 = require("../../mind/friends/types");
|
|
48
|
+
const ouro_uti_1 = require("./ouro-uti");
|
|
49
|
+
const subagent_installer_1 = require("./subagent-installer");
|
|
50
|
+
const hatch_flow_1 = require("./hatch-flow");
|
|
51
|
+
function usage() {
|
|
52
|
+
return [
|
|
53
|
+
"Usage:",
|
|
54
|
+
" ouro [up]",
|
|
55
|
+
" ouro stop|status|logs|hatch",
|
|
56
|
+
" ouro chat <agent>",
|
|
57
|
+
" ouro msg --to <agent> [--session <id>] [--task <ref>] <message>",
|
|
58
|
+
" ouro poke <agent> --task <task-id>",
|
|
59
|
+
" ouro link <agent> --friend <id> --provider <provider> --external-id <external-id>",
|
|
60
|
+
].join("\n");
|
|
61
|
+
}
|
|
62
|
+
function parseMessageCommand(args) {
|
|
63
|
+
let to;
|
|
64
|
+
let sessionId;
|
|
65
|
+
let taskRef;
|
|
66
|
+
const messageParts = [];
|
|
67
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
68
|
+
const token = args[i];
|
|
69
|
+
if (token === "--to") {
|
|
70
|
+
to = args[i + 1];
|
|
71
|
+
i += 1;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (token === "--session") {
|
|
75
|
+
sessionId = args[i + 1];
|
|
76
|
+
i += 1;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (token === "--task") {
|
|
80
|
+
taskRef = args[i + 1];
|
|
81
|
+
i += 1;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
messageParts.push(token);
|
|
85
|
+
}
|
|
86
|
+
const content = messageParts.join(" ").trim();
|
|
87
|
+
if (!to || !content)
|
|
88
|
+
throw new Error(`Usage\n${usage()}`);
|
|
89
|
+
return {
|
|
90
|
+
kind: "message.send",
|
|
91
|
+
from: "ouro-cli",
|
|
92
|
+
to,
|
|
93
|
+
content,
|
|
94
|
+
sessionId,
|
|
95
|
+
taskRef,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function parsePokeCommand(args) {
|
|
99
|
+
const agent = args[0];
|
|
100
|
+
if (!agent)
|
|
101
|
+
throw new Error(`Usage\n${usage()}`);
|
|
102
|
+
let taskId;
|
|
103
|
+
for (let i = 1; i < args.length; i += 1) {
|
|
104
|
+
if (args[i] === "--task") {
|
|
105
|
+
taskId = args[i + 1];
|
|
106
|
+
i += 1;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (!taskId)
|
|
110
|
+
throw new Error(`Usage\n${usage()}`);
|
|
111
|
+
return { kind: "task.poke", agent, taskId };
|
|
112
|
+
}
|
|
113
|
+
function parseLinkCommand(args) {
|
|
114
|
+
const agent = args[0];
|
|
115
|
+
if (!agent)
|
|
116
|
+
throw new Error(`Usage\n${usage()}`);
|
|
117
|
+
let friendId;
|
|
118
|
+
let providerRaw;
|
|
119
|
+
let externalId;
|
|
120
|
+
for (let i = 1; i < args.length; i += 1) {
|
|
121
|
+
const token = args[i];
|
|
122
|
+
if (token === "--friend") {
|
|
123
|
+
friendId = args[i + 1];
|
|
124
|
+
i += 1;
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (token === "--provider") {
|
|
128
|
+
providerRaw = args[i + 1];
|
|
129
|
+
i += 1;
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (token === "--external-id") {
|
|
133
|
+
externalId = args[i + 1];
|
|
134
|
+
i += 1;
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (!friendId || !providerRaw || !externalId) {
|
|
139
|
+
throw new Error(`Usage\n${usage()}`);
|
|
140
|
+
}
|
|
141
|
+
if (!(0, types_1.isIdentityProvider)(providerRaw)) {
|
|
142
|
+
throw new Error(`Unknown identity provider '${providerRaw}'. Use aad|local|teams-conversation.`);
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
kind: "friend.link",
|
|
146
|
+
agent,
|
|
147
|
+
friendId,
|
|
148
|
+
provider: providerRaw,
|
|
149
|
+
externalId,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
function isAgentProvider(value) {
|
|
153
|
+
return value === "azure" || value === "anthropic" || value === "minimax" || value === "openai-codex";
|
|
154
|
+
}
|
|
155
|
+
function parseHatchCommand(args) {
|
|
156
|
+
let agentName;
|
|
157
|
+
let humanName;
|
|
158
|
+
let providerRaw;
|
|
159
|
+
let migrationPath;
|
|
160
|
+
const credentials = {};
|
|
161
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
162
|
+
const token = args[i];
|
|
163
|
+
if (token === "--agent") {
|
|
164
|
+
agentName = args[i + 1];
|
|
165
|
+
i += 1;
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
if (token === "--human") {
|
|
169
|
+
humanName = args[i + 1];
|
|
170
|
+
i += 1;
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
if (token === "--provider") {
|
|
174
|
+
providerRaw = args[i + 1];
|
|
175
|
+
i += 1;
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
if (token === "--setup-token") {
|
|
179
|
+
credentials.setupToken = args[i + 1];
|
|
180
|
+
i += 1;
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
if (token === "--oauth-token") {
|
|
184
|
+
credentials.oauthAccessToken = args[i + 1];
|
|
185
|
+
i += 1;
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
if (token === "--api-key") {
|
|
189
|
+
credentials.apiKey = args[i + 1];
|
|
190
|
+
i += 1;
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
if (token === "--endpoint") {
|
|
194
|
+
credentials.endpoint = args[i + 1];
|
|
195
|
+
i += 1;
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
if (token === "--deployment") {
|
|
199
|
+
credentials.deployment = args[i + 1];
|
|
200
|
+
i += 1;
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
if (token === "--migration-path") {
|
|
204
|
+
migrationPath = args[i + 1];
|
|
205
|
+
i += 1;
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
if (providerRaw && !isAgentProvider(providerRaw)) {
|
|
210
|
+
throw new Error("Unknown provider. Use azure|anthropic|minimax|openai-codex.");
|
|
211
|
+
}
|
|
212
|
+
const provider = providerRaw && isAgentProvider(providerRaw) ? providerRaw : undefined;
|
|
213
|
+
return {
|
|
214
|
+
kind: "hatch.start",
|
|
215
|
+
agentName,
|
|
216
|
+
humanName,
|
|
217
|
+
provider,
|
|
218
|
+
credentials: Object.keys(credentials).length > 0 ? credentials : undefined,
|
|
219
|
+
migrationPath,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
function parseOuroCommand(args) {
|
|
223
|
+
const [head, second] = args;
|
|
224
|
+
if (!head)
|
|
225
|
+
return { kind: "daemon.up" };
|
|
226
|
+
if (head === "up")
|
|
227
|
+
return { kind: "daemon.up" };
|
|
228
|
+
if (head === "stop")
|
|
229
|
+
return { kind: "daemon.stop" };
|
|
230
|
+
if (head === "status")
|
|
231
|
+
return { kind: "daemon.status" };
|
|
232
|
+
if (head === "logs")
|
|
233
|
+
return { kind: "daemon.logs" };
|
|
234
|
+
if (head === "hatch")
|
|
235
|
+
return parseHatchCommand(args.slice(1));
|
|
236
|
+
if (head === "chat") {
|
|
237
|
+
if (!second)
|
|
238
|
+
throw new Error(`Usage\n${usage()}`);
|
|
239
|
+
return { kind: "chat.connect", agent: second };
|
|
240
|
+
}
|
|
241
|
+
if (head === "msg")
|
|
242
|
+
return parseMessageCommand(args.slice(1));
|
|
243
|
+
if (head === "poke")
|
|
244
|
+
return parsePokeCommand(args.slice(1));
|
|
245
|
+
if (head === "link")
|
|
246
|
+
return parseLinkCommand(args.slice(1));
|
|
247
|
+
throw new Error(`Unknown command '${args.join(" ")}'.\n${usage()}`);
|
|
248
|
+
}
|
|
249
|
+
function defaultSendCommand(socketPath, command) {
|
|
250
|
+
return new Promise((resolve, reject) => {
|
|
251
|
+
const client = net.createConnection(socketPath);
|
|
252
|
+
let raw = "";
|
|
253
|
+
client.on("connect", () => {
|
|
254
|
+
client.write(JSON.stringify(command));
|
|
255
|
+
client.end();
|
|
256
|
+
});
|
|
257
|
+
client.on("data", (chunk) => {
|
|
258
|
+
raw += chunk.toString("utf-8");
|
|
259
|
+
});
|
|
260
|
+
client.on("error", reject);
|
|
261
|
+
client.on("end", () => {
|
|
262
|
+
const trimmed = raw.trim();
|
|
263
|
+
if (trimmed.length === 0 && command.kind === "daemon.stop") {
|
|
264
|
+
resolve({ ok: true, message: "daemon stopped" });
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
if (trimmed.length === 0) {
|
|
268
|
+
reject(new Error("Daemon returned empty response."));
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
try {
|
|
272
|
+
const parsed = JSON.parse(trimmed);
|
|
273
|
+
resolve(parsed);
|
|
274
|
+
}
|
|
275
|
+
catch (error) {
|
|
276
|
+
reject(error);
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
function defaultStartDaemonProcess(socketPath) {
|
|
282
|
+
const entry = path.join((0, identity_1.getRepoRoot)(), "dist", "heart", "daemon", "daemon-entry.js");
|
|
283
|
+
const child = (0, child_process_1.spawn)("node", [entry, "--socket", socketPath], {
|
|
284
|
+
detached: true,
|
|
285
|
+
stdio: "ignore",
|
|
286
|
+
});
|
|
287
|
+
child.unref();
|
|
288
|
+
return Promise.resolve({ pid: child.pid ?? null });
|
|
289
|
+
}
|
|
290
|
+
function defaultWriteStdout(text) {
|
|
291
|
+
// eslint-disable-next-line no-console -- terminal UX: CLI command output
|
|
292
|
+
console.log(text);
|
|
293
|
+
}
|
|
294
|
+
function defaultCheckSocketAlive(socketPath) {
|
|
295
|
+
return new Promise((resolve) => {
|
|
296
|
+
const client = net.createConnection(socketPath);
|
|
297
|
+
let raw = "";
|
|
298
|
+
let done = false;
|
|
299
|
+
const finalize = (alive) => {
|
|
300
|
+
if (done)
|
|
301
|
+
return;
|
|
302
|
+
done = true;
|
|
303
|
+
resolve(alive);
|
|
304
|
+
};
|
|
305
|
+
if ("setTimeout" in client && typeof client.setTimeout === "function") {
|
|
306
|
+
client.setTimeout(800, () => {
|
|
307
|
+
client.destroy();
|
|
308
|
+
finalize(false);
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
client.on("connect", () => {
|
|
312
|
+
client.write(JSON.stringify({ kind: "daemon.status" }));
|
|
313
|
+
client.end();
|
|
314
|
+
});
|
|
315
|
+
client.on("data", (chunk) => {
|
|
316
|
+
raw += chunk.toString("utf-8");
|
|
317
|
+
});
|
|
318
|
+
client.on("error", () => finalize(false));
|
|
319
|
+
client.on("end", () => {
|
|
320
|
+
if (raw.trim().length === 0) {
|
|
321
|
+
finalize(false);
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
try {
|
|
325
|
+
JSON.parse(raw);
|
|
326
|
+
finalize(true);
|
|
327
|
+
}
|
|
328
|
+
catch {
|
|
329
|
+
finalize(false);
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
function defaultCleanupStaleSocket(socketPath) {
|
|
335
|
+
if (fs.existsSync(socketPath)) {
|
|
336
|
+
fs.unlinkSync(socketPath);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
function defaultFallbackPendingMessage(command) {
|
|
340
|
+
const inboxDir = path.join((0, identity_1.getAgentBundlesRoot)(), `${command.to}.ouro`, "inbox");
|
|
341
|
+
const pendingPath = path.join(inboxDir, "pending.jsonl");
|
|
342
|
+
const queuedAt = new Date().toISOString();
|
|
343
|
+
const payload = {
|
|
344
|
+
from: command.from,
|
|
345
|
+
to: command.to,
|
|
346
|
+
content: command.content,
|
|
347
|
+
priority: command.priority ?? "normal",
|
|
348
|
+
sessionId: command.sessionId,
|
|
349
|
+
taskRef: command.taskRef,
|
|
350
|
+
queuedAt,
|
|
351
|
+
};
|
|
352
|
+
fs.mkdirSync(inboxDir, { recursive: true });
|
|
353
|
+
fs.appendFileSync(pendingPath, `${JSON.stringify(payload)}\n`, "utf-8");
|
|
354
|
+
(0, runtime_1.emitNervesEvent)({
|
|
355
|
+
level: "warn",
|
|
356
|
+
component: "daemon",
|
|
357
|
+
event: "daemon.message_fallback_queued",
|
|
358
|
+
message: "queued message to pending fallback file",
|
|
359
|
+
meta: {
|
|
360
|
+
to: command.to,
|
|
361
|
+
path: pendingPath,
|
|
362
|
+
sessionId: command.sessionId ?? null,
|
|
363
|
+
taskRef: command.taskRef ?? null,
|
|
364
|
+
},
|
|
365
|
+
});
|
|
366
|
+
return pendingPath;
|
|
367
|
+
}
|
|
368
|
+
async function defaultInstallSubagents() {
|
|
369
|
+
return (0, subagent_installer_1.installSubagentsForAvailableCli)({
|
|
370
|
+
repoRoot: (0, identity_1.getRepoRoot)(),
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
async function defaultPromptInput(question) {
|
|
374
|
+
const readline = await Promise.resolve().then(() => __importStar(require("readline/promises")));
|
|
375
|
+
const rl = readline.createInterface({
|
|
376
|
+
input: process.stdin,
|
|
377
|
+
output: process.stdout,
|
|
378
|
+
});
|
|
379
|
+
try {
|
|
380
|
+
const response = await rl.question(question);
|
|
381
|
+
return response.trim();
|
|
382
|
+
}
|
|
383
|
+
finally {
|
|
384
|
+
rl.close();
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
function defaultListDiscoveredAgents() {
|
|
388
|
+
const bundlesRoot = (0, identity_1.getAgentBundlesRoot)();
|
|
389
|
+
let entries;
|
|
390
|
+
try {
|
|
391
|
+
entries = fs.readdirSync(bundlesRoot, { withFileTypes: true });
|
|
392
|
+
}
|
|
393
|
+
catch {
|
|
394
|
+
return [];
|
|
395
|
+
}
|
|
396
|
+
const discovered = [];
|
|
397
|
+
for (const entry of entries) {
|
|
398
|
+
if (!entry.isDirectory() || !entry.name.endsWith(".ouro"))
|
|
399
|
+
continue;
|
|
400
|
+
const agentName = entry.name.slice(0, -5);
|
|
401
|
+
const configPath = path.join(bundlesRoot, entry.name, "agent.json");
|
|
402
|
+
let enabled = true;
|
|
403
|
+
try {
|
|
404
|
+
const raw = fs.readFileSync(configPath, "utf-8");
|
|
405
|
+
const parsed = JSON.parse(raw);
|
|
406
|
+
if (typeof parsed.enabled === "boolean") {
|
|
407
|
+
enabled = parsed.enabled;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
catch {
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
413
|
+
if (enabled) {
|
|
414
|
+
discovered.push(agentName);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
return discovered.sort((left, right) => left.localeCompare(right));
|
|
418
|
+
}
|
|
419
|
+
async function defaultLinkFriendIdentity(command) {
|
|
420
|
+
const friendStore = new store_file_1.FileFriendStore(path.join((0, identity_1.getAgentBundlesRoot)(), `${command.agent}.ouro`, "friends"));
|
|
421
|
+
const current = await friendStore.get(command.friendId);
|
|
422
|
+
if (!current) {
|
|
423
|
+
return `friend not found: ${command.friendId}`;
|
|
424
|
+
}
|
|
425
|
+
const alreadyLinked = current.externalIds.some((ext) => ext.provider === command.provider && ext.externalId === command.externalId);
|
|
426
|
+
if (alreadyLinked) {
|
|
427
|
+
return `identity already linked: ${command.provider}:${command.externalId}`;
|
|
428
|
+
}
|
|
429
|
+
const now = new Date().toISOString();
|
|
430
|
+
await friendStore.put(command.friendId, {
|
|
431
|
+
...current,
|
|
432
|
+
externalIds: [
|
|
433
|
+
...current.externalIds,
|
|
434
|
+
{
|
|
435
|
+
provider: command.provider,
|
|
436
|
+
externalId: command.externalId,
|
|
437
|
+
linkedAt: now,
|
|
438
|
+
},
|
|
439
|
+
],
|
|
440
|
+
updatedAt: now,
|
|
441
|
+
});
|
|
442
|
+
return `linked ${command.provider}:${command.externalId} to ${command.friendId}`;
|
|
443
|
+
}
|
|
444
|
+
function createDefaultOuroCliDeps(socketPath = "/tmp/ouroboros-daemon.sock") {
|
|
445
|
+
return {
|
|
446
|
+
socketPath,
|
|
447
|
+
sendCommand: defaultSendCommand,
|
|
448
|
+
startDaemonProcess: defaultStartDaemonProcess,
|
|
449
|
+
writeStdout: defaultWriteStdout,
|
|
450
|
+
checkSocketAlive: defaultCheckSocketAlive,
|
|
451
|
+
cleanupStaleSocket: defaultCleanupStaleSocket,
|
|
452
|
+
fallbackPendingMessage: defaultFallbackPendingMessage,
|
|
453
|
+
installSubagents: defaultInstallSubagents,
|
|
454
|
+
linkFriendIdentity: defaultLinkFriendIdentity,
|
|
455
|
+
listDiscoveredAgents: defaultListDiscoveredAgents,
|
|
456
|
+
runHatchFlow: hatch_flow_1.runHatchFlow,
|
|
457
|
+
promptInput: defaultPromptInput,
|
|
458
|
+
registerOuroBundleType: ouro_uti_1.registerOuroBundleUti,
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
function toDaemonCommand(command) {
|
|
462
|
+
return command;
|
|
463
|
+
}
|
|
464
|
+
async function resolveHatchInput(command, deps) {
|
|
465
|
+
const prompt = deps.promptInput;
|
|
466
|
+
const agentName = command.agentName ?? (prompt ? await prompt("Hatchling name: ") : "");
|
|
467
|
+
const humanName = command.humanName ?? (prompt ? await prompt("Your name: ") : os.userInfo().username);
|
|
468
|
+
const providerRaw = command.provider ?? (prompt ? await prompt("Provider (azure|anthropic|minimax|openai-codex): ") : "");
|
|
469
|
+
if (!agentName || !humanName || !isAgentProvider(providerRaw)) {
|
|
470
|
+
throw new Error(`Usage\n${usage()}`);
|
|
471
|
+
}
|
|
472
|
+
const credentials = { ...(command.credentials ?? {}) };
|
|
473
|
+
if (providerRaw === "anthropic" && !credentials.setupToken && prompt) {
|
|
474
|
+
credentials.setupToken = await prompt("Anthropic setup-token: ");
|
|
475
|
+
}
|
|
476
|
+
if (providerRaw === "openai-codex" && !credentials.oauthAccessToken && prompt) {
|
|
477
|
+
credentials.oauthAccessToken = await prompt("OpenAI Codex OAuth token: ");
|
|
478
|
+
}
|
|
479
|
+
if (providerRaw === "minimax" && !credentials.apiKey && prompt) {
|
|
480
|
+
credentials.apiKey = await prompt("MiniMax API key: ");
|
|
481
|
+
}
|
|
482
|
+
if (providerRaw === "azure") {
|
|
483
|
+
if (!credentials.apiKey && prompt)
|
|
484
|
+
credentials.apiKey = await prompt("Azure API key: ");
|
|
485
|
+
if (!credentials.endpoint && prompt)
|
|
486
|
+
credentials.endpoint = await prompt("Azure endpoint: ");
|
|
487
|
+
if (!credentials.deployment && prompt)
|
|
488
|
+
credentials.deployment = await prompt("Azure deployment: ");
|
|
489
|
+
}
|
|
490
|
+
return {
|
|
491
|
+
agentName,
|
|
492
|
+
humanName,
|
|
493
|
+
provider: providerRaw,
|
|
494
|
+
credentials,
|
|
495
|
+
migrationPath: command.migrationPath,
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
async function registerOuroBundleTypeNonBlocking(deps) {
|
|
499
|
+
const registerOuroBundleType = deps.registerOuroBundleType;
|
|
500
|
+
if (!registerOuroBundleType)
|
|
501
|
+
return;
|
|
502
|
+
try {
|
|
503
|
+
await Promise.resolve(registerOuroBundleType());
|
|
504
|
+
}
|
|
505
|
+
catch (error) {
|
|
506
|
+
(0, runtime_1.emitNervesEvent)({
|
|
507
|
+
level: "warn",
|
|
508
|
+
component: "daemon",
|
|
509
|
+
event: "daemon.ouro_uti_register_error",
|
|
510
|
+
message: "failed .ouro UTI registration from CLI flow",
|
|
511
|
+
meta: { error: error instanceof Error ? error.message : String(error) },
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
async function runOuroCli(args, deps = createDefaultOuroCliDeps()) {
|
|
516
|
+
let command = parseOuroCommand(args);
|
|
517
|
+
if (args.length === 0) {
|
|
518
|
+
const discovered = await Promise.resolve(deps.listDiscoveredAgents ? deps.listDiscoveredAgents() : defaultListDiscoveredAgents());
|
|
519
|
+
if (discovered.length === 0) {
|
|
520
|
+
command = { kind: "hatch.start" };
|
|
521
|
+
}
|
|
522
|
+
else if (discovered.length === 1) {
|
|
523
|
+
command = { kind: "chat.connect", agent: discovered[0] };
|
|
524
|
+
}
|
|
525
|
+
else {
|
|
526
|
+
const message = `who do you want to talk to? ${discovered.join(", ")} (use: ouro chat <agent>)`;
|
|
527
|
+
deps.writeStdout(message);
|
|
528
|
+
return message;
|
|
529
|
+
}
|
|
530
|
+
(0, runtime_1.emitNervesEvent)({
|
|
531
|
+
component: "daemon",
|
|
532
|
+
event: "daemon.cli_auto_route",
|
|
533
|
+
message: "routed bare ouro command from discovered agents",
|
|
534
|
+
meta: { target: command.kind, count: discovered.length },
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
(0, runtime_1.emitNervesEvent)({
|
|
538
|
+
component: "daemon",
|
|
539
|
+
event: "daemon.cli_command",
|
|
540
|
+
message: "ouro CLI command invoked",
|
|
541
|
+
meta: { kind: command.kind },
|
|
542
|
+
});
|
|
543
|
+
if (command.kind === "daemon.up") {
|
|
544
|
+
try {
|
|
545
|
+
await deps.installSubagents();
|
|
546
|
+
}
|
|
547
|
+
catch (error) {
|
|
548
|
+
(0, runtime_1.emitNervesEvent)({
|
|
549
|
+
level: "warn",
|
|
550
|
+
component: "daemon",
|
|
551
|
+
event: "daemon.subagent_install_error",
|
|
552
|
+
message: "subagent auto-install failed",
|
|
553
|
+
meta: { error: error instanceof Error ? error.message : String(error) },
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
await registerOuroBundleTypeNonBlocking(deps);
|
|
557
|
+
const alive = await deps.checkSocketAlive(deps.socketPath);
|
|
558
|
+
if (alive) {
|
|
559
|
+
const message = `daemon already running (${deps.socketPath})`;
|
|
560
|
+
deps.writeStdout(message);
|
|
561
|
+
return message;
|
|
562
|
+
}
|
|
563
|
+
deps.cleanupStaleSocket(deps.socketPath);
|
|
564
|
+
const started = await deps.startDaemonProcess(deps.socketPath);
|
|
565
|
+
const message = `daemon started (pid ${started.pid ?? "unknown"})`;
|
|
566
|
+
deps.writeStdout(message);
|
|
567
|
+
return message;
|
|
568
|
+
}
|
|
569
|
+
if (command.kind === "friend.link") {
|
|
570
|
+
const linker = deps.linkFriendIdentity ?? defaultLinkFriendIdentity;
|
|
571
|
+
const message = await linker(command);
|
|
572
|
+
deps.writeStdout(message);
|
|
573
|
+
return message;
|
|
574
|
+
}
|
|
575
|
+
if (command.kind === "hatch.start") {
|
|
576
|
+
const hatchRunner = deps.runHatchFlow;
|
|
577
|
+
if (!hatchRunner) {
|
|
578
|
+
const response = await deps.sendCommand(deps.socketPath, { kind: "hatch.start" });
|
|
579
|
+
const message = response.summary ?? response.message ?? (response.ok ? "ok" : `error: ${response.error ?? "unknown error"}`);
|
|
580
|
+
deps.writeStdout(message);
|
|
581
|
+
return message;
|
|
582
|
+
}
|
|
583
|
+
const hatchInput = await resolveHatchInput(command, deps);
|
|
584
|
+
const result = await hatchRunner(hatchInput);
|
|
585
|
+
try {
|
|
586
|
+
await deps.installSubagents();
|
|
587
|
+
}
|
|
588
|
+
catch (error) {
|
|
589
|
+
(0, runtime_1.emitNervesEvent)({
|
|
590
|
+
level: "warn",
|
|
591
|
+
component: "daemon",
|
|
592
|
+
event: "daemon.subagent_install_error",
|
|
593
|
+
message: "subagent auto-install failed",
|
|
594
|
+
meta: { error: error instanceof Error ? error.message : String(error) },
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
await registerOuroBundleTypeNonBlocking(deps);
|
|
598
|
+
const alive = await deps.checkSocketAlive(deps.socketPath);
|
|
599
|
+
let daemonMessage = `daemon already running (${deps.socketPath})`;
|
|
600
|
+
if (!alive) {
|
|
601
|
+
deps.cleanupStaleSocket(deps.socketPath);
|
|
602
|
+
const started = await deps.startDaemonProcess(deps.socketPath);
|
|
603
|
+
daemonMessage = `daemon started (pid ${started.pid ?? "unknown"})`;
|
|
604
|
+
}
|
|
605
|
+
const message = `hatched ${hatchInput.agentName} at ${result.bundleRoot} using specialist identity ${result.selectedIdentity}; ${daemonMessage}`;
|
|
606
|
+
deps.writeStdout(message);
|
|
607
|
+
return message;
|
|
608
|
+
}
|
|
609
|
+
const daemonCommand = toDaemonCommand(command);
|
|
610
|
+
let response;
|
|
611
|
+
try {
|
|
612
|
+
response = await deps.sendCommand(deps.socketPath, daemonCommand);
|
|
613
|
+
}
|
|
614
|
+
catch (error) {
|
|
615
|
+
if (command.kind === "message.send") {
|
|
616
|
+
const pendingPath = deps.fallbackPendingMessage(command);
|
|
617
|
+
const message = `daemon unavailable; queued message fallback at ${pendingPath}`;
|
|
618
|
+
deps.writeStdout(message);
|
|
619
|
+
return message;
|
|
620
|
+
}
|
|
621
|
+
throw error;
|
|
622
|
+
}
|
|
623
|
+
const message = response.summary ?? response.message ?? (response.ok ? "ok" : `error: ${response.error ?? "unknown error"}`);
|
|
624
|
+
deps.writeStdout(message);
|
|
625
|
+
return message;
|
|
626
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const process_manager_1 = require("./process-manager");
|
|
5
|
+
const daemon_1 = require("./daemon");
|
|
6
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
7
|
+
const message_router_1 = require("./message-router");
|
|
8
|
+
const health_monitor_1 = require("./health-monitor");
|
|
9
|
+
const task_scheduler_1 = require("./task-scheduler");
|
|
10
|
+
const runtime_logging_1 = require("./runtime-logging");
|
|
11
|
+
function parseSocketPath(argv) {
|
|
12
|
+
const socketIndex = argv.indexOf("--socket");
|
|
13
|
+
if (socketIndex >= 0) {
|
|
14
|
+
const value = argv[socketIndex + 1];
|
|
15
|
+
if (value && value.trim().length > 0)
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
return "/tmp/ouroboros-daemon.sock";
|
|
19
|
+
}
|
|
20
|
+
const socketPath = parseSocketPath(process.argv);
|
|
21
|
+
(0, runtime_logging_1.configureDaemonRuntimeLogger)("daemon");
|
|
22
|
+
(0, runtime_1.emitNervesEvent)({
|
|
23
|
+
component: "daemon",
|
|
24
|
+
event: "daemon.entry_start",
|
|
25
|
+
message: "starting daemon entrypoint",
|
|
26
|
+
meta: { socketPath },
|
|
27
|
+
});
|
|
28
|
+
const processManager = new process_manager_1.DaemonProcessManager({
|
|
29
|
+
agents: [
|
|
30
|
+
{ name: "ouroboros", entry: "heart/agent-entry.js", channel: "cli", autoStart: true },
|
|
31
|
+
{ name: "slugger", entry: "heart/agent-entry.js", channel: "cli", autoStart: true },
|
|
32
|
+
],
|
|
33
|
+
});
|
|
34
|
+
const scheduler = new task_scheduler_1.TaskDrivenScheduler({
|
|
35
|
+
agents: ["ouroboros", "slugger"],
|
|
36
|
+
});
|
|
37
|
+
const router = new message_router_1.FileMessageRouter();
|
|
38
|
+
const healthMonitor = new health_monitor_1.HealthMonitor({
|
|
39
|
+
processManager,
|
|
40
|
+
scheduler,
|
|
41
|
+
alertSink: (message) => {
|
|
42
|
+
(0, runtime_1.emitNervesEvent)({
|
|
43
|
+
level: "error",
|
|
44
|
+
component: "daemon",
|
|
45
|
+
event: "daemon.health_alert",
|
|
46
|
+
message: "health monitor produced critical alert",
|
|
47
|
+
meta: { message },
|
|
48
|
+
});
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
const daemon = new daemon_1.OuroDaemon({
|
|
52
|
+
socketPath,
|
|
53
|
+
processManager,
|
|
54
|
+
scheduler,
|
|
55
|
+
healthMonitor,
|
|
56
|
+
router,
|
|
57
|
+
});
|
|
58
|
+
void daemon.start().catch(async () => {
|
|
59
|
+
(0, runtime_1.emitNervesEvent)({
|
|
60
|
+
level: "error",
|
|
61
|
+
component: "daemon",
|
|
62
|
+
event: "daemon.entry_error",
|
|
63
|
+
message: "daemon entrypoint failed",
|
|
64
|
+
meta: {},
|
|
65
|
+
});
|
|
66
|
+
await daemon.stop();
|
|
67
|
+
process.exit(1);
|
|
68
|
+
});
|
|
69
|
+
process.on("SIGINT", () => {
|
|
70
|
+
void daemon.stop().then(() => process.exit(0));
|
|
71
|
+
});
|
|
72
|
+
process.on("SIGTERM", () => {
|
|
73
|
+
void daemon.stop().then(() => process.exit(0));
|
|
74
|
+
});
|