@ouro.bot/cli 0.1.0-alpha.425 → 0.1.0-alpha.427
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/changelog.json
CHANGED
|
@@ -1,6 +1,24 @@
|
|
|
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.427",
|
|
6
|
+
"changes": [
|
|
7
|
+
"Root `ouro connect` now runs the same shared live provider verification path as `ouro up` and `ouro auth verify` before it renders the connect bay, so freshly authed providers and failed live checks show their real current state.",
|
|
8
|
+
"The root connect bay now groups capabilities into a clearer `Next best move`, `Provider core`, `Portable`, and `This machine` layout, with truthful lane-specific status for outward and inner providers.",
|
|
9
|
+
"Shared provider health checks now refresh readiness for every selected provider/model pair instead of stopping after the first failure, and `ouro connect` keeps working when provider selection is missing so repair guidance can still render.",
|
|
10
|
+
"Auth/provider/testing docs now describe the live-verifying connect bay behavior, and `@ouro.bot/cli` plus the `ouro.bot` wrapper are version-synced for the truthful connect release."
|
|
11
|
+
]
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"version": "0.1.0-alpha.426",
|
|
15
|
+
"changes": [
|
|
16
|
+
"`ouro up` no longer marks `starting daemon` complete when a replacement daemon still is not answering; it now narrates replacement progress in plain language and reports replacement timeout as an incomplete replacement instead of a fake success.",
|
|
17
|
+
"Root `ouro connect --agent <agent>` now prints a short `checking current connections` preflight while it reads portable and machine-local runtime settings before showing the connect bay menu.",
|
|
18
|
+
"Auth/provider/setup docs now codify the human CLI rule that waits longer than about three seconds should show current work, and they describe the new daemon replacement wording and connect-bay preflight.",
|
|
19
|
+
"`@ouro.bot/cli` and the `ouro.bot` wrapper are version-synced for the daemon replacement and connect-bay progress release."
|
|
20
|
+
]
|
|
21
|
+
},
|
|
4
22
|
{
|
|
5
23
|
"version": "0.1.0-alpha.425",
|
|
6
24
|
"changes": [
|
|
@@ -378,7 +378,9 @@ async function checkAgentConfigWithProviderHealth(agentName, bundlesRoot, deps =
|
|
|
378
378
|
});
|
|
379
379
|
}
|
|
380
380
|
}
|
|
381
|
+
let firstFailure = null;
|
|
381
382
|
for (const group of pingGroups.values()) {
|
|
383
|
+
deps.onProgress?.(`checking ${group.provider} / ${group.model}...`);
|
|
382
384
|
const result = await ping(group.provider, providerCredentialConfig(group.record), { model: group.model });
|
|
383
385
|
if (!result.ok) {
|
|
384
386
|
for (const lane of group.lanes) {
|
|
@@ -392,7 +394,8 @@ async function checkAgentConfigWithProviderHealth(agentName, bundlesRoot, deps =
|
|
|
392
394
|
attempts: pingAttemptCount(result),
|
|
393
395
|
});
|
|
394
396
|
}
|
|
395
|
-
|
|
397
|
+
firstFailure ??= failedPingResult(agentName, group.lanes[0], group.provider, group.model, result);
|
|
398
|
+
continue;
|
|
396
399
|
}
|
|
397
400
|
for (const lane of group.lanes) {
|
|
398
401
|
writeLaneReadiness({
|
|
@@ -405,6 +408,8 @@ async function checkAgentConfigWithProviderHealth(agentName, bundlesRoot, deps =
|
|
|
405
408
|
});
|
|
406
409
|
}
|
|
407
410
|
}
|
|
411
|
+
if (firstFailure)
|
|
412
|
+
return firstFailure;
|
|
408
413
|
(0, runtime_1.emitNervesEvent)({
|
|
409
414
|
component: "daemon",
|
|
410
415
|
event: "daemon.agent_config_valid",
|
|
@@ -329,12 +329,10 @@ async function runCommandProgressPhase(progress, label, run, detail) {
|
|
|
329
329
|
}
|
|
330
330
|
}
|
|
331
331
|
function daemonProgressSummary(result) {
|
|
332
|
-
if (result.verifyStartupStatus === false)
|
|
333
|
-
return "not answering yet";
|
|
334
332
|
if (result.alreadyRunning)
|
|
335
333
|
return "already running";
|
|
336
|
-
if (result.message.includes("
|
|
337
|
-
return "
|
|
334
|
+
if (result.message.includes("replaced"))
|
|
335
|
+
return "replacement ready";
|
|
338
336
|
return "ready";
|
|
339
337
|
}
|
|
340
338
|
async function reportPostRepairProviderHealth(deps, repairedAgents, onProgress) {
|
|
@@ -464,6 +462,7 @@ async function ensureDaemonRunning(deps, options = {}) {
|
|
|
464
462
|
cleanupStaleSocket: deps.cleanupStaleSocket,
|
|
465
463
|
startDaemonProcess: deps.startDaemonProcess,
|
|
466
464
|
checkSocketAlive: deps.checkSocketAlive,
|
|
465
|
+
onProgress: deps.reportDaemonStartupPhase,
|
|
467
466
|
});
|
|
468
467
|
if (!runtimeResult.verifyStartupStatus) {
|
|
469
468
|
return runtimeResult;
|
|
@@ -1626,27 +1625,218 @@ function enableAgentSense(agent, sense, deps) {
|
|
|
1626
1625
|
};
|
|
1627
1626
|
fs.writeFileSync(configPath, `${JSON.stringify(raw, null, 2)}\n`, "utf-8");
|
|
1628
1627
|
}
|
|
1629
|
-
|
|
1628
|
+
const CONNECT_MENU_PROMPT = "Choose [1-6] or type a name: ";
|
|
1629
|
+
const CONNECT_TITLE_WIDTH = 34;
|
|
1630
|
+
const CONNECT_STATUS_PRIORITY = {
|
|
1631
|
+
"needs attention": 0,
|
|
1632
|
+
locked: 1,
|
|
1633
|
+
"needs credentials": 2,
|
|
1634
|
+
"needs setup": 3,
|
|
1635
|
+
missing: 4,
|
|
1636
|
+
"not attached": 5,
|
|
1637
|
+
ready: 6,
|
|
1638
|
+
attached: 6,
|
|
1639
|
+
};
|
|
1640
|
+
const RESET = "\x1b[0m";
|
|
1641
|
+
const BOLD = "\x1b[1m";
|
|
1642
|
+
const DIM = "\x1b[2m";
|
|
1643
|
+
const TEAL = "\x1b[38;2;78;201;176m";
|
|
1644
|
+
const GREEN = "\x1b[38;2;46;204;64m";
|
|
1645
|
+
const YELLOW = "\x1b[38;2;230;190;50m";
|
|
1646
|
+
/* v8 ignore start -- cosmetic ANSI wrappers @preserve */
|
|
1647
|
+
function connectBold(text) { return `${BOLD}${text}${RESET}`; }
|
|
1648
|
+
function connectDim(text) { return `${DIM}${text}${RESET}`; }
|
|
1649
|
+
function connectTeal(text) { return `${TEAL}${text}${RESET}`; }
|
|
1650
|
+
function connectGreen(text) { return `${GREEN}${text}${RESET}`; }
|
|
1651
|
+
function connectYellow(text) { return `${YELLOW}${text}${RESET}`; }
|
|
1652
|
+
/* v8 ignore stop */
|
|
1653
|
+
function connectMenuIsTTY(deps) {
|
|
1654
|
+
return deps.isTTY ?? process.stdout.isTTY === true;
|
|
1655
|
+
}
|
|
1656
|
+
function connectStatusText(status, isTTY) {
|
|
1657
|
+
if (!isTTY)
|
|
1658
|
+
return status;
|
|
1659
|
+
if (status === "ready" || status === "attached")
|
|
1660
|
+
return connectGreen(status);
|
|
1661
|
+
if (status === "not attached")
|
|
1662
|
+
return connectDim(status);
|
|
1663
|
+
return connectYellow(status);
|
|
1664
|
+
}
|
|
1665
|
+
function connectSectionHeader(label, isTTY) {
|
|
1666
|
+
const rule = "─".repeat(Math.max(6, CONNECT_TITLE_WIDTH - label.length));
|
|
1667
|
+
if (!isTTY)
|
|
1668
|
+
return `${label}\n${rule}`;
|
|
1669
|
+
return ` ${connectTeal("──")} ${connectBold(label)} ${connectTeal(rule)}`;
|
|
1670
|
+
}
|
|
1671
|
+
function summarizeProviderLane(agent, lane, providerHealth) {
|
|
1672
|
+
if (lane.status === "unconfigured") {
|
|
1673
|
+
return {
|
|
1674
|
+
lane: lane.lane,
|
|
1675
|
+
status: "needs setup",
|
|
1676
|
+
title: "choose provider and model",
|
|
1677
|
+
detail: "needs setup",
|
|
1678
|
+
action: lane.repairCommand,
|
|
1679
|
+
};
|
|
1680
|
+
}
|
|
1681
|
+
const fallbackAction = lane.credential.repairCommand ?? providerHealth?.fix;
|
|
1682
|
+
if (lane.credential.status === "missing") {
|
|
1683
|
+
return {
|
|
1684
|
+
lane: lane.lane,
|
|
1685
|
+
status: "needs credentials",
|
|
1686
|
+
title: `${lane.provider} / ${lane.model}`,
|
|
1687
|
+
detail: "credentials missing",
|
|
1688
|
+
action: fallbackAction,
|
|
1689
|
+
};
|
|
1690
|
+
}
|
|
1691
|
+
if (lane.credential.status === "invalid-pool") {
|
|
1692
|
+
return {
|
|
1693
|
+
lane: lane.lane,
|
|
1694
|
+
status: "needs attention",
|
|
1695
|
+
title: `${lane.provider} / ${lane.model}`,
|
|
1696
|
+
detail: "vault unavailable",
|
|
1697
|
+
action: fallbackAction,
|
|
1698
|
+
};
|
|
1699
|
+
}
|
|
1700
|
+
if (lane.readiness.status === "failed") {
|
|
1701
|
+
return {
|
|
1702
|
+
lane: lane.lane,
|
|
1703
|
+
status: "needs attention",
|
|
1704
|
+
title: `${lane.provider} / ${lane.model}`,
|
|
1705
|
+
detail: `failed live check: ${lane.readiness.error ?? "unknown error"}`,
|
|
1706
|
+
action: providerHealth?.fix ?? `ouro auth --agent ${agent} --provider ${lane.provider}`,
|
|
1707
|
+
};
|
|
1708
|
+
}
|
|
1709
|
+
if (lane.readiness.status === "stale") {
|
|
1710
|
+
return {
|
|
1711
|
+
lane: lane.lane,
|
|
1712
|
+
status: "needs attention",
|
|
1713
|
+
title: `${lane.provider} / ${lane.model}`,
|
|
1714
|
+
detail: ["live check is stale", lane.readiness.reason].filter(Boolean).join(": "),
|
|
1715
|
+
action: providerHealth?.fix,
|
|
1716
|
+
};
|
|
1717
|
+
}
|
|
1718
|
+
if (lane.readiness.status === "ready") {
|
|
1719
|
+
return {
|
|
1720
|
+
lane: lane.lane,
|
|
1721
|
+
status: "ready",
|
|
1722
|
+
title: `${lane.provider} / ${lane.model}`,
|
|
1723
|
+
detail: "ready",
|
|
1724
|
+
};
|
|
1725
|
+
}
|
|
1726
|
+
return {
|
|
1727
|
+
lane: lane.lane,
|
|
1728
|
+
status: "needs attention",
|
|
1729
|
+
title: `${lane.provider} / ${lane.model}`,
|
|
1730
|
+
detail: "live check did not complete yet",
|
|
1731
|
+
action: providerHealth?.fix,
|
|
1732
|
+
};
|
|
1733
|
+
}
|
|
1734
|
+
function summarizeProvidersForConnect(agent, visibility, providerHealth) {
|
|
1735
|
+
const laneSummaries = visibility.lanes.map((lane) => summarizeProviderLane(agent, lane, providerHealth));
|
|
1736
|
+
const worstLaneStatus = laneSummaries.reduce((worst, lane) => CONNECT_STATUS_PRIORITY[lane.status] < CONNECT_STATUS_PRIORITY[worst] ? lane.status : worst, "ready");
|
|
1737
|
+
const providerHealthStatus = !providerHealth || providerHealth.ok
|
|
1738
|
+
? undefined
|
|
1739
|
+
: (() => {
|
|
1740
|
+
const error = String(providerHealth.error).toLowerCase();
|
|
1741
|
+
const fix = String(providerHealth.fix).toLowerCase();
|
|
1742
|
+
if (error.includes("failed live check"))
|
|
1743
|
+
return "needs attention";
|
|
1744
|
+
if (error.includes("has no credentials"))
|
|
1745
|
+
return "needs credentials";
|
|
1746
|
+
if (error.includes("missing") && error.includes("provider"))
|
|
1747
|
+
return "needs setup";
|
|
1748
|
+
if (error.includes("vault is locked") || error.includes("vault locked"))
|
|
1749
|
+
return "locked";
|
|
1750
|
+
if (fix.includes("ouro auth"))
|
|
1751
|
+
return "needs credentials";
|
|
1752
|
+
if (fix.includes("ouro use"))
|
|
1753
|
+
return "needs setup";
|
|
1754
|
+
if (fix.includes("vault unlock"))
|
|
1755
|
+
return "locked";
|
|
1756
|
+
return "needs attention";
|
|
1757
|
+
})();
|
|
1758
|
+
const nextLane = laneSummaries.find((lane) => lane.status !== "ready");
|
|
1759
|
+
return {
|
|
1760
|
+
status: providerHealthStatus ?? worstLaneStatus,
|
|
1761
|
+
detailLines: laneSummaries.flatMap((lane) => [
|
|
1762
|
+
`${lane.lane.padEnd(8)} ${lane.title}`,
|
|
1763
|
+
` ${lane.detail}`,
|
|
1764
|
+
]),
|
|
1765
|
+
nextAction: nextLane?.action ?? providerHealth?.fix,
|
|
1766
|
+
nextNote: nextLane ? `${nextLane.lane} ${nextLane.detail}` : undefined,
|
|
1767
|
+
};
|
|
1768
|
+
}
|
|
1769
|
+
function connectEntryNeedsAttention(entry) {
|
|
1770
|
+
return entry.status !== "ready" && entry.status !== "attached";
|
|
1771
|
+
}
|
|
1772
|
+
function connectNextEntry(entries) {
|
|
1773
|
+
return entries.find((entry) => connectEntryNeedsAttention(entry));
|
|
1774
|
+
}
|
|
1775
|
+
function appendConnectOptionalLine(lines, prefix, value) {
|
|
1776
|
+
if (typeof value === "string" && value.length > 0) {
|
|
1777
|
+
lines.push(` ${prefix}${value}`);
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
function connectNextMoveLines(entries, isTTY) {
|
|
1781
|
+
const next = connectNextEntry(entries);
|
|
1782
|
+
if (!next) {
|
|
1783
|
+
return [
|
|
1784
|
+
connectSectionHeader("Next best move", isTTY),
|
|
1785
|
+
" Everything here is ready. Pick what you want to review or refresh.",
|
|
1786
|
+
];
|
|
1787
|
+
}
|
|
1788
|
+
const lines = [
|
|
1789
|
+
connectSectionHeader("Next best move", isTTY),
|
|
1790
|
+
` ${next.name} - ${next.status}`,
|
|
1791
|
+
];
|
|
1792
|
+
appendConnectOptionalLine(lines, "", next.nextNote);
|
|
1793
|
+
appendConnectOptionalLine(lines, "run: ", next.nextAction);
|
|
1794
|
+
return lines;
|
|
1795
|
+
}
|
|
1796
|
+
function renderConnectEntry(entry, isTTY) {
|
|
1797
|
+
const label = `${entry.option}. ${entry.name}`.padEnd(25);
|
|
1798
|
+
const lines = [` ${label} ${connectStatusText(entry.status, isTTY)}`];
|
|
1799
|
+
for (const detail of entry.detailLines ?? []) {
|
|
1800
|
+
lines.push(` ${detail}`);
|
|
1801
|
+
}
|
|
1802
|
+
if (entry.description) {
|
|
1803
|
+
lines.push(isTTY ? ` ${connectDim(entry.description)}` : ` ${entry.description}`);
|
|
1804
|
+
}
|
|
1805
|
+
return lines;
|
|
1806
|
+
}
|
|
1807
|
+
function readConnectBaySenseFlags(agent, deps) {
|
|
1808
|
+
const configPath = path.join(providerCliAgentRoot({ agent }, deps), "agent.json");
|
|
1809
|
+
const parsed = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
1810
|
+
return {
|
|
1811
|
+
teamsEnabled: parsed.senses?.teams?.enabled === true,
|
|
1812
|
+
blueBubblesEnabled: parsed.senses?.bluebubbles?.enabled === true,
|
|
1813
|
+
};
|
|
1814
|
+
}
|
|
1815
|
+
async function buildConnectMenu(agent, deps, onProgress) {
|
|
1816
|
+
const bundlesRoot = path.dirname(providerCliAgentRoot({ agent }, deps));
|
|
1817
|
+
let providerHealth;
|
|
1818
|
+
try {
|
|
1819
|
+
onProgress?.("checking selected providers");
|
|
1820
|
+
providerHealth = await checkAgentProviderHealth(agent, bundlesRoot, deps, onProgress);
|
|
1821
|
+
}
|
|
1822
|
+
catch (error) {
|
|
1823
|
+
providerHealth = {
|
|
1824
|
+
ok: false,
|
|
1825
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1826
|
+
fix: `Run 'ouro auth verify --agent ${agent}' to inspect provider health.`,
|
|
1827
|
+
};
|
|
1828
|
+
}
|
|
1630
1829
|
const providerVisibility = (0, provider_visibility_1.buildAgentProviderVisibility)({
|
|
1631
1830
|
agentName: agent,
|
|
1632
1831
|
agentRoot: providerCliAgentRoot({ agent }, deps),
|
|
1633
1832
|
homeDir: providerCliHomeDir(deps),
|
|
1634
1833
|
});
|
|
1635
|
-
const
|
|
1636
|
-
|
|
1637
|
-
: providerVisibility.lanes.some((lane) => lane.status === "configured" && lane.credential.status !== "present")
|
|
1638
|
-
? "needs auth"
|
|
1639
|
-
: providerVisibility.lanes.some((lane) => lane.status === "configured" && (lane.readiness.status === "failed" || lane.readiness.status === "stale"))
|
|
1640
|
-
? "needs attention"
|
|
1641
|
-
: "ready";
|
|
1642
|
-
const providerDetail = providerVisibility.lanes.map((lane) => lane.status === "configured"
|
|
1643
|
-
? `${lane.lane}: ${lane.provider} / ${lane.model}`
|
|
1644
|
-
: `${lane.lane}: choose provider/model`).join(" | ");
|
|
1834
|
+
const providerSummary = summarizeProvidersForConnect(agent, providerVisibility, providerHealth);
|
|
1835
|
+
onProgress?.("loading portable settings");
|
|
1645
1836
|
const runtimeConfig = await (0, runtime_credentials_1.refreshRuntimeCredentialConfig)(agent, { preserveCachedOnFailure: true });
|
|
1837
|
+
onProgress?.("loading this machine's settings");
|
|
1646
1838
|
const machineRuntime = await (0, runtime_credentials_1.refreshMachineRuntimeCredentialConfig)(agent, currentMachineId(deps), { preserveCachedOnFailure: true });
|
|
1647
|
-
const
|
|
1648
|
-
const teamsEnabled = agentConfig.senses?.teams?.enabled === true;
|
|
1649
|
-
const blueBubblesEnabled = agentConfig.senses?.bluebubbles?.enabled === true;
|
|
1839
|
+
const { teamsEnabled, blueBubblesEnabled } = readConnectBaySenseFlags(agent, deps);
|
|
1650
1840
|
const perplexityStatus = runtimeConfig.ok
|
|
1651
1841
|
? hasRuntimeConfigValue(runtimeConfig.config, "integrations.perplexityApiKey") ? "ready" : "missing"
|
|
1652
1842
|
: runtimeConfigReadStatus(runtimeConfig);
|
|
@@ -1668,29 +1858,90 @@ async function buildConnectMenu(agent, deps) {
|
|
|
1668
1858
|
? "attached"
|
|
1669
1859
|
: "not attached"
|
|
1670
1860
|
: machineRuntimeReadStatus(machineRuntime);
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1861
|
+
const entries = [
|
|
1862
|
+
{
|
|
1863
|
+
option: "1",
|
|
1864
|
+
name: "Providers",
|
|
1865
|
+
section: "Provider core",
|
|
1866
|
+
status: providerSummary.status,
|
|
1867
|
+
detailLines: providerSummary.detailLines,
|
|
1868
|
+
nextAction: providerSummary.nextAction,
|
|
1869
|
+
nextNote: providerSummary.nextNote,
|
|
1870
|
+
},
|
|
1871
|
+
{
|
|
1872
|
+
option: "2",
|
|
1873
|
+
name: "Perplexity search",
|
|
1874
|
+
section: "Portable",
|
|
1875
|
+
status: perplexityStatus,
|
|
1876
|
+
description: "Web search via Perplexity.",
|
|
1877
|
+
nextAction: connectEntryNeedsAttention({
|
|
1878
|
+
option: "2",
|
|
1879
|
+
name: "Perplexity search",
|
|
1880
|
+
section: "Portable",
|
|
1881
|
+
status: perplexityStatus,
|
|
1882
|
+
}) ? `ouro connect perplexity --agent ${agent}` : undefined,
|
|
1883
|
+
},
|
|
1884
|
+
{
|
|
1885
|
+
option: "3",
|
|
1886
|
+
name: "Memory embeddings",
|
|
1887
|
+
section: "Portable",
|
|
1888
|
+
status: embeddingsStatus,
|
|
1889
|
+
description: "Memory retrieval and note search.",
|
|
1890
|
+
nextAction: connectEntryNeedsAttention({
|
|
1891
|
+
option: "3",
|
|
1892
|
+
name: "Memory embeddings",
|
|
1893
|
+
section: "Portable",
|
|
1894
|
+
status: embeddingsStatus,
|
|
1895
|
+
}) ? `ouro connect embeddings --agent ${agent}` : undefined,
|
|
1896
|
+
},
|
|
1897
|
+
{
|
|
1898
|
+
option: "4",
|
|
1899
|
+
name: "Teams",
|
|
1900
|
+
section: "Portable",
|
|
1901
|
+
status: teamsStatus,
|
|
1902
|
+
description: "Microsoft Teams sense credentials.",
|
|
1903
|
+
nextAction: connectEntryNeedsAttention({
|
|
1904
|
+
option: "4",
|
|
1905
|
+
name: "Teams",
|
|
1906
|
+
section: "Portable",
|
|
1907
|
+
status: teamsStatus,
|
|
1908
|
+
}) ? `ouro connect teams --agent ${agent}` : undefined,
|
|
1909
|
+
},
|
|
1910
|
+
{
|
|
1911
|
+
option: "5",
|
|
1912
|
+
name: "BlueBubbles iMessage",
|
|
1913
|
+
section: "This machine",
|
|
1914
|
+
status: blueBubblesStatus,
|
|
1915
|
+
description: "Local Mac Messages bridge.",
|
|
1916
|
+
nextAction: connectEntryNeedsAttention({
|
|
1917
|
+
option: "5",
|
|
1918
|
+
name: "BlueBubbles iMessage",
|
|
1919
|
+
section: "This machine",
|
|
1920
|
+
status: blueBubblesStatus,
|
|
1921
|
+
}) ? `ouro connect bluebubbles --agent ${agent}` : undefined,
|
|
1922
|
+
},
|
|
1923
|
+
];
|
|
1924
|
+
const isTTY = connectMenuIsTTY(deps);
|
|
1925
|
+
const lines = [
|
|
1926
|
+
isTTY ? connectBold(`${agent} connect bay`) : `${agent} connect bay`,
|
|
1927
|
+
isTTY
|
|
1928
|
+
? connectDim("Bring one capability online. Provider status is checked live.")
|
|
1929
|
+
: "Bring one capability online. Provider status is checked live.",
|
|
1689
1930
|
"",
|
|
1690
|
-
|
|
1931
|
+
...connectNextMoveLines(entries, isTTY),
|
|
1691
1932
|
"",
|
|
1692
|
-
|
|
1693
|
-
|
|
1933
|
+
];
|
|
1934
|
+
for (const section of ["Provider core", "Portable", "This machine"]) {
|
|
1935
|
+
lines.push(connectSectionHeader(section, isTTY));
|
|
1936
|
+
for (const entry of entries.filter((candidate) => candidate.section === section)) {
|
|
1937
|
+
lines.push(...renderConnectEntry(entry, isTTY));
|
|
1938
|
+
lines.push("");
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
lines.push(isTTY ? ` ${connectDim("6. Not now")}` : " 6. Not now");
|
|
1942
|
+
lines.push("");
|
|
1943
|
+
lines.push(CONNECT_MENU_PROMPT);
|
|
1944
|
+
return lines.join("\n");
|
|
1694
1945
|
}
|
|
1695
1946
|
async function executeConnectPerplexity(agent, deps) {
|
|
1696
1947
|
if (agent === "SerpentGuide") {
|
|
@@ -1951,7 +2202,14 @@ async function executeConnect(command, deps) {
|
|
|
1951
2202
|
return executeConnectTeams(command.agent, deps);
|
|
1952
2203
|
if (command.target === "bluebubbles")
|
|
1953
2204
|
return executeConnectBlueBubbles(command.agent, deps);
|
|
1954
|
-
const
|
|
2205
|
+
const progress = createHumanCommandProgress(deps, "connect");
|
|
2206
|
+
let menu;
|
|
2207
|
+
try {
|
|
2208
|
+
menu = await runCommandProgressPhase(progress, "checking current connections", () => buildConnectMenu(command.agent, deps, (message) => progress.updateDetail(message)), () => "ready");
|
|
2209
|
+
}
|
|
2210
|
+
finally {
|
|
2211
|
+
progress.end();
|
|
2212
|
+
}
|
|
1955
2213
|
const promptInput = deps.promptInput;
|
|
1956
2214
|
if (!promptInput) {
|
|
1957
2215
|
const message = [
|
|
@@ -3348,12 +3606,14 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
3348
3606
|
progress.announceStep?.(label);
|
|
3349
3607
|
},
|
|
3350
3608
|
}, { initialAlive: daemonAliveBeforeStart });
|
|
3351
|
-
progress.completePhase("starting daemon", daemonProgressSummary(daemonResult));
|
|
3352
3609
|
if (daemonResult.verifyStartupStatus === false) {
|
|
3610
|
+
;
|
|
3611
|
+
progress.announceStep?.("replacement daemon did not answer in time");
|
|
3353
3612
|
progress.end();
|
|
3354
3613
|
deps.writeStdout(daemonResult.message);
|
|
3355
3614
|
return daemonResult.message;
|
|
3356
3615
|
}
|
|
3616
|
+
progress.completePhase("starting daemon", daemonProgressSummary(daemonResult));
|
|
3357
3617
|
if (!providerChecksAlreadyRun || daemonResult.alreadyRunning) {
|
|
3358
3618
|
progress.startPhase("provider checks");
|
|
3359
3619
|
const providerDegraded = await checkAlreadyRunningAgentProviders(deps, (msg) => progress.updateDetail(msg));
|
|
@@ -9,6 +9,7 @@ async function verifyDaemonStarted(deps) {
|
|
|
9
9
|
const maxWaitMs = 10_000;
|
|
10
10
|
const pollIntervalMs = 500;
|
|
11
11
|
const deadline = Date.now() + maxWaitMs;
|
|
12
|
+
deps.onProgress?.("waiting for the replacement daemon to answer");
|
|
12
13
|
while (Date.now() < deadline) {
|
|
13
14
|
await new Promise((r) => setTimeout(r, pollIntervalMs));
|
|
14
15
|
if (await deps.checkSocketAlive(deps.socketPath))
|
|
@@ -102,7 +103,9 @@ async function ensureCurrentDaemonRuntime(deps) {
|
|
|
102
103
|
if (driftReasons.length > 0) {
|
|
103
104
|
const includesVersionDrift = driftReasons.some((entry) => entry.key === "version");
|
|
104
105
|
const publicDriftSummary = formatRuntimeDriftPublicSummary(driftReasons);
|
|
106
|
+
deps.onProgress?.("preparing a replacement for the running background service");
|
|
105
107
|
try {
|
|
108
|
+
deps.onProgress?.("stopping the running background service");
|
|
106
109
|
await deps.stopDaemon();
|
|
107
110
|
}
|
|
108
111
|
catch (error) {
|
|
@@ -110,8 +113,8 @@ async function ensureCurrentDaemonRuntime(deps) {
|
|
|
110
113
|
result = {
|
|
111
114
|
alreadyRunning: true,
|
|
112
115
|
message: includesVersionDrift
|
|
113
|
-
? `daemon already running (${deps.socketPath}; could not replace
|
|
114
|
-
: `daemon already running (${deps.socketPath}; could not replace runtime drift ${publicDriftSummary}: ${reason})`,
|
|
116
|
+
? `daemon already running (${deps.socketPath}; could not replace the running background service ${runningVersion} -> ${deps.localVersion}: ${reason})`
|
|
117
|
+
: `daemon already running (${deps.socketPath}; could not replace the running background service after runtime drift ${publicDriftSummary}: ${reason})`,
|
|
115
118
|
};
|
|
116
119
|
(0, runtime_1.emitNervesEvent)({
|
|
117
120
|
level: "warn",
|
|
@@ -138,16 +141,17 @@ async function ensureCurrentDaemonRuntime(deps) {
|
|
|
138
141
|
return result;
|
|
139
142
|
}
|
|
140
143
|
deps.cleanupStaleSocket(deps.socketPath);
|
|
144
|
+
deps.onProgress?.("starting the replacement background service");
|
|
141
145
|
const started = await deps.startDaemonProcess(deps.socketPath);
|
|
142
146
|
const pid = started.pid ?? "unknown";
|
|
143
147
|
const verified = await verifyDaemonStarted(deps);
|
|
144
148
|
/* v8 ignore next -- daemon liveness failure: requires real daemon crash timing @preserve */
|
|
145
|
-
const suffix = verified ? "" : "\
|
|
149
|
+
const suffix = verified ? "" : "\nreplacement daemon did not answer in time; check logs with `ouro logs` or run `ouro doctor`.";
|
|
146
150
|
result = {
|
|
147
151
|
alreadyRunning: false,
|
|
148
152
|
message: includesVersionDrift
|
|
149
|
-
? `
|
|
150
|
-
: `
|
|
153
|
+
? `replaced the running background service ${runningVersion} -> ${deps.localVersion} (pid ${pid})${suffix}`
|
|
154
|
+
: `replaced the running background service after runtime drift: ${publicDriftSummary} (pid ${pid})${suffix}`,
|
|
151
155
|
verifyStartupStatus: verified,
|
|
152
156
|
startedPid: started.pid ?? null,
|
|
153
157
|
};
|