@ouro.bot/cli 0.1.0-alpha.440 → 0.1.0-alpha.442
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 +16 -0
- package/dist/heart/daemon/cli-exec.js +11 -19
- package/dist/heart/daemon/cli-help.js +4 -4
- package/dist/heart/daemon/connect-bay.js +17 -18
- package/dist/heart/daemon/human-command-screens.js +15 -15
- package/dist/heart/daemon/terminal-ui.js +20 -23
- package/dist/heart/daemon/up-progress.js +3 -3
- package/dist/heart/identity.js +38 -2
- package/dist/repertoire/vault-unlock.js +160 -20
- package/package.json +1 -1
package/changelog.json
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
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.442",
|
|
6
|
+
"changes": [
|
|
7
|
+
"The shared CLI masthead now lands as a clean `OUROBOROS` wordmark instead of the older circle treatment, with compact/plain render paths trimmed down so the banner feels intentional rather than doubled or noisy.",
|
|
8
|
+
"The main human-facing screens now use warmer but more concrete first-run language: `ouro up`, the home screen, status, help, hatch, vault outcomes, and the connections screen now explain what Ouro is actually doing without leaning on unexplained `house` or `bay` metaphors.",
|
|
9
|
+
"Failed live provider checks in the connections screen now stay in the honest `needs attention` bucket instead of being downgraded to `needs credentials`, and hermetic runtime plus packaged-install coverage lock the wording into the shipped CLI."
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"version": "0.1.0-alpha.441",
|
|
14
|
+
"changes": [
|
|
15
|
+
"`ouro up` now lets the shared startup TUI own the masthead render path, so the screen no longer double-prints into scrollback and the shipped banner is a clean, correctly spelled classic `OUROBOROS` wordmark.",
|
|
16
|
+
"Vault unlock lookup now normalizes the canonical vault host while still reusing previously saved local unlock material from legacy vault coordinates, so a machine that already unlocked an agent vault does not get treated like it forgot after harmless vault-host drift.",
|
|
17
|
+
"macOS keychain read failures now surface as truthful local-store errors instead of being mislabeled as a locked vault, and new masthead/vault coverage plus packaged-install verification lock the fix into the shipped CLI."
|
|
18
|
+
]
|
|
19
|
+
},
|
|
4
20
|
{
|
|
5
21
|
"version": "0.1.0-alpha.440",
|
|
6
22
|
"changes": [
|
|
@@ -91,7 +91,6 @@ const agentic_repair_1 = require("./agentic-repair");
|
|
|
91
91
|
const readiness_repair_1 = require("./readiness-repair");
|
|
92
92
|
const human_readiness_1 = require("./human-readiness");
|
|
93
93
|
const human_command_screens_1 = require("./human-command-screens");
|
|
94
|
-
const terminal_ui_1 = require("./terminal-ui");
|
|
95
94
|
const startup_tui_1 = require("./startup-tui");
|
|
96
95
|
const stale_bundle_prune_1 = require("./stale-bundle-prune");
|
|
97
96
|
const up_progress_1 = require("./up-progress");
|
|
@@ -1212,7 +1211,7 @@ async function executeVaultUnlock(command, deps) {
|
|
|
1212
1211
|
{
|
|
1213
1212
|
title: "Next moves",
|
|
1214
1213
|
lines: [
|
|
1215
|
-
`Run ouro up
|
|
1214
|
+
`Run ouro up so Ouro can check ${command.agent} again.`,
|
|
1216
1215
|
`If credentials are still missing, run ouro auth --agent ${command.agent} --provider <provider>.`,
|
|
1217
1216
|
],
|
|
1218
1217
|
},
|
|
@@ -1282,7 +1281,7 @@ async function executeVaultCreate(command, deps) {
|
|
|
1282
1281
|
];
|
|
1283
1282
|
return writeCommandOutcome(deps, {
|
|
1284
1283
|
title: "Credential vault",
|
|
1285
|
-
subtitle: `${command.agent}
|
|
1284
|
+
subtitle: `${command.agent}'s credential vault is ready.`,
|
|
1286
1285
|
summary: `All raw credentials for ${command.agent} now live in this vault.`,
|
|
1287
1286
|
sections: [
|
|
1288
1287
|
{
|
|
@@ -1299,7 +1298,7 @@ async function executeVaultCreate(command, deps) {
|
|
|
1299
1298
|
title: "Next moves",
|
|
1300
1299
|
lines: [
|
|
1301
1300
|
`Authenticate the providers ${command.agent} should use with ouro auth --agent ${command.agent} --provider <provider>.`,
|
|
1302
|
-
`Then run ouro up so
|
|
1301
|
+
`Then run ouro up so Ouro can bring ${command.agent} online.`,
|
|
1303
1302
|
],
|
|
1304
1303
|
},
|
|
1305
1304
|
],
|
|
@@ -1494,7 +1493,7 @@ async function executeVaultRecover(command, deps) {
|
|
|
1494
1493
|
title: "Next moves",
|
|
1495
1494
|
lines: [
|
|
1496
1495
|
`Run ouro auth verify --agent ${command.agent} to re-check the stored providers.`,
|
|
1497
|
-
`Then run ouro up so
|
|
1496
|
+
`Then run ouro up so Ouro can check ${command.agent} again.`,
|
|
1498
1497
|
],
|
|
1499
1498
|
},
|
|
1500
1499
|
],
|
|
@@ -2000,7 +1999,7 @@ async function buildConnectMenu(agent, deps, onProgress) {
|
|
|
2000
1999
|
{
|
|
2001
2000
|
option: "1",
|
|
2002
2001
|
name: "Providers",
|
|
2003
|
-
section: "
|
|
2002
|
+
section: "Providers",
|
|
2004
2003
|
status: providerSummary.status,
|
|
2005
2004
|
detailLines: providerSummary.detailLines,
|
|
2006
2005
|
laneSummaries: providerSummary.laneSummaries,
|
|
@@ -2167,7 +2166,7 @@ async function executeConnectPerplexity(agent, deps) {
|
|
|
2167
2166
|
],
|
|
2168
2167
|
nextMoves: [
|
|
2169
2168
|
"Ask the agent to search.",
|
|
2170
|
-
`Reopen the
|
|
2169
|
+
`Reopen the connections screen with ouro connect --agent ${agent} whenever you want to review capabilities.`,
|
|
2171
2170
|
],
|
|
2172
2171
|
fallbackLines: [
|
|
2173
2172
|
`Perplexity connected for ${agent}`,
|
|
@@ -2248,7 +2247,7 @@ async function executeConnectEmbeddings(agent, deps) {
|
|
|
2248
2247
|
],
|
|
2249
2248
|
nextMoves: [
|
|
2250
2249
|
`Rerun ouro connect embeddings --agent ${agent} with a working key.`,
|
|
2251
|
-
`Use ouro connect --agent ${agent} to review the rest of the
|
|
2250
|
+
`Use ouro connect --agent ${agent} to review the rest of the connections screen.`,
|
|
2252
2251
|
],
|
|
2253
2252
|
fallbackLines: [
|
|
2254
2253
|
`Embeddings key was saved for ${agent}, but the live check failed.`,
|
|
@@ -2277,7 +2276,7 @@ async function executeConnectEmbeddings(agent, deps) {
|
|
|
2277
2276
|
],
|
|
2278
2277
|
nextMoves: [
|
|
2279
2278
|
"Ask the agent to search notes or memory.",
|
|
2280
|
-
`Reopen the
|
|
2279
|
+
`Reopen the connections screen with ouro connect --agent ${agent} whenever you want to review capabilities.`,
|
|
2281
2280
|
],
|
|
2282
2281
|
fallbackLines: [
|
|
2283
2282
|
`Embeddings connected for ${agent}`,
|
|
@@ -2372,7 +2371,7 @@ async function executeConnectTeams(agent, deps) {
|
|
|
2372
2371
|
],
|
|
2373
2372
|
nextMoves: [
|
|
2374
2373
|
"Run ouro up so the daemon picks up the Teams sense change.",
|
|
2375
|
-
`Reopen the
|
|
2374
|
+
`Reopen the connections screen with ouro connect --agent ${agent} whenever you want to review capabilities.`,
|
|
2376
2375
|
],
|
|
2377
2376
|
fallbackLines: [
|
|
2378
2377
|
`Teams connected for ${agent}`,
|
|
@@ -3933,13 +3932,6 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
3933
3932
|
}
|
|
3934
3933
|
const linkedVersionBeforeUp = deps.getCurrentCliVersion?.() ?? null;
|
|
3935
3934
|
const outputIsTTY = deps.isTTY ?? process.stdout.isTTY === true;
|
|
3936
|
-
if (outputIsTTY && deps.writeRaw) {
|
|
3937
|
-
deps.writeRaw(`${(0, terminal_ui_1.renderOuroMasthead)({
|
|
3938
|
-
isTTY: true,
|
|
3939
|
-
columns: deps.stdoutColumns ?? process.stdout.columns,
|
|
3940
|
-
subtitle: "Preparing the house.",
|
|
3941
|
-
}).trimEnd()}\n\n`);
|
|
3942
|
-
}
|
|
3943
3935
|
const progress = new up_progress_1.UpProgress({
|
|
3944
3936
|
write: deps.writeRaw ?? deps.writeStdout,
|
|
3945
3937
|
isTTY: outputIsTTY,
|
|
@@ -5387,7 +5379,7 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
5387
5379
|
if (ttyBoardEnabled(deps)) {
|
|
5388
5380
|
deps.writeStdout(renderCommandBoard(deps, {
|
|
5389
5381
|
title: "Hatch an agent",
|
|
5390
|
-
subtitle: "Let’s
|
|
5382
|
+
subtitle: "Let’s set up a new agent.",
|
|
5391
5383
|
summary: "Ouro will walk through the essentials, then hand the conversation to the specialist.",
|
|
5392
5384
|
sections: [
|
|
5393
5385
|
{
|
|
@@ -5438,7 +5430,7 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
5438
5430
|
lines: [
|
|
5439
5431
|
`Bundle: ${result.bundleRoot}`,
|
|
5440
5432
|
`Specialist identity: ${result.selectedIdentity}`,
|
|
5441
|
-
`
|
|
5433
|
+
`Runtime status: ${daemonResult.message}`,
|
|
5442
5434
|
],
|
|
5443
5435
|
},
|
|
5444
5436
|
{
|
|
@@ -14,7 +14,7 @@ exports.getCommandHelp = getCommandHelp;
|
|
|
14
14
|
exports.COMMAND_REGISTRY = {
|
|
15
15
|
up: {
|
|
16
16
|
category: "Lifecycle",
|
|
17
|
-
description: "
|
|
17
|
+
description: "Start and check Ouro: bring up the background runtime, refresh what this machine needs, and show anything that still needs attention. In a human TTY, bare `ouro` opens the home screen instead; noninteractive shells still route bare `ouro` to `ouro up`.",
|
|
18
18
|
usage: "ouro [up] [--no-repair]",
|
|
19
19
|
example: "ouro up --no-repair",
|
|
20
20
|
},
|
|
@@ -32,7 +32,7 @@ exports.COMMAND_REGISTRY = {
|
|
|
32
32
|
},
|
|
33
33
|
status: {
|
|
34
34
|
category: "Lifecycle",
|
|
35
|
-
description: "Show
|
|
35
|
+
description: "Show Ouro status for this machine",
|
|
36
36
|
usage: "ouro status",
|
|
37
37
|
example: "ouro status",
|
|
38
38
|
},
|
|
@@ -165,7 +165,7 @@ exports.COMMAND_REGISTRY = {
|
|
|
165
165
|
},
|
|
166
166
|
connect: {
|
|
167
167
|
category: "Auth",
|
|
168
|
-
description: "
|
|
168
|
+
description: "Set up providers, portable integrations, and local senses from one guided screen",
|
|
169
169
|
usage: "ouro connect [providers|perplexity|embeddings|teams|bluebubbles] [--agent <name>]",
|
|
170
170
|
example: "ouro connect",
|
|
171
171
|
subcommands: ["providers", "perplexity", "embeddings", "teams", "bluebubbles"],
|
|
@@ -278,7 +278,7 @@ const SUBCOMMAND_HELP = {
|
|
|
278
278
|
example: "ouro connect perplexity",
|
|
279
279
|
},
|
|
280
280
|
"connect providers": {
|
|
281
|
-
description: "Open provider
|
|
281
|
+
description: "Open provider setup from the connections screen without remembering the auth command",
|
|
282
282
|
usage: "ouro connect providers [--agent <name>]",
|
|
283
283
|
example: "ouro connect providers",
|
|
284
284
|
},
|
|
@@ -87,9 +87,8 @@ function resolveProviderHealthStatus(providerHealth) {
|
|
|
87
87
|
return "needs setup";
|
|
88
88
|
if (issue?.kind === "provider-credentials-missing")
|
|
89
89
|
return "needs credentials";
|
|
90
|
-
if (issue?.kind === "provider-live-check-failed")
|
|
91
|
-
return
|
|
92
|
-
}
|
|
90
|
+
if (issue?.kind === "provider-live-check-failed")
|
|
91
|
+
return "needs attention";
|
|
93
92
|
const error = String(providerHealth.error).toLowerCase();
|
|
94
93
|
const fix = String(providerHealth.fix).toLowerCase();
|
|
95
94
|
if (error.includes("failed live check"))
|
|
@@ -169,8 +168,8 @@ function panel(title, body, width) {
|
|
|
169
168
|
return lines;
|
|
170
169
|
}
|
|
171
170
|
function renderHeader(agent, width) {
|
|
172
|
-
return panel(`${agent}
|
|
173
|
-
tty("
|
|
171
|
+
return panel(`${agent} connections`, [
|
|
172
|
+
tty("Set up or review one capability at a time.", BONE, true),
|
|
174
173
|
tty("Everything on this screen was checked live just now.", MIST),
|
|
175
174
|
], width);
|
|
176
175
|
}
|
|
@@ -266,23 +265,23 @@ function renderTtyBay(entries, options) {
|
|
|
266
265
|
const masthead = (0, terminal_ui_1.renderOuroMasthead)({
|
|
267
266
|
isTTY: true,
|
|
268
267
|
columns,
|
|
269
|
-
subtitle: "
|
|
268
|
+
subtitle: "Set up connections one step at a time.",
|
|
270
269
|
}).trimEnd();
|
|
271
270
|
const header = renderHeader(options.agent, fullWidth);
|
|
272
271
|
const nextEntry = entries.find((entry) => isProblemStatus(entry.status));
|
|
273
|
-
const providerEntry = entries.find((entry) => entry.section === "
|
|
272
|
+
const providerEntry = entries.find((entry) => entry.section === "Providers");
|
|
274
273
|
const portableEntries = entries.filter((entry) => entry.section === "Portable");
|
|
275
274
|
const machineEntries = entries.filter((entry) => entry.section === "This machine");
|
|
276
275
|
const wide = columns >= 118;
|
|
277
276
|
const footer = [
|
|
278
|
-
tty("
|
|
277
|
+
tty("Choose a number, or type the capability name.", MIST),
|
|
279
278
|
options.prompt,
|
|
280
279
|
];
|
|
281
280
|
if (!wide) {
|
|
282
281
|
const panels = [
|
|
283
282
|
header,
|
|
284
|
-
panel("
|
|
285
|
-
panel("
|
|
283
|
+
panel("Recommended next step", nextMoveBody(nextEntry), fullWidth),
|
|
284
|
+
panel("Providers", renderProviderBody(providerEntry, fullWidth), fullWidth),
|
|
286
285
|
panel("Portable", renderCapabilityBody(portableEntries, fullWidth), fullWidth),
|
|
287
286
|
panel("This machine", renderCapabilityBody(machineEntries, fullWidth), fullWidth),
|
|
288
287
|
];
|
|
@@ -291,18 +290,18 @@ function renderTtyBay(entries, options) {
|
|
|
291
290
|
const gap = 2;
|
|
292
291
|
const leftWidth = Math.max(52, Math.floor((fullWidth - gap) / 2));
|
|
293
292
|
const rightWidth = Math.max(40, fullWidth - gap - leftWidth);
|
|
294
|
-
const topRow = combineColumns(panel("
|
|
295
|
-
const bottomRow = combineColumns(panel("
|
|
293
|
+
const topRow = combineColumns(panel("Recommended next step", nextMoveBody(nextEntry), leftWidth), panel("This machine", renderCapabilityBody(machineEntries, rightWidth), rightWidth), leftWidth, rightWidth, gap);
|
|
294
|
+
const bottomRow = combineColumns(panel("Providers", renderProviderBody(providerEntry, leftWidth), leftWidth), panel("Portable", renderCapabilityBody(portableEntries, rightWidth), rightWidth), leftWidth, rightWidth, gap);
|
|
296
295
|
return [masthead, "", ...header, "", ...topRow, "", ...bottomRow, "", ...footer].join("\n");
|
|
297
296
|
}
|
|
298
297
|
function renderNonTtyBay(entries, options) {
|
|
299
298
|
const nextEntry = entries.find((entry) => isProblemStatus(entry.status));
|
|
300
299
|
const lines = [
|
|
301
|
-
`${options.agent}
|
|
302
|
-
"
|
|
300
|
+
`${options.agent} connections`,
|
|
301
|
+
"Set up or review one capability at a time. Provider status was checked live just now.",
|
|
303
302
|
"",
|
|
304
|
-
"
|
|
305
|
-
"
|
|
303
|
+
"Recommended next step",
|
|
304
|
+
"---------------------",
|
|
306
305
|
];
|
|
307
306
|
if (!nextEntry) {
|
|
308
307
|
lines.push("Everything here is ready. Pick what you want to review or refresh.");
|
|
@@ -315,7 +314,7 @@ function renderNonTtyBay(entries, options) {
|
|
|
315
314
|
lines.push(`run: ${nextEntry.nextAction}`);
|
|
316
315
|
}
|
|
317
316
|
lines.push("");
|
|
318
|
-
for (const section of ["
|
|
317
|
+
for (const section of ["Providers", "Portable", "This machine"]) {
|
|
319
318
|
lines.push(section);
|
|
320
319
|
lines.push("-".repeat(Math.max(6, section.length + 4)));
|
|
321
320
|
for (const entry of entries.filter((candidate) => candidate.section === section)) {
|
|
@@ -338,7 +337,7 @@ function renderNonTtyBay(entries, options) {
|
|
|
338
337
|
}
|
|
339
338
|
lines.push("6. Not now");
|
|
340
339
|
lines.push("");
|
|
341
|
-
lines.push("
|
|
340
|
+
lines.push("Choose a number, or type the capability name.");
|
|
342
341
|
lines.push(options.prompt);
|
|
343
342
|
return lines.join("\n");
|
|
344
343
|
}
|
|
@@ -21,7 +21,7 @@ function renderScreenEvent(screen) {
|
|
|
21
21
|
function buildOuroHomeActions(agents) {
|
|
22
22
|
if (agents.length === 0) {
|
|
23
23
|
return [
|
|
24
|
-
{ key: "1", label: "
|
|
24
|
+
{ key: "1", label: "Create a new agent", kind: "hatch", command: "ouro hatch" },
|
|
25
25
|
{ key: "2", label: "Clone an existing bundle", kind: "clone", command: "ouro clone <remote>" },
|
|
26
26
|
{ key: "3", label: "Show help", kind: "help", command: "ouro --help" },
|
|
27
27
|
{ key: "4", label: "Exit", kind: "exit", command: "exit" },
|
|
@@ -36,9 +36,9 @@ function buildOuroHomeActions(agents) {
|
|
|
36
36
|
}));
|
|
37
37
|
return [
|
|
38
38
|
...actions,
|
|
39
|
-
{ key: String(actions.length + 1), label: "
|
|
40
|
-
{ key: String(actions.length + 2), label: "
|
|
41
|
-
{ key: String(actions.length + 3), label: "
|
|
39
|
+
{ key: String(actions.length + 1), label: "Start or check Ouro", kind: "up", command: "ouro up" },
|
|
40
|
+
{ key: String(actions.length + 2), label: "Set up connections", kind: "connect", command: "ouro connect --agent <agent>" },
|
|
41
|
+
{ key: String(actions.length + 3), label: "Fix setup issues", kind: "repair", command: "ouro repair --agent <agent>" },
|
|
42
42
|
{ key: String(actions.length + 4), label: "Show help", kind: "help", command: "ouro --help" },
|
|
43
43
|
{ key: String(actions.length + 5), label: "Exit", kind: "exit", command: "exit" },
|
|
44
44
|
];
|
|
@@ -60,10 +60,10 @@ function renderOuroHomeScreen(options) {
|
|
|
60
60
|
const actions = buildOuroHomeActions(options.agents);
|
|
61
61
|
const sections = [
|
|
62
62
|
{
|
|
63
|
-
title: options.agents.length === 0 ? "Start here" : "
|
|
63
|
+
title: options.agents.length === 0 ? "Start here" : "Available agents",
|
|
64
64
|
lines: options.agents.length === 0
|
|
65
|
-
? ["No agents are
|
|
66
|
-
: options.agents.map((agent) => `${agent} is
|
|
65
|
+
? ["No agents are set up on this machine yet."]
|
|
66
|
+
: options.agents.map((agent) => `${agent} is available.`),
|
|
67
67
|
},
|
|
68
68
|
];
|
|
69
69
|
const actionRows = actions.map((action, index) => ({
|
|
@@ -77,13 +77,13 @@ function renderOuroHomeScreen(options) {
|
|
|
77
77
|
columns: options.columns,
|
|
78
78
|
masthead: {
|
|
79
79
|
subtitle: options.agents.length === 0
|
|
80
|
-
? "No agents are
|
|
81
|
-
: "
|
|
80
|
+
? "No agents are set up on this machine yet."
|
|
81
|
+
: "Choose an agent or a setup task.",
|
|
82
82
|
},
|
|
83
83
|
title: "Ouro home",
|
|
84
84
|
summary: options.agents.length === 0
|
|
85
|
-
? "
|
|
86
|
-
: "Choose
|
|
85
|
+
? "Create a new agent or clone an existing bundle to get started."
|
|
86
|
+
: "Choose an agent or a setup task without memorizing commands.",
|
|
87
87
|
sections,
|
|
88
88
|
actions: actionRows,
|
|
89
89
|
prompt: `Choose [1-${actions.length}] or type a name: `,
|
|
@@ -159,7 +159,7 @@ function renderHouseStatusScreen(options) {
|
|
|
159
159
|
renderScreenEvent("house-status");
|
|
160
160
|
const sections = [
|
|
161
161
|
{
|
|
162
|
-
title: "
|
|
162
|
+
title: "Runtime",
|
|
163
163
|
lines: [
|
|
164
164
|
`Daemon: ${options.payload.overview.daemon}`,
|
|
165
165
|
`Health: ${options.payload.overview.health}`,
|
|
@@ -226,9 +226,9 @@ function renderHouseStatusScreen(options) {
|
|
|
226
226
|
});
|
|
227
227
|
}
|
|
228
228
|
return renderHumanCommandBoard({
|
|
229
|
-
title: "
|
|
230
|
-
subtitle: "
|
|
231
|
-
summary: "What is
|
|
229
|
+
title: "Ouro status",
|
|
230
|
+
subtitle: "Current runtime status for this machine.",
|
|
231
|
+
summary: "What is running, what is stopped, and what needs attention.",
|
|
232
232
|
isTTY: options.isTTY,
|
|
233
233
|
columns: options.columns,
|
|
234
234
|
sections,
|
|
@@ -17,6 +17,14 @@ const GLOW = "\x1b[38;2;74;227;108m";
|
|
|
17
17
|
const BONE = "\x1b[38;2;237;242;238m";
|
|
18
18
|
const MIST = "\x1b[38;2;154;174;159m";
|
|
19
19
|
const ANSI_RE = /\x1b\[[0-9;]*m/g;
|
|
20
|
+
const MASTHEAD_WORD = "OUROBOROS";
|
|
21
|
+
const CLASSIC_WORDMARK_GLYPHS = {
|
|
22
|
+
O: [" ___ ", " / _ \\ ", "| | | |", "| |_| |", " \\___/ "],
|
|
23
|
+
U: [" _ _ ", "| | | |", "| | | |", "| |_| |", " \\___/ "],
|
|
24
|
+
R: [" ____ ", "| _ \\ ", "| |_) |", "| _ < ", "|_| \\_\\"],
|
|
25
|
+
B: [" ____ ", "| __ ) ", "| _ \\ ", "| |_) |", "|____/ "],
|
|
26
|
+
S: [" ____ ", "/ ___| ", "\\___ \\ ", " ___) |", "|____/ "],
|
|
27
|
+
};
|
|
20
28
|
function color(text, tone, bold = false) {
|
|
21
29
|
if (!text)
|
|
22
30
|
return text;
|
|
@@ -87,37 +95,26 @@ function renderPanelPlain(title, lines) {
|
|
|
87
95
|
}
|
|
88
96
|
function mastheadArt(columns) {
|
|
89
97
|
if ((columns ?? 88) >= 74) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
" '------------------------'",
|
|
99
|
-
];
|
|
98
|
+
const rows = Array.from({ length: 5 }, () => []);
|
|
99
|
+
for (const letter of MASTHEAD_WORD.split("")) {
|
|
100
|
+
const glyph = CLASSIC_WORDMARK_GLYPHS[letter];
|
|
101
|
+
for (const [index, line] of glyph.entries()) {
|
|
102
|
+
rows[index].push(line);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return rows.map((row) => row.join(" "));
|
|
100
106
|
}
|
|
101
|
-
return [
|
|
102
|
-
" O U R O B O R O S",
|
|
103
|
-
" -----------------",
|
|
104
|
-
];
|
|
107
|
+
return [MASTHEAD_WORD];
|
|
105
108
|
}
|
|
106
109
|
function renderOuroMasthead(options) {
|
|
107
|
-
const lines = mastheadArt(options.columns);
|
|
108
|
-
const
|
|
109
|
-
const branded = [
|
|
110
|
-
...lines,
|
|
111
|
-
"OUROBOROS",
|
|
112
|
-
subtitle,
|
|
113
|
-
];
|
|
110
|
+
const lines = options.isTTY ? mastheadArt(options.columns) : [MASTHEAD_WORD];
|
|
111
|
+
const branded = options.subtitle ? [...lines, options.subtitle] : lines;
|
|
114
112
|
if (!options.isTTY) {
|
|
115
113
|
return `${branded.join("\n")}\n`;
|
|
116
114
|
}
|
|
117
115
|
const ttyLines = [
|
|
118
116
|
...lines.map((line, index) => color(line, index < 2 ? GLOW : SCALE, true)),
|
|
119
|
-
color(
|
|
120
|
-
color(subtitle, MIST),
|
|
117
|
+
...(options.subtitle ? [color(options.subtitle, MIST)] : []),
|
|
121
118
|
];
|
|
122
119
|
return `${ttyLines.join("\n")}\n`;
|
|
123
120
|
}
|
|
@@ -296,10 +296,10 @@ class UpProgress {
|
|
|
296
296
|
isTTY: true,
|
|
297
297
|
columns: this.columns,
|
|
298
298
|
masthead: {
|
|
299
|
-
subtitle: "
|
|
299
|
+
subtitle: "Starting the local agent runtime.",
|
|
300
300
|
},
|
|
301
|
-
title: "
|
|
302
|
-
summary: "Ouro is
|
|
301
|
+
title: "Starting Ouro",
|
|
302
|
+
summary: "Ouro is starting the background runtime, checking credentials, and surfacing anything that needs attention before chat begins.",
|
|
303
303
|
currentStep: {
|
|
304
304
|
label: currentStepLabel,
|
|
305
305
|
detailLines: currentStepDetails,
|
package/dist/heart/identity.js
CHANGED
|
@@ -33,7 +33,9 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.HARNESS_CANONICAL_REPO_URL = exports.DEFAULT_AGENT_SENSES = exports.DEFAULT_VAULT_SERVER_URL = exports.DEFAULT_AGENT_PHRASES = exports.DEFAULT_AGENT_CONTEXT = exports.PROVIDER_CREDENTIALS = void 0;
|
|
36
|
+
exports.HARNESS_CANONICAL_REPO_URL = exports.DEFAULT_AGENT_SENSES = exports.LEGACY_VAULT_SERVER_URL_ALIASES = exports.DEFAULT_VAULT_SERVER_URL = exports.DEFAULT_AGENT_PHRASES = exports.DEFAULT_AGENT_CONTEXT = exports.PROVIDER_CREDENTIALS = void 0;
|
|
37
|
+
exports.normalizeVaultServerUrl = normalizeVaultServerUrl;
|
|
38
|
+
exports.getVaultServerUrlCandidates = getVaultServerUrlCandidates;
|
|
37
39
|
exports.defaultStableVaultEmail = defaultStableVaultEmail;
|
|
38
40
|
exports.resolveVaultConfig = resolveVaultConfig;
|
|
39
41
|
exports.normalizeSenses = normalizeSenses;
|
|
@@ -77,6 +79,40 @@ exports.DEFAULT_AGENT_PHRASES = {
|
|
|
77
79
|
followup: ["processing"],
|
|
78
80
|
};
|
|
79
81
|
exports.DEFAULT_VAULT_SERVER_URL = "https://vault.ouroboros.bot";
|
|
82
|
+
exports.LEGACY_VAULT_SERVER_URL_ALIASES = [
|
|
83
|
+
"https://vault.ouro.bot",
|
|
84
|
+
"https://ouro-vault.gentleflower-74452a1e.eastus2.azurecontainerapps.io",
|
|
85
|
+
];
|
|
86
|
+
function normalizeVaultServerUrl(serverUrl) {
|
|
87
|
+
const trimmed = serverUrl.trim();
|
|
88
|
+
const withoutTrailingSlash = trimmed.replace(/\/+$/, "");
|
|
89
|
+
if (!withoutTrailingSlash) {
|
|
90
|
+
return exports.DEFAULT_VAULT_SERVER_URL;
|
|
91
|
+
}
|
|
92
|
+
if (exports.LEGACY_VAULT_SERVER_URL_ALIASES.includes(withoutTrailingSlash)) {
|
|
93
|
+
return exports.DEFAULT_VAULT_SERVER_URL;
|
|
94
|
+
}
|
|
95
|
+
return withoutTrailingSlash;
|
|
96
|
+
}
|
|
97
|
+
function getVaultServerUrlCandidates(serverUrl) {
|
|
98
|
+
const raw = serverUrl.trim();
|
|
99
|
+
const withoutTrailingSlash = raw.replace(/\/+$/, "");
|
|
100
|
+
const normalized = normalizeVaultServerUrl(serverUrl);
|
|
101
|
+
const candidates = [normalized];
|
|
102
|
+
for (const candidate of [withoutTrailingSlash, raw]) {
|
|
103
|
+
if (candidate && !candidates.includes(candidate)) {
|
|
104
|
+
candidates.push(candidate);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (normalized === exports.DEFAULT_VAULT_SERVER_URL) {
|
|
108
|
+
for (const alias of exports.LEGACY_VAULT_SERVER_URL_ALIASES) {
|
|
109
|
+
if (!candidates.includes(alias)) {
|
|
110
|
+
candidates.push(alias);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return candidates;
|
|
115
|
+
}
|
|
80
116
|
function defaultStableVaultEmail(agentName) {
|
|
81
117
|
const local = agentName
|
|
82
118
|
.toLowerCase()
|
|
@@ -91,7 +127,7 @@ function defaultStableVaultEmail(agentName) {
|
|
|
91
127
|
function resolveVaultConfig(agentName, config) {
|
|
92
128
|
return {
|
|
93
129
|
email: config?.email ?? defaultStableVaultEmail(agentName),
|
|
94
|
-
serverUrl: config?.serverUrl ?? exports.DEFAULT_VAULT_SERVER_URL,
|
|
130
|
+
serverUrl: normalizeVaultServerUrl(config?.serverUrl ?? exports.DEFAULT_VAULT_SERVER_URL),
|
|
95
131
|
};
|
|
96
132
|
}
|
|
97
133
|
exports.DEFAULT_AGENT_SENSES = {
|
|
@@ -48,6 +48,7 @@ const fs = __importStar(require("node:fs"));
|
|
|
48
48
|
const os = __importStar(require("node:os"));
|
|
49
49
|
const path = __importStar(require("node:path"));
|
|
50
50
|
const runtime_1 = require("../nerves/runtime");
|
|
51
|
+
const identity_1 = require("../heart/identity");
|
|
51
52
|
const VAULT_UNLOCK_SERVICE = "ouro.vault";
|
|
52
53
|
const CREDENTIAL_VAULT_NOT_CONFIGURED_PREFIX = "credential vault is not configured in ";
|
|
53
54
|
const PLAINTEXT_UNLOCK_DIR = path.join(".ouro-cli", "vault-unlock");
|
|
@@ -68,6 +69,19 @@ function vaultKey(config) {
|
|
|
68
69
|
function vaultLabel(config) {
|
|
69
70
|
return `${config.email} at ${config.serverUrl}`;
|
|
70
71
|
}
|
|
72
|
+
function canonicalizeVaultUnlockConfig(config) {
|
|
73
|
+
return {
|
|
74
|
+
...config,
|
|
75
|
+
serverUrl: (0, identity_1.normalizeVaultServerUrl)(config.serverUrl),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function vaultConfigCandidates(config) {
|
|
79
|
+
const canonical = canonicalizeVaultUnlockConfig(config);
|
|
80
|
+
return (0, identity_1.getVaultServerUrlCandidates)(config.serverUrl).map((serverUrl) => ({
|
|
81
|
+
...canonical,
|
|
82
|
+
serverUrl,
|
|
83
|
+
}));
|
|
84
|
+
}
|
|
71
85
|
function plaintextUnlockPath(config, deps) {
|
|
72
86
|
const digest = crypto.createHash("sha256").update(vaultKey(config)).digest("hex").slice(0, 24);
|
|
73
87
|
return path.join(homeDir(deps), PLAINTEXT_UNLOCK_DIR, `${digest}.secret`);
|
|
@@ -179,6 +193,7 @@ function validateStoreKind(store) {
|
|
|
179
193
|
return requested;
|
|
180
194
|
}
|
|
181
195
|
function resolveVaultUnlockStore(config, deps = {}) {
|
|
196
|
+
const canonicalConfig = canonicalizeVaultUnlockConfig(config);
|
|
182
197
|
const requested = validateStoreKind(deps.store);
|
|
183
198
|
const currentPlatform = platform(deps);
|
|
184
199
|
if (requested === "macos-keychain") {
|
|
@@ -200,33 +215,89 @@ function resolveVaultUnlockStore(config, deps = {}) {
|
|
|
200
215
|
if (currentPlatform !== "win32") {
|
|
201
216
|
throw new Error(`windows-dpapi unlock store is only available on Windows; this machine is ${currentPlatform}.`);
|
|
202
217
|
}
|
|
203
|
-
return { kind: "windows-dpapi", secure: true, location: windowsDpapiUnlockPath(
|
|
218
|
+
return { kind: "windows-dpapi", secure: true, location: windowsDpapiUnlockPath(canonicalConfig, deps) };
|
|
204
219
|
}
|
|
205
220
|
if (requested === "plaintext-file") {
|
|
206
|
-
return { kind: "plaintext-file", secure: false, location: plaintextUnlockPath(
|
|
221
|
+
return { kind: "plaintext-file", secure: false, location: plaintextUnlockPath(canonicalConfig, deps) };
|
|
207
222
|
}
|
|
208
223
|
if (currentPlatform === "darwin") {
|
|
209
224
|
return { kind: "macos-keychain", secure: true, location: "macOS Keychain" };
|
|
210
225
|
}
|
|
211
226
|
if (currentPlatform === "win32") {
|
|
212
|
-
return { kind: "windows-dpapi", secure: true, location: windowsDpapiUnlockPath(
|
|
227
|
+
return { kind: "windows-dpapi", secure: true, location: windowsDpapiUnlockPath(canonicalConfig, deps) };
|
|
213
228
|
}
|
|
214
229
|
if (currentPlatform === "linux" && commandExists("secret-tool", deps)) {
|
|
215
230
|
return { kind: "linux-secret-service", secure: true, location: "Secret Service via secret-tool" };
|
|
216
231
|
}
|
|
217
|
-
throw new Error(missingSecureStoreMessage(
|
|
232
|
+
throw new Error(missingSecureStoreMessage(canonicalConfig));
|
|
218
233
|
}
|
|
219
|
-
function
|
|
234
|
+
function readFromMacosKeychainExact(accountKey, deps) {
|
|
220
235
|
const result = spawnSync(deps)("security", [
|
|
221
236
|
"find-generic-password",
|
|
222
237
|
"-s",
|
|
223
238
|
VAULT_UNLOCK_SERVICE,
|
|
224
239
|
"-a",
|
|
225
|
-
|
|
240
|
+
accountKey,
|
|
226
241
|
"-w",
|
|
227
242
|
], { encoding: "utf8" });
|
|
228
243
|
const secret = typeof result.stdout === "string" ? result.stdout.trim() : "";
|
|
229
|
-
|
|
244
|
+
if (result.status === 0) {
|
|
245
|
+
return secret || null;
|
|
246
|
+
}
|
|
247
|
+
const stderr = typeof result.stderr === "string" ? result.stderr.trim() : "";
|
|
248
|
+
const error = result.error instanceof Error ? result.error.message : "";
|
|
249
|
+
const detail = stderr || error;
|
|
250
|
+
if (!detail || /could not be found in the keychain/i.test(detail)) {
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
throw new Error(`failed to read vault unlock secret from macOS Keychain: ${detail}`);
|
|
254
|
+
}
|
|
255
|
+
function noteVaultUnlockSelfHeal(config, storeKind, sourceServerUrl) {
|
|
256
|
+
(0, runtime_1.emitNervesEvent)({
|
|
257
|
+
component: "repertoire",
|
|
258
|
+
event: "repertoire.vault_unlock_self_healed",
|
|
259
|
+
message: "rewrote local unlock material using canonical vault coordinates",
|
|
260
|
+
meta: {
|
|
261
|
+
store: storeKind,
|
|
262
|
+
email: config.email,
|
|
263
|
+
sourceServerUrl,
|
|
264
|
+
targetServerUrl: config.serverUrl,
|
|
265
|
+
},
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
function warnVaultUnlockSelfHealFailure(config, storeKind, sourceServerUrl, error) {
|
|
269
|
+
(0, runtime_1.emitNervesEvent)({
|
|
270
|
+
level: "warn",
|
|
271
|
+
component: "repertoire",
|
|
272
|
+
event: "repertoire.vault_unlock_self_heal_failed",
|
|
273
|
+
message: "failed to rewrite local unlock material using canonical vault coordinates",
|
|
274
|
+
meta: {
|
|
275
|
+
store: storeKind,
|
|
276
|
+
email: config.email,
|
|
277
|
+
sourceServerUrl,
|
|
278
|
+
targetServerUrl: config.serverUrl,
|
|
279
|
+
error: error instanceof Error ? error.message : String(error),
|
|
280
|
+
},
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
function readFromMacosKeychain(config, deps) {
|
|
284
|
+
const candidates = vaultConfigCandidates(config);
|
|
285
|
+
for (const [index, candidate] of candidates.entries()) {
|
|
286
|
+
const secret = readFromMacosKeychainExact(vaultKey(candidate), deps);
|
|
287
|
+
if (!secret)
|
|
288
|
+
continue;
|
|
289
|
+
if (index > 0) {
|
|
290
|
+
try {
|
|
291
|
+
writeToMacosKeychain(config, secret, deps);
|
|
292
|
+
noteVaultUnlockSelfHeal(config, "macos-keychain", candidate.serverUrl);
|
|
293
|
+
}
|
|
294
|
+
catch (error) {
|
|
295
|
+
warnVaultUnlockSelfHealFailure(config, "macos-keychain", candidate.serverUrl, error);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return secret;
|
|
299
|
+
}
|
|
300
|
+
return null;
|
|
230
301
|
}
|
|
231
302
|
function writeToMacosKeychain(config, secret, deps) {
|
|
232
303
|
const result = spawnSync(deps)("security", [
|
|
@@ -244,16 +315,44 @@ function writeToMacosKeychain(config, secret, deps) {
|
|
|
244
315
|
throw new Error(`failed to store vault unlock secret in macOS Keychain${stderr ? `: ${stderr}` : ""}`);
|
|
245
316
|
}
|
|
246
317
|
}
|
|
247
|
-
function
|
|
318
|
+
function readFromLinuxSecretServiceExact(accountKey, deps) {
|
|
248
319
|
const result = spawnSync(deps)("secret-tool", [
|
|
249
320
|
"lookup",
|
|
250
321
|
"service",
|
|
251
322
|
VAULT_UNLOCK_SERVICE,
|
|
252
323
|
"account",
|
|
253
|
-
|
|
324
|
+
accountKey,
|
|
254
325
|
], { encoding: "utf8" });
|
|
255
326
|
const secret = typeof result.stdout === "string" ? result.stdout.trim() : "";
|
|
256
|
-
|
|
327
|
+
if (result.status === 0) {
|
|
328
|
+
return secret || null;
|
|
329
|
+
}
|
|
330
|
+
const stderr = typeof result.stderr === "string" ? result.stderr.trim() : "";
|
|
331
|
+
const error = result.error instanceof Error ? result.error.message : "";
|
|
332
|
+
const detail = stderr || error;
|
|
333
|
+
if (!detail || /not found/i.test(detail)) {
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
throw new Error(`failed to read vault unlock secret from Linux Secret Service: ${detail}`);
|
|
337
|
+
}
|
|
338
|
+
function readFromLinuxSecretService(config, deps) {
|
|
339
|
+
const candidates = vaultConfigCandidates(config);
|
|
340
|
+
for (const [index, candidate] of candidates.entries()) {
|
|
341
|
+
const secret = readFromLinuxSecretServiceExact(vaultKey(candidate), deps);
|
|
342
|
+
if (!secret)
|
|
343
|
+
continue;
|
|
344
|
+
if (index > 0) {
|
|
345
|
+
try {
|
|
346
|
+
writeToLinuxSecretService(config, secret, deps);
|
|
347
|
+
noteVaultUnlockSelfHeal(config, "linux-secret-service", candidate.serverUrl);
|
|
348
|
+
}
|
|
349
|
+
catch (error) {
|
|
350
|
+
warnVaultUnlockSelfHealFailure(config, "linux-secret-service", candidate.serverUrl, error);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return secret;
|
|
354
|
+
}
|
|
355
|
+
return null;
|
|
257
356
|
}
|
|
258
357
|
function writeToLinuxSecretService(config, secret, deps) {
|
|
259
358
|
const result = spawnSync(deps)("secret-tool", [
|
|
@@ -306,7 +405,7 @@ if ($payload.mode -eq "protect") {
|
|
|
306
405
|
}
|
|
307
406
|
return typeof result.stdout === "string" ? result.stdout : "";
|
|
308
407
|
}
|
|
309
|
-
function
|
|
408
|
+
function readFromWindowsDpapiExact(config, deps) {
|
|
310
409
|
const filePath = windowsDpapiUnlockPath(config, deps);
|
|
311
410
|
if (!fs.existsSync(filePath))
|
|
312
411
|
return null;
|
|
@@ -316,13 +415,32 @@ function readFromWindowsDpapi(config, deps) {
|
|
|
316
415
|
const secret = runWindowsDpapi("unprotect", { ciphertext }, deps).trim();
|
|
317
416
|
return secret || null;
|
|
318
417
|
}
|
|
418
|
+
function readFromWindowsDpapi(config, deps) {
|
|
419
|
+
const candidates = vaultConfigCandidates(config);
|
|
420
|
+
for (const [index, candidate] of candidates.entries()) {
|
|
421
|
+
const secret = readFromWindowsDpapiExact(candidate, deps);
|
|
422
|
+
if (!secret)
|
|
423
|
+
continue;
|
|
424
|
+
if (index > 0) {
|
|
425
|
+
try {
|
|
426
|
+
writeToWindowsDpapi(config, secret, deps);
|
|
427
|
+
noteVaultUnlockSelfHeal(config, "windows-dpapi", candidate.serverUrl);
|
|
428
|
+
}
|
|
429
|
+
catch (error) {
|
|
430
|
+
warnVaultUnlockSelfHealFailure(config, "windows-dpapi", candidate.serverUrl, error);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
return secret;
|
|
434
|
+
}
|
|
435
|
+
return null;
|
|
436
|
+
}
|
|
319
437
|
function writeToWindowsDpapi(config, secret, deps) {
|
|
320
438
|
const filePath = windowsDpapiUnlockPath(config, deps);
|
|
321
439
|
const ciphertext = runWindowsDpapi("protect", { secret }, deps).trim();
|
|
322
440
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
323
441
|
fs.writeFileSync(filePath, `${ciphertext}\n`, "utf8");
|
|
324
442
|
}
|
|
325
|
-
function
|
|
443
|
+
function readFromPlaintextFileExact(config, deps) {
|
|
326
444
|
const filePath = plaintextUnlockPath(config, deps);
|
|
327
445
|
if (!fs.existsSync(filePath))
|
|
328
446
|
return null;
|
|
@@ -335,6 +453,25 @@ function readFromPlaintextFile(config, deps) {
|
|
|
335
453
|
const secret = fs.readFileSync(filePath, "utf8").trim();
|
|
336
454
|
return secret || null;
|
|
337
455
|
}
|
|
456
|
+
function readFromPlaintextFile(config, deps) {
|
|
457
|
+
const candidates = vaultConfigCandidates(config);
|
|
458
|
+
for (const [index, candidate] of candidates.entries()) {
|
|
459
|
+
const secret = readFromPlaintextFileExact(candidate, deps);
|
|
460
|
+
if (!secret)
|
|
461
|
+
continue;
|
|
462
|
+
if (index > 0) {
|
|
463
|
+
try {
|
|
464
|
+
writeToPlaintextFile(config, secret, deps);
|
|
465
|
+
noteVaultUnlockSelfHeal(config, "plaintext-file", candidate.serverUrl);
|
|
466
|
+
}
|
|
467
|
+
catch (error) {
|
|
468
|
+
warnVaultUnlockSelfHealFailure(config, "plaintext-file", candidate.serverUrl, error);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
return secret;
|
|
472
|
+
}
|
|
473
|
+
return null;
|
|
474
|
+
}
|
|
338
475
|
function writeToPlaintextFile(config, secret, deps) {
|
|
339
476
|
const filePath = plaintextUnlockPath(config, deps);
|
|
340
477
|
fs.mkdirSync(path.dirname(filePath), { recursive: true, mode: 0o700 });
|
|
@@ -369,10 +506,11 @@ function writeToStore(config, store, secret, deps) {
|
|
|
369
506
|
writeToPlaintextFile(config, secret, deps);
|
|
370
507
|
}
|
|
371
508
|
function readVaultUnlockSecret(config, deps = {}) {
|
|
372
|
-
const
|
|
373
|
-
const
|
|
509
|
+
const canonicalConfig = canonicalizeVaultUnlockConfig(config);
|
|
510
|
+
const store = resolveVaultUnlockStore(canonicalConfig, deps);
|
|
511
|
+
const secret = readFromStore(canonicalConfig, store, deps);
|
|
374
512
|
if (!secret) {
|
|
375
|
-
throw new Error(lockedMessage(
|
|
513
|
+
throw new Error(lockedMessage(canonicalConfig, store));
|
|
376
514
|
}
|
|
377
515
|
(0, runtime_1.emitNervesEvent)({
|
|
378
516
|
component: "repertoire",
|
|
@@ -383,12 +521,13 @@ function readVaultUnlockSecret(config, deps = {}) {
|
|
|
383
521
|
return { secret, store };
|
|
384
522
|
}
|
|
385
523
|
function storeVaultUnlockSecret(config, secret, deps = {}) {
|
|
524
|
+
const canonicalConfig = canonicalizeVaultUnlockConfig(config);
|
|
386
525
|
const trimmed = secret.trim();
|
|
387
526
|
if (!trimmed) {
|
|
388
527
|
throw new Error("vault unlock secret is required");
|
|
389
528
|
}
|
|
390
|
-
const store = resolveVaultUnlockStore(
|
|
391
|
-
writeToStore(
|
|
529
|
+
const store = resolveVaultUnlockStore(canonicalConfig, deps);
|
|
530
|
+
writeToStore(canonicalConfig, store, trimmed, deps);
|
|
392
531
|
(0, runtime_1.emitNervesEvent)({
|
|
393
532
|
component: "repertoire",
|
|
394
533
|
event: "repertoire.vault_unlock_stored",
|
|
@@ -399,15 +538,16 @@ function storeVaultUnlockSecret(config, secret, deps = {}) {
|
|
|
399
538
|
}
|
|
400
539
|
function getVaultUnlockStatus(config, deps = {}) {
|
|
401
540
|
try {
|
|
402
|
-
const
|
|
403
|
-
const
|
|
541
|
+
const canonicalConfig = canonicalizeVaultUnlockConfig(config);
|
|
542
|
+
const store = resolveVaultUnlockStore(canonicalConfig, deps);
|
|
543
|
+
const stored = !!readFromStore(canonicalConfig, store, deps);
|
|
404
544
|
return {
|
|
405
545
|
configured: true,
|
|
406
546
|
stored,
|
|
407
547
|
store,
|
|
408
548
|
fix: stored
|
|
409
549
|
? "Vault unlock secret is available on this machine."
|
|
410
|
-
: lockedMessage(
|
|
550
|
+
: lockedMessage(canonicalConfig, store),
|
|
411
551
|
};
|
|
412
552
|
}
|
|
413
553
|
catch (error) {
|