@lunora/cli 1.0.0-alpha.8 → 1.0.0-alpha.81
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/LICENSE.md +6 -0
- package/__assets__/package-og.svg +1 -1
- package/dist/bin.mjs +1 -1
- package/dist/index.d.mts +293 -134
- package/dist/index.d.ts +293 -134
- package/dist/index.mjs +8 -9
- package/dist/packem_chunks/handler.mjs +87 -6
- package/dist/packem_chunks/handler10.mjs +8 -14
- package/dist/packem_chunks/handler11.mjs +20 -189
- package/dist/packem_chunks/handler12.mjs +176 -115
- package/dist/packem_chunks/handler13.mjs +118 -52
- package/dist/packem_chunks/handler14.mjs +50 -43
- package/dist/packem_chunks/handler15.mjs +48 -67
- package/dist/packem_chunks/handler16.mjs +85 -37
- package/dist/packem_chunks/handler17.mjs +39 -100
- package/dist/packem_chunks/handler18.mjs +87 -152
- package/dist/packem_chunks/handler19.mjs +148 -67
- package/dist/packem_chunks/handler2.mjs +6 -4
- package/dist/packem_chunks/handler20.mjs +77 -75
- package/dist/packem_chunks/handler21.mjs +71 -288
- package/dist/packem_chunks/handler3.mjs +8 -4
- package/dist/packem_chunks/handler4.mjs +2 -2
- package/dist/packem_chunks/handler5.mjs +7 -4
- package/dist/packem_chunks/handler6.mjs +10 -7
- package/dist/packem_chunks/handler7.mjs +2 -2
- package/dist/packem_chunks/handler8.mjs +1 -1
- package/dist/packem_chunks/handler9.mjs +323 -12
- package/dist/packem_chunks/planDevCommand.mjs +758 -81
- package/dist/packem_chunks/runCodegenCommand.mjs +5 -4
- package/dist/packem_chunks/runDeployCommand.mjs +126 -20
- package/dist/packem_chunks/runInitCommand.mjs +1661 -179
- package/dist/packem_chunks/runMigrateGenerateCommand.mjs +47 -41
- package/dist/packem_chunks/runResetCommand.mjs +2 -2
- package/dist/packem_chunks/runRpcCommand.mjs +3 -2
- package/dist/packem_shared/{COMMANDS-Bn8luojF.mjs → COMMANDS-D0tmnAwr.mjs} +106 -27
- package/dist/packem_shared/{DEFAULT_IMPORT_BATCH_SIZE-Ck-2bU08.mjs → DEFAULT_IMPORT_BATCH_SIZE-D0VOTerB.mjs} +7 -2
- package/dist/packem_shared/{api-spec-CtA6ilu4.mjs → api-spec-Bx0iKbxA.mjs} +3 -1
- package/dist/packem_shared/{buildRegistryIndex-BcYe607_.mjs → buildRegistryIndex-BS5ig822.mjs} +1 -1
- package/dist/packem_shared/codegen-error-DJG-ghs_.mjs +31 -0
- package/dist/packem_shared/{command-BDXcJCCJ.mjs → command-lYnl4QyF.mjs} +6 -1
- package/dist/packem_shared/{commands-DqsEzojt.mjs → commands-ClEvcz3V.mjs} +224 -18
- package/dist/packem_shared/{createLogger-CHPNjFw2.mjs → createLogger-CIWSHrTL.mjs} +40 -8
- package/dist/packem_shared/{createRecordingSpawner-DxI3mebw.mjs → createRecordingSpawner-WuSn20kb.mjs} +23 -2
- package/dist/packem_shared/{detect-package-manager-DYp7n3mJ.mjs → detect-package-manager-DvEthdCw.mjs} +26 -30
- package/dist/packem_shared/{insertSchemaExtension-BuzF6-t2.mjs → insertSchemaExtension-DAqbfr9Z.mjs} +15 -10
- package/dist/packem_shared/{open-url-Dfq6fAyT.mjs → open-url-4PBLY9X0.mjs} +3 -2
- package/dist/packem_shared/{output-format-7gyGR3h8.mjs → output-format-B4642rjE.mjs} +1 -1
- package/dist/packem_shared/{parseManifest--vZf2FY1.mjs → parseManifest-Dbp-Q2q3.mjs} +36 -9
- package/dist/packem_shared/prompt-cancelled-APzX1Im-.mjs +9 -0
- package/dist/packem_shared/runAddCommand-DGjFXGqa.mjs +4 -0
- package/dist/packem_shared/storage-DEXpJkXh.mjs +84 -0
- package/dist/packem_shared/tui-prompts-BjEN8XgP.mjs +658 -0
- package/dist/packem_shared/wrangler-secrets-Dq_Fkbm-.mjs +49 -0
- package/package.json +16 -13
- package/skills/lunora-quickstart/SKILL.md +25 -5
- package/skills/lunora-setup-storage/SKILL.md +7 -3
- package/dist/packem_shared/features-ocSSpZtS.mjs +0 -24
- package/dist/packem_shared/parseArgs-YXFuKdEk.mjs +0 -56
- package/dist/packem_shared/runAddCommand-G544_v6e.mjs +0 -4
- package/dist/packem_shared/tui-prompts-XHFxlOg5.mjs +0 -269
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, writeFileSync, mkdtempSync, rmSync, readFileSync } from 'node:fs';
|
|
2
2
|
import { tmpdir } from 'node:os';
|
|
3
3
|
import { discoverSchema, discoverMigrations } from '@lunora/codegen';
|
|
4
|
+
import { LunoraError } from '@lunora/errors';
|
|
4
5
|
import { join } from '@visulima/path';
|
|
5
6
|
import { Project } from 'ts-morph';
|
|
6
7
|
import { r as resolveAdminBaseUrl } from '../packem_shared/admin-url-4UzT-CI4.mjs';
|
|
7
|
-
import { d as defineHandler } from '../packem_shared/command-
|
|
8
|
+
import { d as defineHandler } from '../packem_shared/command-lYnl4QyF.mjs';
|
|
8
9
|
import { diffSnapshots, renderMigrationFile } from '../packem_shared/diffSnapshots-BeDvvNiF.mjs';
|
|
9
10
|
import { a as resolveProductionWorkerUrl } from '../packem_shared/resolve-target-qbsJ_5sF.mjs';
|
|
10
11
|
import schemaIrToSnapshot from '../packem_shared/schemaIrToSnapshot-DdsljJT-.mjs';
|
|
11
|
-
import { runExportCommand, runImportCommand } from '../packem_shared/DEFAULT_IMPORT_BATCH_SIZE-
|
|
12
|
+
import { runExportCommand, runImportCommand } from '../packem_shared/DEFAULT_IMPORT_BATCH_SIZE-D0VOTerB.mjs';
|
|
12
13
|
|
|
13
14
|
const SNAPSHOT_FILENAME = ".snapshot.json";
|
|
14
15
|
const NON_ALPHANUMERIC = /[^\da-z]+/gu;
|
|
@@ -41,12 +42,12 @@ const loadSnapshot = (path) => {
|
|
|
41
42
|
const raw = readFileSync(path, "utf8");
|
|
42
43
|
const parsed = JSON.parse(raw);
|
|
43
44
|
if (parsed.version !== 1) {
|
|
44
|
-
throw new
|
|
45
|
+
throw new LunoraError("INTERNAL", `unsupported snapshot version: ${parsed.version}`);
|
|
45
46
|
}
|
|
46
47
|
return parsed;
|
|
47
48
|
} catch (error) {
|
|
48
49
|
const message = error instanceof Error ? error.message : String(error);
|
|
49
|
-
throw new
|
|
50
|
+
throw new LunoraError("INTERNAL", `failed to read ${path}: ${message}`, { cause: error });
|
|
50
51
|
}
|
|
51
52
|
};
|
|
52
53
|
const runMigrateGenerateCommand = (options) => {
|
|
@@ -305,44 +306,49 @@ const runMigrateToHyperdriveCommand = async (options) => {
|
|
|
305
306
|
}
|
|
306
307
|
const temporaryDirectory = options.out === void 0 ? mkdtempSync(join(tmpdir(), "lunora-d1ps-")) : void 0;
|
|
307
308
|
const dumpPath = options.out ?? join(temporaryDirectory, "dump.ndjson");
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
309
|
+
try {
|
|
310
|
+
logger.info(`Exporting .global() data from the D1 source (${fromUrl ?? "http://localhost:8787"}) …`);
|
|
311
|
+
const exportResult = await runExportCommand({
|
|
312
|
+
fetchImpl: options.fetchImpl,
|
|
313
|
+
logger,
|
|
314
|
+
out: dumpPath,
|
|
315
|
+
prod: options.prod,
|
|
316
|
+
tables: options.tables,
|
|
317
|
+
token: options.fromToken,
|
|
318
|
+
url: fromUrl
|
|
319
|
+
});
|
|
320
|
+
if (exportResult.code !== 0) {
|
|
321
|
+
return { code: exportResult.code };
|
|
322
|
+
}
|
|
323
|
+
logger.info(`Exported ${String(exportResult.rows)} row(s) (${String(exportResult.bytes)} bytes).`);
|
|
324
|
+
logger.info(`Importing into the Hyperdrive target (${toUrl ?? "http://localhost:8787"}) …`);
|
|
325
|
+
const importResult = await runImportCommand({
|
|
326
|
+
batchSize: options.batchSize,
|
|
327
|
+
fetchImpl: options.fetchImpl,
|
|
328
|
+
file: dumpPath,
|
|
329
|
+
logger,
|
|
330
|
+
prod: options.prod,
|
|
331
|
+
token: options.toToken,
|
|
332
|
+
url: toUrl
|
|
333
|
+
});
|
|
334
|
+
if (importResult.code !== 0) {
|
|
335
|
+
return { code: importResult.code };
|
|
336
|
+
}
|
|
337
|
+
if (importResult.inserted === exportResult.rows) {
|
|
338
|
+
logger.info(
|
|
339
|
+
`✓ Migrated ${String(exportResult.rows)} row(s) — counts match. Verify your app reads from Hyperdrive, then decommission the D1 binding.`
|
|
340
|
+
);
|
|
341
|
+
} else {
|
|
342
|
+
logger.warn(
|
|
343
|
+
`Imported ${String(importResult.inserted)} of ${String(exportResult.rows)} exported row(s) — the remainder likely already existed in the target (see conflicts above). Re-run after resolving, or inspect the dump with --out.`
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
return { code: 0 };
|
|
347
|
+
} finally {
|
|
348
|
+
if (temporaryDirectory !== void 0) {
|
|
349
|
+
rmSync(temporaryDirectory, { force: true, recursive: true });
|
|
350
|
+
}
|
|
344
351
|
}
|
|
345
|
-
return { code: 0 };
|
|
346
352
|
};
|
|
347
353
|
const execute = defineHandler(({ argument, cwd, logger, options }) => {
|
|
348
354
|
const sub = argument[0];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync, rmSync } from 'node:fs';
|
|
2
2
|
import { join } from '@visulima/path';
|
|
3
|
-
import { d as defineHandler } from '../packem_shared/command-
|
|
4
|
-
import {
|
|
3
|
+
import { d as defineHandler } from '../packem_shared/command-lYnl4QyF.mjs';
|
|
4
|
+
import { b as tuiConfirm } from '../packem_shared/tui-prompts-BjEN8XgP.mjs';
|
|
5
5
|
|
|
6
6
|
const runResetCommand = async (options) => {
|
|
7
7
|
const cwd = options.cwd ?? process.cwd();
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
2
|
+
import { d as defineHandler } from '../packem_shared/command-lYnl4QyF.mjs';
|
|
2
3
|
import { r as resolveWorkerUrl } from '../packem_shared/resolve-target-qbsJ_5sF.mjs';
|
|
3
4
|
|
|
4
5
|
const parseArgsJson = (raw) => {
|
|
@@ -9,7 +10,7 @@ const parseArgsJson = (raw) => {
|
|
|
9
10
|
return JSON.parse(raw);
|
|
10
11
|
} catch (error) {
|
|
11
12
|
const message = error instanceof Error ? error.message : String(error);
|
|
12
|
-
throw new
|
|
13
|
+
throw new LunoraError("INTERNAL", `failed to parse --args as JSON: ${message}`, { cause: error });
|
|
13
14
|
}
|
|
14
15
|
};
|
|
15
16
|
const TRAILING_SLASH = /\/$/u;
|
|
@@ -1,20 +1,27 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync } from 'node:fs';
|
|
1
|
+
import { mkdirSync, readFileSync, lstatSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { resolveHint, isLunoraError, flattenHint, findSolutionByMessage } from '@lunora/errors';
|
|
2
3
|
import { createCerebro } from '@visulima/cerebro';
|
|
3
4
|
import completionCommand from '@visulima/cerebro/command/completion';
|
|
4
5
|
import versionCommand from '@visulima/cerebro/command/version';
|
|
5
|
-
import { A as API_SPEC_HELP } from './api-spec-
|
|
6
|
-
import { createLogger } from './createLogger-
|
|
7
|
-
import {
|
|
6
|
+
import { A as API_SPEC_HELP } from './api-spec-Bx0iKbxA.mjs';
|
|
7
|
+
import { createLogger } from './createLogger-CIWSHrTL.mjs';
|
|
8
|
+
import { VisulimaError, renderError } from '@visulima/error';
|
|
9
|
+
import { homedir } from 'node:os';
|
|
8
10
|
import { join } from 'node:path';
|
|
9
11
|
|
|
10
12
|
const addCommand = {
|
|
11
|
-
argument: {
|
|
12
|
-
|
|
13
|
+
argument: {
|
|
14
|
+
description: "Feature or registry item: ai | auth | email | storage | crons | presence | queue | workflow | flags | backup | …",
|
|
15
|
+
name: "feature",
|
|
16
|
+
type: String
|
|
17
|
+
},
|
|
18
|
+
description: "Add a feature or registry item (ai, auth, email, storage, crons, …) to the current Lunora project",
|
|
13
19
|
examples: [
|
|
14
20
|
["lunora add auth", "Add authentication (asks which provider)"],
|
|
15
21
|
["lunora add auth --provider clerk", "Add Clerk auth without prompting"],
|
|
16
22
|
["lunora add email", "Add transactional email (Cloudflare Email Workers + dev mail catcher)"],
|
|
17
|
-
["lunora add storage", "Add the R2 storage registry item"],
|
|
23
|
+
["lunora add storage", "Add the R2 storage registry item (asks for the bucket name)"],
|
|
24
|
+
["lunora add storage --bucket my-app-uploads", "Add storage with a bucket name, no prompt"],
|
|
18
25
|
["lunora add crons", "Add the scheduled-jobs registry item"],
|
|
19
26
|
["lunora add storage --ref alpha", "Add an item from the alpha branch's registry"]
|
|
20
27
|
],
|
|
@@ -25,7 +32,10 @@ const addCommand = {
|
|
|
25
32
|
name: "add",
|
|
26
33
|
options: [
|
|
27
34
|
{ description: "auth: provider to use without prompting (auth | clerk | auth0)", name: "provider", type: String },
|
|
28
|
-
{ description: "
|
|
35
|
+
{ description: "auth: D1 database name to use without prompting (lowercase alphanumeric + hyphens)", name: "db", type: String },
|
|
36
|
+
{ description: "storage: R2 bucket name to use without prompting (lowercase alphanumeric + hyphens)", name: "bucket", type: String },
|
|
37
|
+
{ description: "email: verified destination address to use without prompting", name: "mail-to", type: String },
|
|
38
|
+
{ description: "Skip prompts (auth provider, DB name, bucket name, mail destination) and use the defaults", name: "yes", type: Boolean },
|
|
29
39
|
{ description: "Local registry root (offline; expects <name>/ subdirs)", name: "from", type: String },
|
|
30
40
|
{ description: "Override the remote registry source base (e.g. gh:owner/repo/registry)", name: "source", type: String },
|
|
31
41
|
{
|
|
@@ -33,7 +43,8 @@ const addCommand = {
|
|
|
33
43
|
name: "ref",
|
|
34
44
|
type: String
|
|
35
45
|
},
|
|
36
|
-
{ description: "Permit --source values outside gh:/github:/https://", name: "allow-unsafe-source", type: Boolean }
|
|
46
|
+
{ description: "Permit --source values outside gh:/github:/https://", name: "allow-unsafe-source", type: Boolean },
|
|
47
|
+
{ description: "Output format: pretty (default) or json", name: "format", type: String }
|
|
37
48
|
]
|
|
38
49
|
};
|
|
39
50
|
|
|
@@ -208,9 +219,19 @@ const deploymentsCommand = {
|
|
|
208
219
|
};
|
|
209
220
|
|
|
210
221
|
const devCommand = {
|
|
222
|
+
argument: {
|
|
223
|
+
description: "Optional subcommand: stop (shut the running dev server down) | status (report it) | logs (print its captured output)",
|
|
224
|
+
name: "args",
|
|
225
|
+
type: String
|
|
226
|
+
},
|
|
211
227
|
description: "Run the dev stack: wrangler worker + studio + codegen watch",
|
|
212
228
|
examples: [
|
|
213
229
|
["lunora dev", "Run the worker + studio + codegen watch"],
|
|
230
|
+
["lunora dev --background", "Run detached: blocks until ready, prints URL + PID, then returns"],
|
|
231
|
+
["lunora dev stop", "Stop the background/tracked dev server (idempotent)"],
|
|
232
|
+
["lunora dev status", "Report the running dev server (URL, PID, uptime)"],
|
|
233
|
+
["lunora dev logs", "Print the captured dev-server log (background runs)"],
|
|
234
|
+
["lunora dev --json", "Machine-readable JSON log lines (also LUNORA_LOG_JSON=1)"],
|
|
214
235
|
["lunora dev --no-studio", "Skip the embedded studio server"],
|
|
215
236
|
["lunora dev --worker-port 8080", "Use a custom wrangler dev port"],
|
|
216
237
|
["lunora dev --remote", "Proxy D1/KV/R2 to the deployed worker (also LUNORA_REMOTE=1)"]
|
|
@@ -220,10 +241,19 @@ const devCommand = {
|
|
|
220
241
|
return { default: m.execute };
|
|
221
242
|
}),
|
|
222
243
|
name: "dev",
|
|
244
|
+
// KEEP IN SYNC with `daemonArguments` in `./lifecycle.ts`: a new flag that
|
|
245
|
+
// must reach a `--background` daemon has to be forwarded there explicitly.
|
|
223
246
|
options: [
|
|
224
247
|
{ description: `Which API spec(s) codegen emits: ${API_SPEC_HELP} (default openapi)`, name: "api-spec", type: String },
|
|
225
248
|
{ description: "Studio server port (default 6173)", name: "port", type: Number },
|
|
226
249
|
{ description: "wrangler dev port (default 8787)", name: "worker-port", type: Number },
|
|
250
|
+
{
|
|
251
|
+
description: "Run the dev server as a managed background process (auto-enabled when an AI agent is detected; LUNORA_AGENT_MODE=0 disables)",
|
|
252
|
+
name: "background",
|
|
253
|
+
type: Boolean
|
|
254
|
+
},
|
|
255
|
+
{ description: "Emit machine-readable JSON log lines (also LUNORA_LOG_JSON=1; auto-enabled for AI agents)", name: "json", type: Boolean },
|
|
256
|
+
{ description: "How many trailing lines `lunora dev logs` prints (default 100, 0 = all)", name: "lines", type: Number },
|
|
227
257
|
{ description: "Don't start the embedded studio server", name: "no-studio", type: Boolean },
|
|
228
258
|
{ description: "Don't watch + regenerate codegen", name: "no-codegen", type: Boolean },
|
|
229
259
|
{ description: "Proxy D1/KV/R2 bindings to the deployed worker (or set LUNORA_REMOTE=1)", name: "remote", type: Boolean }
|
|
@@ -256,21 +286,24 @@ const doctorCommand = {
|
|
|
256
286
|
};
|
|
257
287
|
|
|
258
288
|
const envCommand = {
|
|
259
|
-
argument: { description: "list | get <KEY> | set <KEY> <VALUE> | unset <KEY> | push | diff | doctor", name: "subcommand", type: String },
|
|
260
|
-
description: "Manage .dev.vars and sync secrets via wrangler (list | get | set | unset | push | diff | doctor)",
|
|
289
|
+
argument: { description: "list | get <KEY> | set <KEY> <VALUE> | unset <KEY> | generate [KEY] | push | diff | doctor", name: "subcommand", type: String },
|
|
290
|
+
description: "Manage .dev.vars and sync secrets via wrangler (list | get | set | unset | generate | push | diff | doctor)",
|
|
261
291
|
examples: [
|
|
262
292
|
["lunora env list", "List .dev.vars keys"],
|
|
263
293
|
["lunora env set API_KEY secret", "Set a local variable"],
|
|
294
|
+
["lunora env generate", "Generate strong values for the project's secrets (print KEY=value)"],
|
|
295
|
+
["lunora env generate AUTH_SECRET --set", "Generate one secret and write it to .dev.vars"],
|
|
264
296
|
["lunora env push --yes", "Upload secrets to Cloudflare"],
|
|
265
297
|
["lunora env diff", "Compare local .dev.vars keys against Cloudflare"]
|
|
266
298
|
],
|
|
267
299
|
group: "Data",
|
|
268
|
-
loader: () => import('../packem_chunks/
|
|
300
|
+
loader: () => import('../packem_chunks/handler9.mjs').then((m) => {
|
|
269
301
|
return { default: m.execute };
|
|
270
302
|
}),
|
|
271
303
|
name: "env",
|
|
272
304
|
options: [
|
|
273
305
|
{ description: "Target production for `push` (passes --env production to wrangler)", name: "prod", type: Boolean },
|
|
306
|
+
{ description: "For `generate` — write the generated secrets into .dev.vars instead of printing them", name: "set", type: Boolean },
|
|
274
307
|
{
|
|
275
308
|
description: "Push secrets to a temporary-account deployment when unauthenticated (wrangler secret put --temporary). Errors if you're already authenticated.",
|
|
276
309
|
name: "temporary",
|
|
@@ -288,7 +321,7 @@ const exportCommand = {
|
|
|
288
321
|
["lunora export --tables messages,users", "Export only specific tables"]
|
|
289
322
|
],
|
|
290
323
|
group: "Data",
|
|
291
|
-
loader: () => import('../packem_chunks/
|
|
324
|
+
loader: () => import('../packem_chunks/handler10.mjs').then((m) => {
|
|
292
325
|
return { default: m.execute };
|
|
293
326
|
}),
|
|
294
327
|
name: "export",
|
|
@@ -310,7 +343,7 @@ const importCommand = {
|
|
|
310
343
|
description: "Bulk-insert rows from an NDJSON file via the worker's admin endpoint",
|
|
311
344
|
examples: [["lunora import backup.ndjson", "Bulk-insert rows from an NDJSON file"]],
|
|
312
345
|
group: "Data",
|
|
313
|
-
loader: () => import('../packem_chunks/
|
|
346
|
+
loader: () => import('../packem_chunks/handler11.mjs').then((m) => {
|
|
314
347
|
return { default: m.execute };
|
|
315
348
|
}),
|
|
316
349
|
name: "import",
|
|
@@ -318,6 +351,7 @@ const importCommand = {
|
|
|
318
351
|
{ description: "Wrap each bare doc as `{table:<name>,doc:...}`", name: "table", type: String },
|
|
319
352
|
{ description: "Rows per HTTP request (default 500)", name: "batch-size", type: Number },
|
|
320
353
|
{ description: "Target production — requires an explicit --url", name: "prod", type: Boolean },
|
|
354
|
+
{ description: "Confirm bulk-writing production (required with --prod)", name: "yes", type: Boolean },
|
|
321
355
|
{ description: "Worker URL (default http://localhost:8787)", name: "url", type: String },
|
|
322
356
|
{
|
|
323
357
|
description: "Admin bearer token (prefer LUNORA_ADMIN_TOKEN; --token is visible to other local processes via the process table)",
|
|
@@ -334,7 +368,7 @@ const infoCommand = {
|
|
|
334
368
|
["lunora info --json", "Emit a JSON snapshot"]
|
|
335
369
|
],
|
|
336
370
|
group: "Project",
|
|
337
|
-
loader: () => import('../packem_chunks/
|
|
371
|
+
loader: () => import('../packem_chunks/handler12.mjs').then((m) => {
|
|
338
372
|
return { default: m.execute };
|
|
339
373
|
}),
|
|
340
374
|
name: "info",
|
|
@@ -415,6 +449,16 @@ const initCommand = {
|
|
|
415
449
|
description: "Also scaffold a CI deploy pipeline: github (.github/workflows/deploy.yml) or gitlab (.gitlab-ci.yml)",
|
|
416
450
|
name: "ci",
|
|
417
451
|
type: String
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
description: "Add features non-interactively after scaffolding (comma-separated): ai | auth | backup | browser | cloudflare-access | crons | email | flags | hyperdrive | payment | presence | queue | storage | workflow",
|
|
455
|
+
name: "add",
|
|
456
|
+
type: String
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
description: "Walk through every step (prompts + output) without writing files, installing, or running git",
|
|
460
|
+
name: "dry-run",
|
|
461
|
+
type: Boolean
|
|
418
462
|
}
|
|
419
463
|
]
|
|
420
464
|
};
|
|
@@ -428,7 +472,7 @@ const insightsCommand = {
|
|
|
428
472
|
["lunora insights --prod --url https://app.example.com --token $LUNORA_ADMIN_TOKEN", "Report against production"]
|
|
429
473
|
],
|
|
430
474
|
group: "Develop",
|
|
431
|
-
loader: () => import('../packem_chunks/
|
|
475
|
+
loader: () => import('../packem_chunks/handler13.mjs').then((m) => {
|
|
432
476
|
return { default: m.execute };
|
|
433
477
|
}),
|
|
434
478
|
name: "insights",
|
|
@@ -450,7 +494,7 @@ const linkCommand = {
|
|
|
450
494
|
["lunora link --remove", "Remove the link"]
|
|
451
495
|
],
|
|
452
496
|
group: "Deploy",
|
|
453
|
-
loader: () => import('../packem_chunks/
|
|
497
|
+
loader: () => import('../packem_chunks/handler14.mjs').then((m) => {
|
|
454
498
|
return { default: m.execute };
|
|
455
499
|
}),
|
|
456
500
|
name: "link",
|
|
@@ -466,7 +510,7 @@ const logsCommand = {
|
|
|
466
510
|
argument: { description: "Worker name (defaults to the name in wrangler config)", name: "worker", type: String },
|
|
467
511
|
description: "Stream live logs from a deployed Lunora Worker",
|
|
468
512
|
group: "Deploy",
|
|
469
|
-
loader: () => import('../packem_chunks/
|
|
513
|
+
loader: () => import('../packem_chunks/handler15.mjs').then((m) => {
|
|
470
514
|
return { default: m.execute };
|
|
471
515
|
}),
|
|
472
516
|
name: "logs",
|
|
@@ -526,7 +570,7 @@ const prepareCommand = {
|
|
|
526
570
|
description: "Run codegen + binding reconcile + wrangler validation (no Vite) — for CI",
|
|
527
571
|
examples: [["lunora prepare", "Codegen + binding reconcile + validate (CI, before deploy)"]],
|
|
528
572
|
group: "Deploy",
|
|
529
|
-
loader: () => import('../packem_chunks/
|
|
573
|
+
loader: () => import('../packem_chunks/handler16.mjs').then((m) => {
|
|
530
574
|
return { default: m.execute };
|
|
531
575
|
}),
|
|
532
576
|
name: "prepare",
|
|
@@ -550,7 +594,7 @@ const registryCommand = {
|
|
|
550
594
|
["lunora registry build --check", "Verify the committed catalog is current"]
|
|
551
595
|
],
|
|
552
596
|
group: "Project",
|
|
553
|
-
loader: () => import('../packem_chunks/
|
|
597
|
+
loader: () => import('../packem_chunks/handler17.mjs').then((m) => {
|
|
554
598
|
return { default: m.execute };
|
|
555
599
|
}),
|
|
556
600
|
name: "registry",
|
|
@@ -600,7 +644,7 @@ const rulesCommand = {
|
|
|
600
644
|
["lunora rules check --strict", "Exit non-zero when rules are missing (CI gate)"]
|
|
601
645
|
],
|
|
602
646
|
group: "Project",
|
|
603
|
-
loader: () => import('../packem_chunks/
|
|
647
|
+
loader: () => import('../packem_chunks/handler18.mjs').then((m) => {
|
|
604
648
|
return { default: m.execute };
|
|
605
649
|
}),
|
|
606
650
|
name: "rules",
|
|
@@ -638,7 +682,7 @@ const seedCommand = {
|
|
|
638
682
|
["lunora seed --seed 7 --dry-run", "Print the NDJSON for seed 7 without inserting"]
|
|
639
683
|
],
|
|
640
684
|
group: "Data",
|
|
641
|
-
loader: () => import('../packem_chunks/
|
|
685
|
+
loader: () => import('../packem_chunks/handler19.mjs').then((m) => {
|
|
642
686
|
return { default: m.execute };
|
|
643
687
|
}),
|
|
644
688
|
name: "seed",
|
|
@@ -667,7 +711,7 @@ const verifyCommand = {
|
|
|
667
711
|
["lunora verify --no-typecheck", "Skip the TypeScript type-check"]
|
|
668
712
|
],
|
|
669
713
|
group: "Deploy",
|
|
670
|
-
loader: () => import('../packem_chunks/
|
|
714
|
+
loader: () => import('../packem_chunks/handler20.mjs').then((m) => {
|
|
671
715
|
return { default: m.execute };
|
|
672
716
|
}),
|
|
673
717
|
name: "verify",
|
|
@@ -686,13 +730,28 @@ const viewCommand = {
|
|
|
686
730
|
["lunora view --remote", "Open the deployed studio"]
|
|
687
731
|
],
|
|
688
732
|
group: "Project",
|
|
689
|
-
loader: () => import('../packem_chunks/
|
|
733
|
+
loader: () => import('../packem_chunks/handler21.mjs').then((m) => {
|
|
690
734
|
return { default: m.execute };
|
|
691
735
|
}),
|
|
692
736
|
name: "view",
|
|
693
737
|
options: [{ description: "Open the deployed worker URL instead of localhost", name: "remote", type: Boolean }]
|
|
694
738
|
};
|
|
695
739
|
|
|
740
|
+
const NO_STACK = { filterStacktrace: () => false, hideErrorCodeView: true };
|
|
741
|
+
const renderLunoraError = (error, options = {}) => {
|
|
742
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
743
|
+
const hint = resolveHint(isLunoraError(error) ? { code: error.code, hint: error.hint, message } : message);
|
|
744
|
+
const rendered = new VisulimaError({
|
|
745
|
+
// `renderError` iterates `hint` as lines; the shared flattener returns one
|
|
746
|
+
// string, so split it back to lines for the terminal renderer.
|
|
747
|
+
hint: hint === void 0 ? void 0 : flattenHint(hint).split("\n"),
|
|
748
|
+
message: options.reason === void 0 ? message : `${options.reason}: ${message}`,
|
|
749
|
+
name: error instanceof Error && error.name.length > 0 ? error.name : "Error"
|
|
750
|
+
});
|
|
751
|
+
rendered.stack = "";
|
|
752
|
+
return renderError(rendered, NO_STACK);
|
|
753
|
+
};
|
|
754
|
+
|
|
696
755
|
const editDistance = (a, b) => {
|
|
697
756
|
const distances = Array.from({ length: b.length + 1 }, (_, index) => index);
|
|
698
757
|
for (let row = 1; row <= a.length; row += 1) {
|
|
@@ -755,6 +814,15 @@ const isNewer = (current, latest) => compareVersions(latest, current) > 0;
|
|
|
755
814
|
const isCacheFresh = (checkedAt, nowMs, ttlMs) => nowMs - checkedAt < ttlMs;
|
|
756
815
|
const formatUpdateNotice = (current, latest) => `Update available for @lunora/cli: ${current} → ${latest} — run \`pnpm add -D @lunora/cli@latest\``;
|
|
757
816
|
const cacheFilePath = (cacheDirectory) => join(cacheDirectory, "lunora-cli-update.json");
|
|
817
|
+
const defaultCacheDirectory = (env) => {
|
|
818
|
+
const base = env.XDG_CACHE_HOME && env.XDG_CACHE_HOME.length > 0 ? env.XDG_CACHE_HOME : join(homedir(), ".cache");
|
|
819
|
+
const directory = join(base, "lunora");
|
|
820
|
+
try {
|
|
821
|
+
mkdirSync(directory, { mode: 448, recursive: true });
|
|
822
|
+
} catch {
|
|
823
|
+
}
|
|
824
|
+
return directory;
|
|
825
|
+
};
|
|
758
826
|
const readCache = (cacheDirectory) => {
|
|
759
827
|
try {
|
|
760
828
|
const parsed = JSON.parse(readFileSync(cacheFilePath(cacheDirectory), "utf8"));
|
|
@@ -770,7 +838,14 @@ const readCache = (cacheDirectory) => {
|
|
|
770
838
|
};
|
|
771
839
|
const writeCache = (cacheDirectory, cache) => {
|
|
772
840
|
try {
|
|
773
|
-
|
|
841
|
+
const path = cacheFilePath(cacheDirectory);
|
|
842
|
+
try {
|
|
843
|
+
if (lstatSync(path).isSymbolicLink()) {
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
846
|
+
} catch {
|
|
847
|
+
}
|
|
848
|
+
writeFileSync(path, `${JSON.stringify(cache)}
|
|
774
849
|
`, "utf8");
|
|
775
850
|
} catch {
|
|
776
851
|
}
|
|
@@ -795,7 +870,7 @@ const maybeNotifyUpdate = async (deps) => {
|
|
|
795
870
|
if (isNotifierDisabled(deps.current, env, isTty)) {
|
|
796
871
|
return;
|
|
797
872
|
}
|
|
798
|
-
const cacheDirectory = deps.cacheDir ??
|
|
873
|
+
const cacheDirectory = deps.cacheDir ?? defaultCacheDirectory(env);
|
|
799
874
|
const nowMs = (deps.now ?? Date.now)();
|
|
800
875
|
const ttlMs = deps.ttlMs ?? CACHE_TTL_MS;
|
|
801
876
|
const cache = readCache(cacheDirectory);
|
|
@@ -907,7 +982,11 @@ const reportRunError = (error) => {
|
|
|
907
982
|
const message = error instanceof Error ? error.message : String(error);
|
|
908
983
|
const unknown = UNKNOWN_COMMAND.exec(message);
|
|
909
984
|
if (!unknown?.groups) {
|
|
910
|
-
|
|
985
|
+
if (isLunoraError(error) || findSolutionByMessage(message) !== void 0) {
|
|
986
|
+
logger.error(renderLunoraError(error));
|
|
987
|
+
} else {
|
|
988
|
+
logger.error(message);
|
|
989
|
+
}
|
|
911
990
|
return;
|
|
912
991
|
}
|
|
913
992
|
const name = unknown.groups.name ?? "";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createWriteStream, createReadStream } from 'node:fs';
|
|
2
2
|
import { unlink, stat } from 'node:fs/promises';
|
|
3
|
+
import { LunoraError } from '@lunora/errors';
|
|
3
4
|
import { r as resolveAdminBaseUrl } from './admin-url-4UzT-CI4.mjs';
|
|
4
5
|
|
|
5
6
|
const EXPORT_ENDPOINT_PATH = "/_lunora/admin/export";
|
|
@@ -129,6 +130,10 @@ const resolveImportRequest = async (options) => {
|
|
|
129
130
|
options.logger.error("--prod requires an explicit --url (refusing to import to the implicit localhost worker)");
|
|
130
131
|
return void 0;
|
|
131
132
|
}
|
|
133
|
+
if (options.prod && options.yes !== true) {
|
|
134
|
+
options.logger.error("import --prod bulk-writes production. Re-run with --yes to confirm.");
|
|
135
|
+
return void 0;
|
|
136
|
+
}
|
|
132
137
|
const token = options.token ?? process.env["LUNORA_ADMIN_TOKEN"];
|
|
133
138
|
if (!token) {
|
|
134
139
|
options.logger.error("admin token required — pass --token or set LUNORA_ADMIN_TOKEN");
|
|
@@ -183,7 +188,7 @@ const runImportCommand = async (options) => {
|
|
|
183
188
|
});
|
|
184
189
|
if (!response.ok) {
|
|
185
190
|
const text = await response.text().catch(() => "<no body>");
|
|
186
|
-
throw new
|
|
191
|
+
throw new LunoraError("INTERNAL", `import batch failed (HTTP ${String(response.status)}): ${text}`);
|
|
187
192
|
}
|
|
188
193
|
const json = await response.json();
|
|
189
194
|
if (json.inserted) {
|
|
@@ -213,7 +218,7 @@ const runImportCommand = async (options) => {
|
|
|
213
218
|
parsedDocument = JSON.parse(trimmed);
|
|
214
219
|
} catch (error) {
|
|
215
220
|
const message = error instanceof Error ? error.message : String(error);
|
|
216
|
-
throw new
|
|
221
|
+
throw new LunoraError("INTERNAL", `invalid JSON on line ${String(lineNumber)}: ${message}`, { cause: error });
|
|
217
222
|
}
|
|
218
223
|
batch.push(JSON.stringify({ doc: parsedDocument, table: options.table }));
|
|
219
224
|
};
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
2
|
+
|
|
1
3
|
const API_SPEC_VALUES = ["both", "none", "openapi", "openrpc"];
|
|
2
4
|
const API_SPEC_HELP = API_SPEC_VALUES.join(" | ");
|
|
3
5
|
const parseApiSpec = (value) => {
|
|
@@ -7,7 +9,7 @@ const parseApiSpec = (value) => {
|
|
|
7
9
|
if (API_SPEC_VALUES.includes(value)) {
|
|
8
10
|
return value;
|
|
9
11
|
}
|
|
10
|
-
throw new
|
|
12
|
+
throw new LunoraError("INTERNAL", `invalid --api-spec "${value}" — expected one of: ${API_SPEC_HELP}`);
|
|
11
13
|
};
|
|
12
14
|
|
|
13
15
|
export { API_SPEC_HELP as A, parseApiSpec as p };
|
package/dist/packem_shared/{buildRegistryIndex-BcYe607_.mjs → buildRegistryIndex-BS5ig822.mjs}
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
|
|
2
2
|
import { join } from '@visulima/path';
|
|
3
|
-
import parseManifest from './parseManifest
|
|
3
|
+
import parseManifest from './parseManifest-Dbp-Q2q3.mjs';
|
|
4
4
|
|
|
5
5
|
const CONTROL_CHARS = /[\u0000-\u001F\u007F-\u009F]/gu;
|
|
6
6
|
const stripControlChars = (value) => value === void 0 ? void 0 : value.replaceAll(CONTROL_CHARS, "");
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { findLunoraSolution } from '@lunora/codegen';
|
|
2
|
+
import { VisulimaError, renderError } from '@visulima/error';
|
|
3
|
+
|
|
4
|
+
const flattenSolutionBody = (solution) => solution.body.split("\n").filter((line) => !line.startsWith("```")).join("\n").replaceAll(/\*\*(.+?)\*\*/gu, "$1").replaceAll(/`([^`]+)`/gu, "$1");
|
|
5
|
+
const NO_STACK = { filterStacktrace: () => false, hideErrorCodeView: true };
|
|
6
|
+
const renderCodegenFailure = (error, reason) => {
|
|
7
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
8
|
+
const solution = findLunoraSolution(message);
|
|
9
|
+
const rendered = new VisulimaError({
|
|
10
|
+
hint: solution ? [solution.header, "", flattenSolutionBody(solution)] : void 0,
|
|
11
|
+
message: reason === void 0 ? `codegen failed: ${message}` : `codegen failed (${reason}): ${message}`,
|
|
12
|
+
name: "CodegenError"
|
|
13
|
+
});
|
|
14
|
+
rendered.stack = "";
|
|
15
|
+
return renderError(rendered, NO_STACK);
|
|
16
|
+
};
|
|
17
|
+
const renderCodegenHint = (message) => {
|
|
18
|
+
const solution = findLunoraSolution(message);
|
|
19
|
+
if (solution === void 0) {
|
|
20
|
+
return void 0;
|
|
21
|
+
}
|
|
22
|
+
const rendered = new VisulimaError({
|
|
23
|
+
hint: [flattenSolutionBody(solution)],
|
|
24
|
+
message: solution.header,
|
|
25
|
+
name: "Hint"
|
|
26
|
+
});
|
|
27
|
+
rendered.stack = "";
|
|
28
|
+
return renderError(rendered, NO_STACK);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export { renderCodegenHint as a, renderCodegenFailure as r };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { createLogger } from './createLogger-
|
|
1
|
+
import { createLogger } from './createLogger-CIWSHrTL.mjs';
|
|
2
|
+
import { P as PromptCancelledError, a as PROMPT_CANCEL_EXIT_CODE } from './prompt-cancelled-APzX1Im-.mjs';
|
|
2
3
|
|
|
3
4
|
const defineHandler = (body) => async (toolbox) => {
|
|
4
5
|
const logger = createLogger();
|
|
@@ -6,6 +7,10 @@ const defineHandler = (body) => async (toolbox) => {
|
|
|
6
7
|
const { code } = await body({ argument: toolbox.argument, cwd: toolbox.process.cwd, logger, options: toolbox.options });
|
|
7
8
|
toolbox.process.exit(code);
|
|
8
9
|
} catch (error) {
|
|
10
|
+
if (error instanceof PromptCancelledError) {
|
|
11
|
+
toolbox.process.exit(PROMPT_CANCEL_EXIT_CODE);
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
9
14
|
logger.error(error instanceof Error ? error.message : String(error));
|
|
10
15
|
toolbox.process.exit(1);
|
|
11
16
|
}
|