@lore-co/cli 0.1.27 → 0.1.29
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 +59 -9
- package/dist/agents.d.ts +3 -1
- package/dist/agents.d.ts.map +1 -1
- package/dist/agents.js +31 -7
- package/dist/agents.js.map +1 -1
- package/dist/cli.d.ts +8 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +182 -71
- package/dist/cli.js.map +1 -1
- package/dist/command-help.d.ts +34 -0
- package/dist/command-help.d.ts.map +1 -0
- package/dist/command-help.js +227 -0
- package/dist/command-help.js.map +1 -0
- package/dist/demo.d.ts.map +1 -1
- package/dist/demo.js +15 -2
- package/dist/demo.js.map +1 -1
- package/dist/generated-assets.d.ts +9 -4
- package/dist/generated-assets.d.ts.map +1 -1
- package/dist/generated-assets.js +5 -4
- package/dist/generated-assets.js.map +1 -1
- package/dist/guard.d.ts.map +1 -1
- package/dist/guard.js +4 -3
- package/dist/guard.js.map +1 -1
- package/dist/recovery-cloud-workspace.d.ts +11 -0
- package/dist/recovery-cloud-workspace.d.ts.map +1 -0
- package/dist/recovery-cloud-workspace.js +113 -0
- package/dist/recovery-cloud-workspace.js.map +1 -0
- package/dist/recovery-cloud.d.ts +31 -0
- package/dist/recovery-cloud.d.ts.map +1 -0
- package/dist/recovery-cloud.js +242 -0
- package/dist/recovery-cloud.js.map +1 -0
- package/dist/recovery-codex.d.ts +5 -0
- package/dist/recovery-codex.d.ts.map +1 -0
- package/dist/recovery-codex.js +111 -0
- package/dist/recovery-codex.js.map +1 -0
- package/dist/recovery-copilot.d.ts +14 -0
- package/dist/recovery-copilot.d.ts.map +1 -0
- package/dist/recovery-copilot.js +120 -0
- package/dist/recovery-copilot.js.map +1 -0
- package/dist/recovery-desktop.d.ts +7 -0
- package/dist/recovery-desktop.d.ts.map +1 -0
- package/dist/recovery-desktop.js +179 -0
- package/dist/recovery-desktop.js.map +1 -0
- package/dist/recovery-external.d.ts +61 -0
- package/dist/recovery-external.d.ts.map +1 -0
- package/dist/recovery-external.js +98 -0
- package/dist/recovery-external.js.map +1 -0
- package/dist/recovery-hooks.d.ts +5 -0
- package/dist/recovery-hooks.d.ts.map +1 -0
- package/dist/recovery-hooks.js +115 -0
- package/dist/recovery-hooks.js.map +1 -0
- package/dist/recovery-hosts.d.ts +13 -0
- package/dist/recovery-hosts.d.ts.map +1 -0
- package/dist/recovery-hosts.js +263 -0
- package/dist/recovery-hosts.js.map +1 -0
- package/dist/recovery-polytoken.d.ts +14 -0
- package/dist/recovery-polytoken.d.ts.map +1 -0
- package/dist/recovery-polytoken.js +194 -0
- package/dist/recovery-polytoken.js.map +1 -0
- package/dist/recovery-remote.d.ts +8 -0
- package/dist/recovery-remote.d.ts.map +1 -0
- package/dist/recovery-remote.js +135 -0
- package/dist/recovery-remote.js.map +1 -0
- package/dist/recovery-state.d.ts +25 -1
- package/dist/recovery-state.d.ts.map +1 -1
- package/dist/recovery-state.js +69 -15
- package/dist/recovery-state.js.map +1 -1
- package/dist/recovery-t3.d.ts +17 -0
- package/dist/recovery-t3.d.ts.map +1 -0
- package/dist/recovery-t3.js +58 -0
- package/dist/recovery-t3.js.map +1 -0
- package/dist/recovery-transfer.d.ts +22 -0
- package/dist/recovery-transfer.d.ts.map +1 -0
- package/dist/recovery-transfer.js +228 -0
- package/dist/recovery-transfer.js.map +1 -0
- package/dist/recovery.d.ts +9 -1
- package/dist/recovery.d.ts.map +1 -1
- package/dist/recovery.js +187 -47
- package/dist/recovery.js.map +1 -1
- package/dist/runtime.d.ts +1 -0
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +1 -0
- package/dist/runtime.js.map +1 -1
- package/dist/self-host.d.ts +1 -1
- package/dist/self-host.js +2 -2
- package/dist/uninstall.d.ts +19 -0
- package/dist/uninstall.d.ts.map +1 -0
- package/dist/uninstall.js +128 -0
- package/dist/uninstall.js.map +1 -0
- package/dist/update.js +3 -3
- package/package.json +3 -3
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { COMMAND_GUIDES, ROOT_HELP, helpTopic } from "./command-help.js";
|
|
2
3
|
import { runShareCommand } from "./share.js";
|
|
3
4
|
import { codexApprovalDetail, inspectCodexHookApproval } from "./codex-hook-approval.js";
|
|
4
5
|
import { claudeOnlyCommand, disableDevinCli, runDevinCliHook } from "./devin-cli.js";
|
|
@@ -17,7 +18,7 @@ import { runAskCommand } from "./ask.js";
|
|
|
17
18
|
import { runRememberCommand } from "./remember.js";
|
|
18
19
|
import { runGuardCommand } from "./guard.js";
|
|
19
20
|
import { runContinueCommand, runResumeCommand } from "./handoff.js";
|
|
20
|
-
import { disableRecovery, prepareRecoveryInstallation, runRecoveryCommand, runRecoveryHook, runWrappedAgent } from "./recovery.js";
|
|
21
|
+
import { disableRecovery, prepareAutomaticRecovery, prepareRecoveryInstallation, runRecoveryCommand, runRecoveryHook, runWrappedAgent } from "./recovery.js";
|
|
21
22
|
import { LAUNCHABLE_AGENTS, isLaunchable, isRecoverySource } from "./agents.js";
|
|
22
23
|
import { runAttachCommand, runLiveHostCommand, runLiveRunCommand, } from "./live.js";
|
|
23
24
|
import { runMachinesCommand } from "./machine.js";
|
|
@@ -26,6 +27,7 @@ import { runDevinCommand } from "./devin.js";
|
|
|
26
27
|
import { runHostCommand } from "./host.js";
|
|
27
28
|
import { runDemoCommand } from "./demo.js";
|
|
28
29
|
import { updateCommand } from "./update.js";
|
|
30
|
+
import { UNINSTALL_HELP, uninstallCommand } from "./uninstall.js";
|
|
29
31
|
import { runSelfHostCommand } from "./self-host.js";
|
|
30
32
|
import { ReliabilityStore, ReliabilityStoreError, integrationInvocationStateKey, } from "./reliability-store.js";
|
|
31
33
|
import { IS_STANDALONE_BINARY, LORE_VERSION } from "./version.js";
|
|
@@ -78,62 +80,6 @@ const AGENT_MANIFESTS = {
|
|
|
78
80
|
opencode: OPENCODE_RELIABILITY_INTEGRATION,
|
|
79
81
|
polytoken: POLYTOKEN_RELIABILITY_INTEGRATION,
|
|
80
82
|
};
|
|
81
|
-
const ROOT_HELP = `lore
|
|
82
|
-
Connect local coding agents to Lore shared engineering memory.
|
|
83
|
-
|
|
84
|
-
Usage:
|
|
85
|
-
lore <command> [options]
|
|
86
|
-
|
|
87
|
-
Commands:
|
|
88
|
-
connect Configure Lore and install native agent integrations
|
|
89
|
-
share Get a private workspace link to a learning, session, or delivery
|
|
90
|
-
ask Query shared knowledge and prior session context
|
|
91
|
-
remember Save a durable fact, convention, correction, or decision
|
|
92
|
-
guard Control Context Guard (off, assist, enforce)
|
|
93
|
-
resume Continue previous work with saved Lore context
|
|
94
|
-
continue Hand the current work to a different agent (--on <agent>)
|
|
95
|
-
run Run a coding agent with configured recovery
|
|
96
|
-
recovery Inspect recovery metrics, record feedback, or disable recovery
|
|
97
|
-
attach Reconnect to a live Lore-managed session (--from <machine>)
|
|
98
|
-
machines List registered machines and their live sessions
|
|
99
|
-
github Prepare/post GitHub reviews and observe corrections
|
|
100
|
-
devin Start and manage Lore-enabled Devin sessions
|
|
101
|
-
host Call auditable APIs from external agent hosts
|
|
102
|
-
status Show connector and agent integration state
|
|
103
|
-
doctor Diagnose configuration, integrations, and API reachability
|
|
104
|
-
self-host Run a version-pinned local Docker Compose deployment
|
|
105
|
-
demo Prove a file-scoped Claude-to-Codex handoff
|
|
106
|
-
update Install the latest Lore CLI binary
|
|
107
|
-
disconnect Remove Lore-owned integrations and local credentials
|
|
108
|
-
hook Internal native hook handler
|
|
109
|
-
|
|
110
|
-
Discover:
|
|
111
|
-
lore connect --help
|
|
112
|
-
lore ask --help
|
|
113
|
-
lore remember --help
|
|
114
|
-
lore guard --help
|
|
115
|
-
lore resume --help
|
|
116
|
-
lore continue --help
|
|
117
|
-
lore attach --help
|
|
118
|
-
lore status --help
|
|
119
|
-
lore doctor --help
|
|
120
|
-
lore self-host --help
|
|
121
|
-
lore disconnect --help
|
|
122
|
-
lore host --help
|
|
123
|
-
|
|
124
|
-
Examples:
|
|
125
|
-
lore connect --token "$LORE_WORKSPACE_TOKEN"
|
|
126
|
-
lore ask "How should payment retries work?"
|
|
127
|
-
lore remember "Use pnpm for this repository." --repo acme/app
|
|
128
|
-
lore resume
|
|
129
|
-
lore continue --on codex
|
|
130
|
-
lore connect github --repo owner/repository
|
|
131
|
-
lore status --json
|
|
132
|
-
lore doctor
|
|
133
|
-
lore demo
|
|
134
|
-
lore update
|
|
135
|
-
lore devin --help
|
|
136
|
-
`;
|
|
137
83
|
const CONNECT_HELP = `lore connect
|
|
138
84
|
Authorize this device and idempotently install agent integrations.
|
|
139
85
|
|
|
@@ -150,6 +96,7 @@ Options:
|
|
|
150
96
|
--agent <name> claude, codex, copilot, copilot-cli, copilot-vscode, cowork, cursor, opencode, polytoken, or t3code
|
|
151
97
|
--timeout-ms <ms> Hook request timeout, 250-10000 (default: 2500)
|
|
152
98
|
--fallback <agent> claude, codex, opencode, devin, cursor, copilot-cli, polytoken
|
|
99
|
+
--no-recovery Disable automatic handoff setup (otherwise enabled with two installed clients)
|
|
153
100
|
--json Print machine-readable output
|
|
154
101
|
--help Show this command's help
|
|
155
102
|
|
|
@@ -990,7 +937,7 @@ function parseConnectorConfig(value) {
|
|
|
990
937
|
timeoutMs,
|
|
991
938
|
};
|
|
992
939
|
}
|
|
993
|
-
async function readConnectorConfig(paths) {
|
|
940
|
+
export async function readConnectorConfig(paths) {
|
|
994
941
|
try {
|
|
995
942
|
return parseConnectorConfig(JSON.parse(await readFile(paths.config, "utf8")));
|
|
996
943
|
}
|
|
@@ -1567,6 +1514,10 @@ function parseConnectArguments(args) {
|
|
|
1567
1514
|
parsed.openBrowser = false;
|
|
1568
1515
|
continue;
|
|
1569
1516
|
}
|
|
1517
|
+
if (argument === "--no-recovery") {
|
|
1518
|
+
parsed.recovery = false;
|
|
1519
|
+
continue;
|
|
1520
|
+
}
|
|
1570
1521
|
if (argument !== "--url" &&
|
|
1571
1522
|
argument !== "--dashboard-url" &&
|
|
1572
1523
|
argument !== "--token" &&
|
|
@@ -1638,8 +1589,8 @@ export async function connectWithCredential(options) {
|
|
|
1638
1589
|
throw new Error("Lore agent integrations currently support macOS and Linux");
|
|
1639
1590
|
}
|
|
1640
1591
|
const paths = getLorePaths(options.home, options.home === undefined ? process.env : {}, options.cwd);
|
|
1641
|
-
|
|
1642
|
-
|
|
1592
|
+
if (options.recovery === false && options.fallback)
|
|
1593
|
+
throw new Error("--no-recovery cannot be combined with --fallback.");
|
|
1643
1594
|
const existing = await readConnectorConfig(paths);
|
|
1644
1595
|
const apiUrl = normalizeApiUrl(options.apiUrl);
|
|
1645
1596
|
const dashboardUrl = options.dashboardUrl === undefined
|
|
@@ -1651,6 +1602,17 @@ export async function connectWithCredential(options) {
|
|
|
1651
1602
|
}
|
|
1652
1603
|
const timeoutMs = options.timeoutMs ?? existing?.timeoutMs ?? 2_500;
|
|
1653
1604
|
const identity = await authenticatedIdentity(apiUrl, token.trim(), timeoutMs);
|
|
1605
|
+
const recoveryEnv = options.home === undefined ? process.env : { ...process.env, ZDOTDIR: paths.home };
|
|
1606
|
+
let recoveryWarning;
|
|
1607
|
+
const externalRecoveryHost = options.agents.some(agent => ["t3code", "cowork", "copilot-vscode"].includes(agent));
|
|
1608
|
+
const installRecovery = options.fallback === undefined ? options.recovery === true ?
|
|
1609
|
+
await prepareAutomaticRecovery(paths, recoveryEnv).catch((error) => { recoveryWarning = `Automatic recovery setup: ${error.message}`; return undefined; }) : undefined :
|
|
1610
|
+
await prepareRecoveryInstallation(paths, options.fallback, recoveryEnv).catch((error) => {
|
|
1611
|
+
// A desktop host can be the source even when only its destination is on PATH.
|
|
1612
|
+
if (externalRecoveryHost && error.message.startsWith("No supported source client is installed."))
|
|
1613
|
+
return undefined;
|
|
1614
|
+
throw error;
|
|
1615
|
+
});
|
|
1654
1616
|
const recoveryAgents = installRecovery ? [...installRecovery.sources, installRecovery.fallback]
|
|
1655
1617
|
.filter((agent) => agent !== "devin") : [];
|
|
1656
1618
|
const requestedAgents = [...new Set([...options.agents, ...recoveryAgents])];
|
|
@@ -1743,7 +1705,12 @@ export async function connectWithCredential(options) {
|
|
|
1743
1705
|
await credentialStore.transferPendingTo(reliabilityStore);
|
|
1744
1706
|
}
|
|
1745
1707
|
await reliabilityStore.releaseAuthBlocked(now);
|
|
1746
|
-
const recoveryNotice = installRecovery ? await installRecovery() :
|
|
1708
|
+
const recoveryNotice = installRecovery ? await installRecovery() : recoveryWarning;
|
|
1709
|
+
const hostRecoveryWarnings = options.recovery === true || options.fallback
|
|
1710
|
+
? await (await import("./recovery-hosts.js")).installExternalRecovery(paths, options.agents, options.cwd ?? process.cwd(), options.fallback)
|
|
1711
|
+
.catch((error) => [`Host recovery setup: ${error.message}`]) : [];
|
|
1712
|
+
if (options.recovery === false)
|
|
1713
|
+
await disableRecovery(paths.home);
|
|
1747
1714
|
return {
|
|
1748
1715
|
connected: true,
|
|
1749
1716
|
apiUrl: config.apiUrl,
|
|
@@ -1752,7 +1719,7 @@ export async function connectWithCredential(options) {
|
|
|
1752
1719
|
config: paths.config,
|
|
1753
1720
|
changedHookFiles,
|
|
1754
1721
|
backups,
|
|
1755
|
-
warnings: [...requestedExpansion.warnings, ...(agents.includes("codex")
|
|
1722
|
+
warnings: [...requestedExpansion.warnings, ...hostRecoveryWarnings, ...(agents.includes("codex")
|
|
1756
1723
|
? ["Codex requires hook approval. Open /hooks in Codex and review any new or changed Lore hooks, then start a fresh session. Run lore doctor to verify approval and the first invocation."]
|
|
1757
1724
|
: [])],
|
|
1758
1725
|
...(recoveryNotice ? { recoveryNotice } : {}),
|
|
@@ -1807,6 +1774,8 @@ async function requestDeviceAuthorization(input) {
|
|
|
1807
1774
|
const intervalMs = authorization.data.intervalSeconds * 1_000;
|
|
1808
1775
|
while (Date.now() < expiresAt) {
|
|
1809
1776
|
await delay(intervalMs);
|
|
1777
|
+
if (Date.now() >= expiresAt)
|
|
1778
|
+
break;
|
|
1810
1779
|
let pollResponse;
|
|
1811
1780
|
try {
|
|
1812
1781
|
pollResponse = await fetch(`${input.apiUrl}/v1/device-authorizations/poll`, {
|
|
@@ -1831,10 +1800,23 @@ async function requestDeviceAuthorization(input) {
|
|
|
1831
1800
|
}
|
|
1832
1801
|
continue;
|
|
1833
1802
|
}
|
|
1803
|
+
if (pollResponse.status >= 500) {
|
|
1804
|
+
await pollResponse.body?.cancel().catch(() => { });
|
|
1805
|
+
continue;
|
|
1806
|
+
}
|
|
1834
1807
|
if (!pollResponse.ok) {
|
|
1835
1808
|
throw new Error("Lore browser approval failed. Run connect --login again.");
|
|
1836
1809
|
}
|
|
1837
|
-
|
|
1810
|
+
let body;
|
|
1811
|
+
try {
|
|
1812
|
+
body = await pollResponse.json();
|
|
1813
|
+
}
|
|
1814
|
+
catch (error) {
|
|
1815
|
+
if (!(error instanceof SyntaxError))
|
|
1816
|
+
continue;
|
|
1817
|
+
throw new Error("Lore returned an incompatible device authorization response.");
|
|
1818
|
+
}
|
|
1819
|
+
const result = PollDeviceAuthorizationResponseSchema.safeParse(body);
|
|
1838
1820
|
if (!result.success) {
|
|
1839
1821
|
throw new Error("Lore returned an incompatible device authorization response.");
|
|
1840
1822
|
}
|
|
@@ -1842,15 +1824,38 @@ async function requestDeviceAuthorization(input) {
|
|
|
1842
1824
|
continue;
|
|
1843
1825
|
}
|
|
1844
1826
|
if (result.data.status === "approved") {
|
|
1845
|
-
return result.data.token;
|
|
1827
|
+
return { token: result.data.token, deviceCode: authorization.data.deviceCode };
|
|
1846
1828
|
}
|
|
1847
1829
|
if (result.data.status === "denied") {
|
|
1848
1830
|
throw new Error("Lore access was denied in the dashboard.");
|
|
1849
1831
|
}
|
|
1832
|
+
if (result.data.status === "consumed") {
|
|
1833
|
+
throw new Error("Lore approval was already completed, but this login did not receive its credential. Run connect --login again.");
|
|
1834
|
+
}
|
|
1850
1835
|
throw new Error("Lore browser approval expired. Run connect --login again.");
|
|
1851
1836
|
}
|
|
1852
1837
|
throw new Error("Lore browser approval expired. Run connect --login again.");
|
|
1853
1838
|
}
|
|
1839
|
+
async function acknowledgeDeviceAuthorization(apiUrl, authorization) {
|
|
1840
|
+
// The credential is already saved. A lost acknowledgement must not undo
|
|
1841
|
+
// login; old servers may lack this endpoint, and unacknowledged grants expire.
|
|
1842
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
1843
|
+
try {
|
|
1844
|
+
const response = await fetch(`${apiUrl}/v1/device-authorizations/acknowledge`, {
|
|
1845
|
+
method: "POST",
|
|
1846
|
+
headers: { accept: "application/json", "content-type": "application/json" },
|
|
1847
|
+
body: JSON.stringify(authorization),
|
|
1848
|
+
signal: AbortSignal.timeout(2_000),
|
|
1849
|
+
});
|
|
1850
|
+
await response.body?.cancel();
|
|
1851
|
+
if (response.ok || (response.status >= 400 && response.status < 500))
|
|
1852
|
+
return;
|
|
1853
|
+
}
|
|
1854
|
+
catch {
|
|
1855
|
+
// Retry a lost response with the same secrets.
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1854
1859
|
async function connectCommand(args) {
|
|
1855
1860
|
const parsed = parseConnectArguments(args);
|
|
1856
1861
|
if (parsed === null) {
|
|
@@ -1876,25 +1881,29 @@ async function connectCommand(args) {
|
|
|
1876
1881
|
if (parsed.login && hasProvidedToken) {
|
|
1877
1882
|
throw new Error("--login cannot be combined with an explicit or environment workspace token. Unset it or use the token directly.");
|
|
1878
1883
|
}
|
|
1879
|
-
const
|
|
1884
|
+
const authorization = parsed.login
|
|
1880
1885
|
? await requestDeviceAuthorization({
|
|
1881
1886
|
apiUrl,
|
|
1882
1887
|
...(dashboardUrl === undefined ? {} : { dashboardUrl }),
|
|
1883
1888
|
agents: parsed.agents,
|
|
1884
1889
|
openBrowser: parsed.openBrowser,
|
|
1885
1890
|
})
|
|
1886
|
-
:
|
|
1891
|
+
: undefined;
|
|
1892
|
+
const token = authorization?.token ?? configured;
|
|
1887
1893
|
if (token === undefined || token.trim() === "") {
|
|
1888
1894
|
throw new Error("Workspace token is required. Use --login, --token <token>, LORE_WORKSPACE_TOKEN, or LORE_TOKEN.");
|
|
1889
1895
|
}
|
|
1890
1896
|
const result = await connectWithCredential({
|
|
1891
1897
|
...(parsed.fallback === undefined ? {} : { fallback: parsed.fallback }),
|
|
1898
|
+
recovery: parsed.recovery ?? true,
|
|
1892
1899
|
apiUrl,
|
|
1893
1900
|
...(dashboardUrl === undefined ? {} : { dashboardUrl }),
|
|
1894
1901
|
token,
|
|
1895
1902
|
agents: parsed.agents,
|
|
1896
1903
|
...(parsed.timeoutMs === undefined ? {} : { timeoutMs: parsed.timeoutMs }),
|
|
1897
1904
|
});
|
|
1905
|
+
if (authorization)
|
|
1906
|
+
await acknowledgeDeviceAuthorization(apiUrl, authorization);
|
|
1898
1907
|
writeResult(result, parsed.json, `access authorized; integrations installed: ${result.agents.join(", ")}\napi_url: ${result.apiUrl}\nconfig: ${result.config}\nRestart your agent and complete a turn, then run lore doctor to verify recording.\n${result.recoveryNotice ? `${result.recoveryNotice}\n` : ""}${result.warnings.map((warning) => `warning: ${warning}\n`).join("")}`);
|
|
1899
1908
|
}
|
|
1900
1909
|
async function queueCount(paths) {
|
|
@@ -2217,7 +2226,10 @@ async function disconnectCommand(args) {
|
|
|
2217
2226
|
if (parsed === null) {
|
|
2218
2227
|
return;
|
|
2219
2228
|
}
|
|
2220
|
-
const
|
|
2229
|
+
const result = await disconnectInstallation();
|
|
2230
|
+
writeResult(result, parsed.json, `disconnected: yes\nchanged_hook_files: ${result.changedHookFiles.length}\n`);
|
|
2231
|
+
}
|
|
2232
|
+
export async function disconnectInstallation(paths = getLorePaths(), preservePendingState = false) {
|
|
2221
2233
|
await disableRecovery(paths.home);
|
|
2222
2234
|
await disableDevinCli(paths.home);
|
|
2223
2235
|
const config = await readConnectorConfig(paths);
|
|
@@ -2267,11 +2279,12 @@ async function disconnectCommand(args) {
|
|
|
2267
2279
|
rm(paths.runtimeInvocationHealthWriter, { force: true }),
|
|
2268
2280
|
rm(paths.runtimeVersion, { force: true }),
|
|
2269
2281
|
rm(paths.runtimePackage, { force: true }),
|
|
2270
|
-
|
|
2271
|
-
|
|
2282
|
+
...(preservePendingState ? [] : [
|
|
2283
|
+
rm(paths.state, { recursive: true, force: true }),
|
|
2284
|
+
rm(paths.queue, { recursive: true, force: true }),
|
|
2285
|
+
]),
|
|
2272
2286
|
]);
|
|
2273
|
-
|
|
2274
|
-
writeResult(result, parsed.json, `disconnected: yes\nchanged_hook_files: ${changedHookFiles.length}\n`);
|
|
2287
|
+
return { connected: false, changedHookFiles, backups };
|
|
2275
2288
|
}
|
|
2276
2289
|
async function apiChecks(config) {
|
|
2277
2290
|
const readinessUrl = `${config.apiUrl}/health/ready`;
|
|
@@ -2536,8 +2549,95 @@ async function doctorCommand(args) {
|
|
|
2536
2549
|
process.exitCode = 1;
|
|
2537
2550
|
}
|
|
2538
2551
|
}
|
|
2552
|
+
async function printCommandHelp(path) {
|
|
2553
|
+
const topic = helpTopic(path);
|
|
2554
|
+
process.stdout.write(`When to use: ${COMMAND_GUIDES[topic.command]}\n\n`);
|
|
2555
|
+
if (topic.text) {
|
|
2556
|
+
process.stdout.write(topic.text);
|
|
2557
|
+
return;
|
|
2558
|
+
}
|
|
2559
|
+
const args = [...(topic.subcommand ? [topic.subcommand] : []), "--help"];
|
|
2560
|
+
// Help never loads workspace credentials, makes requests, or runs an agent.
|
|
2561
|
+
switch (topic.command) {
|
|
2562
|
+
case "connect":
|
|
2563
|
+
process.stdout.write(CONNECT_HELP);
|
|
2564
|
+
return;
|
|
2565
|
+
case "status":
|
|
2566
|
+
process.stdout.write(STATUS_HELP);
|
|
2567
|
+
return;
|
|
2568
|
+
case "doctor":
|
|
2569
|
+
process.stdout.write(DOCTOR_HELP);
|
|
2570
|
+
return;
|
|
2571
|
+
case "disconnect":
|
|
2572
|
+
process.stdout.write(DISCONNECT_HELP);
|
|
2573
|
+
return;
|
|
2574
|
+
case "uninstall":
|
|
2575
|
+
process.stdout.write(UNINSTALL_HELP);
|
|
2576
|
+
return;
|
|
2577
|
+
case "share":
|
|
2578
|
+
await runShareCommand(args, null);
|
|
2579
|
+
return;
|
|
2580
|
+
case "ask":
|
|
2581
|
+
await runAskCommand(args, null);
|
|
2582
|
+
return;
|
|
2583
|
+
case "remember":
|
|
2584
|
+
await runRememberCommand(args, null);
|
|
2585
|
+
return;
|
|
2586
|
+
case "guard":
|
|
2587
|
+
await runGuardCommand(args, null);
|
|
2588
|
+
return;
|
|
2589
|
+
case "resume":
|
|
2590
|
+
await runResumeCommand(args, null, getLorePaths());
|
|
2591
|
+
return;
|
|
2592
|
+
case "continue":
|
|
2593
|
+
await runContinueCommand(args, null, getLorePaths());
|
|
2594
|
+
return;
|
|
2595
|
+
case "attach":
|
|
2596
|
+
await runAttachCommand(args, null, getLorePaths());
|
|
2597
|
+
return;
|
|
2598
|
+
case "machines":
|
|
2599
|
+
await runMachinesCommand(args, null, getLorePaths());
|
|
2600
|
+
return;
|
|
2601
|
+
case "host":
|
|
2602
|
+
await runHostCommand(args);
|
|
2603
|
+
return;
|
|
2604
|
+
case "devin":
|
|
2605
|
+
if (topic.subcommand === "cli") {
|
|
2606
|
+
process.stdout.write((await import("./devin-cli.js")).DEVIN_CLI_HELP);
|
|
2607
|
+
return;
|
|
2608
|
+
}
|
|
2609
|
+
await runDevinCommand(args);
|
|
2610
|
+
return;
|
|
2611
|
+
case "self-host":
|
|
2612
|
+
await runSelfHostCommand(args);
|
|
2613
|
+
return;
|
|
2614
|
+
case "demo":
|
|
2615
|
+
await runDemoCommand(args, null);
|
|
2616
|
+
return;
|
|
2617
|
+
case "update":
|
|
2618
|
+
await updateCommand(args);
|
|
2619
|
+
return;
|
|
2620
|
+
default: throw new Error(`Help is unavailable for ${topic.command}`);
|
|
2621
|
+
}
|
|
2622
|
+
}
|
|
2539
2623
|
export async function runCli(args = process.argv.slice(2)) {
|
|
2540
2624
|
const command = args[0];
|
|
2625
|
+
if (command === "help") {
|
|
2626
|
+
const path = args.slice(1);
|
|
2627
|
+
if (!path.length || (path.length === 1 && ["--help", "-h"].includes(path[0])))
|
|
2628
|
+
process.stdout.write(ROOT_HELP);
|
|
2629
|
+
else
|
|
2630
|
+
await printCommandHelp(path);
|
|
2631
|
+
return;
|
|
2632
|
+
}
|
|
2633
|
+
const separator = args.indexOf("--");
|
|
2634
|
+
const helpIndex = args.findIndex((value, index) => index > 0 && (separator < 0 || index < separator) && (value === "--help" || value === "-h"));
|
|
2635
|
+
if (helpIndex > 0) {
|
|
2636
|
+
const subcommand = args[1];
|
|
2637
|
+
const grouped = ["connect", "guard", "recovery", "github", "devin", "host", "self-host"].includes(command ?? "");
|
|
2638
|
+
await printCommandHelp([command, ...(grouped && subcommand && !subcommand.startsWith("-") ? [subcommand] : [])]);
|
|
2639
|
+
return;
|
|
2640
|
+
}
|
|
2541
2641
|
if (command === undefined || command === "--help" || command === "-h") {
|
|
2542
2642
|
process.stdout.write(ROOT_HELP);
|
|
2543
2643
|
return;
|
|
@@ -2577,6 +2677,11 @@ export async function runCli(args = process.argv.slice(2)) {
|
|
|
2577
2677
|
await runWrappedAgent(commandArgs, getLorePaths(process.env.LORE_HOME));
|
|
2578
2678
|
return;
|
|
2579
2679
|
case "recovery":
|
|
2680
|
+
if (commandArgs[0] === "cloud") {
|
|
2681
|
+
const paths = getLorePaths(process.env.LORE_HOME);
|
|
2682
|
+
await (await import("./recovery-cloud.js")).runCloudRecoveryCommand(commandArgs.slice(1), paths, await readConnectorConfig(paths));
|
|
2683
|
+
return;
|
|
2684
|
+
}
|
|
2580
2685
|
await runRecoveryCommand(commandArgs, getLorePaths(process.env.LORE_HOME));
|
|
2581
2686
|
return;
|
|
2582
2687
|
case "recovery-hook":
|
|
@@ -2638,6 +2743,12 @@ export async function runCli(args = process.argv.slice(2)) {
|
|
|
2638
2743
|
case "disconnect":
|
|
2639
2744
|
await disconnectCommand(commandArgs);
|
|
2640
2745
|
return;
|
|
2746
|
+
case "uninstall":
|
|
2747
|
+
await uninstallCommand(commandArgs, {
|
|
2748
|
+
disconnect: () => disconnectInstallation(getLorePaths(), true),
|
|
2749
|
+
retainedDirectory: getLorePaths().loreDirectory,
|
|
2750
|
+
});
|
|
2751
|
+
return;
|
|
2641
2752
|
case "devin-cli-hook":
|
|
2642
2753
|
try {
|
|
2643
2754
|
const result = await runDevinCliHook(getLorePaths(process.env.LORE_HOME).home);
|