@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
- /* v8 ignore next 49 -- integration: interactive terminal specialist session @preserve */
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 humanName = await prompt("Your name: ");
471
- const providerRaw = await prompt("Provider (azure|anthropic|minimax|openai-codex): ");
472
- if (!humanName || !isAgentProvider(providerRaw)) {
473
- process.stdout.write("Invalid input. Run `ouro hatch` to try again.\n");
474
- return null;
475
- }
476
- const credentials = {};
477
- if (providerRaw === "anthropic")
478
- credentials.setupToken = await prompt("Anthropic API key: ");
479
- if (providerRaw === "openai-codex")
480
- credentials.oauthAccessToken = await prompt("OpenAI Codex OAuth token: ");
481
- if (providerRaw === "minimax")
482
- credentials.apiKey = await prompt("MiniMax API key: ");
483
- if (providerRaw === "azure") {
484
- credentials.apiKey = await prompt("Azure API key: ");
485
- credentials.endpoint = await prompt("Azure endpoint: ");
486
- credentials.deployment = await prompt("Azure deployment: ");
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 a `name` parameter once I have enough information from the human.",
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
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.7",
3
+ "version": "0.1.0-alpha.9",
4
4
  "main": "dist/heart/daemon/ouro-entry.js",
5
5
  "bin": {
6
6
  "ouro": "dist/heart/daemon/ouro-entry.js",