@ouro.bot/cli 0.1.0-alpha.393 → 0.1.0-alpha.394

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/changelog.json CHANGED
@@ -1,6 +1,16 @@
1
1
  {
2
2
  "_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
3
3
  "versions": [
4
+ {
5
+ "version": "0.1.0-alpha.394",
6
+ "changes": [
7
+ "Added `ouro vault replace --agent <agent>` for existing pre-vault agents whose bundle has vault coordinates but no saved unlock secret and no local JSON credential export.",
8
+ "`ouro vault status --agent <agent>` now clearly reports when an existing agent has not configured a vault locator yet and points to `ouro vault create --agent <agent>` instead of implying an unlockable vault exists.",
9
+ "Locked-vault repair guidance now distinguishes saved-secret unlock, no-export replacement, and JSON-export recovery across provider checks, auth, provider refresh, vault config status, and vault unlock errors.",
10
+ "Interactive repair prompts now warn humans to run vault unlock only when they have the saved unlock secret, and docs explain how old auth-style agents continue by replacing the vault and re-entering credentials.",
11
+ "`@ouro.bot/cli` and the `ouro.bot` wrapper are version-synced for the pre-vault replacement repair release."
12
+ ]
13
+ },
4
14
  {
5
15
  "version": "0.1.0-alpha.393",
6
16
  "changes": [
@@ -49,6 +49,7 @@ const identity_1 = require("../identity");
49
49
  const migrate_config_1 = require("../migrate-config");
50
50
  const provider_models_1 = require("../provider-models");
51
51
  const provider_credentials_1 = require("../provider-credentials");
52
+ const vault_unlock_1 = require("../../repertoire/vault-unlock");
52
53
  const ANTHROPIC_SETUP_TOKEN_PREFIX = "sk-ant-oat01-";
53
54
  const ANTHROPIC_SETUP_TOKEN_MIN_LENGTH = 80;
54
55
  function assertPersistentProviderCredentialsAllowed(agentName) {
@@ -358,7 +359,7 @@ async function runRuntimeAuthFlow(input, deps = {}) {
358
359
  });
359
360
  const vault = await (0, provider_credentials_1.refreshProviderCredentialPool)(input.agentName);
360
361
  if (!vault.ok && vault.reason === "unavailable") {
361
- throw new Error(`${vault.error}\nRun \`ouro vault unlock --agent ${input.agentName}\`, then retry auth.`);
362
+ throw new Error(`${vault.error}\n${(0, vault_unlock_1.vaultUnlockReplaceRecoverFix)(input.agentName, `Then retry 'ouro auth --agent ${input.agentName} --provider ${input.provider}'.`)}`);
362
363
  }
363
364
  const credentials = await collectRuntimeAuthCredentials(input, deps);
364
365
  const { credentialPath } = await storeProviderCredentials(input.agentName, input.provider, credentials);
@@ -44,6 +44,7 @@ const provider_models_1 = require("../provider-models");
44
44
  const machine_identity_1 = require("../machine-identity");
45
45
  const provider_state_1 = require("../provider-state");
46
46
  const provider_credentials_1 = require("../provider-credentials");
47
+ const vault_unlock_1 = require("../../repertoire/vault-unlock");
47
48
  function isAgentProvider(value) {
48
49
  return Object.prototype.hasOwnProperty.call(identity_1.PROVIDER_CREDENTIALS, value);
49
50
  }
@@ -260,11 +261,7 @@ function isVaultLockedError(error) {
260
261
  return /(?:ouro )?credential vault is locked|vault(?: is)? locked/.test(normalized);
261
262
  }
262
263
  function vaultUnlockOrRecoverFix(agentName, nextStep = "Then run 'ouro up' again.") {
263
- return [
264
- `Run 'ouro vault unlock --agent ${agentName}' if you have the saved vault unlock secret.`,
265
- `If nobody saved it, run 'ouro vault recover --agent ${agentName} --from <json>' with a local credential export.`,
266
- nextStep,
267
- ].join(" ");
264
+ return (0, vault_unlock_1.vaultUnlockReplaceRecoverFix)(agentName, nextStep);
268
265
  }
269
266
  function failedPingResult(agentName, lane, provider, model, result) {
270
267
  return {
@@ -686,13 +686,19 @@ function readVaultRecoverSource(sourcePath) {
686
686
  runtimeConfig: recoverRuntimeConfig(parsed),
687
687
  };
688
688
  }
689
- function defaultRecoveredVaultEmail(agentName, now) {
689
+ function defaultReplacementVaultEmail(agentName, now, action) {
690
690
  const local = agentName
691
691
  .toLowerCase()
692
692
  .replace(/[^a-z0-9._-]+/g, "-")
693
693
  .replace(/^-+|-+$/g, "") || "agent";
694
694
  const stamp = now.toISOString().replace(/[-:.TZ]/g, "").slice(0, 14);
695
- return `${local}+recovered-${stamp}@ouro.bot`;
695
+ return `${local}+${action}-${stamp}@ouro.bot`;
696
+ }
697
+ function defaultRecoveredVaultEmail(agentName, now) {
698
+ return defaultReplacementVaultEmail(agentName, now, "recovered");
699
+ }
700
+ function defaultReplacedVaultEmail(agentName, now) {
701
+ return defaultReplacementVaultEmail(agentName, now, "replaced");
696
702
  }
697
703
  function ensureVaultSecretPrompt(promptSecret, action) {
698
704
  if (promptSecret)
@@ -702,6 +708,27 @@ function ensureVaultSecretPrompt(promptSecret, action) {
702
708
  function rejectGeneratedVaultUnlockSecret(action) {
703
709
  throw new Error(`vault ${action} no longer supports --generate-unlock-secret. Re-run without that flag and enter a human-chosen unlock secret; Ouro will not print vault unlock secrets.`);
704
710
  }
711
+ async function createReplacementVaultForAgent(input) {
712
+ const result = await (0, vault_setup_1.createVaultAccount)("Ouro credential vault", input.serverUrl, input.email, input.unlockSecret);
713
+ if (!result.success) {
714
+ const message = [
715
+ `vault ${input.action} failed for ${input.agentName}: ${result.error}`,
716
+ "",
717
+ "This creates a replacement vault. If that vault account already exists, retry with a fresh --email value.",
718
+ ].join("\n");
719
+ input.deps.writeStdout(message);
720
+ return { ok: false, message };
721
+ }
722
+ writeAgentVaultConfig(input.agentName, input.configPath, input.config, { email: input.email, serverUrl: input.serverUrl });
723
+ const store = (0, vault_unlock_1.storeVaultUnlockSecret)({
724
+ agentName: input.agentName,
725
+ email: input.email,
726
+ serverUrl: input.serverUrl,
727
+ }, input.unlockSecret, { homeDir: input.deps.homeDir, store: input.store });
728
+ (0, credential_access_1.resetCredentialStore)();
729
+ await (0, credential_access_1.getCredentialStore)(input.agentName).get("__ouro_vault_probe__");
730
+ return { ok: true, store };
731
+ }
705
732
  async function executeVaultUnlock(command, deps) {
706
733
  if (command.agent === "SerpentGuide") {
707
734
  throw new Error("SerpentGuide does not have a persistent credential vault. Hatch bootstrap uses selected provider credentials in memory only.");
@@ -773,6 +800,51 @@ async function executeVaultCreate(command, deps) {
773
800
  deps.writeStdout(message);
774
801
  return message;
775
802
  }
803
+ async function executeVaultReplace(command, deps) {
804
+ if (command.agent === "SerpentGuide") {
805
+ throw new Error("SerpentGuide does not have a persistent credential vault. Replace the hatchling agent vault, not SerpentGuide.");
806
+ }
807
+ if (command.generateUnlockSecret)
808
+ rejectGeneratedVaultUnlockSecret("replace");
809
+ const promptSecret = ensureVaultSecretPrompt(deps.promptSecret, "replace");
810
+ const now = providerCliNow(deps);
811
+ const { configPath, config } = (0, auth_flow_1.readAgentConfigForAgent)(command.agent, deps.bundlesRoot);
812
+ const configuredVault = (0, identity_1.resolveVaultConfig)(command.agent, config.vault);
813
+ const email = command.email ?? defaultReplacedVaultEmail(command.agent, now);
814
+ const serverUrl = command.serverUrl ?? config.vault?.serverUrl ?? configuredVault.serverUrl;
815
+ const unlockSecret = (await promptSecret(`Choose replacement Ouro vault unlock secret for ${email}: `)).trim();
816
+ if (!unlockSecret) {
817
+ throw new Error("vault replace requires a replacement unlock secret. Re-run in an interactive terminal and enter a human-chosen unlock secret.");
818
+ }
819
+ const replacement = await createReplacementVaultForAgent({
820
+ action: "replace",
821
+ agentName: command.agent,
822
+ email,
823
+ serverUrl,
824
+ unlockSecret,
825
+ store: command.store,
826
+ deps,
827
+ configPath,
828
+ config,
829
+ });
830
+ if (!replacement.ok)
831
+ return replacement.message;
832
+ const message = [
833
+ `vault replaced for ${command.agent}`,
834
+ `vault: ${email} at ${serverUrl}`,
835
+ `local unlock store: ${replacement.store.kind}${replacement.store.secure ? "" : " (explicit plaintext fallback)"}`,
836
+ "credentials imported: none",
837
+ "This is the no-export path for agents that predate vault auth or lost an unsaved unlock secret.",
838
+ "Re-auth/re-enter the credentials this agent should use:",
839
+ ` ouro auth --agent ${command.agent} --provider <provider>`,
840
+ ` ouro vault config set --agent ${command.agent} --key <field>`,
841
+ ` ouro provider refresh --agent ${command.agent}`,
842
+ ` ouro auth verify --agent ${command.agent}`,
843
+ "Keep the replacement vault unlock secret saved outside Ouro. Another machine will need it once.",
844
+ ].join("\n");
845
+ deps.writeStdout(message);
846
+ return message;
847
+ }
776
848
  async function executeVaultRecover(command, deps) {
777
849
  if (command.agent === "SerpentGuide") {
778
850
  throw new Error("SerpentGuide does not have a persistent credential vault. Recover the hatchling agent vault, not SerpentGuide.");
@@ -790,24 +862,19 @@ async function executeVaultRecover(command, deps) {
790
862
  if (!unlockSecret) {
791
863
  throw new Error("vault recover requires a replacement unlock secret. Re-run in an interactive terminal and enter a human-chosen unlock secret.");
792
864
  }
793
- const result = await (0, vault_setup_1.createVaultAccount)("Ouro credential vault", serverUrl, email, unlockSecret);
794
- if (!result.success) {
795
- const message = [
796
- `vault recover failed for ${command.agent}: ${result.error}`,
797
- "",
798
- "Recovery creates a replacement vault. If that vault account already exists, retry with a fresh --email value.",
799
- ].join("\n");
800
- deps.writeStdout(message);
801
- return message;
802
- }
803
- writeAgentVaultConfig(command.agent, configPath, config, { email, serverUrl });
804
- const store = (0, vault_unlock_1.storeVaultUnlockSecret)({
865
+ const replacement = await createReplacementVaultForAgent({
866
+ action: "recover",
805
867
  agentName: command.agent,
806
868
  email,
807
869
  serverUrl,
808
- }, unlockSecret, { homeDir: deps.homeDir, store: command.store });
809
- (0, credential_access_1.resetCredentialStore)();
810
- await (0, credential_access_1.getCredentialStore)(command.agent).get("__ouro_vault_probe__");
870
+ unlockSecret,
871
+ store: command.store,
872
+ deps,
873
+ configPath,
874
+ config,
875
+ });
876
+ if (!replacement.ok)
877
+ return replacement.message;
811
878
  const importedProviders = new Set();
812
879
  let mergedRuntimeConfig = {};
813
880
  for (const source of sourceImports) {
@@ -832,7 +899,7 @@ async function executeVaultRecover(command, deps) {
832
899
  const message = [
833
900
  `vault recovered for ${command.agent}`,
834
901
  `vault: ${email} at ${serverUrl}`,
835
- `local unlock store: ${store.kind}${store.secure ? "" : " (explicit plaintext fallback)"}`,
902
+ `local unlock store: ${replacement.store.kind}${replacement.store.secure ? "" : " (explicit plaintext fallback)"}`,
836
903
  `sources imported: ${sourceImports.length}`,
837
904
  `provider credentials imported: ${providerList.length === 0 ? "none" : providerList.join(", ")}`,
838
905
  `runtime credentials imported: ${runtimeFields.length === 0 ? "none" : runtimeFields.join(", ")}`,
@@ -850,6 +917,19 @@ async function executeVaultStatus(command, deps) {
850
917
  }
851
918
  const { config } = (0, auth_flow_1.readAgentConfigForAgent)(command.agent, deps.bundlesRoot);
852
919
  const vault = (0, identity_1.resolveVaultConfig)(command.agent, config.vault);
920
+ if (!config.vault) {
921
+ const lines = [
922
+ `agent: ${command.agent}`,
923
+ `vault: ${vault.email} at ${vault.serverUrl}`,
924
+ "vault locator: not configured in agent.json",
925
+ "local unlock: not checked",
926
+ "",
927
+ `fix: Run 'ouro vault create --agent ${command.agent}' to create this agent's vault, then run 'ouro auth --agent ${command.agent} --provider <provider>' and 'ouro provider refresh --agent ${command.agent}'.`,
928
+ ];
929
+ const message = lines.join("\n");
930
+ deps.writeStdout(message);
931
+ return message;
932
+ }
853
933
  const status = (0, vault_unlock_1.getVaultUnlockStatus)({
854
934
  agentName: command.agent,
855
935
  email: vault.email,
@@ -858,7 +938,7 @@ async function executeVaultStatus(command, deps) {
858
938
  const lines = [
859
939
  `agent: ${command.agent}`,
860
940
  `vault: ${vault.email} at ${vault.serverUrl}`,
861
- `vault locator: ${config.vault ? "agent.json" : "default"}`,
941
+ "vault locator: agent.json",
862
942
  `local unlock store: ${status.store ? `${status.store.kind}${status.store.secure ? "" : " (explicit plaintext fallback)"}` : "unavailable"}`,
863
943
  `local unlock: ${status.stored ? "available" : "missing"}`,
864
944
  ];
@@ -976,7 +1056,7 @@ async function executeVaultConfigStatus(command, deps) {
976
1056
  lines.push(`error: ${runtime.error}`);
977
1057
  lines.push(runtime.reason === "missing"
978
1058
  ? `fix: Run 'ouro vault config set --agent ${command.agent} --key <field>' to store runtime credentials.`
979
- : `fix: Run 'ouro vault unlock --agent ${command.agent}', then retry.`);
1059
+ : `fix: ${(0, vault_unlock_1.vaultUnlockReplaceRecoverFix)(command.agent, "Then retry 'ouro vault config status'.")}`);
980
1060
  }
981
1061
  const message = lines.join("\n");
982
1062
  deps.writeStdout(message);
@@ -1243,7 +1323,7 @@ async function executeProviderRefresh(command, deps) {
1243
1323
  }
1244
1324
  else {
1245
1325
  lines.push(`provider credential refresh failed for ${command.agent}: ${pool.error}`);
1246
- lines.push(`Run \`ouro vault unlock --agent ${command.agent}\`, then retry.`);
1326
+ lines.push((0, vault_unlock_1.vaultUnlockReplaceRecoverFix)(command.agent, "Then retry 'ouro provider refresh'."));
1247
1327
  const message = lines.join("\n");
1248
1328
  deps.writeStdout(message);
1249
1329
  return message;
@@ -2714,6 +2794,9 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
2714
2794
  if (command.kind === "vault.create") {
2715
2795
  return executeVaultCreate(command, deps);
2716
2796
  }
2797
+ if (command.kind === "vault.replace") {
2798
+ return executeVaultReplace(command, deps);
2799
+ }
2717
2800
  if (command.kind === "vault.recover") {
2718
2801
  return executeVaultRecover(command, deps);
2719
2802
  }
@@ -2761,7 +2844,7 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
2761
2844
  if (command.kind === "auth.verify") {
2762
2845
  const poolResult = await (0, provider_credentials_1.refreshProviderCredentialPool)(command.agent);
2763
2846
  if (!poolResult.ok) {
2764
- const message = `vault unavailable: ${poolResult.error}\nRun \`ouro vault unlock --agent ${command.agent}\`, then retry.`;
2847
+ const message = `vault unavailable: ${poolResult.error}\n${(0, vault_unlock_1.vaultUnlockReplaceRecoverFix)(command.agent, "Then retry 'ouro auth verify'.")}`;
2765
2848
  deps.writeStdout(message);
2766
2849
  return message;
2767
2850
  }
@@ -184,10 +184,10 @@ exports.COMMAND_REGISTRY = {
184
184
  },
185
185
  vault: {
186
186
  category: "Auth",
187
- description: "Create, recover, unlock, inspect, and populate the agent credential vault",
188
- usage: "ouro vault <create|recover|unlock|status|config> --agent <name>",
187
+ description: "Create, replace, recover, unlock, inspect, and populate the agent credential vault",
188
+ usage: "ouro vault <create|replace|recover|unlock|status|config> --agent <name>",
189
189
  example: "ouro vault status --agent ouroboros",
190
- subcommands: ["create", "recover", "unlock", "status", "config set", "config status"],
190
+ subcommands: ["create", "replace", "recover", "unlock", "status", "config set", "config status"],
191
191
  },
192
192
  thoughts: {
193
193
  category: "Internal",
@@ -269,6 +269,11 @@ const SUBCOMMAND_HELP = {
269
269
  usage: "ouro vault create --agent <name> --email <email> [--server <url>] [--store <store>]",
270
270
  example: "ouro vault create --agent ouroboros --email ouroboros@ouro.bot",
271
271
  },
272
+ "vault replace": {
273
+ description: "Create an empty replacement agent vault when no unlock secret or JSON export exists",
274
+ usage: "ouro vault replace --agent <name> [--email <email>] [--server <url>] [--store <store>]",
275
+ example: "ouro vault replace --agent ouroboros",
276
+ },
272
277
  "vault recover": {
273
278
  description: "Create a replacement agent vault and import local JSON credential exports",
274
279
  usage: "ouro vault recover --agent <name> --from <json> [--from <json>] [--email <email>] [--server <url>] [--store <store>]",
@@ -85,6 +85,7 @@ function usage() {
85
85
  " ouro auth verify --agent <name> [--provider <provider>]",
86
86
  " ouro auth switch --agent <name> --provider <provider>",
87
87
  " ouro vault create --agent <name> --email <email> [--server <url>] [--store <store>]",
88
+ " ouro vault replace --agent <name> [--email <email>] [--server <url>] [--store <store>]",
88
89
  " ouro vault recover --agent <name> --from <json> [--from <json>] [--email <email>] [--server <url>] [--store <store>]",
89
90
  " ouro vault unlock --agent <name> [--store auto|macos-keychain|windows-dpapi|linux-secret-service|plaintext-file]",
90
91
  " ouro vault status --agent <name> [--store auto|macos-keychain|windows-dpapi|linux-secret-service|plaintext-file]",
@@ -479,6 +480,9 @@ function parseVaultCommand(args) {
479
480
  continue;
480
481
  }
481
482
  if (token === "--from") {
483
+ if (sub !== "recover") {
484
+ throw new Error("--from is only valid with `ouro vault recover`; use `ouro vault replace` when there is no JSON export to import.");
485
+ }
482
486
  const value = rest[i + 1];
483
487
  if (!value)
484
488
  throw new Error("Usage: ouro vault recover --agent <name> --from <json> [--from <json>]");
@@ -490,10 +494,10 @@ function parseVaultCommand(args) {
490
494
  generateUnlockSecret = true;
491
495
  continue;
492
496
  }
493
- throw new Error("Usage: ouro vault create|recover|unlock|status --agent <name>");
497
+ throw new Error("Usage: ouro vault create|replace|recover|unlock|status --agent <name>");
494
498
  }
495
- if (!agent || (sub !== "create" && sub !== "recover" && sub !== "unlock" && sub !== "status")) {
496
- throw new Error("Usage: ouro vault create|recover|unlock|status --agent <name>");
499
+ if (!agent || (sub !== "create" && sub !== "replace" && sub !== "recover" && sub !== "unlock" && sub !== "status")) {
500
+ throw new Error("Usage: ouro vault create|replace|recover|unlock|status --agent <name>");
497
501
  }
498
502
  if (sub === "create") {
499
503
  return {
@@ -505,6 +509,16 @@ function parseVaultCommand(args) {
505
509
  ...(generateUnlockSecret ? { generateUnlockSecret: true } : {}),
506
510
  };
507
511
  }
512
+ if (sub === "replace") {
513
+ return {
514
+ kind: "vault.replace",
515
+ agent,
516
+ ...(email ? { email } : {}),
517
+ ...(serverUrl ? { serverUrl } : {}),
518
+ ...(store ? { store } : {}),
519
+ ...(generateUnlockSecret ? { generateUnlockSecret: true } : {}),
520
+ };
521
+ }
508
522
  if (sub === "recover") {
509
523
  if (sources.length === 0) {
510
524
  throw new Error("Usage: ouro vault recover --agent <name> --from <json> [--from <json>]");
@@ -63,6 +63,9 @@ function isAffirmativeAnswer(answer) {
63
63
  }
64
64
  function writeDeclinedRepair(degraded, command, deps) {
65
65
  deps.writeStdout(`repair skipped for ${degraded.agent}; run \`${command}\` later.`);
66
+ if (degraded.fixHint.includes("ouro vault replace") || degraded.fixHint.includes("ouro vault recover")) {
67
+ deps.writeStdout(`repair options for ${degraded.agent}: ${degraded.fixHint}`);
68
+ }
66
69
  }
67
70
  function runnableRepairActionFor(degraded) {
68
71
  if (isVaultUnlockIssue(degraded)) {
@@ -106,7 +109,7 @@ async function runInteractiveRepair(degraded, deps) {
106
109
  for (const entry of degraded) {
107
110
  const action = runnableRepairActionFor(entry);
108
111
  if (action?.kind === "vault-unlock") {
109
- const answer = await deps.promptInput(`run \`${action.command}\` now? [y/n] `);
112
+ const answer = await deps.promptInput(`run \`${action.command}\` now? Only say yes if you have the saved unlock secret. [y/n] `);
110
113
  if (isAffirmativeAnswer(answer)) {
111
114
  try {
112
115
  if (!deps.runVaultUnlock) {
@@ -99,7 +99,7 @@ function numberField(record, key, fallback) {
99
99
  function compactRuntimeConfigError(agent, error) {
100
100
  const compact = error.replace(/\s+/g, " ").trim();
101
101
  if (/credential vault is locked|vault locked|vault is locked/i.test(compact)) {
102
- return `vault locked; run 'ouro vault unlock --agent ${agent}'`;
102
+ return `vault locked; run 'ouro vault unlock --agent ${agent}' if you have the saved secret, or 'ouro vault replace --agent ${agent}' if none was saved`;
103
103
  }
104
104
  return compact || "unavailable";
105
105
  }
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.vaultUnlockReplaceRecoverFix = vaultUnlockReplaceRecoverFix;
36
37
  exports.resolveVaultUnlockStore = resolveVaultUnlockStore;
37
38
  exports.readVaultUnlockSecret = readVaultUnlockSecret;
38
39
  exports.storeVaultUnlockSecret = storeVaultUnlockSecret;
@@ -95,6 +96,23 @@ function missingSecureStoreMessage(config) {
95
96
  : "Run `ouro vault unlock --store plaintext-file` to store the vault unlock secret in a chmod 0600 local file.",
96
97
  ].join("\n");
97
98
  }
99
+ function vaultUnlockReplaceRecoverFix(agentName, nextStep = "Then run 'ouro up' again.") {
100
+ return [
101
+ `Run 'ouro vault unlock --agent ${agentName}' if you have the saved vault unlock secret.`,
102
+ `If this agent predates vault auth or nobody saved the unlock secret, run 'ouro vault replace --agent ${agentName}' to create a new empty vault, then re-auth/re-enter credentials.`,
103
+ `If you do have a local JSON credential export, run 'ouro vault recover --agent ${agentName} --from <json>' to create a replacement vault and import it.`,
104
+ nextStep,
105
+ ].join(" ");
106
+ }
107
+ function lostUnlockSecretGuidance(config) {
108
+ if (!config.agentName) {
109
+ return "If nobody saved that unlock secret, run `ouro vault replace --agent <agent>` to create a new empty vault and re-enter credentials. If you do have a local JSON credential export, run `ouro vault recover --agent <agent> --from <json>` to import it.";
110
+ }
111
+ return [
112
+ `If nobody saved that unlock secret, run \`ouro vault replace --agent ${config.agentName}\` to create a new empty vault and re-enter credentials.`,
113
+ `If you do have a local JSON credential export, run \`ouro vault recover --agent ${config.agentName} --from <json>\` to import it.`,
114
+ ].join(" ");
115
+ }
98
116
  function lockedMessage(config, store) {
99
117
  const agentPart = config.agentName ? ` for ${config.agentName}` : "";
100
118
  const command = config.agentName
@@ -111,9 +129,7 @@ function lockedMessage(config, store) {
111
129
  "This can happen on a new computer, after a local profile or hostname migration, or if the local unlock entry was removed.",
112
130
  "",
113
131
  `Run \`${command}\` and enter the saved agent vault unlock secret from the human/operator who controls that vault.`,
114
- config.agentName
115
- ? `If nobody saved that unlock secret, run \`ouro vault recover --agent ${config.agentName} --from <json>\` with a local credential export, or create a replacement vault and re-enter credentials.`
116
- : "If nobody saved that unlock secret, run `ouro vault recover --agent <agent> --from <json>` with a local credential export, or create a replacement vault and re-enter credentials.",
132
+ lostUnlockSecretGuidance(config),
117
133
  ].join("\n");
118
134
  }
119
135
  function validateStoreKind(store) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.393",
3
+ "version": "0.1.0-alpha.394",
4
4
  "main": "dist/heart/daemon/ouro-entry.js",
5
5
  "bin": {
6
6
  "cli": "dist/heart/daemon/ouro-bot-entry.js",