@ouro.bot/cli 0.1.0-alpha.431 → 0.1.0-alpha.433
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-defaults.js +26 -4
- package/dist/heart/daemon/cli-exec.js +573 -168
- package/dist/heart/daemon/cli-help.js +6 -6
- package/dist/heart/daemon/human-command-screens.js +102 -6
- package/dist/heart/daemon/terminal-ui.js +67 -18
- package/dist/heart/daemon/up-progress.js +66 -24
- package/dist/heart/versioning/update-checker.js +2 -0
- package/package.json +1 -1
|
@@ -76,6 +76,7 @@ const provider_state_1 = require("../provider-state");
|
|
|
76
76
|
const machine_identity_1 = require("../machine-identity");
|
|
77
77
|
const provider_models_1 = require("../provider-models");
|
|
78
78
|
const ouro_version_manager_1 = require("../versioning/ouro-version-manager");
|
|
79
|
+
const update_checker_1 = require("../versioning/update-checker");
|
|
79
80
|
const sync_1 = require("../sync");
|
|
80
81
|
const cli_parse_1 = require("./cli-parse");
|
|
81
82
|
const cli_parse_2 = require("./cli-parse");
|
|
@@ -104,6 +105,55 @@ const DEFAULT_DAEMON_STARTUP_POLL_INTERVAL_MS = 500;
|
|
|
104
105
|
const DEFAULT_DAEMON_STARTUP_STABILITY_WINDOW_MS = 1_500;
|
|
105
106
|
const DEFAULT_DAEMON_STARTUP_RETRY_LIMIT = 1;
|
|
106
107
|
const DEFAULT_DAEMON_STARTUP_LOG_LINES = 10;
|
|
108
|
+
function summarizeCliUpdateCheckStatus(error, timedOut = false) {
|
|
109
|
+
const normalized = error.trim().toLowerCase();
|
|
110
|
+
if (timedOut || normalized.includes("timed out") || normalized.includes("abort")) {
|
|
111
|
+
return "skipped; registry did not answer";
|
|
112
|
+
}
|
|
113
|
+
if (normalized.includes("registry unavailable")) {
|
|
114
|
+
return "skipped; registry unavailable";
|
|
115
|
+
}
|
|
116
|
+
if (normalized.includes("network") ||
|
|
117
|
+
normalized.includes("fetch failed") ||
|
|
118
|
+
normalized.includes("enotfound") ||
|
|
119
|
+
normalized.includes("eai_again") ||
|
|
120
|
+
normalized.includes("econnreset")) {
|
|
121
|
+
return "skipped; registry unavailable";
|
|
122
|
+
}
|
|
123
|
+
return "skipped; update check unavailable";
|
|
124
|
+
}
|
|
125
|
+
async function runCliUpdateCheckWithTimeout(checkForCliUpdate, timeoutMs = update_checker_1.CLI_UPDATE_CHECK_TIMEOUT_MS) {
|
|
126
|
+
return await new Promise((resolve, reject) => {
|
|
127
|
+
let settled = false;
|
|
128
|
+
const timeoutId = setTimeout(() => {
|
|
129
|
+
settled = true;
|
|
130
|
+
resolve({
|
|
131
|
+
timedOut: true,
|
|
132
|
+
result: {
|
|
133
|
+
available: false,
|
|
134
|
+
error: `update check timed out after ${Math.max(1, Math.round(timeoutMs / 1000))}s`,
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
}, timeoutMs);
|
|
138
|
+
/* v8 ignore start -- Promise-settlement wiring is exercised by command tests; v8 misses these callback lines @preserve */
|
|
139
|
+
void checkForCliUpdate()
|
|
140
|
+
.then((result) => {
|
|
141
|
+
if (settled)
|
|
142
|
+
return;
|
|
143
|
+
settled = true;
|
|
144
|
+
clearTimeout(timeoutId);
|
|
145
|
+
resolve({ result, timedOut: false });
|
|
146
|
+
})
|
|
147
|
+
.catch((error) => {
|
|
148
|
+
if (settled)
|
|
149
|
+
return;
|
|
150
|
+
settled = true;
|
|
151
|
+
clearTimeout(timeoutId);
|
|
152
|
+
reject(error);
|
|
153
|
+
});
|
|
154
|
+
/* v8 ignore stop */
|
|
155
|
+
});
|
|
156
|
+
}
|
|
107
157
|
async function checkAgentProviders(deps, agentsOverride, onProgress) {
|
|
108
158
|
const agents = agentsOverride ?? await listCliAgents(deps);
|
|
109
159
|
const bundlesRoot = deps.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
|
|
@@ -376,15 +426,14 @@ function ttyBoardEnabled(deps) {
|
|
|
376
426
|
return deps.isTTY ?? process.stdout.isTTY === true;
|
|
377
427
|
}
|
|
378
428
|
function renderCommandBoard(deps, options) {
|
|
379
|
-
return (0,
|
|
380
|
-
isTTY: true,
|
|
381
|
-
columns: deps.stdoutColumns ?? process.stdout.columns,
|
|
382
|
-
masthead: {
|
|
383
|
-
subtitle: options.subtitle,
|
|
384
|
-
},
|
|
429
|
+
return (0, human_command_screens_1.renderHumanCommandBoard)({
|
|
385
430
|
title: options.title,
|
|
431
|
+
subtitle: options.subtitle,
|
|
386
432
|
summary: options.summary,
|
|
433
|
+
isTTY: true,
|
|
434
|
+
columns: deps.stdoutColumns ?? process.stdout.columns,
|
|
387
435
|
sections: options.sections,
|
|
436
|
+
actions: options.actions,
|
|
388
437
|
}).trimEnd();
|
|
389
438
|
}
|
|
390
439
|
function writeConnectorIntro(deps, options) {
|
|
@@ -398,6 +447,57 @@ function writeConnectorIntro(deps, options) {
|
|
|
398
447
|
: options.fallbackLines.join("\n");
|
|
399
448
|
deps.writeStdout(text);
|
|
400
449
|
}
|
|
450
|
+
function formatLocalUnlockStoreLine(store) {
|
|
451
|
+
return `local unlock store: ${store.kind}${store.secure ? "" : " (explicit plaintext fallback)"}`;
|
|
452
|
+
}
|
|
453
|
+
function writeCommandOutcome(deps, options) {
|
|
454
|
+
const message = ttyBoardEnabled(deps)
|
|
455
|
+
? renderCommandBoard(deps, {
|
|
456
|
+
title: options.title,
|
|
457
|
+
subtitle: options.subtitle,
|
|
458
|
+
summary: options.summary,
|
|
459
|
+
sections: options.sections,
|
|
460
|
+
})
|
|
461
|
+
: options.fallbackLines.join("\n");
|
|
462
|
+
deps.writeStdout(message);
|
|
463
|
+
return message;
|
|
464
|
+
}
|
|
465
|
+
function writeCapabilityOutcome(deps, options) {
|
|
466
|
+
return writeCommandOutcome(deps, {
|
|
467
|
+
title: "Capability connected",
|
|
468
|
+
subtitle: options.subtitle,
|
|
469
|
+
summary: options.summary,
|
|
470
|
+
sections: [
|
|
471
|
+
{
|
|
472
|
+
title: "What changed",
|
|
473
|
+
lines: options.whatChanged,
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
title: "Next moves",
|
|
477
|
+
lines: options.nextMoves,
|
|
478
|
+
},
|
|
479
|
+
],
|
|
480
|
+
fallbackLines: options.fallbackLines,
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
function writeCapabilityAttention(deps, options) {
|
|
484
|
+
return writeCommandOutcome(deps, {
|
|
485
|
+
title: "Capability needs attention",
|
|
486
|
+
subtitle: options.subtitle,
|
|
487
|
+
summary: options.summary,
|
|
488
|
+
sections: [
|
|
489
|
+
{
|
|
490
|
+
title: "What changed",
|
|
491
|
+
lines: options.whatChanged,
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
title: "Next moves",
|
|
495
|
+
lines: options.nextMoves,
|
|
496
|
+
},
|
|
497
|
+
],
|
|
498
|
+
fallbackLines: options.fallbackLines,
|
|
499
|
+
});
|
|
500
|
+
}
|
|
401
501
|
async function promptForNamedAgent(title, subtitle, agents, deps) {
|
|
402
502
|
if (!deps.promptInput)
|
|
403
503
|
throw new Error("agent selection requires interactive input");
|
|
@@ -906,10 +1006,6 @@ function pushAgentBundleAfterCliMutation(agent, deps) {
|
|
|
906
1006
|
}
|
|
907
1007
|
return `bundle sync: could not push bundle changes (${result.error})`;
|
|
908
1008
|
}
|
|
909
|
-
function appendBundleSyncSummary(message, agent, deps) {
|
|
910
|
-
const syncSummary = pushAgentBundleAfterCliMutation(agent, deps);
|
|
911
|
-
return syncSummary ? `${message}\n${syncSummary}` : message;
|
|
912
|
-
}
|
|
913
1009
|
function writeAgentVaultConfig(agentName, configPath, config, vault) {
|
|
914
1010
|
const nextConfig = {
|
|
915
1011
|
...config,
|
|
@@ -1094,13 +1190,34 @@ async function executeVaultUnlock(command, deps) {
|
|
|
1094
1190
|
finally {
|
|
1095
1191
|
progress.end();
|
|
1096
1192
|
}
|
|
1097
|
-
const
|
|
1193
|
+
const fallbackLines = [
|
|
1098
1194
|
`vault unlocked for ${command.agent} on this machine`,
|
|
1099
1195
|
`vault: ${vault.email} at ${vault.serverUrl}`,
|
|
1100
|
-
|
|
1101
|
-
]
|
|
1102
|
-
deps
|
|
1103
|
-
|
|
1196
|
+
formatLocalUnlockStoreLine(store),
|
|
1197
|
+
];
|
|
1198
|
+
return writeCommandOutcome(deps, {
|
|
1199
|
+
title: "Credential vault",
|
|
1200
|
+
subtitle: `${command.agent}'s vault is open on this machine again.`,
|
|
1201
|
+
summary: `This machine can now open ${command.agent}'s vault without re-entering the unlock secret every request.`,
|
|
1202
|
+
sections: [
|
|
1203
|
+
{
|
|
1204
|
+
title: "What changed",
|
|
1205
|
+
lines: [
|
|
1206
|
+
`Vault: ${vault.email} at ${vault.serverUrl}`,
|
|
1207
|
+
formatLocalUnlockStoreLine(store),
|
|
1208
|
+
"secret was not printed",
|
|
1209
|
+
],
|
|
1210
|
+
},
|
|
1211
|
+
{
|
|
1212
|
+
title: "Next moves",
|
|
1213
|
+
lines: [
|
|
1214
|
+
`Run ouro up to let the house retry ${command.agent}.`,
|
|
1215
|
+
`If credentials are still missing, run ouro auth --agent ${command.agent} --provider <provider>.`,
|
|
1216
|
+
],
|
|
1217
|
+
},
|
|
1218
|
+
],
|
|
1219
|
+
fallbackLines,
|
|
1220
|
+
});
|
|
1104
1221
|
}
|
|
1105
1222
|
async function executeVaultCreate(command, deps) {
|
|
1106
1223
|
if (command.agent === "SerpentGuide") {
|
|
@@ -1153,15 +1270,40 @@ async function executeVaultCreate(command, deps) {
|
|
|
1153
1270
|
/* v8 ignore next -- defensive: success path assigns store before continuing @preserve */
|
|
1154
1271
|
if (!store)
|
|
1155
1272
|
throw new Error(`vault create failed for ${command.agent}: local unlock material was not saved`);
|
|
1156
|
-
const
|
|
1273
|
+
const syncSummary = pushAgentBundleAfterCliMutation(command.agent, deps);
|
|
1274
|
+
const fallbackLines = [
|
|
1157
1275
|
`vault created for ${command.agent}`,
|
|
1158
1276
|
`vault: ${email} at ${serverUrl}`,
|
|
1159
|
-
|
|
1277
|
+
formatLocalUnlockStoreLine(store),
|
|
1160
1278
|
"All raw credentials for this agent will be stored in this Ouro credential vault.",
|
|
1161
1279
|
"Keep the vault unlock secret saved outside Ouro. Another machine will need it once.",
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
return
|
|
1280
|
+
...(syncSummary ? [syncSummary] : []),
|
|
1281
|
+
];
|
|
1282
|
+
return writeCommandOutcome(deps, {
|
|
1283
|
+
title: "Credential vault",
|
|
1284
|
+
subtitle: `${command.agent} has a vault home now.`,
|
|
1285
|
+
summary: `All raw credentials for ${command.agent} now live in this vault.`,
|
|
1286
|
+
sections: [
|
|
1287
|
+
{
|
|
1288
|
+
title: "What changed",
|
|
1289
|
+
lines: [
|
|
1290
|
+
`Vault: ${email} at ${serverUrl}`,
|
|
1291
|
+
formatLocalUnlockStoreLine(store),
|
|
1292
|
+
"This vault will hold provider and runtime credentials for the agent.",
|
|
1293
|
+
"secret was not printed",
|
|
1294
|
+
...(syncSummary ? [syncSummary] : []),
|
|
1295
|
+
],
|
|
1296
|
+
},
|
|
1297
|
+
{
|
|
1298
|
+
title: "Next moves",
|
|
1299
|
+
lines: [
|
|
1300
|
+
`Authenticate the providers ${command.agent} should use with ouro auth --agent ${command.agent} --provider <provider>.`,
|
|
1301
|
+
`Then run ouro up so the house can bring ${command.agent} online.`,
|
|
1302
|
+
],
|
|
1303
|
+
},
|
|
1304
|
+
],
|
|
1305
|
+
fallbackLines,
|
|
1306
|
+
});
|
|
1165
1307
|
}
|
|
1166
1308
|
async function executeVaultReplace(command, deps) {
|
|
1167
1309
|
if (command.agent === "SerpentGuide") {
|
|
@@ -1204,16 +1346,42 @@ async function executeVaultReplace(command, deps) {
|
|
|
1204
1346
|
throw new Error(`vault replace failed for ${command.agent}: no vault repair result`);
|
|
1205
1347
|
if (!repair.ok)
|
|
1206
1348
|
return repair.message;
|
|
1207
|
-
const
|
|
1349
|
+
const syncSummary = pushAgentBundleAfterCliMutation(command.agent, deps);
|
|
1350
|
+
const fallbackLines = [
|
|
1208
1351
|
`vault replaced for ${command.agent}`,
|
|
1209
1352
|
`vault: ${email} at ${serverUrl}`,
|
|
1210
|
-
|
|
1353
|
+
formatLocalUnlockStoreLine(repair.store),
|
|
1211
1354
|
"imported: none",
|
|
1212
1355
|
`next: ouro repair --agent ${command.agent}`,
|
|
1213
1356
|
"Keep the vault unlock secret saved outside Ouro. Another machine will need it once.",
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
return
|
|
1357
|
+
...(syncSummary ? [syncSummary] : []),
|
|
1358
|
+
];
|
|
1359
|
+
return writeCommandOutcome(deps, {
|
|
1360
|
+
title: "Credential vault",
|
|
1361
|
+
subtitle: `${command.agent} has a fresh vault.`,
|
|
1362
|
+
summary: `${command.agent} now has a fresh empty vault.`,
|
|
1363
|
+
sections: [
|
|
1364
|
+
{
|
|
1365
|
+
title: "What changed",
|
|
1366
|
+
lines: [
|
|
1367
|
+
`Vault: ${email} at ${serverUrl}`,
|
|
1368
|
+
formatLocalUnlockStoreLine(repair.store),
|
|
1369
|
+
"Imported: none",
|
|
1370
|
+
"secret was not printed",
|
|
1371
|
+
...(syncSummary ? [syncSummary] : []),
|
|
1372
|
+
],
|
|
1373
|
+
},
|
|
1374
|
+
{
|
|
1375
|
+
title: "Next moves",
|
|
1376
|
+
lines: [
|
|
1377
|
+
`Re-enter provider credentials with ouro auth --agent ${command.agent} --provider <provider>.`,
|
|
1378
|
+
`Re-enter runtime secrets with ouro connect --agent ${command.agent} or ouro vault config set --agent ${command.agent} --key <field>.`,
|
|
1379
|
+
`Then run ouro repair --agent ${command.agent} or ouro up.`,
|
|
1380
|
+
],
|
|
1381
|
+
},
|
|
1382
|
+
],
|
|
1383
|
+
fallbackLines,
|
|
1384
|
+
});
|
|
1217
1385
|
}
|
|
1218
1386
|
async function executeVaultRecover(command, deps) {
|
|
1219
1387
|
if (command.agent === "SerpentGuide") {
|
|
@@ -1290,19 +1458,47 @@ async function executeVaultRecover(command, deps) {
|
|
|
1290
1458
|
progress.end();
|
|
1291
1459
|
}
|
|
1292
1460
|
const providerList = [...importedProviders].sort();
|
|
1293
|
-
const
|
|
1461
|
+
const syncSummary = pushAgentBundleAfterCliMutation(command.agent, deps);
|
|
1462
|
+
const fallbackLines = [
|
|
1294
1463
|
`vault recovered for ${command.agent}`,
|
|
1295
1464
|
`vault: ${email} at ${serverUrl}`,
|
|
1296
|
-
|
|
1465
|
+
formatLocalUnlockStoreLine(repair.store),
|
|
1297
1466
|
`sources imported: ${sourceImports.length}`,
|
|
1298
1467
|
`provider credentials imported: ${providerList.length === 0 ? "none" : providerList.join(", ")}`,
|
|
1299
1468
|
`runtime credentials imported: ${runtimeFields.length === 0 ? "none" : runtimeFields.join(", ")}`,
|
|
1300
1469
|
`machine runtime credentials imported: ${machineRuntimeFields.length === 0 ? "none" : machineRuntimeFields.join(", ")}`,
|
|
1301
1470
|
"credential values were not printed",
|
|
1302
1471
|
"Keep the vault unlock secret saved outside Ouro. Another machine will need it once.",
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
return
|
|
1472
|
+
...(syncSummary ? [syncSummary] : []),
|
|
1473
|
+
];
|
|
1474
|
+
return writeCommandOutcome(deps, {
|
|
1475
|
+
title: "Credential vault",
|
|
1476
|
+
subtitle: `${command.agent}'s vault is back in service.`,
|
|
1477
|
+
summary: `Recovered credentials have been moved back into ${command.agent}'s vault.`,
|
|
1478
|
+
sections: [
|
|
1479
|
+
{
|
|
1480
|
+
title: "What changed",
|
|
1481
|
+
lines: [
|
|
1482
|
+
`Vault: ${email} at ${serverUrl}`,
|
|
1483
|
+
formatLocalUnlockStoreLine(repair.store),
|
|
1484
|
+
`Sources imported: ${sourceImports.length}`,
|
|
1485
|
+
`Provider credentials: ${providerList.length === 0 ? "none" : providerList.join(", ")}`,
|
|
1486
|
+
`Runtime credentials: ${runtimeFields.length === 0 ? "none" : runtimeFields.join(", ")}`,
|
|
1487
|
+
`Machine runtime credentials: ${machineRuntimeFields.length === 0 ? "none" : machineRuntimeFields.join(", ")}`,
|
|
1488
|
+
"secret was not printed",
|
|
1489
|
+
...(syncSummary ? [syncSummary] : []),
|
|
1490
|
+
],
|
|
1491
|
+
},
|
|
1492
|
+
{
|
|
1493
|
+
title: "Next moves",
|
|
1494
|
+
lines: [
|
|
1495
|
+
`Run ouro auth verify --agent ${command.agent} to re-check the stored providers.`,
|
|
1496
|
+
`Then run ouro up so the house can retry ${command.agent}.`,
|
|
1497
|
+
],
|
|
1498
|
+
},
|
|
1499
|
+
],
|
|
1500
|
+
fallbackLines,
|
|
1501
|
+
});
|
|
1306
1502
|
}
|
|
1307
1503
|
async function executeVaultStatus(command, deps) {
|
|
1308
1504
|
if (command.agent === "SerpentGuide") {
|
|
@@ -1931,16 +2127,27 @@ async function executeConnectPerplexity(agent, deps) {
|
|
|
1931
2127
|
if (!verification.ok) {
|
|
1932
2128
|
progress.failPhase("verifying Perplexity search", verification.summary);
|
|
1933
2129
|
progress.end();
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
2130
|
+
return writeCapabilityAttention(deps, {
|
|
2131
|
+
subtitle: `${agent}'s Perplexity key needs another pass.`,
|
|
2132
|
+
summary: "Perplexity search was saved, but the live check failed.",
|
|
2133
|
+
whatChanged: [
|
|
2134
|
+
`Stored: ${stored.itemPath}`,
|
|
2135
|
+
`Live check: ${verification.summary}`,
|
|
2136
|
+
"secret was not printed",
|
|
2137
|
+
],
|
|
2138
|
+
nextMoves: [
|
|
2139
|
+
`Rerun ouro connect perplexity --agent ${agent} with a working key.`,
|
|
2140
|
+
`Use ouro connect --agent ${agent} to review the rest of the capability bay.`,
|
|
2141
|
+
],
|
|
2142
|
+
fallbackLines: [
|
|
2143
|
+
`Perplexity key was saved for ${agent}, but the live check failed.`,
|
|
2144
|
+
`stored: ${stored.itemPath}`,
|
|
2145
|
+
`live check: ${verification.summary}`,
|
|
2146
|
+
"secret was not printed",
|
|
2147
|
+
"",
|
|
2148
|
+
`Next: rerun \`ouro connect perplexity --agent ${agent}\` with a working key.`,
|
|
2149
|
+
],
|
|
2150
|
+
});
|
|
1944
2151
|
}
|
|
1945
2152
|
progress.completePhase("verifying Perplexity search", verification.summary);
|
|
1946
2153
|
reload = await runCommandProgressPhase(progress, `applying change to running ${agent}`, () => applyRuntimeChangeToRunningAgent(agent, deps, (message) => progress.updateDetail(message)), (result) => result);
|
|
@@ -1948,17 +2155,29 @@ async function executeConnectPerplexity(agent, deps) {
|
|
|
1948
2155
|
finally {
|
|
1949
2156
|
progress.end();
|
|
1950
2157
|
}
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
2158
|
+
return writeCapabilityOutcome(deps, {
|
|
2159
|
+
subtitle: `${agent}'s search compass is online.`,
|
|
2160
|
+
summary: `Perplexity search is ready to travel with ${agent}.`,
|
|
2161
|
+
whatChanged: [
|
|
2162
|
+
`Capability: Perplexity search`,
|
|
2163
|
+
`Stored: ${stored.itemPath}`,
|
|
2164
|
+
`Running agent: ${reload}`,
|
|
2165
|
+
"secret was not printed",
|
|
2166
|
+
],
|
|
2167
|
+
nextMoves: [
|
|
2168
|
+
"Ask the agent to search.",
|
|
2169
|
+
`Reopen the connect bay with ouro connect --agent ${agent} whenever you want to review capabilities.`,
|
|
2170
|
+
],
|
|
2171
|
+
fallbackLines: [
|
|
2172
|
+
`Perplexity connected for ${agent}`,
|
|
2173
|
+
"capability: Perplexity search",
|
|
2174
|
+
`stored: ${stored.itemPath}`,
|
|
2175
|
+
`running agent: ${reload}`,
|
|
2176
|
+
"secret was not printed",
|
|
2177
|
+
"",
|
|
2178
|
+
"Next: ask the agent to search.",
|
|
2179
|
+
],
|
|
2180
|
+
});
|
|
1962
2181
|
}
|
|
1963
2182
|
async function executeConnectEmbeddings(agent, deps) {
|
|
1964
2183
|
if (agent === "SerpentGuide") {
|
|
@@ -2018,16 +2237,27 @@ async function executeConnectEmbeddings(agent, deps) {
|
|
|
2018
2237
|
if (!verification.ok) {
|
|
2019
2238
|
progress.failPhase("verifying memory embeddings", verification.summary);
|
|
2020
2239
|
progress.end();
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2240
|
+
return writeCapabilityAttention(deps, {
|
|
2241
|
+
subtitle: `${agent}'s memory key needs another pass.`,
|
|
2242
|
+
summary: "Memory embeddings were saved, but the live check failed.",
|
|
2243
|
+
whatChanged: [
|
|
2244
|
+
`Stored: ${stored.itemPath}`,
|
|
2245
|
+
`Live check: ${verification.summary}`,
|
|
2246
|
+
"secret was not printed",
|
|
2247
|
+
],
|
|
2248
|
+
nextMoves: [
|
|
2249
|
+
`Rerun ouro connect embeddings --agent ${agent} with a working key.`,
|
|
2250
|
+
`Use ouro connect --agent ${agent} to review the rest of the capability bay.`,
|
|
2251
|
+
],
|
|
2252
|
+
fallbackLines: [
|
|
2253
|
+
`Embeddings key was saved for ${agent}, but the live check failed.`,
|
|
2254
|
+
`stored: ${stored.itemPath}`,
|
|
2255
|
+
`live check: ${verification.summary}`,
|
|
2256
|
+
"secret was not printed",
|
|
2257
|
+
"",
|
|
2258
|
+
`Next: rerun \`ouro connect embeddings --agent ${agent}\` with a working key.`,
|
|
2259
|
+
],
|
|
2260
|
+
});
|
|
2031
2261
|
}
|
|
2032
2262
|
progress.completePhase("verifying memory embeddings", verification.summary);
|
|
2033
2263
|
reload = await runCommandProgressPhase(progress, `applying change to running ${agent}`, () => applyRuntimeChangeToRunningAgent(agent, deps, (message) => progress.updateDetail(message)), (result) => result);
|
|
@@ -2035,17 +2265,29 @@ async function executeConnectEmbeddings(agent, deps) {
|
|
|
2035
2265
|
finally {
|
|
2036
2266
|
progress.end();
|
|
2037
2267
|
}
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2268
|
+
return writeCapabilityOutcome(deps, {
|
|
2269
|
+
subtitle: `${agent}'s memory index is online.`,
|
|
2270
|
+
summary: `Memory embeddings are ready to travel with ${agent}.`,
|
|
2271
|
+
whatChanged: [
|
|
2272
|
+
"Capability: memory embeddings",
|
|
2273
|
+
`Stored: ${stored.itemPath}`,
|
|
2274
|
+
`Running agent: ${reload}`,
|
|
2275
|
+
"secret was not printed",
|
|
2276
|
+
],
|
|
2277
|
+
nextMoves: [
|
|
2278
|
+
"Ask the agent to search notes or memory.",
|
|
2279
|
+
`Reopen the connect bay with ouro connect --agent ${agent} whenever you want to review capabilities.`,
|
|
2280
|
+
],
|
|
2281
|
+
fallbackLines: [
|
|
2282
|
+
`Embeddings connected for ${agent}`,
|
|
2283
|
+
"capability: memory embeddings",
|
|
2284
|
+
`stored: ${stored.itemPath}`,
|
|
2285
|
+
`running agent: ${reload}`,
|
|
2286
|
+
"secret was not printed",
|
|
2287
|
+
"",
|
|
2288
|
+
"Next: ask the agent to search notes or memory.",
|
|
2289
|
+
],
|
|
2290
|
+
});
|
|
2049
2291
|
}
|
|
2050
2292
|
async function executeConnectTeams(agent, deps) {
|
|
2051
2293
|
if (agent === "SerpentGuide") {
|
|
@@ -2053,11 +2295,38 @@ async function executeConnectTeams(agent, deps) {
|
|
|
2053
2295
|
}
|
|
2054
2296
|
const promptInput = requirePromptInput(deps, "Teams setup");
|
|
2055
2297
|
const promptSecret = requirePromptSecret(deps, "Teams client secret entry");
|
|
2056
|
-
deps
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
"
|
|
2060
|
-
|
|
2298
|
+
writeConnectorIntro(deps, {
|
|
2299
|
+
title: "Connect Teams",
|
|
2300
|
+
subtitle: `${agent} gets a portable Teams sense.`,
|
|
2301
|
+
summary: "Add the app credentials once, keep the secret hidden, and let Teams travel with this agent.",
|
|
2302
|
+
sections: [
|
|
2303
|
+
{
|
|
2304
|
+
title: "Unlocks",
|
|
2305
|
+
lines: [
|
|
2306
|
+
"Microsoft Teams messages and actions inside Ouro.",
|
|
2307
|
+
],
|
|
2308
|
+
},
|
|
2309
|
+
{
|
|
2310
|
+
title: "What you need",
|
|
2311
|
+
lines: [
|
|
2312
|
+
"A Teams client ID, client secret, and tenant ID.",
|
|
2313
|
+
"The client secret stays hidden while you type.",
|
|
2314
|
+
],
|
|
2315
|
+
},
|
|
2316
|
+
{
|
|
2317
|
+
title: "Where it lives",
|
|
2318
|
+
lines: [
|
|
2319
|
+
`${agent}'s vault runtime/config item.`,
|
|
2320
|
+
"It travels with the agent across machines.",
|
|
2321
|
+
],
|
|
2322
|
+
},
|
|
2323
|
+
],
|
|
2324
|
+
fallbackLines: [
|
|
2325
|
+
`Connect Teams for ${agent}`,
|
|
2326
|
+
"The client secret stays hidden while you type.",
|
|
2327
|
+
`Ouro stores the setup in ${agent}'s vault runtime/config item.`,
|
|
2328
|
+
],
|
|
2329
|
+
});
|
|
2061
2330
|
const clientId = (await promptInput("Teams client ID: ")).trim();
|
|
2062
2331
|
if (!clientId)
|
|
2063
2332
|
throw new Error("Teams client ID cannot be blank");
|
|
@@ -2089,17 +2358,32 @@ async function executeConnectTeams(agent, deps) {
|
|
|
2089
2358
|
finally {
|
|
2090
2359
|
progress.end();
|
|
2091
2360
|
}
|
|
2092
|
-
const
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2361
|
+
const syncSummary = pushAgentBundleAfterCliMutation(agent, deps);
|
|
2362
|
+
return writeCapabilityOutcome(deps, {
|
|
2363
|
+
subtitle: `${agent}'s Teams sense is configured.`,
|
|
2364
|
+
summary: `Teams is ready for ${agent}.`,
|
|
2365
|
+
whatChanged: [
|
|
2366
|
+
"Capability: Teams sense",
|
|
2367
|
+
`Stored: ${stored.itemPath}`,
|
|
2368
|
+
"agent.json: senses.teams.enabled = true",
|
|
2369
|
+
"secret was not printed",
|
|
2370
|
+
...(syncSummary ? [syncSummary] : []),
|
|
2371
|
+
],
|
|
2372
|
+
nextMoves: [
|
|
2373
|
+
"Run ouro up so the daemon picks up the Teams sense change.",
|
|
2374
|
+
`Reopen the connect bay with ouro connect --agent ${agent} whenever you want to review capabilities.`,
|
|
2375
|
+
],
|
|
2376
|
+
fallbackLines: [
|
|
2377
|
+
`Teams connected for ${agent}`,
|
|
2378
|
+
"capability: Teams sense",
|
|
2379
|
+
`stored: ${stored.itemPath}`,
|
|
2380
|
+
"agent.json: senses.teams.enabled = true",
|
|
2381
|
+
"secret was not printed",
|
|
2382
|
+
"",
|
|
2383
|
+
"Next: run `ouro up` so the daemon picks up the Teams sense change.",
|
|
2384
|
+
...(syncSummary ? [syncSummary] : []),
|
|
2385
|
+
],
|
|
2386
|
+
});
|
|
2103
2387
|
}
|
|
2104
2388
|
async function executeConnectBlueBubbles(agent, deps) {
|
|
2105
2389
|
if (agent === "SerpentGuide") {
|
|
@@ -2107,11 +2391,38 @@ async function executeConnectBlueBubbles(agent, deps) {
|
|
|
2107
2391
|
}
|
|
2108
2392
|
const promptInput = requirePromptInput(deps, "BlueBubbles setup");
|
|
2109
2393
|
const promptSecret = requirePromptSecret(deps, "BlueBubbles password entry");
|
|
2110
|
-
deps
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
"
|
|
2114
|
-
|
|
2394
|
+
writeConnectorIntro(deps, {
|
|
2395
|
+
title: "Connect BlueBubbles",
|
|
2396
|
+
subtitle: `${agent} gets a local Messages bridge on this machine.`,
|
|
2397
|
+
summary: "Attach this Mac's BlueBubbles bridge without pretending it travels anywhere else.",
|
|
2398
|
+
sections: [
|
|
2399
|
+
{
|
|
2400
|
+
title: "Unlocks",
|
|
2401
|
+
lines: [
|
|
2402
|
+
"Local iMessage bridge access on this machine only.",
|
|
2403
|
+
],
|
|
2404
|
+
},
|
|
2405
|
+
{
|
|
2406
|
+
title: "What you need",
|
|
2407
|
+
lines: [
|
|
2408
|
+
"A BlueBubbles server URL and app password.",
|
|
2409
|
+
"The app password stays hidden while you type.",
|
|
2410
|
+
],
|
|
2411
|
+
},
|
|
2412
|
+
{
|
|
2413
|
+
title: "Where it lives",
|
|
2414
|
+
lines: [
|
|
2415
|
+
`${agent}'s machine runtime config for this machine.`,
|
|
2416
|
+
"It does not travel to other machines unless you attach them too.",
|
|
2417
|
+
],
|
|
2418
|
+
},
|
|
2419
|
+
],
|
|
2420
|
+
fallbackLines: [
|
|
2421
|
+
`Connect BlueBubbles for ${agent}`,
|
|
2422
|
+
"This is a local attachment for this machine.",
|
|
2423
|
+
"The app password stays hidden while you type.",
|
|
2424
|
+
],
|
|
2425
|
+
});
|
|
2115
2426
|
const serverUrl = (await promptInput("BlueBubbles server URL for this machine: ")).trim();
|
|
2116
2427
|
if (!serverUrl)
|
|
2117
2428
|
throw new Error("BlueBubbles server URL cannot be blank");
|
|
@@ -2156,17 +2467,32 @@ async function executeConnectBlueBubbles(agent, deps) {
|
|
|
2156
2467
|
progress.end();
|
|
2157
2468
|
throw error;
|
|
2158
2469
|
}
|
|
2159
|
-
const
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2470
|
+
const syncSummary = pushAgentBundleAfterCliMutation(agent, deps);
|
|
2471
|
+
return writeCapabilityOutcome(deps, {
|
|
2472
|
+
subtitle: `${agent}'s local bridge is attached.`,
|
|
2473
|
+
summary: `BlueBubbles is attached on this machine for ${agent}.`,
|
|
2474
|
+
whatChanged: [
|
|
2475
|
+
`Machine: ${machineId}`,
|
|
2476
|
+
`Stored: ${stored.itemPath}`,
|
|
2477
|
+
"agent.json: senses.bluebubbles.enabled = true",
|
|
2478
|
+
"secret was not printed",
|
|
2479
|
+
...(syncSummary ? [syncSummary] : []),
|
|
2480
|
+
],
|
|
2481
|
+
nextMoves: [
|
|
2482
|
+
"Point BlueBubbles at this machine's webhook, then run ouro up.",
|
|
2483
|
+
`Attach other machines separately if ${agent} should use BlueBubbles there too.`,
|
|
2484
|
+
],
|
|
2485
|
+
fallbackLines: [
|
|
2486
|
+
`BlueBubbles attached for ${agent} on this machine`,
|
|
2487
|
+
`machine: ${machineId}`,
|
|
2488
|
+
`stored: ${stored.itemPath}`,
|
|
2489
|
+
"agent.json: senses.bluebubbles.enabled = true",
|
|
2490
|
+
"secret was not printed",
|
|
2491
|
+
"",
|
|
2492
|
+
"Next: point BlueBubbles at this machine's webhook, then run `ouro up`.",
|
|
2493
|
+
...(syncSummary ? [syncSummary] : []),
|
|
2494
|
+
],
|
|
2495
|
+
});
|
|
2170
2496
|
}
|
|
2171
2497
|
async function executeConnectProviders(agent, deps) {
|
|
2172
2498
|
const promptInput = deps.promptInput;
|
|
@@ -2613,27 +2939,51 @@ async function executeAuthRun(command, deps) {
|
|
|
2613
2939
|
// Behavior: ouro auth stores credentials only — does NOT switch provider.
|
|
2614
2940
|
// Use `ouro auth switch` to change the active provider.
|
|
2615
2941
|
// Verify the credentials actually work by pinging the provider.
|
|
2942
|
+
let verificationStatus = "not checked";
|
|
2616
2943
|
/* v8 ignore start -- integration: real API ping after auth @preserve */
|
|
2617
2944
|
try {
|
|
2618
2945
|
progress.startPhase(`verifying ${provider}`);
|
|
2619
2946
|
const credential = await readProviderCredentialRecord(command.agent, provider, deps, {
|
|
2620
2947
|
onProgress: (message) => progress.updateDetail(message),
|
|
2621
2948
|
});
|
|
2622
|
-
|
|
2949
|
+
verificationStatus = credential.ok
|
|
2623
2950
|
? await verifyProviderCredentials(provider, {
|
|
2624
2951
|
[provider]: { ...credential.record.config, ...credential.record.credentials },
|
|
2625
2952
|
})
|
|
2626
2953
|
: `stored but could not be re-read from vault (${credential.error})`;
|
|
2627
|
-
progress.completePhase(`verifying ${provider}`,
|
|
2954
|
+
progress.completePhase(`verifying ${provider}`, verificationStatus);
|
|
2628
2955
|
}
|
|
2629
2956
|
catch (error) {
|
|
2630
2957
|
// Verification failure is non-blocking — credentials were saved regardless.
|
|
2631
|
-
|
|
2958
|
+
verificationStatus = `skipped (${error instanceof Error ? error.message : String(error)})`;
|
|
2959
|
+
progress.completePhase(`verifying ${provider}`, verificationStatus);
|
|
2632
2960
|
}
|
|
2633
2961
|
/* v8 ignore stop */
|
|
2634
2962
|
progress.end();
|
|
2635
|
-
deps
|
|
2636
|
-
|
|
2963
|
+
return writeCommandOutcome(deps, {
|
|
2964
|
+
title: "Provider auth",
|
|
2965
|
+
subtitle: `${command.agent} just refreshed ${provider}.`,
|
|
2966
|
+
summary: `${command.agent} can now use ${provider} when this lane is selected.`,
|
|
2967
|
+
sections: [
|
|
2968
|
+
{
|
|
2969
|
+
title: "What changed",
|
|
2970
|
+
lines: [
|
|
2971
|
+
`Stored in: ${result.credentialPath}`,
|
|
2972
|
+
`Provider: ${provider}`,
|
|
2973
|
+
`Live check: ${verificationStatus}`,
|
|
2974
|
+
"secret was not printed",
|
|
2975
|
+
],
|
|
2976
|
+
},
|
|
2977
|
+
{
|
|
2978
|
+
title: "Next moves",
|
|
2979
|
+
lines: [
|
|
2980
|
+
`Choose it for a lane with ouro use --agent ${command.agent} --lane <outward|inner> --provider ${provider} --model <model>.`,
|
|
2981
|
+
`Double-check it any time with ouro auth verify --agent ${command.agent} --provider ${provider}.`,
|
|
2982
|
+
],
|
|
2983
|
+
},
|
|
2984
|
+
],
|
|
2985
|
+
fallbackLines: [result.message],
|
|
2986
|
+
});
|
|
2637
2987
|
}
|
|
2638
2988
|
async function readinessReportForAgent(agent, deps) {
|
|
2639
2989
|
const bundlesRoot = deps.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
|
|
@@ -3578,21 +3928,24 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
3578
3928
|
deps.writeRaw(`${(0, terminal_ui_1.renderOuroMasthead)({
|
|
3579
3929
|
isTTY: true,
|
|
3580
3930
|
columns: deps.stdoutColumns ?? process.stdout.columns,
|
|
3581
|
-
subtitle: "
|
|
3931
|
+
subtitle: "Preparing the house.",
|
|
3582
3932
|
}).trimEnd()}\n\n`);
|
|
3583
3933
|
}
|
|
3584
3934
|
const progress = new up_progress_1.UpProgress({
|
|
3585
3935
|
write: deps.writeRaw ?? deps.writeStdout,
|
|
3586
3936
|
isTTY: outputIsTTY,
|
|
3937
|
+
columns: deps.stdoutColumns ?? process.stdout.columns,
|
|
3587
3938
|
now: deps.now ?? (() => Date.now()),
|
|
3588
3939
|
autoRender: true,
|
|
3589
3940
|
});
|
|
3590
3941
|
// ── versioned CLI update check ──
|
|
3591
3942
|
if (deps.checkForCliUpdate) {
|
|
3592
3943
|
progress.startPhase("update check");
|
|
3944
|
+
progress.updateDetail("checking npm registry\ncontinuing startup if it stays quiet");
|
|
3593
3945
|
let pendingReExec = false;
|
|
3946
|
+
let updateCheckStatus = "up to date";
|
|
3594
3947
|
try {
|
|
3595
|
-
const updateResult = await deps.checkForCliUpdate
|
|
3948
|
+
const { result: updateResult, timedOut } = await runCliUpdateCheckWithTimeout(deps.checkForCliUpdate, deps.updateCheckTimeoutMs ?? update_checker_1.CLI_UPDATE_CHECK_TIMEOUT_MS);
|
|
3596
3949
|
if (updateResult.available && updateResult.latestVersion) {
|
|
3597
3950
|
/* v8 ignore next -- fallback: getCurrentCliVersion always injected in tests @preserve */
|
|
3598
3951
|
const currentVersion = linkedVersionBeforeUp ?? "unknown";
|
|
@@ -3606,9 +3959,13 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
3606
3959
|
}
|
|
3607
3960
|
pendingReExec = true;
|
|
3608
3961
|
}
|
|
3962
|
+
else if (updateResult.error) {
|
|
3963
|
+
updateCheckStatus = summarizeCliUpdateCheckStatus(updateResult.error, timedOut);
|
|
3964
|
+
}
|
|
3609
3965
|
/* v8 ignore start -- update check error: tested via daemon-cli-update-flow.test.ts @preserve */
|
|
3610
3966
|
}
|
|
3611
3967
|
catch (error) {
|
|
3968
|
+
updateCheckStatus = summarizeCliUpdateCheckStatus(error instanceof Error ? error.message : String(error));
|
|
3612
3969
|
(0, runtime_1.emitNervesEvent)({
|
|
3613
3970
|
level: "warn",
|
|
3614
3971
|
component: "daemon",
|
|
@@ -3623,7 +3980,7 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
3623
3980
|
deps.reExecFromNewVersion(args);
|
|
3624
3981
|
}
|
|
3625
3982
|
else {
|
|
3626
|
-
progress.completePhase("update check",
|
|
3983
|
+
progress.completePhase("update check", updateCheckStatus);
|
|
3627
3984
|
}
|
|
3628
3985
|
}
|
|
3629
3986
|
progress.startPhase("system setup");
|
|
@@ -3777,56 +4134,72 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
3777
4134
|
});
|
|
3778
4135
|
}
|
|
3779
4136
|
else {
|
|
3780
|
-
const
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
}
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
const
|
|
3796
|
-
const
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
4137
|
+
const typedDegraded = daemonResult.stability.degraded.filter((entry) => (0, readiness_repair_1.isKnownReadinessIssue)(entry.issue));
|
|
4138
|
+
const untypedDegraded = daemonResult.stability.degraded.filter((entry) => !(0, readiness_repair_1.isKnownReadinessIssue)(entry.issue));
|
|
4139
|
+
let repairsAttempted = false;
|
|
4140
|
+
const repairedAgents = new Set();
|
|
4141
|
+
if (typedDegraded.length > 0) {
|
|
4142
|
+
const guidedRepair = await runReadinessRepairForDegraded(typedDegraded, deps);
|
|
4143
|
+
if (guidedRepair.repairsAttempted) {
|
|
4144
|
+
repairsAttempted = true;
|
|
4145
|
+
typedDegraded.forEach((entry) => repairedAgents.add(entry.agent));
|
|
4146
|
+
}
|
|
4147
|
+
}
|
|
4148
|
+
if (untypedDegraded.length > 0) {
|
|
4149
|
+
const repairResult = await (0, agentic_repair_1.runAgenticRepair)(untypedDegraded, {
|
|
4150
|
+
/* v8 ignore start -- production provider discovery wiring @preserve */
|
|
4151
|
+
discoverWorkingProvider: async (agentName) => {
|
|
4152
|
+
const { discoverWorkingProvider: discover } = await Promise.resolve().then(() => __importStar(require("./provider-discovery")));
|
|
4153
|
+
const { pingProvider } = await Promise.resolve().then(() => __importStar(require("../provider-ping")));
|
|
4154
|
+
return discover({
|
|
4155
|
+
agentName,
|
|
4156
|
+
pingProvider: pingProvider,
|
|
4157
|
+
});
|
|
4158
|
+
},
|
|
4159
|
+
createProviderRuntime: agentic_repair_1.createAgenticDiagnosisProviderRuntime,
|
|
4160
|
+
readDaemonLogsTail: () => {
|
|
4161
|
+
try {
|
|
4162
|
+
const fs = require("node:fs");
|
|
4163
|
+
const path = require("node:path");
|
|
4164
|
+
const logsDir = path.join(process.env["HOME"] ?? "", ".agentstate", "daemon", "logs");
|
|
4165
|
+
const files = fs.readdirSync(logsDir).filter((f) => f.endsWith(".log")).sort();
|
|
4166
|
+
if (files.length === 0)
|
|
4167
|
+
return "(no daemon logs found)";
|
|
4168
|
+
const lastLog = fs.readFileSync(path.join(logsDir, files[files.length - 1]), "utf8");
|
|
4169
|
+
const lines = lastLog.split("\n");
|
|
4170
|
+
return lines.slice(-50).join("\n");
|
|
4171
|
+
}
|
|
4172
|
+
catch {
|
|
4173
|
+
return "(unable to read daemon logs)";
|
|
4174
|
+
}
|
|
4175
|
+
},
|
|
4176
|
+
/* v8 ignore stop */
|
|
4177
|
+
runInteractiveRepair: interactive_repair_1.runInteractiveRepair,
|
|
4178
|
+
promptInput: deps.promptInput ?? (async () => "n"),
|
|
4179
|
+
writeStdout: deps.writeStdout,
|
|
4180
|
+
runAuthFlow: async (agent, providerOverride) => {
|
|
4181
|
+
await executeAuthRun({
|
|
4182
|
+
kind: "auth.run",
|
|
4183
|
+
agent,
|
|
4184
|
+
...(providerOverride ? { provider: providerOverride } : {}),
|
|
4185
|
+
}, deps);
|
|
4186
|
+
},
|
|
4187
|
+
runVaultUnlock: async (agent) => {
|
|
4188
|
+
await executeVaultUnlock({ kind: "vault.unlock", agent }, deps);
|
|
4189
|
+
},
|
|
4190
|
+
skipQueueSummary: true,
|
|
4191
|
+
});
|
|
4192
|
+
if (repairResult.repairsAttempted) {
|
|
4193
|
+
repairsAttempted = true;
|
|
4194
|
+
untypedDegraded
|
|
4195
|
+
.filter(interactive_repair_1.hasRunnableInteractiveRepair)
|
|
4196
|
+
.forEach((entry) => repairedAgents.add(entry.agent));
|
|
4197
|
+
}
|
|
4198
|
+
}
|
|
4199
|
+
if (repairsAttempted) {
|
|
3827
4200
|
progress.startPhase("post-repair check");
|
|
3828
|
-
await reportPostRepairProviderHealth(deps, repairedAgents, (msg) => progress.updateDetail(msg));
|
|
3829
|
-
progress.completePhase("post-repair check", providerRepairCountSummary(repairedAgents.
|
|
4201
|
+
await reportPostRepairProviderHealth(deps, [...repairedAgents], (msg) => progress.updateDetail(msg));
|
|
4202
|
+
progress.completePhase("post-repair check", providerRepairCountSummary(repairedAgents.size));
|
|
3830
4203
|
}
|
|
3831
4204
|
}
|
|
3832
4205
|
}
|
|
@@ -4028,16 +4401,16 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
4028
4401
|
const sections = [localSection];
|
|
4029
4402
|
if (deps.checkForCliUpdate) {
|
|
4030
4403
|
try {
|
|
4031
|
-
const updateResult = await deps.checkForCliUpdate
|
|
4404
|
+
const { result: updateResult, timedOut } = await runCliUpdateCheckWithTimeout(deps.checkForCliUpdate, deps.updateCheckTimeoutMs ?? update_checker_1.CLI_UPDATE_CHECK_TIMEOUT_MS);
|
|
4032
4405
|
if (updateResult.latestVersion) {
|
|
4033
4406
|
sections.push(`published latest: ${updateResult.latestVersion} (${updateResult.available ? "update available" : "up to date"})`);
|
|
4034
4407
|
}
|
|
4035
4408
|
else if (updateResult.error) {
|
|
4036
|
-
sections.push(`published latest: unavailable (${updateResult.error})`);
|
|
4409
|
+
sections.push(`published latest: unavailable (${summarizeCliUpdateCheckStatus(updateResult.error, timedOut)})`);
|
|
4037
4410
|
}
|
|
4038
4411
|
}
|
|
4039
4412
|
catch (err) {
|
|
4040
|
-
const reason = err instanceof Error ? err.message : String(err);
|
|
4413
|
+
const reason = summarizeCliUpdateCheckStatus(err instanceof Error ? err.message : String(err));
|
|
4041
4414
|
sections.push(`published latest: unavailable (${reason})`);
|
|
4042
4415
|
}
|
|
4043
4416
|
}
|
|
@@ -5040,9 +5413,31 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
5040
5413
|
await deps.startChat(hatchInput.agentName);
|
|
5041
5414
|
return "";
|
|
5042
5415
|
}
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5416
|
+
return writeCommandOutcome(deps, {
|
|
5417
|
+
title: "Hatch complete",
|
|
5418
|
+
subtitle: `${hatchInput.agentName} just arrived.`,
|
|
5419
|
+
summary: `${hatchInput.agentName} is ready for first contact.`,
|
|
5420
|
+
sections: [
|
|
5421
|
+
{
|
|
5422
|
+
title: "What changed",
|
|
5423
|
+
lines: [
|
|
5424
|
+
`Bundle: ${result.bundleRoot}`,
|
|
5425
|
+
`Specialist identity: ${result.selectedIdentity}`,
|
|
5426
|
+
`House status: ${daemonResult.message}`,
|
|
5427
|
+
],
|
|
5428
|
+
},
|
|
5429
|
+
{
|
|
5430
|
+
title: "Next moves",
|
|
5431
|
+
lines: [
|
|
5432
|
+
`Talk to them with ouro chat ${hatchInput.agentName}.`,
|
|
5433
|
+
`Use ouro connect --agent ${hatchInput.agentName} to bring more capabilities online.`,
|
|
5434
|
+
],
|
|
5435
|
+
},
|
|
5436
|
+
],
|
|
5437
|
+
fallbackLines: [
|
|
5438
|
+
`hatched ${hatchInput.agentName} at ${result.bundleRoot} using specialist identity ${result.selectedIdentity}; ${daemonResult.message}`,
|
|
5439
|
+
],
|
|
5440
|
+
});
|
|
5046
5441
|
}
|
|
5047
5442
|
// ── doctor (local, no daemon socket needed) ──
|
|
5048
5443
|
if (command.kind === "doctor") {
|
|
@@ -5227,7 +5622,17 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
5227
5622
|
}
|
|
5228
5623
|
const fallbackMessage = response.summary ?? response.message ?? (response.ok ? "ok" : `error: ${response.error ?? "unknown error"}`);
|
|
5229
5624
|
const message = command.kind === "daemon.status"
|
|
5230
|
-
? (
|
|
5625
|
+
? (() => {
|
|
5626
|
+
const payload = (0, cli_render_1.parseStatusPayload)(response.data);
|
|
5627
|
+
if (payload && ttyBoardEnabled(deps)) {
|
|
5628
|
+
return (0, human_command_screens_1.renderHouseStatusScreen)({
|
|
5629
|
+
payload,
|
|
5630
|
+
isTTY: true,
|
|
5631
|
+
columns: deps.stdoutColumns ?? process.stdout.columns,
|
|
5632
|
+
}).trimEnd();
|
|
5633
|
+
}
|
|
5634
|
+
return (0, cli_render_1.formatDaemonStatusOutput)(response, fallbackMessage);
|
|
5635
|
+
})()
|
|
5231
5636
|
: fallbackMessage;
|
|
5232
5637
|
deps.writeStdout(message);
|
|
5233
5638
|
return message;
|