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