@loreai/gateway 0.14.0 → 0.14.1
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/dist/bin.cjs +27 -0
- package/dist/index.cjs +1042 -0
- package/dist/index.d.cts +21 -0
- package/package.json +10 -10
- package/dist/index.js +0 -50087
- package/src/auth.ts +0 -133
- package/src/batch-queue.ts +0 -575
- package/src/cache-analytics.ts +0 -344
- package/src/cli/agents.ts +0 -107
- package/src/cli/bin.ts +0 -11
- package/src/cli/help.ts +0 -55
- package/src/cli/lib/binary.ts +0 -353
- package/src/cli/lib/bspatch.ts +0 -306
- package/src/cli/lib/delta-upgrade.ts +0 -790
- package/src/cli/lib/errors.ts +0 -48
- package/src/cli/lib/ghcr.ts +0 -389
- package/src/cli/lib/patch-cache.ts +0 -342
- package/src/cli/lib/upgrade.ts +0 -454
- package/src/cli/lib/version-check.ts +0 -385
- package/src/cli/main.ts +0 -152
- package/src/cli/run.ts +0 -181
- package/src/cli/start.ts +0 -82
- package/src/cli/upgrade.ts +0 -311
- package/src/cli/version.ts +0 -22
- package/src/compaction.ts +0 -195
- package/src/config.ts +0 -199
- package/src/idle.ts +0 -240
- package/src/index.ts +0 -41
- package/src/llm-adapter.ts +0 -182
- package/src/pipeline.ts +0 -1681
- package/src/recall.ts +0 -433
- package/src/recorder.ts +0 -192
- package/src/server.ts +0 -250
- package/src/session.ts +0 -207
- package/src/stream/anthropic.ts +0 -708
- package/src/temporal-adapter.ts +0 -310
- package/src/translate/anthropic.ts +0 -469
- package/src/translate/openai.ts +0 -536
- package/src/translate/types.ts +0 -222
- package/src/worker-model.ts +0 -408
|
@@ -1,385 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Background Version Check
|
|
3
|
-
*
|
|
4
|
-
* Provides "new version available" notifications for the Lore CLI.
|
|
5
|
-
* On startup, a non-blocking background fetch checks for the latest version.
|
|
6
|
-
* The result is cached to disk and displayed on subsequent invocations.
|
|
7
|
-
*
|
|
8
|
-
* For nightly builds (version contains "-dev."), checks GHCR via the OCI
|
|
9
|
-
* manifest annotation. For stable builds, checks GitHub Releases.
|
|
10
|
-
*
|
|
11
|
-
* Adapted from Sentry CLI's version-check.ts for Lore:
|
|
12
|
-
* - File-based persistence instead of SQLite
|
|
13
|
-
* - No Sentry SDK telemetry — errors are silently swallowed
|
|
14
|
-
* - Inline ANSI codes instead of external color library
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
18
|
-
import { join } from "node:path";
|
|
19
|
-
import { getConfigDir } from "./binary";
|
|
20
|
-
import { VERSION } from "../version";
|
|
21
|
-
import {
|
|
22
|
-
prefetchNightlyPatches,
|
|
23
|
-
prefetchStablePatches,
|
|
24
|
-
} from "./delta-upgrade";
|
|
25
|
-
import { cleanupPatchCache } from "./patch-cache";
|
|
26
|
-
import { fetchLatestFromGitHub, fetchLatestNightlyVersion, getReleaseChannel } from "./upgrade";
|
|
27
|
-
|
|
28
|
-
// ---------------------------------------------------------------------------
|
|
29
|
-
// Constants
|
|
30
|
-
// ---------------------------------------------------------------------------
|
|
31
|
-
|
|
32
|
-
/** Target check interval: ~24 hours */
|
|
33
|
-
const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Minimum time between successive "new version available" notifications.
|
|
37
|
-
*
|
|
38
|
-
* Rate-limits the banner to once per 24h regardless of how many commands
|
|
39
|
-
* run in that window, preventing clutter in scripts, CI output, and
|
|
40
|
-
* screen-sharing sessions.
|
|
41
|
-
*/
|
|
42
|
-
const NOTIFICATION_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
43
|
-
|
|
44
|
-
/** Jitter factor for probabilistic checking (±20%) */
|
|
45
|
-
const JITTER_FACTOR = 0.2;
|
|
46
|
-
|
|
47
|
-
/** Commands/flags that should not show update notifications */
|
|
48
|
-
const SUPPRESSED_ARGS = new Set([
|
|
49
|
-
"upgrade",
|
|
50
|
-
"--version",
|
|
51
|
-
"-v",
|
|
52
|
-
"--json",
|
|
53
|
-
"help",
|
|
54
|
-
]);
|
|
55
|
-
|
|
56
|
-
// ---------------------------------------------------------------------------
|
|
57
|
-
// ANSI color helpers (inline, no external deps)
|
|
58
|
-
// ---------------------------------------------------------------------------
|
|
59
|
-
|
|
60
|
-
const isColorSupported =
|
|
61
|
-
process.env.FORCE_COLOR !== "0" &&
|
|
62
|
-
process.env.NO_COLOR === undefined &&
|
|
63
|
-
(process.stderr.isTTY ?? false);
|
|
64
|
-
|
|
65
|
-
function cyan(text: string): string {
|
|
66
|
-
return isColorSupported ? `\x1b[36m${text}\x1b[39m` : text;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function dim(text: string): string {
|
|
70
|
-
return isColorSupported ? `\x1b[2m${text}\x1b[22m` : text;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// ---------------------------------------------------------------------------
|
|
74
|
-
// File-based persistence (replaces Sentry CLI's SQLite)
|
|
75
|
-
// ---------------------------------------------------------------------------
|
|
76
|
-
|
|
77
|
-
const VERSION_CHECK_FILE = "version-check.json";
|
|
78
|
-
|
|
79
|
-
type VersionCheckData = {
|
|
80
|
-
lastChecked: number | null;
|
|
81
|
-
latestVersion: string | null;
|
|
82
|
-
lastNotified: number | null;
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
function getVersionCheckPath(): string {
|
|
86
|
-
return join(getConfigDir(), VERSION_CHECK_FILE);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function readVersionCheckData(): VersionCheckData {
|
|
90
|
-
try {
|
|
91
|
-
const content = readFileSync(getVersionCheckPath(), "utf-8");
|
|
92
|
-
const data = JSON.parse(content) as Partial<VersionCheckData>;
|
|
93
|
-
return {
|
|
94
|
-
lastChecked: typeof data.lastChecked === "number" ? data.lastChecked : null,
|
|
95
|
-
latestVersion: typeof data.latestVersion === "string" ? data.latestVersion : null,
|
|
96
|
-
lastNotified: typeof data.lastNotified === "number" ? data.lastNotified : null,
|
|
97
|
-
};
|
|
98
|
-
} catch {
|
|
99
|
-
return { lastChecked: null, latestVersion: null, lastNotified: null };
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function writeVersionCheckData(data: VersionCheckData): void {
|
|
104
|
-
try {
|
|
105
|
-
const dir = getConfigDir();
|
|
106
|
-
if (!existsSync(dir)) {
|
|
107
|
-
mkdirSync(dir, { recursive: true });
|
|
108
|
-
}
|
|
109
|
-
writeFileSync(getVersionCheckPath(), JSON.stringify(data), "utf-8");
|
|
110
|
-
} catch {
|
|
111
|
-
// Best-effort — don't fail CLI if persistence fails
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function setVersionCheckInfo(latestVersion: string): void {
|
|
116
|
-
const existing = readVersionCheckData();
|
|
117
|
-
writeVersionCheckData({
|
|
118
|
-
...existing,
|
|
119
|
-
lastChecked: Date.now(),
|
|
120
|
-
latestVersion,
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function markUpdateNotified(): void {
|
|
125
|
-
const existing = readVersionCheckData();
|
|
126
|
-
writeVersionCheckData({
|
|
127
|
-
...existing,
|
|
128
|
-
lastNotified: Date.now(),
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Clear the cached version check state.
|
|
134
|
-
*
|
|
135
|
-
* Should be called when the release channel changes so that stale version
|
|
136
|
-
* data from the previous channel is not shown in update notifications.
|
|
137
|
-
*/
|
|
138
|
-
export function clearVersionCheckCache(): void {
|
|
139
|
-
writeVersionCheckData({
|
|
140
|
-
lastChecked: null,
|
|
141
|
-
latestVersion: null,
|
|
142
|
-
lastNotified: null,
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// ---------------------------------------------------------------------------
|
|
147
|
-
// Check scheduling (probabilistic, ~24h interval with jitter)
|
|
148
|
-
// ---------------------------------------------------------------------------
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Determine if we should check for updates based on time since last check.
|
|
152
|
-
* Uses probabilistic approach: probability increases as we approach/pass the interval.
|
|
153
|
-
*/
|
|
154
|
-
function shouldCheckForUpdate(): boolean {
|
|
155
|
-
const { lastChecked } = readVersionCheckData();
|
|
156
|
-
|
|
157
|
-
if (lastChecked === null) {
|
|
158
|
-
return true;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
const elapsed = Date.now() - lastChecked;
|
|
162
|
-
|
|
163
|
-
// Add jitter to the interval (±20%)
|
|
164
|
-
const jitter = (Math.random() - 0.5) * 2 * JITTER_FACTOR;
|
|
165
|
-
const effectiveInterval = CHECK_INTERVAL_MS * (1 + jitter);
|
|
166
|
-
|
|
167
|
-
// Probability ramps up as we approach/exceed the interval
|
|
168
|
-
// At 0% of interval: ~0% chance
|
|
169
|
-
// At 100% of interval: ~63% chance (1 - 1/e)
|
|
170
|
-
// At 200% of interval: ~86% chance
|
|
171
|
-
const probability = 1 - Math.exp(-elapsed / effectiveInterval);
|
|
172
|
-
|
|
173
|
-
return Math.random() < probability;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// ---------------------------------------------------------------------------
|
|
177
|
-
// Notification rate limiting
|
|
178
|
-
// ---------------------------------------------------------------------------
|
|
179
|
-
|
|
180
|
-
/** Whether we've already returned an update notification this process. */
|
|
181
|
-
let notifiedThisProcess = false;
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Check whether enough time has passed since the last notification.
|
|
185
|
-
* Returns true on first-ever notification (lastNotified === null).
|
|
186
|
-
*/
|
|
187
|
-
function canNotifyAgain(lastNotified: number | null): boolean {
|
|
188
|
-
if (lastNotified === null) {
|
|
189
|
-
return true;
|
|
190
|
-
}
|
|
191
|
-
return Date.now() - lastNotified >= NOTIFICATION_INTERVAL_MS;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// ---------------------------------------------------------------------------
|
|
195
|
-
// Background check
|
|
196
|
-
// ---------------------------------------------------------------------------
|
|
197
|
-
|
|
198
|
-
/** AbortController for pending version check fetch */
|
|
199
|
-
let pendingAbortController: AbortController | null = null;
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* Pre-fetch delta patches for a newly discovered version.
|
|
203
|
-
* Best-effort: errors are silently caught so the version check still succeeds.
|
|
204
|
-
*/
|
|
205
|
-
async function maybePrefetchPatches(
|
|
206
|
-
channel: "stable" | "nightly",
|
|
207
|
-
latestVersion: string,
|
|
208
|
-
signal: AbortSignal,
|
|
209
|
-
): Promise<void> {
|
|
210
|
-
if (Bun.semver.order(latestVersion, VERSION) !== 1) {
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
try {
|
|
214
|
-
if (channel === "nightly") {
|
|
215
|
-
await prefetchNightlyPatches(latestVersion, signal);
|
|
216
|
-
} else {
|
|
217
|
-
await prefetchStablePatches(latestVersion, signal);
|
|
218
|
-
}
|
|
219
|
-
} catch {
|
|
220
|
-
// Pre-fetch is best-effort
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// Opportunistic cleanup of stale cached patches
|
|
224
|
-
try {
|
|
225
|
-
await cleanupPatchCache();
|
|
226
|
-
} catch {
|
|
227
|
-
/* ignore */
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* Start a background check for new versions.
|
|
233
|
-
* Does not block — fires a fetch and lets it complete in the background.
|
|
234
|
-
* Never throws — errors are silently swallowed.
|
|
235
|
-
*/
|
|
236
|
-
function checkForUpdateInBackgroundImpl(): void {
|
|
237
|
-
try {
|
|
238
|
-
if (!shouldCheckForUpdate()) {
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
} catch {
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
pendingAbortController = new AbortController();
|
|
246
|
-
const { signal } = pendingAbortController;
|
|
247
|
-
|
|
248
|
-
const channel = getReleaseChannel();
|
|
249
|
-
|
|
250
|
-
// Fire-and-forget — this promise is intentionally not awaited.
|
|
251
|
-
// The version check runs concurrently with the main command.
|
|
252
|
-
// Results are cached to disk for the next invocation to display.
|
|
253
|
-
(async () => {
|
|
254
|
-
try {
|
|
255
|
-
const latestVersion =
|
|
256
|
-
channel === "nightly"
|
|
257
|
-
? await fetchLatestNightlyVersion(signal)
|
|
258
|
-
: await fetchLatestFromGitHub(signal);
|
|
259
|
-
setVersionCheckInfo(latestVersion);
|
|
260
|
-
|
|
261
|
-
// Pre-fetch delta patches so `lore upgrade` can apply them offline
|
|
262
|
-
await maybePrefetchPatches(channel, latestVersion, signal);
|
|
263
|
-
} catch {
|
|
264
|
-
// Errors here are expected (network failures, timeouts, aborts).
|
|
265
|
-
// Silently swallow — the user will just not see the update nag.
|
|
266
|
-
} finally {
|
|
267
|
-
pendingAbortController = null;
|
|
268
|
-
}
|
|
269
|
-
})();
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
// ---------------------------------------------------------------------------
|
|
273
|
-
// Notification message
|
|
274
|
-
// ---------------------------------------------------------------------------
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* Check whether stderr is attached to a TTY.
|
|
278
|
-
*
|
|
279
|
-
* Non-TTY output covers scripts piping into other commands, CI logs, and
|
|
280
|
-
* editors capturing CLI output. The update banner is human-only signal —
|
|
281
|
-
* suppress it when no human will read it.
|
|
282
|
-
*/
|
|
283
|
-
function isStderrTTY(): boolean {
|
|
284
|
-
return Boolean(process.stderr.isTTY);
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
/**
|
|
288
|
-
* Build the update notification message.
|
|
289
|
-
* Returns null if up-to-date, no cached info, rate-limited, non-TTY, or error.
|
|
290
|
-
*/
|
|
291
|
-
function getUpdateNotificationImpl(): string | null {
|
|
292
|
-
// Gate 1: non-TTY stderr (scripts, CI, pipes)
|
|
293
|
-
if (!isStderrTTY()) {
|
|
294
|
-
return null;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
// Gate 2: don't double-emit within the same process
|
|
298
|
-
if (notifiedThisProcess) {
|
|
299
|
-
return null;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
try {
|
|
303
|
-
const { latestVersion, lastNotified } = readVersionCheckData();
|
|
304
|
-
|
|
305
|
-
if (!latestVersion) {
|
|
306
|
-
return null;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
// Only notify if latest is strictly newer than current
|
|
310
|
-
if (Bun.semver.order(latestVersion, VERSION) !== 1) {
|
|
311
|
-
return null;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
// Gate 3: daily rate limit across CLI invocations
|
|
315
|
-
if (!canNotifyAgain(lastNotified)) {
|
|
316
|
-
return null;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
const channel = getReleaseChannel();
|
|
320
|
-
const label =
|
|
321
|
-
channel === "nightly" ? "New nightly available:" : "Update available:";
|
|
322
|
-
|
|
323
|
-
// Record that we're about to print the banner so repeat invocations
|
|
324
|
-
// within the rate-limit window stay silent.
|
|
325
|
-
try {
|
|
326
|
-
markUpdateNotified();
|
|
327
|
-
} catch {
|
|
328
|
-
// Non-fatal: banner still prints, won't be rate-limited next run
|
|
329
|
-
}
|
|
330
|
-
notifiedThisProcess = true;
|
|
331
|
-
|
|
332
|
-
return `\n${dim(label)} ${cyan(VERSION)} -> ${cyan(latestVersion)} Run ${cyan('"lore upgrade"')} to update.\n`;
|
|
333
|
-
} catch {
|
|
334
|
-
return null;
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
// ---------------------------------------------------------------------------
|
|
339
|
-
// Public API
|
|
340
|
-
// ---------------------------------------------------------------------------
|
|
341
|
-
|
|
342
|
-
/**
|
|
343
|
-
* Check if update notifications should be suppressed for these args.
|
|
344
|
-
*/
|
|
345
|
-
export function shouldSuppressNotification(args: string[]): boolean {
|
|
346
|
-
return args.some((arg) => SUPPRESSED_ARGS.has(arg));
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
/**
|
|
350
|
-
* Check if update checking is disabled via environment variable.
|
|
351
|
-
*/
|
|
352
|
-
function isUpdateCheckDisabled(): boolean {
|
|
353
|
-
return process.env.LORE_NO_UPDATE_CHECK === "1";
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
/**
|
|
357
|
-
* Start a background check for new versions (if not disabled).
|
|
358
|
-
* Does not block — fires a fetch and lets it complete in the background.
|
|
359
|
-
*/
|
|
360
|
-
export function maybeCheckForUpdateInBackground(): void {
|
|
361
|
-
if (isUpdateCheckDisabled()) {
|
|
362
|
-
return;
|
|
363
|
-
}
|
|
364
|
-
checkForUpdateInBackgroundImpl();
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
/**
|
|
368
|
-
* Get the update notification message if a new version is available.
|
|
369
|
-
* Returns null if disabled, up-to-date, no cached info, or on error.
|
|
370
|
-
*/
|
|
371
|
-
export function getUpdateNotification(): string | null {
|
|
372
|
-
if (isUpdateCheckDisabled()) {
|
|
373
|
-
return null;
|
|
374
|
-
}
|
|
375
|
-
return getUpdateNotificationImpl();
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
/**
|
|
379
|
-
* Abort any pending version check to allow process exit.
|
|
380
|
-
* Call this when main CLI work is complete.
|
|
381
|
-
*/
|
|
382
|
-
export function abortPendingVersionCheck(): void {
|
|
383
|
-
pendingAbortController?.abort();
|
|
384
|
-
pendingAbortController = null;
|
|
385
|
-
}
|
package/src/cli/main.ts
DELETED
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CLI entry point — argument parsing and command dispatch.
|
|
3
|
-
*
|
|
4
|
-
* Uses Node.js built-in `parseArgs` from `node:util`.
|
|
5
|
-
*
|
|
6
|
-
* Commands:
|
|
7
|
-
* (none) / run → start gateway + launch agent
|
|
8
|
-
* start → start gateway server only
|
|
9
|
-
* upgrade → self-update
|
|
10
|
-
* help → print usage
|
|
11
|
-
*/
|
|
12
|
-
import { parseArgs } from "node:util";
|
|
13
|
-
import { printHelp, printVersion } from "./help";
|
|
14
|
-
import { commandStart, type StartOptions } from "./start";
|
|
15
|
-
import {
|
|
16
|
-
abortPendingVersionCheck,
|
|
17
|
-
getUpdateNotification,
|
|
18
|
-
maybeCheckForUpdateInBackground,
|
|
19
|
-
shouldSuppressNotification,
|
|
20
|
-
} from "./lib/version-check";
|
|
21
|
-
|
|
22
|
-
// ---------------------------------------------------------------------------
|
|
23
|
-
// Argument parsing
|
|
24
|
-
// ---------------------------------------------------------------------------
|
|
25
|
-
|
|
26
|
-
/** Options shared by all commands. */
|
|
27
|
-
const OPTIONS = {
|
|
28
|
-
port: { type: "string" as const, short: "p" },
|
|
29
|
-
host: { type: "string" as const, short: "H" },
|
|
30
|
-
debug: { type: "boolean" as const, short: "d" },
|
|
31
|
-
version: { type: "boolean" as const, short: "v" },
|
|
32
|
-
help: { type: "boolean" as const, short: "h" },
|
|
33
|
-
} as const;
|
|
34
|
-
|
|
35
|
-
function parsePort(value: string): number {
|
|
36
|
-
const n = Number.parseInt(value, 10);
|
|
37
|
-
if (Number.isNaN(n) || n < 0 || n > 65535) {
|
|
38
|
-
console.error(`Error: Invalid port "${value}". Must be 0–65535.`);
|
|
39
|
-
process.exit(1);
|
|
40
|
-
}
|
|
41
|
-
return n;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function buildStartOptions(values: {
|
|
45
|
-
port?: string;
|
|
46
|
-
host?: string;
|
|
47
|
-
debug?: boolean;
|
|
48
|
-
}): StartOptions {
|
|
49
|
-
return {
|
|
50
|
-
port: values.port ? parsePort(values.port) : undefined,
|
|
51
|
-
host: values.host ?? undefined,
|
|
52
|
-
debug: values.debug ?? undefined,
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// ---------------------------------------------------------------------------
|
|
57
|
-
// Main
|
|
58
|
-
// ---------------------------------------------------------------------------
|
|
59
|
-
|
|
60
|
-
export async function _cli(): Promise<void> {
|
|
61
|
-
// Parse known options, allow positional args for command + pass-through
|
|
62
|
-
let values: ReturnType<typeof parseArgs>["values"];
|
|
63
|
-
let positionals: string[];
|
|
64
|
-
|
|
65
|
-
try {
|
|
66
|
-
const parsed = parseArgs({
|
|
67
|
-
args: process.argv.slice(2),
|
|
68
|
-
options: OPTIONS,
|
|
69
|
-
allowPositionals: true,
|
|
70
|
-
strict: false,
|
|
71
|
-
});
|
|
72
|
-
values = parsed.values;
|
|
73
|
-
positionals = parsed.positionals;
|
|
74
|
-
} catch (e) {
|
|
75
|
-
console.error(`Error: ${e instanceof Error ? e.message : e}`);
|
|
76
|
-
printHelp();
|
|
77
|
-
process.exit(1);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// --version / -v
|
|
81
|
-
if (values.version) {
|
|
82
|
-
printVersion();
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// --help / -h (no command)
|
|
87
|
-
if (values.help && positionals.length === 0) {
|
|
88
|
-
printHelp();
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Determine command (first positional, or "run" as default)
|
|
93
|
-
const command = positionals[0] ?? "run";
|
|
94
|
-
const rest = positionals.slice(1);
|
|
95
|
-
|
|
96
|
-
const startOpts = buildStartOptions(
|
|
97
|
-
values as { port?: string; host?: string; debug?: boolean },
|
|
98
|
-
);
|
|
99
|
-
|
|
100
|
-
// Start background update check (non-blocking).
|
|
101
|
-
// Suppressed for commands where the banner would be confusing or redundant.
|
|
102
|
-
const suppressNotification = shouldSuppressNotification(positionals);
|
|
103
|
-
if (!suppressNotification) {
|
|
104
|
-
maybeCheckForUpdateInBackground();
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
try {
|
|
108
|
-
switch (command) {
|
|
109
|
-
case "start":
|
|
110
|
-
await commandStart(startOpts);
|
|
111
|
-
break;
|
|
112
|
-
|
|
113
|
-
case "run": {
|
|
114
|
-
// Lazy-import to avoid pulling in child_process + agent detection
|
|
115
|
-
// when only `lore start` or `lore help` is needed.
|
|
116
|
-
const { commandRun } = await import("./run");
|
|
117
|
-
await commandRun(startOpts, rest);
|
|
118
|
-
break;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
case "upgrade": {
|
|
122
|
-
const { commandUpgrade } = await import("./upgrade");
|
|
123
|
-
await commandUpgrade(rest);
|
|
124
|
-
break;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
case "help":
|
|
128
|
-
printHelp();
|
|
129
|
-
break;
|
|
130
|
-
|
|
131
|
-
default:
|
|
132
|
-
// Unknown first arg — treat it as `lore run <unknown> ...`
|
|
133
|
-
// This allows `lore claude` as shorthand for `lore run claude`.
|
|
134
|
-
{
|
|
135
|
-
const { commandRun } = await import("./run");
|
|
136
|
-
await commandRun(startOpts, [command, ...rest]);
|
|
137
|
-
}
|
|
138
|
-
break;
|
|
139
|
-
}
|
|
140
|
-
} finally {
|
|
141
|
-
// Abort any pending version check to allow clean exit
|
|
142
|
-
abortPendingVersionCheck();
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Show update notification after command completes
|
|
146
|
-
if (!suppressNotification) {
|
|
147
|
-
const notification = getUpdateNotification();
|
|
148
|
-
if (notification) {
|
|
149
|
-
process.stderr.write(notification);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|