@ouro.bot/cli 0.1.0-alpha.418 → 0.1.0-alpha.419
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/README.md +2 -1
- package/changelog.json +11 -0
- package/dist/heart/daemon/cli-exec.js +143 -62
- package/dist/heart/daemon/up-progress.js +23 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -99,6 +99,7 @@ Task docs do not live in this repo anymore. Planning and doing docs live in the
|
|
|
99
99
|
- Vault unlock material is local machine state. Prefer macOS Keychain, Windows DPAPI, or Linux Secret Service; plaintext fallback is allowed only by explicit human choice.
|
|
100
100
|
- New vault unlock secrets are confirmed before use and rejected if they do not meet the minimum strength requirements.
|
|
101
101
|
- Provider and runtime credentials are loaded into process memory at startup/auth/unlock/refresh and reused. The remote vault is not queried for every model or sense request.
|
|
102
|
+
- Human-facing CLI commands that can wait on browser auth, vault IO, daemon startup, daemon restart, provider checks, or connector setup use a shared progress checklist. If a cursor may blink for more than a few seconds, the command should print or animate the current step instead of going quiet.
|
|
102
103
|
- CLI commands that mutate bundle config, such as vault setup or `ouro connect bluebubbles`, run bundle sync after the change when `sync.enabled` is true and report a compact `bundle sync:` line.
|
|
103
104
|
- The daemon discovers bundles dynamically from `~/AgentBundles`.
|
|
104
105
|
- `ouro status` reports version, last-updated time, discovered agents, senses, and workers.
|
|
@@ -120,7 +121,7 @@ ouro auth --agent <name>
|
|
|
120
121
|
ouro auth --agent <name> --provider <provider>
|
|
121
122
|
```
|
|
122
123
|
|
|
123
|
-
`ouro auth` stores credentials in the owning agent's vault. It does not switch a lane or write provider/model selection.
|
|
124
|
+
`ouro auth` stores credentials in the owning agent's vault. It does not switch a lane or write provider/model selection. The command shows progress while browser login, vault storage, refresh, and verification are happening.
|
|
124
125
|
|
|
125
126
|
When you want this machine to use a provider/model for a lane, use:
|
|
126
127
|
|
package/changelog.json
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
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.419",
|
|
6
|
+
"changes": [
|
|
7
|
+
"`ouro auth`, `ouro provider refresh`, `ouro connect perplexity`, and `ouro connect bluebubbles` now use the shared human CLI progress checklist so browser login, vault reads/writes, daemon reloads, and verification steps stay visible instead of leaving a blinking cursor.",
|
|
8
|
+
"`ouro connect perplexity` now introduces the flow before the hidden API-key prompt, shows vault storage and reload progress, keeps the key out of output, and ends with a compact next step for using Perplexity search.",
|
|
9
|
+
"`ouro connect bluebubbles` now introduces the local-machine attachment before prompts, shows machine runtime config and `agent.json` enablement progress, and keeps the app password out of output.",
|
|
10
|
+
"`ouro provider refresh` now shows vault-read progress and reload status, and refresh/auth/connect failure paths preserve the last visible progress context while still rethrowing actionable errors.",
|
|
11
|
+
"The CLI progress renderer is documented as a shared human-facing contract: long-running human flows should show current work, stay concise, and never print secrets.",
|
|
12
|
+
"`@ouro.bot/cli` and the `ouro.bot` wrapper are version-synced for the provider onboarding progress release."
|
|
13
|
+
]
|
|
14
|
+
},
|
|
4
15
|
{
|
|
5
16
|
"version": "0.1.0-alpha.418",
|
|
6
17
|
"changes": [
|
|
@@ -179,6 +179,16 @@ function providerRepairCountSummary(count) {
|
|
|
179
179
|
return "ok";
|
|
180
180
|
return `${count} ${count === 1 ? "needs" : "need"} attention`;
|
|
181
181
|
}
|
|
182
|
+
function createHumanCommandProgress(deps, commandName) {
|
|
183
|
+
return new up_progress_1.CommandProgress({
|
|
184
|
+
write: deps.writeRaw ?? deps.writeStdout,
|
|
185
|
+
isTTY: deps.isTTY ?? false,
|
|
186
|
+
now: deps.now ?? (() => Date.now()),
|
|
187
|
+
autoRender: true,
|
|
188
|
+
eventScope: "command",
|
|
189
|
+
commandName,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
182
192
|
function daemonProgressSummary(result) {
|
|
183
193
|
if (result.verifyStartupStatus === false)
|
|
184
194
|
return "not answering yet";
|
|
@@ -1142,18 +1152,35 @@ function runtimeScopeLabel(scope) {
|
|
|
1142
1152
|
}
|
|
1143
1153
|
async function storeRuntimeConfigKey(input) {
|
|
1144
1154
|
const machineId = input.scope === "machine" ? currentMachineId(input.deps) : undefined;
|
|
1155
|
+
input.onProgress?.("checking existing runtime config");
|
|
1145
1156
|
const current = input.scope === "machine"
|
|
1146
1157
|
? await (0, runtime_credentials_1.refreshMachineRuntimeCredentialConfig)(input.agent, machineId, { preserveCachedOnFailure: true })
|
|
1147
1158
|
: await (0, runtime_credentials_1.refreshRuntimeCredentialConfig)(input.agent, { preserveCachedOnFailure: true });
|
|
1148
1159
|
if (!current.ok && current.reason !== "missing") {
|
|
1149
1160
|
throw new Error(`cannot read existing runtime credentials from ${current.itemPath}: ${current.error}`);
|
|
1150
1161
|
}
|
|
1162
|
+
input.onProgress?.(`storing ${input.key} in ${current.itemPath}`);
|
|
1151
1163
|
const nextConfig = setRuntimeConfigValue(current.ok ? current.config : {}, input.key, input.value);
|
|
1152
1164
|
const stored = input.scope === "machine"
|
|
1153
1165
|
? await (0, runtime_credentials_1.upsertMachineRuntimeCredentialConfig)(input.agent, machineId, nextConfig, providerCliNow(input.deps))
|
|
1154
1166
|
: await (0, runtime_credentials_1.upsertRuntimeCredentialConfig)(input.agent, nextConfig, providerCliNow(input.deps));
|
|
1167
|
+
input.onProgress?.(`stored ${input.key}; credential value was not printed`);
|
|
1155
1168
|
return { revision: stored.revision, itemPath: stored.itemPath, ...(machineId ? { machineId } : {}) };
|
|
1156
1169
|
}
|
|
1170
|
+
async function reloadRunningAgentAfterCredentialChange(agent, deps) {
|
|
1171
|
+
try {
|
|
1172
|
+
const alive = await deps.checkSocketAlive(deps.socketPath);
|
|
1173
|
+
if (!alive)
|
|
1174
|
+
return "daemon is not running; next `ouro up` will load it";
|
|
1175
|
+
const response = await deps.sendCommand(deps.socketPath, { kind: "agent.restart", agent });
|
|
1176
|
+
if (response.ok)
|
|
1177
|
+
return `restarted ${agent} so the running agent reloads credentials`;
|
|
1178
|
+
return `daemon restart skipped: ${response.error ?? response.message ?? "unknown daemon error"}`;
|
|
1179
|
+
}
|
|
1180
|
+
catch (error) {
|
|
1181
|
+
return `daemon restart skipped: ${error instanceof Error ? error.message : String(error)}`;
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1157
1184
|
async function executeVaultConfigSet(command, deps) {
|
|
1158
1185
|
if (command.agent === "SerpentGuide") {
|
|
1159
1186
|
throw new Error("SerpentGuide does not have persistent runtime credentials. Store credentials in the hatchling agent vault.");
|
|
@@ -1268,18 +1295,16 @@ function enableAgentSense(agent, sense, deps) {
|
|
|
1268
1295
|
function connectMenu(agent) {
|
|
1269
1296
|
return [
|
|
1270
1297
|
`Connect ${agent}`,
|
|
1298
|
+
"Pick what this agent should be able to use.",
|
|
1271
1299
|
"",
|
|
1272
|
-
"Portable agent capabilities",
|
|
1273
1300
|
" 1. Perplexity search",
|
|
1274
|
-
"
|
|
1301
|
+
" Portable. Stores an API key in the agent vault.",
|
|
1275
1302
|
"",
|
|
1276
|
-
"This machine only",
|
|
1277
1303
|
" 2. BlueBubbles iMessage",
|
|
1278
|
-
"
|
|
1304
|
+
" This machine only. Connects a local Mac Messages bridge.",
|
|
1279
1305
|
"",
|
|
1280
|
-
"Model providers",
|
|
1281
1306
|
" 3. Provider auth",
|
|
1282
|
-
`
|
|
1307
|
+
` Model credentials: ouro auth --agent ${agent} --provider <provider>`,
|
|
1283
1308
|
"",
|
|
1284
1309
|
" 4. Cancel",
|
|
1285
1310
|
"",
|
|
@@ -1291,23 +1316,45 @@ async function executeConnectPerplexity(agent, deps) {
|
|
|
1291
1316
|
throw new Error("SerpentGuide has no persistent runtime credentials. Connect Perplexity on the hatchling agent instead.");
|
|
1292
1317
|
}
|
|
1293
1318
|
const promptSecret = requirePromptSecret(deps, "Perplexity API key entry");
|
|
1319
|
+
deps.writeStdout([
|
|
1320
|
+
`Connect Perplexity for ${agent}`,
|
|
1321
|
+
"The API key stays hidden while you type.",
|
|
1322
|
+
`Ouro stores it in ${agent}'s vault runtime/config item.`,
|
|
1323
|
+
].join("\n"));
|
|
1294
1324
|
const key = (await promptSecret("Perplexity API key: ")).trim();
|
|
1295
1325
|
if (!key)
|
|
1296
1326
|
throw new Error("Perplexity API key cannot be blank");
|
|
1297
|
-
const
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1327
|
+
const progress = createHumanCommandProgress(deps, "connect perplexity");
|
|
1328
|
+
let stored;
|
|
1329
|
+
let reload;
|
|
1330
|
+
try {
|
|
1331
|
+
progress.startPhase("saving Perplexity search");
|
|
1332
|
+
stored = await storeRuntimeConfigKey({
|
|
1333
|
+
agent,
|
|
1334
|
+
key: "integrations.perplexityApiKey",
|
|
1335
|
+
value: key,
|
|
1336
|
+
scope: "agent",
|
|
1337
|
+
deps,
|
|
1338
|
+
onProgress: (message) => progress.updateDetail(message),
|
|
1339
|
+
});
|
|
1340
|
+
progress.completePhase("saving Perplexity search", "secret stored");
|
|
1341
|
+
progress.startPhase(`reloading ${agent}`);
|
|
1342
|
+
reload = await reloadRunningAgentAfterCredentialChange(agent, deps);
|
|
1343
|
+
progress.completePhase(`reloading ${agent}`, reload);
|
|
1344
|
+
progress.end();
|
|
1345
|
+
}
|
|
1346
|
+
catch (error) {
|
|
1347
|
+
progress.end();
|
|
1348
|
+
throw error;
|
|
1349
|
+
}
|
|
1304
1350
|
const message = [
|
|
1305
1351
|
`Perplexity connected for ${agent}`,
|
|
1306
1352
|
"capability: Perplexity search",
|
|
1307
1353
|
`stored: ${stored.itemPath}`,
|
|
1354
|
+
`reload: ${reload}`,
|
|
1308
1355
|
"secret was not printed",
|
|
1309
1356
|
"",
|
|
1310
|
-
"Next: ask the agent to search
|
|
1357
|
+
"Next: ask the agent to search.",
|
|
1311
1358
|
].join("\n");
|
|
1312
1359
|
deps.writeStdout(message);
|
|
1313
1360
|
return message;
|
|
@@ -1318,6 +1365,11 @@ async function executeConnectBlueBubbles(agent, deps) {
|
|
|
1318
1365
|
}
|
|
1319
1366
|
const promptInput = requirePromptInput(deps, "BlueBubbles setup");
|
|
1320
1367
|
const promptSecret = requirePromptSecret(deps, "BlueBubbles password entry");
|
|
1368
|
+
deps.writeStdout([
|
|
1369
|
+
`Connect BlueBubbles for ${agent}`,
|
|
1370
|
+
"This is a local attachment for this machine.",
|
|
1371
|
+
"The app password stays hidden while you type.",
|
|
1372
|
+
].join("\n"));
|
|
1321
1373
|
const serverUrl = (await promptInput("BlueBubbles server URL for this machine: ")).trim();
|
|
1322
1374
|
if (!serverUrl)
|
|
1323
1375
|
throw new Error("BlueBubbles server URL cannot be blank");
|
|
@@ -1328,25 +1380,40 @@ async function executeConnectBlueBubbles(agent, deps) {
|
|
|
1328
1380
|
const webhookPath = normalizeWebhookPath(await promptInput("Local webhook path [/bluebubbles-webhook]: "), "/bluebubbles-webhook");
|
|
1329
1381
|
const requestTimeoutMs = parseOptionalPositiveInteger(await promptInput("Request timeout ms [30000]: "), 30000, "BlueBubbles request timeout");
|
|
1330
1382
|
const machineId = currentMachineId(deps);
|
|
1331
|
-
const
|
|
1332
|
-
|
|
1333
|
-
|
|
1383
|
+
const progress = createHumanCommandProgress(deps, "connect bluebubbles");
|
|
1384
|
+
let stored;
|
|
1385
|
+
try {
|
|
1386
|
+
progress.startPhase("saving BlueBubbles attachment");
|
|
1387
|
+
progress.updateDetail("checking existing machine runtime config");
|
|
1388
|
+
const current = await (0, runtime_credentials_1.refreshMachineRuntimeCredentialConfig)(agent, machineId, { preserveCachedOnFailure: true });
|
|
1389
|
+
if (!current.ok && current.reason !== "missing") {
|
|
1390
|
+
progress.end();
|
|
1391
|
+
throw new Error(`cannot read existing machine runtime credentials from ${current.itemPath}: ${current.error}`);
|
|
1392
|
+
}
|
|
1393
|
+
const nextConfig = {
|
|
1394
|
+
...(current.ok ? current.config : {}),
|
|
1395
|
+
bluebubbles: {
|
|
1396
|
+
serverUrl,
|
|
1397
|
+
password,
|
|
1398
|
+
accountId: "default",
|
|
1399
|
+
},
|
|
1400
|
+
bluebubblesChannel: {
|
|
1401
|
+
port,
|
|
1402
|
+
webhookPath,
|
|
1403
|
+
requestTimeoutMs,
|
|
1404
|
+
},
|
|
1405
|
+
};
|
|
1406
|
+
progress.updateDetail("storing local machine config");
|
|
1407
|
+
stored = await (0, runtime_credentials_1.upsertMachineRuntimeCredentialConfig)(agent, machineId, nextConfig, providerCliNow(deps));
|
|
1408
|
+
progress.updateDetail("enabling BlueBubbles in agent.json");
|
|
1409
|
+
enableAgentSense(agent, "bluebubbles", deps);
|
|
1410
|
+
progress.completePhase("saving BlueBubbles attachment", "secret stored");
|
|
1411
|
+
progress.end();
|
|
1412
|
+
}
|
|
1413
|
+
catch (error) {
|
|
1414
|
+
progress.end();
|
|
1415
|
+
throw error;
|
|
1334
1416
|
}
|
|
1335
|
-
const nextConfig = {
|
|
1336
|
-
...(current.ok ? current.config : {}),
|
|
1337
|
-
bluebubbles: {
|
|
1338
|
-
serverUrl,
|
|
1339
|
-
password,
|
|
1340
|
-
accountId: "default",
|
|
1341
|
-
},
|
|
1342
|
-
bluebubblesChannel: {
|
|
1343
|
-
port,
|
|
1344
|
-
webhookPath,
|
|
1345
|
-
requestTimeoutMs,
|
|
1346
|
-
},
|
|
1347
|
-
};
|
|
1348
|
-
const stored = await (0, runtime_credentials_1.upsertMachineRuntimeCredentialConfig)(agent, machineId, nextConfig, providerCliNow(deps));
|
|
1349
|
-
enableAgentSense(agent, "bluebubbles", deps);
|
|
1350
1417
|
const message = appendBundleSyncSummary([
|
|
1351
1418
|
`BlueBubbles attached for ${agent} on this machine`,
|
|
1352
1419
|
`machine: ${machineId}`,
|
|
@@ -1648,38 +1715,40 @@ async function executeProviderRefresh(command, deps) {
|
|
|
1648
1715
|
deps.writeStdout(message);
|
|
1649
1716
|
return message;
|
|
1650
1717
|
}
|
|
1651
|
-
const
|
|
1718
|
+
const progress = createHumanCommandProgress(deps, "provider refresh");
|
|
1719
|
+
progress.startPhase("refreshing provider credentials");
|
|
1720
|
+
let pool;
|
|
1721
|
+
try {
|
|
1722
|
+
pool = await (0, provider_credentials_1.refreshProviderCredentialPool)(command.agent, {
|
|
1723
|
+
onProgress: (message) => progress.updateDetail(message),
|
|
1724
|
+
});
|
|
1725
|
+
}
|
|
1726
|
+
catch (error) {
|
|
1727
|
+
progress.end();
|
|
1728
|
+
throw error;
|
|
1729
|
+
}
|
|
1652
1730
|
const lines = [];
|
|
1653
1731
|
if (pool.ok) {
|
|
1654
1732
|
const summary = (0, provider_credentials_1.summarizeProviderCredentialPool)(pool.pool);
|
|
1655
1733
|
lines.push(`refreshed provider credential snapshot for ${command.agent}`);
|
|
1656
1734
|
lines.push(`providers: ${summary.providers.map((provider) => provider.provider).join(", ") || "none"}`);
|
|
1735
|
+
progress.completePhase("refreshing provider credentials", summary.providers.map((provider) => provider.provider).join(", ") || "none");
|
|
1657
1736
|
}
|
|
1658
1737
|
else {
|
|
1738
|
+
progress.end();
|
|
1659
1739
|
lines.push(`provider credential refresh failed for ${command.agent}: ${pool.error}`);
|
|
1660
1740
|
lines.push((0, vault_unlock_1.vaultUnlockReplaceRecoverFix)(command.agent, "Then retry 'ouro provider refresh'."));
|
|
1661
1741
|
const message = lines.join("\n");
|
|
1662
1742
|
deps.writeStdout(message);
|
|
1663
1743
|
return message;
|
|
1664
1744
|
}
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
else {
|
|
1673
|
-
lines.push(`daemon restart skipped: ${response.error ?? response.message ?? "unknown daemon error"}`);
|
|
1674
|
-
}
|
|
1675
|
-
}
|
|
1676
|
-
else {
|
|
1677
|
-
lines.push("daemon is not running; the next start will load the refreshed snapshot");
|
|
1678
|
-
}
|
|
1679
|
-
}
|
|
1680
|
-
catch (error) {
|
|
1681
|
-
lines.push(`daemon restart skipped: ${error instanceof Error ? error.message : String(error)}`);
|
|
1682
|
-
}
|
|
1745
|
+
progress.startPhase(`reloading ${command.agent}`);
|
|
1746
|
+
const reload = await reloadRunningAgentAfterCredentialChange(command.agent, deps);
|
|
1747
|
+
progress.completePhase(`reloading ${command.agent}`, reload);
|
|
1748
|
+
progress.end();
|
|
1749
|
+
lines.push(reload === "daemon is not running; next `ouro up` will load it"
|
|
1750
|
+
? "daemon is not running; the next start will load the refreshed snapshot"
|
|
1751
|
+
: reload);
|
|
1683
1752
|
const message = lines.join("\n");
|
|
1684
1753
|
deps.writeStdout(message);
|
|
1685
1754
|
return message;
|
|
@@ -3348,31 +3417,43 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
3348
3417
|
const provider = command.provider ?? (0, auth_flow_1.readAgentConfigForAgent)(command.agent, deps.bundlesRoot).config.humanFacing.provider;
|
|
3349
3418
|
/* v8 ignore next -- tests always inject runAuthFlow; default is for production @preserve */
|
|
3350
3419
|
const authRunner = deps.runAuthFlow ?? (await Promise.resolve().then(() => __importStar(require("../auth/auth-flow")))).runRuntimeAuthFlow;
|
|
3351
|
-
const
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3420
|
+
const progress = createHumanCommandProgress(deps, "auth");
|
|
3421
|
+
progress.startPhase(`authenticating ${provider}`);
|
|
3422
|
+
let result;
|
|
3423
|
+
try {
|
|
3424
|
+
result = await authRunner({
|
|
3425
|
+
agentName: command.agent,
|
|
3426
|
+
provider,
|
|
3427
|
+
promptInput: deps.promptInput,
|
|
3428
|
+
onProgress: (message) => progress.updateDetail(message),
|
|
3429
|
+
});
|
|
3430
|
+
}
|
|
3431
|
+
catch (error) {
|
|
3432
|
+
progress.end();
|
|
3433
|
+
throw error;
|
|
3434
|
+
}
|
|
3435
|
+
progress.completePhase(`authenticating ${provider}`, "credentials stored");
|
|
3357
3436
|
// Behavior: ouro auth stores credentials only — does NOT switch provider.
|
|
3358
3437
|
// Use `ouro auth switch` to change the active provider.
|
|
3359
|
-
deps.writeStdout(result.message);
|
|
3360
3438
|
// Verify the credentials actually work by pinging the provider
|
|
3361
3439
|
/* v8 ignore start -- integration: real API ping after auth @preserve */
|
|
3362
3440
|
try {
|
|
3363
|
-
|
|
3441
|
+
progress.startPhase(`verifying ${provider}`);
|
|
3364
3442
|
const credential = await readProviderCredentialRecord(command.agent, provider, deps);
|
|
3365
3443
|
const status = credential.ok
|
|
3366
3444
|
? await verifyProviderCredentials(provider, {
|
|
3367
3445
|
[provider]: { ...credential.record.config, ...credential.record.credentials },
|
|
3368
3446
|
})
|
|
3369
3447
|
: `stored but could not be re-read from vault (${credential.error})`;
|
|
3370
|
-
|
|
3448
|
+
progress.completePhase(`verifying ${provider}`, status);
|
|
3371
3449
|
}
|
|
3372
|
-
catch {
|
|
3373
|
-
// Verification failure is non-blocking — credentials were saved regardless
|
|
3450
|
+
catch (error) {
|
|
3451
|
+
// Verification failure is non-blocking — credentials were saved regardless.
|
|
3452
|
+
progress.completePhase(`verifying ${provider}`, `skipped (${error instanceof Error ? error.message : String(error)})`);
|
|
3374
3453
|
}
|
|
3375
3454
|
/* v8 ignore stop */
|
|
3455
|
+
progress.end();
|
|
3456
|
+
deps.writeStdout(result.message);
|
|
3376
3457
|
return result.message;
|
|
3377
3458
|
}
|
|
3378
3459
|
// ── auth verify (local, no daemon socket needed) ──
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* UpProgress — accumulated-checklist progress renderer
|
|
3
|
+
* UpProgress — accumulated-checklist progress renderer.
|
|
4
4
|
*
|
|
5
5
|
* Displays completed phases with checkmarks, the current phase with a
|
|
6
6
|
* spinner and elapsed time, and pending phases as plain text. Uses ANSI
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* long operations never leave a dead-looking cursor.
|
|
13
13
|
*/
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.UpProgress = void 0;
|
|
15
|
+
exports.CommandProgress = exports.UpProgress = void 0;
|
|
16
16
|
const runtime_1 = require("../../nerves/runtime");
|
|
17
17
|
// ── ANSI constants (shared with startup-tui.ts pattern) ──
|
|
18
18
|
const SPINNER_FRAMES = "\u280B\u2819\u2839\u2838\u283C\u2834\u2826\u2827\u2807\u280F";
|
|
@@ -29,6 +29,8 @@ class UpProgress {
|
|
|
29
29
|
renderIntervalMs;
|
|
30
30
|
setTimer;
|
|
31
31
|
clearTimer;
|
|
32
|
+
eventScope;
|
|
33
|
+
commandName;
|
|
32
34
|
completed = [];
|
|
33
35
|
currentPhase = null;
|
|
34
36
|
currentDetail = null;
|
|
@@ -48,6 +50,8 @@ class UpProgress {
|
|
|
48
50
|
this.setTimer = options?.setInterval ?? ((callback, ms) => setInterval(callback, ms));
|
|
49
51
|
this.clearTimer = options?.clearInterval ?? ((handle) => clearInterval(handle));
|
|
50
52
|
/* v8 ignore stop */
|
|
53
|
+
this.eventScope = options?.eventScope ?? "up";
|
|
54
|
+
this.commandName = options?.commandName ?? null;
|
|
51
55
|
}
|
|
52
56
|
/**
|
|
53
57
|
* Begin a new phase with spinner. If a phase is already active, it is
|
|
@@ -109,12 +113,22 @@ class UpProgress {
|
|
|
109
113
|
this.currentPhase = null;
|
|
110
114
|
this.currentDetail = null;
|
|
111
115
|
this.stopAutoRender();
|
|
112
|
-
(
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
116
|
+
if (this.eventScope === "command") {
|
|
117
|
+
(0, runtime_1.emitNervesEvent)({
|
|
118
|
+
component: "daemon",
|
|
119
|
+
event: "daemon.cli_progress_phase_complete",
|
|
120
|
+
message: `phase complete: ${label}`,
|
|
121
|
+
meta: { command: this.commandName, phase: label, detail: detail ?? null, elapsedMs },
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
(0, runtime_1.emitNervesEvent)({
|
|
126
|
+
component: "daemon",
|
|
127
|
+
event: "daemon.up_phase_complete",
|
|
128
|
+
message: `phase complete: ${label}`,
|
|
129
|
+
meta: { phase: label, detail: detail ?? null, elapsedMs },
|
|
130
|
+
});
|
|
131
|
+
}
|
|
118
132
|
if (this.isTTY) {
|
|
119
133
|
this.flushRender();
|
|
120
134
|
}
|
|
@@ -201,3 +215,4 @@ class UpProgress {
|
|
|
201
215
|
}
|
|
202
216
|
}
|
|
203
217
|
exports.UpProgress = UpProgress;
|
|
218
|
+
exports.CommandProgress = UpProgress;
|