@ouro.bot/cli 0.1.0-alpha.7 → 0.1.0-alpha.9
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.
|
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.ensureDaemonRunning = ensureDaemonRunning;
|
|
37
37
|
exports.parseOuroCommand = parseOuroCommand;
|
|
38
|
+
exports.discoverExistingCredentials = discoverExistingCredentials;
|
|
38
39
|
exports.createDefaultOuroCliDeps = createDefaultOuroCliDeps;
|
|
39
40
|
exports.runOuroCli = runOuroCli;
|
|
40
41
|
const child_process_1 = require("child_process");
|
|
@@ -458,7 +459,61 @@ async function defaultLinkFriendIdentity(command) {
|
|
|
458
459
|
});
|
|
459
460
|
return `linked ${command.provider}:${command.externalId} to ${command.friendId}`;
|
|
460
461
|
}
|
|
461
|
-
|
|
462
|
+
function discoverExistingCredentials(secretsRoot) {
|
|
463
|
+
const found = [];
|
|
464
|
+
let entries;
|
|
465
|
+
try {
|
|
466
|
+
entries = fs.readdirSync(secretsRoot, { withFileTypes: true });
|
|
467
|
+
}
|
|
468
|
+
catch {
|
|
469
|
+
return found;
|
|
470
|
+
}
|
|
471
|
+
for (const entry of entries) {
|
|
472
|
+
if (!entry.isDirectory())
|
|
473
|
+
continue;
|
|
474
|
+
const secretsPath = path.join(secretsRoot, entry.name, "secrets.json");
|
|
475
|
+
let raw;
|
|
476
|
+
try {
|
|
477
|
+
raw = fs.readFileSync(secretsPath, "utf-8");
|
|
478
|
+
}
|
|
479
|
+
catch {
|
|
480
|
+
continue;
|
|
481
|
+
}
|
|
482
|
+
let parsed;
|
|
483
|
+
try {
|
|
484
|
+
parsed = JSON.parse(raw);
|
|
485
|
+
}
|
|
486
|
+
catch {
|
|
487
|
+
continue;
|
|
488
|
+
}
|
|
489
|
+
if (!parsed.providers)
|
|
490
|
+
continue;
|
|
491
|
+
for (const [provName, provConfig] of Object.entries(parsed.providers)) {
|
|
492
|
+
if (provName === "anthropic" && provConfig.setupToken) {
|
|
493
|
+
found.push({ agentName: entry.name, provider: "anthropic", credentials: { setupToken: provConfig.setupToken } });
|
|
494
|
+
}
|
|
495
|
+
else if (provName === "openai-codex" && provConfig.oauthAccessToken) {
|
|
496
|
+
found.push({ agentName: entry.name, provider: "openai-codex", credentials: { oauthAccessToken: provConfig.oauthAccessToken } });
|
|
497
|
+
}
|
|
498
|
+
else if (provName === "minimax" && provConfig.apiKey) {
|
|
499
|
+
found.push({ agentName: entry.name, provider: "minimax", credentials: { apiKey: provConfig.apiKey } });
|
|
500
|
+
}
|
|
501
|
+
else if (provName === "azure" && provConfig.apiKey && provConfig.endpoint && provConfig.deployment) {
|
|
502
|
+
found.push({ agentName: entry.name, provider: "azure", credentials: { apiKey: provConfig.apiKey, endpoint: provConfig.endpoint, deployment: provConfig.deployment } });
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
// Deduplicate by provider+credential value (keep first seen)
|
|
507
|
+
const seen = new Set();
|
|
508
|
+
return found.filter((cred) => {
|
|
509
|
+
const key = `${cred.provider}:${JSON.stringify(cred.credentials)}`;
|
|
510
|
+
if (seen.has(key))
|
|
511
|
+
return false;
|
|
512
|
+
seen.add(key);
|
|
513
|
+
return true;
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
/* v8 ignore next 79 -- integration: interactive terminal specialist session @preserve */
|
|
462
517
|
async function defaultRunAdoptionSpecialist() {
|
|
463
518
|
const readline = await Promise.resolve().then(() => __importStar(require("readline/promises")));
|
|
464
519
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -467,36 +522,79 @@ async function defaultRunAdoptionSpecialist() {
|
|
|
467
522
|
return answer.trim();
|
|
468
523
|
};
|
|
469
524
|
try {
|
|
470
|
-
const
|
|
471
|
-
const
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
525
|
+
const secretsRoot = path.join(os.homedir(), ".agentsecrets");
|
|
526
|
+
const discovered = discoverExistingCredentials(secretsRoot);
|
|
527
|
+
let providerRaw;
|
|
528
|
+
let credentials = {};
|
|
529
|
+
if (discovered.length > 0) {
|
|
530
|
+
process.stdout.write("\nwelcome to ouro. let's get you set up.\n");
|
|
531
|
+
process.stdout.write("i found existing API credentials:\n\n");
|
|
532
|
+
const unique = [...new Map(discovered.map((d) => [`${d.provider}`, d])).values()];
|
|
533
|
+
for (let i = 0; i < unique.length; i++) {
|
|
534
|
+
process.stdout.write(` ${i + 1}. ${unique[i].provider} (from ${unique[i].agentName})\n`);
|
|
535
|
+
}
|
|
536
|
+
process.stdout.write("\n");
|
|
537
|
+
const choice = await prompt("use one of these? enter number, or 'new' for a different key: ");
|
|
538
|
+
const idx = parseInt(choice, 10) - 1;
|
|
539
|
+
if (idx >= 0 && idx < unique.length) {
|
|
540
|
+
providerRaw = unique[idx].provider;
|
|
541
|
+
credentials = unique[idx].credentials;
|
|
542
|
+
}
|
|
543
|
+
else {
|
|
544
|
+
const pRaw = await prompt("provider (anthropic/azure/minimax/openai-codex): ");
|
|
545
|
+
if (!isAgentProvider(pRaw)) {
|
|
546
|
+
process.stdout.write("unknown provider. run `ouro hatch` to try again.\n");
|
|
547
|
+
rl.close();
|
|
548
|
+
return null;
|
|
549
|
+
}
|
|
550
|
+
providerRaw = pRaw;
|
|
551
|
+
if (providerRaw === "anthropic")
|
|
552
|
+
credentials.setupToken = await prompt("API key: ");
|
|
553
|
+
if (providerRaw === "openai-codex")
|
|
554
|
+
credentials.oauthAccessToken = await prompt("OAuth token: ");
|
|
555
|
+
if (providerRaw === "minimax")
|
|
556
|
+
credentials.apiKey = await prompt("API key: ");
|
|
557
|
+
if (providerRaw === "azure") {
|
|
558
|
+
credentials.apiKey = await prompt("API key: ");
|
|
559
|
+
credentials.endpoint = await prompt("endpoint: ");
|
|
560
|
+
credentials.deployment = await prompt("deployment: ");
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
else {
|
|
565
|
+
process.stdout.write("\nwelcome to ouro. let's get you set up.\n");
|
|
566
|
+
process.stdout.write("i need an API key to power our conversation.\n\n");
|
|
567
|
+
const pRaw = await prompt("provider (anthropic/azure/minimax/openai-codex): ");
|
|
568
|
+
if (!isAgentProvider(pRaw)) {
|
|
569
|
+
process.stdout.write("unknown provider. run `ouro hatch` to try again.\n");
|
|
570
|
+
rl.close();
|
|
571
|
+
return null;
|
|
572
|
+
}
|
|
573
|
+
providerRaw = pRaw;
|
|
574
|
+
if (providerRaw === "anthropic")
|
|
575
|
+
credentials.setupToken = await prompt("API key: ");
|
|
576
|
+
if (providerRaw === "openai-codex")
|
|
577
|
+
credentials.oauthAccessToken = await prompt("OAuth token: ");
|
|
578
|
+
if (providerRaw === "minimax")
|
|
579
|
+
credentials.apiKey = await prompt("API key: ");
|
|
580
|
+
if (providerRaw === "azure") {
|
|
581
|
+
credentials.apiKey = await prompt("API key: ");
|
|
582
|
+
credentials.endpoint = await prompt("endpoint: ");
|
|
583
|
+
credentials.deployment = await prompt("deployment: ");
|
|
584
|
+
}
|
|
487
585
|
}
|
|
488
586
|
rl.close();
|
|
587
|
+
process.stdout.write("\n");
|
|
489
588
|
// Locate the bundled AdoptionSpecialist.ouro shipped with the npm package
|
|
490
589
|
const bundleSourceDir = path.resolve(__dirname, "..", "..", "..", "AdoptionSpecialist.ouro");
|
|
491
590
|
const bundlesRoot = (0, identity_1.getAgentBundlesRoot)();
|
|
492
|
-
const secretsRoot = path.join(os.homedir(), ".agentsecrets");
|
|
493
591
|
return await (0, specialist_orchestrator_1.runAdoptionSpecialist)({
|
|
494
592
|
bundleSourceDir,
|
|
495
593
|
bundlesRoot,
|
|
496
594
|
secretsRoot,
|
|
497
595
|
provider: providerRaw,
|
|
498
596
|
credentials,
|
|
499
|
-
humanName,
|
|
597
|
+
humanName: os.userInfo().username,
|
|
500
598
|
createReadline: () => {
|
|
501
599
|
const rl2 = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
502
600
|
return { question: (q) => rl2.question(q), close: () => rl2.close() };
|
|
@@ -27,9 +27,16 @@ function buildSpecialistSystemPrompt(soulText, identityText, existingBundles) {
|
|
|
27
27
|
sections.push("## Existing agents\nThe human has no agents yet. This will be their first hatchling.");
|
|
28
28
|
}
|
|
29
29
|
sections.push([
|
|
30
|
+
"## Conversation flow",
|
|
31
|
+
"I start by warmly greeting the human and asking their name.",
|
|
32
|
+
"I then learn about what they want their agent to do — goals, personality, working style.",
|
|
33
|
+
"I keep the conversation natural and concise. I do not overwhelm with questions.",
|
|
34
|
+
"When I have enough context, I suggest a name for the hatchling and confirm with the human.",
|
|
35
|
+
"Then I call `hatch_agent` with the agent name and the human's name.",
|
|
36
|
+
"",
|
|
30
37
|
"## Tools",
|
|
31
38
|
"I have these tools available:",
|
|
32
|
-
"- `hatch_agent`: Create a new agent bundle. I call this with
|
|
39
|
+
"- `hatch_agent`: Create a new agent bundle. I call this with `name` (the agent name, PascalCase) and `humanName` (what the human told me their name is).",
|
|
33
40
|
"- `final_answer`: End the conversation with a final message to the human. I call this when the adoption process is complete.",
|
|
34
41
|
"- `read_file`: Read a file from disk. Useful for reviewing existing agent bundles or migration sources.",
|
|
35
42
|
"- `list_directory`: List directory contents. Useful for exploring existing agent bundles.",
|
|
@@ -52,8 +52,12 @@ const hatchAgentTool = {
|
|
|
52
52
|
type: "string",
|
|
53
53
|
description: "the name for the new agent (PascalCase, e.g. 'Slugger')",
|
|
54
54
|
},
|
|
55
|
+
humanName: {
|
|
56
|
+
type: "string",
|
|
57
|
+
description: "the human's preferred name, as they told you during conversation",
|
|
58
|
+
},
|
|
55
59
|
},
|
|
56
|
-
required: ["name"],
|
|
60
|
+
required: ["name", "humanName"],
|
|
57
61
|
},
|
|
58
62
|
},
|
|
59
63
|
};
|
|
@@ -83,7 +87,7 @@ async function execSpecialistTool(name, args, deps) {
|
|
|
83
87
|
}
|
|
84
88
|
const input = {
|
|
85
89
|
agentName,
|
|
86
|
-
humanName: deps.humanName,
|
|
90
|
+
humanName: args.humanName || deps.humanName,
|
|
87
91
|
provider: deps.provider,
|
|
88
92
|
credentials: deps.credentials,
|
|
89
93
|
};
|