@lunora/cli 1.0.0-alpha.100 → 1.0.0-alpha.102

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.
Files changed (83) hide show
  1. package/dist/bin.mjs +2 -10
  2. package/dist/index.mjs +1 -18
  3. package/dist/packem_chunks/handler.mjs +1 -160
  4. package/dist/packem_chunks/handler10.mjs +1 -16
  5. package/dist/packem_chunks/handler11.mjs +1 -23
  6. package/dist/packem_chunks/handler12.mjs +2 -192
  7. package/dist/packem_chunks/handler13.mjs +2 -131
  8. package/dist/packem_chunks/handler14.mjs +1 -65
  9. package/dist/packem_chunks/handler15.mjs +1 -100
  10. package/dist/packem_chunks/handler16.mjs +1 -44
  11. package/dist/packem_chunks/handler17.mjs +1 -105
  12. package/dist/packem_chunks/handler18.mjs +3 -170
  13. package/dist/packem_chunks/handler19.mjs +1 -128
  14. package/dist/packem_chunks/handler2.mjs +2 -116
  15. package/dist/packem_chunks/handler20.mjs +1 -94
  16. package/dist/packem_chunks/handler21.mjs +2 -202
  17. package/dist/packem_chunks/handler3.mjs +2 -208
  18. package/dist/packem_chunks/handler4.mjs +1 -33
  19. package/dist/packem_chunks/handler5.mjs +1 -52
  20. package/dist/packem_chunks/handler6.mjs +1 -94
  21. package/dist/packem_chunks/handler7.mjs +1 -42
  22. package/dist/packem_chunks/handler8.mjs +1 -174
  23. package/dist/packem_chunks/handler9.mjs +8 -334
  24. package/dist/packem_chunks/planDevCommand.mjs +7 -1181
  25. package/dist/packem_chunks/runCodegenCommand.mjs +4 -53
  26. package/dist/packem_chunks/runDeployCommand.mjs +1 -619
  27. package/dist/packem_chunks/runInitCommand.mjs +51 -1411
  28. package/dist/packem_chunks/runMigrateGenerateCommand.mjs +9 -442
  29. package/dist/packem_chunks/runResetCommand.mjs +1 -41
  30. package/dist/packem_chunks/runRpcCommand.mjs +1 -69
  31. package/dist/packem_shared/COMMANDS-DRqlsGT2.mjs +3 -0
  32. package/dist/packem_shared/DEFAULT_IMPORT_BATCH_SIZE-DL87PIEl.mjs +8 -0
  33. package/dist/packem_shared/admin-url-DfVehV3e.mjs +1 -0
  34. package/dist/packem_shared/api-spec-BENwiyUa.mjs +1 -0
  35. package/dist/packem_shared/buildRegistryIndex-DwySASBu.mjs +1 -0
  36. package/dist/packem_shared/codegen-error-DJN6pTH5.mjs +3 -0
  37. package/dist/packem_shared/command-Bjv4VmYA.mjs +1 -0
  38. package/dist/packem_shared/commands-BhX2Bo9B.mjs +19 -0
  39. package/dist/packem_shared/createLogger--C3x1FNE.mjs +2 -0
  40. package/dist/packem_shared/createRecordingSpawner-C8_7nffs.mjs +1 -0
  41. package/dist/packem_shared/detect-package-manager-B2eIuAiP.mjs +1 -0
  42. package/dist/packem_shared/diffSnapshots-9bDd9nOK.mjs +5 -0
  43. package/dist/packem_shared/docker-CKvYE9YF.mjs +1 -0
  44. package/dist/packem_shared/insertSchemaExtension-DZReBZ4_.mjs +8 -0
  45. package/dist/packem_shared/open-url-CTU_g9gr.mjs +1 -0
  46. package/dist/packem_shared/output-format-D7cKB-O5.mjs +2 -0
  47. package/dist/packem_shared/parseManifest-x3WsxKHz.mjs +1 -0
  48. package/dist/packem_shared/prompt-cancelled-C8Sj7OqI.mjs +1 -0
  49. package/dist/packem_shared/resolve-target-vxaXHmvg.mjs +1 -0
  50. package/dist/packem_shared/runAddCommand--TBYJQYi.mjs +1 -0
  51. package/dist/packem_shared/schema-drift-gate-CpqG-xP4.mjs +1 -0
  52. package/dist/packem_shared/schemaIrToSnapshot-Clwd2A8e.mjs +1 -0
  53. package/dist/packem_shared/storage-DOvAKGi4.mjs +1 -0
  54. package/dist/packem_shared/tui-prompts-CCt3jm1k.mjs +4 -0
  55. package/dist/packem_shared/wrangler-name-HIl0Z6yx.mjs +1 -0
  56. package/dist/packem_shared/wrangler-secrets-BMRJwKQU.mjs +1 -0
  57. package/package.json +6 -6
  58. package/dist/packem_shared/COMMANDS-BOJIDoVY.mjs +0 -1031
  59. package/dist/packem_shared/DEFAULT_IMPORT_BATCH_SIZE-D0VOTerB.mjs +0 -249
  60. package/dist/packem_shared/admin-url-4UzT-CI4.mjs +0 -19
  61. package/dist/packem_shared/api-spec-Bx0iKbxA.mjs +0 -15
  62. package/dist/packem_shared/buildRegistryIndex-BS5ig822.mjs +0 -38
  63. package/dist/packem_shared/codegen-error-DJG-ghs_.mjs +0 -31
  64. package/dist/packem_shared/command-lYnl4QyF.mjs +0 -19
  65. package/dist/packem_shared/commands-D5Yxt9VY.mjs +0 -991
  66. package/dist/packem_shared/createLogger-CIWSHrTL.mjs +0 -105
  67. package/dist/packem_shared/createRecordingSpawner-WuSn20kb.mjs +0 -64
  68. package/dist/packem_shared/detect-package-manager-v4hHpQd0.mjs +0 -62
  69. package/dist/packem_shared/diffSnapshots-BeDvvNiF.mjs +0 -161
  70. package/dist/packem_shared/docker-hMQ97KSQ.mjs +0 -21
  71. package/dist/packem_shared/insertSchemaExtension-DAqbfr9Z.mjs +0 -64
  72. package/dist/packem_shared/open-url-4PBLY9X0.mjs +0 -42
  73. package/dist/packem_shared/output-format-B4642rjE.mjs +0 -17
  74. package/dist/packem_shared/parseManifest-Dbp-Q2q3.mjs +0 -121
  75. package/dist/packem_shared/prompt-cancelled-APzX1Im-.mjs +0 -9
  76. package/dist/packem_shared/resolve-target-qbsJ_5sF.mjs +0 -16
  77. package/dist/packem_shared/runAddCommand-D1hgfqFQ.mjs +0 -4
  78. package/dist/packem_shared/schema-drift-gate-BtBt0as0.mjs +0 -79
  79. package/dist/packem_shared/schemaIrToSnapshot-DdsljJT-.mjs +0 -43
  80. package/dist/packem_shared/storage-BXU4ax4O.mjs +0 -84
  81. package/dist/packem_shared/tui-prompts-BjEN8XgP.mjs +0 -658
  82. package/dist/packem_shared/wrangler-name-cy4yhm9j.mjs +0 -12
  83. package/dist/packem_shared/wrangler-secrets-Coni-mER.mjs +0 -49
@@ -1,105 +0,0 @@
1
- import { STEP_BADGE_NAMES, LunoraReporter } from '@lunora/config';
2
- import { JsonReporter } from '@visulima/pail/reporter/json';
3
- import { createPail } from '@visulima/pail/server';
4
-
5
- let sharedPail;
6
- let jsonForced = false;
7
- let configuredReporters;
8
- const wantJson = () => {
9
- if (jsonForced) {
10
- return true;
11
- }
12
- const flag = process.env.LUNORA_LOG_JSON;
13
- return flag === "1" || flag === "true";
14
- };
15
- const constructReporter = (Reporter) => new Reporter();
16
- const buildReporters = () => {
17
- if (jsonForced) {
18
- return [constructReporter(JsonReporter)];
19
- }
20
- if (configuredReporters !== void 0 && configuredReporters.length > 0) {
21
- return configuredReporters;
22
- }
23
- return [constructReporter(wantJson() ? JsonReporter : LunoraReporter)];
24
- };
25
- const forceJsonLogging = () => {
26
- if (jsonForced) {
27
- return;
28
- }
29
- jsonForced = true;
30
- sharedPail = void 0;
31
- };
32
- const logHandlers = {
33
- compose: (...reporters) => reporters,
34
- console: () => constructReporter(LunoraReporter),
35
- json: () => constructReporter(JsonReporter)
36
- };
37
- const configureLogHandlers = (reporters) => {
38
- configuredReporters = Array.isArray(reporters) ? reporters : [reporters];
39
- sharedPail = void 0;
40
- };
41
- const STEP_LOG_TYPES = Object.fromEntries(STEP_BADGE_NAMES.map((name) => [name, { label: name, logLevel: "informational" }]));
42
- const getPail = () => {
43
- sharedPail ??= createPail({
44
- reporters: buildReporters(),
45
- scope: ["lunora"],
46
- stderr: process.stderr,
47
- stdout: process.stdout,
48
- types: STEP_LOG_TYPES
49
- });
50
- return sharedPail;
51
- };
52
- const createLogger = () => {
53
- return {
54
- debug: (message) => {
55
- getPail().debug(message);
56
- },
57
- error: (message) => {
58
- getPail().error(message);
59
- },
60
- info: (message) => {
61
- getPail().info(message);
62
- },
63
- success: (message) => {
64
- getPail().success(message);
65
- },
66
- warn: (message) => {
67
- getPail().warn(message);
68
- }
69
- };
70
- };
71
- const createStderrLogger = () => {
72
- const write = (tag, message) => {
73
- process.stderr.write(`${tag} ${message}
74
- `);
75
- };
76
- return {
77
- debug: (message) => {
78
- write("debug", message);
79
- },
80
- error: (message) => {
81
- write("error", message);
82
- },
83
- info: (message) => {
84
- write("info ", message);
85
- },
86
- success: (message) => {
87
- write("ok ", message);
88
- },
89
- warn: (message) => {
90
- write("warn ", message);
91
- }
92
- };
93
- };
94
- const pail = /* @__PURE__ */ new Proxy({}, {
95
- get(_target, property) {
96
- const instance = getPail();
97
- const value = instance[property];
98
- return typeof value === "function" ? value.bind(instance) : value;
99
- }
100
- });
101
- const logStep = (type, message) => {
102
- getPail()[type](message);
103
- };
104
-
105
- export { configureLogHandlers, createLogger, createStderrLogger, forceJsonLogging, getPail, logHandlers, logStep, pail };
@@ -1,64 +0,0 @@
1
- import { spawn } from 'node:child_process';
2
-
3
- const NEEDS_CMD_QUOTING = /[\s"%&<>^|]/u;
4
- const BACKSLASH_RUN_BEFORE_QUOTE = /(\\*)"/gu;
5
- const TRAILING_BACKSLASH_RUN = /(\\+)$/u;
6
- const spawnShellCompat = (command, args, platform = process.platform) => {
7
- if (platform !== "win32" || command === process.execPath) {
8
- return { args: [...args], command, shell: false };
9
- }
10
- const quote = (value) => {
11
- if (value === "") {
12
- return `""`;
13
- }
14
- if (!NEEDS_CMD_QUOTING.test(value)) {
15
- return value;
16
- }
17
- const escaped = value.replaceAll(BACKSLASH_RUN_BEFORE_QUOTE, String.raw`$1$1\"`).replace(TRAILING_BACKSLASH_RUN, "$1$1");
18
- return `"${escaped}"`;
19
- };
20
- return { args: args.map((argument) => quote(argument)), command: quote(command), shell: true };
21
- };
22
- const defaultSpawner = (descriptor) => new Promise((resolve, reject) => {
23
- const hasInput = typeof descriptor.input === "string";
24
- const wantCapture = descriptor.captureStdout === true;
25
- let stdout = "inherit";
26
- if (wantCapture) {
27
- stdout = "pipe";
28
- } else if (descriptor.stdoutToStderr) {
29
- stdout = 2;
30
- }
31
- const exec = spawnShellCompat(descriptor.command, descriptor.args);
32
- const child = spawn(exec.command, exec.args, {
33
- cwd: descriptor.cwd ?? process.cwd(),
34
- env: descriptor.env ? { ...process.env, ...descriptor.env } : process.env,
35
- shell: exec.shell,
36
- stdio: [hasInput ? "pipe" : "inherit", stdout, "inherit"]
37
- });
38
- let captured = "";
39
- if (wantCapture && child.stdout) {
40
- child.stdout.on("data", (chunk) => {
41
- captured += chunk.toString("utf8");
42
- process.stdout.write(chunk);
43
- });
44
- }
45
- child.on("error", (error) => {
46
- reject(error);
47
- });
48
- child.on("exit", (code, signal) => {
49
- resolve({ code: code ?? (signal ? 1 : 0), stdout: wantCapture ? captured : void 0 });
50
- });
51
- if (hasInput && child.stdin) {
52
- child.stdin.end(descriptor.input);
53
- }
54
- });
55
- const createRecordingSpawner = (exitCode = 0) => {
56
- const calls = [];
57
- const spawner = (descriptor) => {
58
- calls.push({ descriptor });
59
- return Promise.resolve({ code: exitCode });
60
- };
61
- return { calls, spawner };
62
- };
63
-
64
- export { createRecordingSpawner, defaultSpawner, spawnShellCompat };
@@ -1,62 +0,0 @@
1
- import { spawnSync } from 'node:child_process';
2
- import { LunoraError } from '@lunora/errors';
3
- import { findPackageManagerSync, identifyInitiatingPackageManager } from '@visulima/package/package-manager';
4
-
5
- const INSTALL_PREFERENCE = ["pnpm", "bun", "yarn", "npm"];
6
- const KNOWN_PACKAGE_MANAGERS = /* @__PURE__ */ new Set(["bun", "npm", "pnpm", "yarn"]);
7
- const isKnownPackageManager = (name) => KNOWN_PACKAGE_MANAGERS.has(name);
8
- const isManagerInstalled = (manager) => {
9
- try {
10
- return spawnSync(manager, ["--version"], { stdio: "ignore", timeout: 5e3 }).status === 0;
11
- } catch {
12
- return false;
13
- }
14
- };
15
- const detectInstalledManagers = (probe = isManagerInstalled) => INSTALL_PREFERENCE.filter((manager) => probe(manager));
16
- const installArgsFor = (manager) => {
17
- return { args: ["install"], command: manager };
18
- };
19
- const detectPackageManager = (startDirectory) => {
20
- try {
21
- return findPackageManagerSync(startDirectory).packageManager;
22
- } catch {
23
- }
24
- const initiating = identifyInitiatingPackageManager();
25
- if (initiating !== void 0) {
26
- const name = initiating.name === "cnpm" ? "npm" : initiating.name;
27
- if (isKnownPackageManager(name)) {
28
- return name;
29
- }
30
- }
31
- const [installed] = detectInstalledManagers();
32
- if (installed !== void 0) {
33
- return installed;
34
- }
35
- throw new LunoraError(
36
- "INTERNAL",
37
- "Could not detect a package manager: no lock file or `packageManager` field was found, and none (pnpm, bun, yarn, npm) is installed on PATH."
38
- );
39
- };
40
- const execArgsFor = (manager, command, args) => {
41
- if (manager === "yarn") {
42
- return { args: [command, ...args], command: "yarn" };
43
- }
44
- if (manager === "bun") {
45
- return { args: ["x", command, ...args], command: "bun" };
46
- }
47
- if (manager === "npm") {
48
- return { args: ["--", command, ...args], command: "npx" };
49
- }
50
- return { args: ["exec", command, ...args], command: "pnpm" };
51
- };
52
- const runScriptCommand = (manager, script) => {
53
- if (manager === "npm") {
54
- return `npm run ${script}`;
55
- }
56
- if (manager === "bun") {
57
- return `bun run ${script}`;
58
- }
59
- return `${manager} ${script}`;
60
- };
61
-
62
- export { detectInstalledManagers as a, detectPackageManager as d, execArgsFor as e, installArgsFor as i, runScriptCommand as r };
@@ -1,161 +0,0 @@
1
- import { quoteIdentifier, sqlAffinityForKind, frameworkColumnDdl, columnRef, physicalIndexName } from '@lunora/d1/dialect';
2
-
3
- const validatorKindToSqlType = (kind) => sqlAffinityForKind(kind);
4
- const renderColumnDefinition = (name, column) => {
5
- const parts = [quoteIdentifier(name), column.sqlType];
6
- if (!column.nullable) {
7
- parts.push("NOT NULL");
8
- }
9
- return parts.join(" ");
10
- };
11
- const renderCreateTable = (table) => {
12
- const columns = Object.entries(table.columns).map(([columnName, column]) => ` ${renderColumnDefinition(columnName, column)}`);
13
- const lines = [...frameworkColumnDdl().map((column) => ` ${column}`), ...columns].join(",\n");
14
- return `CREATE TABLE IF NOT EXISTS ${quoteIdentifier(table.name)} (
15
- ${lines}
16
- );`;
17
- };
18
- const renderDropTable = (tableName) => `DROP TABLE IF EXISTS ${quoteIdentifier(tableName)};`;
19
- const renderAddColumn = (tableName, columnName, column) => `ALTER TABLE ${quoteIdentifier(tableName)} ADD COLUMN ${renderColumnDefinition(columnName, column)};`;
20
- const renderCreateIndex = (tableName, index) => {
21
- const fields = index.fields.map((field) => columnRef(field)).join(", ");
22
- const uniqueClause = index.unique ? "UNIQUE " : "";
23
- return `CREATE ${uniqueClause}INDEX IF NOT EXISTS ${physicalIndexName(tableName, index.name)} ON ${quoteIdentifier(tableName)} (${fields});`;
24
- };
25
- const renderDropIndex = (tableName, indexName) => `DROP INDEX IF EXISTS ${physicalIndexName(tableName, indexName)};`;
26
- const diffExistingColumn = (tableName, columnName, old, column, unsupported) => {
27
- if (old.sqlType !== column.sqlType) {
28
- unsupported.push({
29
- kind: "columnTypeChange",
30
- summary: `column type change on ${tableName}.${columnName}: ${old.sqlType} → ${column.sqlType} (write SQL manually)`
31
- });
32
- }
33
- if (old.nullable !== column.nullable) {
34
- unsupported.push({
35
- kind: "columnTypeChange",
36
- summary: `nullability change on ${tableName}.${columnName}: ${old.nullable ? "NULL" : "NOT NULL"} → ${column.nullable ? "NULL" : "NOT NULL"} (write SQL manually)`
37
- });
38
- }
39
- };
40
- const diffColumns = (tableName, previous, next, entries, unsupported) => {
41
- for (const [columnName, column] of Object.entries(next)) {
42
- const old = previous[columnName];
43
- if (old === void 0) {
44
- entries.push({
45
- kind: "addColumn",
46
- sql: renderAddColumn(tableName, columnName, column),
47
- summary: `ADD COLUMN ${tableName}.${columnName}`
48
- });
49
- continue;
50
- }
51
- diffExistingColumn(tableName, columnName, old, column, unsupported);
52
- }
53
- for (const columnName of Object.keys(previous)) {
54
- if (next[columnName] === void 0) {
55
- unsupported.push({
56
- kind: "dropColumn",
57
- summary: `DROP COLUMN ${tableName}.${columnName} (SQLite drop-column requires careful migration — write SQL manually)`
58
- });
59
- }
60
- }
61
- };
62
- const diffIndexes = (tableName, previous, next, entries, unsupported) => {
63
- for (const [indexName, index] of Object.entries(next)) {
64
- const old = previous[indexName];
65
- if (old === void 0) {
66
- entries.push({
67
- kind: "createIndex",
68
- sql: renderCreateIndex(tableName, index),
69
- summary: `CREATE INDEX ${indexName} ON ${tableName}`
70
- });
71
- continue;
72
- }
73
- const fieldsEqual = old.fields.length === index.fields.length && old.fields.every((field, i) => field === index.fields[i]);
74
- if (!fieldsEqual || old.unique !== index.unique) {
75
- unsupported.push({
76
- kind: "indexRename",
77
- summary: `index ${indexName} changed on ${tableName} — drop+create manually if intentional`
78
- });
79
- }
80
- }
81
- for (const indexName of Object.keys(previous)) {
82
- if (next[indexName] === void 0) {
83
- entries.push({
84
- kind: "dropIndex",
85
- sql: renderDropIndex(tableName, indexName),
86
- summary: `DROP INDEX ${indexName}`
87
- });
88
- }
89
- }
90
- };
91
- const diffNewTable = (tableName, table, entries) => {
92
- entries.push({
93
- kind: "createTable",
94
- sql: renderCreateTable(table),
95
- summary: `CREATE TABLE ${tableName}`
96
- });
97
- for (const index of Object.values(table.indexes)) {
98
- entries.push({
99
- kind: "createIndex",
100
- sql: renderCreateIndex(tableName, index),
101
- summary: `CREATE INDEX ${index.name} ON ${tableName}`
102
- });
103
- }
104
- };
105
- const diffSnapshots = (previous, next) => {
106
- const previousTables = previous?.tables ?? {};
107
- const entries = [];
108
- const unsupported = [];
109
- for (const [tableName, table] of Object.entries(next.tables)) {
110
- const old = previousTables[tableName];
111
- if (old === void 0) {
112
- diffNewTable(tableName, table, entries);
113
- continue;
114
- }
115
- diffColumns(tableName, old.columns, table.columns, entries, unsupported);
116
- diffIndexes(tableName, old.indexes, table.indexes, entries, unsupported);
117
- }
118
- for (const [tableName] of Object.entries(previousTables)) {
119
- if (next.tables[tableName] === void 0) {
120
- entries.push({
121
- kind: "dropTable",
122
- sql: renderDropTable(tableName),
123
- summary: `DROP TABLE ${tableName}`
124
- });
125
- }
126
- }
127
- return {
128
- empty: entries.length === 0 && unsupported.length === 0,
129
- entries,
130
- unsupported
131
- };
132
- };
133
- const renderMigrationFile = (name, diff, generatedAt) => {
134
- const lines = [
135
- `-- Lunora migration: ${name}`,
136
- `-- Generated at ${generatedAt}`,
137
- "-- This file was produced by `lunora migrate generate`. Review carefully before applying.",
138
- ""
139
- ];
140
- for (const entry of diff.entries) {
141
- lines.push(`-- ${entry.summary}`, entry.sql, "");
142
- }
143
- if (diff.unsupported.length > 0) {
144
- lines.push(
145
- "-- ---------------------------------------------------------------",
146
- "-- The following deltas are NOT auto-generated in v0.1.",
147
- "-- Write the appropriate SQL below by hand:",
148
- "--"
149
- );
150
- for (const entry of diff.unsupported) {
151
- lines.push(`-- * ${entry.summary}`);
152
- }
153
- lines.push("-- ---------------------------------------------------------------", "");
154
- }
155
- if (diff.empty) {
156
- lines.push("-- No changes detected. Re-running `lunora migrate generate` will overwrite this file.", "");
157
- }
158
- return lines.join("\n");
159
- };
160
-
161
- export { diffSnapshots, renderAddColumn, renderCreateIndex, renderCreateTable, renderDropIndex, renderDropTable, renderMigrationFile, validatorKindToSqlType };
@@ -1,21 +0,0 @@
1
- import { spawnSync } from 'node:child_process';
2
-
3
- const isDockerAvailable = () => {
4
- try {
5
- return spawnSync("docker", ["info"], { stdio: "ignore" }).status === 0;
6
- } catch {
7
- return false;
8
- }
9
- };
10
- const isRailpackAvailable = () => {
11
- if (typeof process.env.BUILDKIT_HOST !== "string" || process.env.BUILDKIT_HOST.length === 0) {
12
- return false;
13
- }
14
- try {
15
- return spawnSync("railpack", ["--version"], { stdio: "ignore" }).status === 0;
16
- } catch {
17
- return false;
18
- }
19
- };
20
-
21
- export { isRailpackAvailable as a, isDockerAvailable as i };
@@ -1,64 +0,0 @@
1
- import { Project, SyntaxKind, Node } from 'ts-morph';
2
-
3
- const VALID_JS_IDENTIFIER = /^[A-Za-z_$][\w$]*$/u;
4
- const startMarker = (key) => `// lunora:add:${key}:start`;
5
- const endMarker = (key) => `// lunora:add:${key}:end`;
6
- const extensionImportSpecifier = (key) => `./${key}/schema`;
7
- const findDefineSchemaCall = (callExpressions) => {
8
- for (const call of callExpressions) {
9
- if (call.getExpression().getText() === "defineSchema") {
10
- return call;
11
- }
12
- }
13
- return void 0;
14
- };
15
- const outermostChainExpression = (defineSchemaCall) => {
16
- let node = defineSchemaCall;
17
- for (let parent = node.getParent(); parent !== void 0; parent = node.getParent()) {
18
- if (Node.isPropertyAccessExpression(parent) && parent.getExpression() === node) {
19
- node = parent;
20
- } else if (Node.isCallExpression(parent) && parent.getExpression() === node) {
21
- node = parent;
22
- } else {
23
- break;
24
- }
25
- }
26
- return node;
27
- };
28
- const insertSchemaExtension = (source, key) => {
29
- if (!VALID_JS_IDENTIFIER.test(key)) {
30
- return { ok: false, reason: "invalid-identifier" };
31
- }
32
- if (source.includes(startMarker(key))) {
33
- return { ok: false, reason: "already-applied" };
34
- }
35
- const project = new Project({
36
- compilerOptions: { allowJs: true },
37
- useInMemoryFileSystem: true
38
- });
39
- const sourceFile = project.createSourceFile("schema.ts", source, { overwrite: true });
40
- const callExpressions = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);
41
- const defineSchemaCall = findDefineSchemaCall(callExpressions);
42
- if (!defineSchemaCall) {
43
- return { ok: false, reason: "no-define-schema" };
44
- }
45
- const tablesArgument = defineSchemaCall.getArguments()[0];
46
- if (tablesArgument?.getKind() !== SyntaxKind.ObjectLiteralExpression) {
47
- return { ok: false, reason: "non-object-argument" };
48
- }
49
- const insertAt = outermostChainExpression(defineSchemaCall).getEnd();
50
- const chainText = `
51
- ${startMarker(key)}
52
- .extend(${key}.extension)
53
- ${endMarker(key)}
54
- `;
55
- sourceFile.insertText(insertAt, chainText);
56
- const importText = `${startMarker(key)}
57
- import { ${key} } from "${extensionImportSpecifier(key)}";
58
- ${endMarker(key)}
59
- `;
60
- sourceFile.insertText(0, importText);
61
- return { ok: true, text: sourceFile.getFullText() };
62
- };
63
-
64
- export { insertSchemaExtension };
@@ -1,42 +0,0 @@
1
- import { spawn } from 'node:child_process';
2
- import { platform } from 'node:os';
3
- import { LunoraError } from '@lunora/errors';
4
-
5
- const platformCommand = () => {
6
- const os = platform();
7
- if (os === "darwin") {
8
- return { args: [], command: "open" };
9
- }
10
- if (os === "win32") {
11
- return { args: ["/c", "start", ""], command: "cmd" };
12
- }
13
- return { args: [], command: "xdg-open" };
14
- };
15
- const escapeForCmd = (url) => url.replaceAll("%", "%25").replaceAll("&", "%26").replaceAll("|", "%7C").replaceAll("^", "%5E").replaceAll("<", "%3C").replaceAll(">", "%3E").replaceAll("(", "%28").replaceAll(")", "%29").replaceAll('"', "%22").replaceAll("!", "%21");
16
- const platformOpener = (url) => new Promise((resolve, reject) => {
17
- const { args, command } = platformCommand();
18
- const safeUrl = platform() === "win32" ? escapeForCmd(url) : url;
19
- const child = spawn(command, [...args, safeUrl], { detached: true, stdio: "ignore" });
20
- child.once("error", (error) => {
21
- reject(error);
22
- });
23
- child.once("spawn", () => {
24
- child.unref();
25
- resolve();
26
- });
27
- });
28
- const openUrl = async (url, options = {}) => {
29
- let parsed;
30
- try {
31
- parsed = new URL(url);
32
- } catch {
33
- throw new LunoraError("INTERNAL", `Invalid URL: ${url}`);
34
- }
35
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
36
- throw new LunoraError("INTERNAL", `Refusing to open non-http(s) URL: ${url}`);
37
- }
38
- const opener = options.opener ?? platformOpener;
39
- await opener(url);
40
- };
41
-
42
- export { openUrl as o };
@@ -1,17 +0,0 @@
1
- import { createStderrLogger } from './createLogger-CIWSHrTL.mjs';
2
-
3
- const OUTPUT_FORMATS = /* @__PURE__ */ new Set(["json", "pretty"]);
4
- const validateOutputFormat = (command, format) => {
5
- if (format !== void 0 && !OUTPUT_FORMATS.has(format)) {
6
- return `${command}: unknown --format "${format}" — expected pretty | json`;
7
- }
8
- return void 0;
9
- };
10
- const isJsonFormat = (format) => format === "json";
11
- const loggerForFormat = (format, prettyLogger) => isJsonFormat(format) ? createStderrLogger() : prettyLogger;
12
- const printJson = (result) => {
13
- process.stdout.write(`${JSON.stringify(result, void 0, 2)}
14
- `);
15
- };
16
-
17
- export { isJsonFormat as i, loggerForFormat as l, printJson as p, validateOutputFormat as v };
@@ -1,121 +0,0 @@
1
- import { LunoraError } from '@lunora/errors';
2
-
3
- const NEWLINE_PRESENT = /[\r\n]/u;
4
- const VALID_ENV_NAME = /^[A-Za-z_]\w*$/u;
5
- const VALID_ITEM_NAME = /^[A-Za-z0-9][\w-]*$/u;
6
- const VALID_MODULE_PATH = /^[\w.-]+(?:\/[\w.-]+)*$/u;
7
- const parseManifest = (raw, itemName) => {
8
- if (typeof raw !== "object" || raw === null) {
9
- throw new LunoraError("INTERNAL", `registry.json for "${itemName}" is not an object`);
10
- }
11
- const record = raw;
12
- const { name } = record;
13
- if (typeof name !== "string" || name.length === 0) {
14
- throw new LunoraError("INTERNAL", `registry.json for "${itemName}" is missing a string "name"`);
15
- }
16
- if (!VALID_ITEM_NAME.test(name)) {
17
- throw new LunoraError(
18
- "INTERNAL",
19
- `registry.json for "${itemName}": name "${name}" must match ${VALID_ITEM_NAME.source} (letters, digits, "-", "_"; no path separators, "..", or code)`
20
- );
21
- }
22
- const filesRaw = record.files;
23
- if (!Array.isArray(filesRaw)) {
24
- throw new TypeError(`registry.json for "${itemName}" is missing a "files" array`);
25
- }
26
- const files = filesRaw.map((entry, index) => {
27
- if (typeof entry !== "object" || entry === null) {
28
- throw new LunoraError("INTERNAL", `registry.json "${itemName}": files[${String(index)}] is not an object`);
29
- }
30
- const fileRecord = entry;
31
- const { from } = fileRecord;
32
- const { to } = fileRecord;
33
- const { merge } = fileRecord;
34
- if (typeof from !== "string" || typeof to !== "string") {
35
- throw new TypeError(`registry.json "${itemName}": files[${String(index)}] needs string "from" and "to"`);
36
- }
37
- if (merge !== "create-or-skip" && merge !== "schema-extension") {
38
- throw new LunoraError("INTERNAL", `registry.json "${itemName}": files[${String(index)}].merge must be "create-or-skip" or "schema-extension"`);
39
- }
40
- for (const [field, value] of [
41
- ["from", from],
42
- ["to", to]
43
- ]) {
44
- if (value.includes("..") || value.startsWith("/")) {
45
- throw new LunoraError(
46
- "INTERNAL",
47
- `registry.json "${itemName}": files[${String(index)}].${field} "${value}" must be a relative path without ".."`
48
- );
49
- }
50
- }
51
- return { from, merge, to };
52
- });
53
- const asStringMap = (value) => typeof value === "object" && value !== null ? value : void 0;
54
- const deps = asStringMap(record.deps);
55
- const devDependencies = asStringMap(record.devDependencies);
56
- const requires = Array.isArray(record.requires) ? record.requires.filter((value) => typeof value === "string") : void 0;
57
- const bindings = Array.isArray(record.bindings) ? record.bindings.filter((value) => {
58
- if (typeof value !== "object" || value === null) {
59
- return false;
60
- }
61
- const bindingRecord = value;
62
- return Array.isArray(bindingRecord.path) && bindingRecord.path.every((segment) => typeof segment === "string");
63
- }) : void 0;
64
- const entrypointReexports = Array.isArray(record.entrypointReexports) ? record.entrypointReexports.filter(
65
- (value) => typeof value === "object" && value !== null && typeof value.module === "string"
66
- ).map((entry) => {
67
- if (entry.module.includes("..") || entry.module.startsWith("/") || !VALID_MODULE_PATH.test(entry.module)) {
68
- throw new LunoraError(
69
- "INTERNAL",
70
- `registry.json "${itemName}": entrypointReexports[].module "${entry.module}" must be a safe relative module path without path traversal or unsafe characters`
71
- );
72
- }
73
- const reexport = { module: entry.module };
74
- if (typeof entry.comment === "string") {
75
- if (NEWLINE_PRESENT.test(entry.comment)) {
76
- throw new LunoraError("INTERNAL", `registry.json "${itemName}": entrypointReexports[].comment must not contain a newline`);
77
- }
78
- reexport.comment = entry.comment;
79
- }
80
- return reexport;
81
- }) : void 0;
82
- const envVariables = Array.isArray(record.envVars) ? record.envVars.filter(
83
- (value) => typeof value === "object" && value !== null && typeof value.name === "string"
84
- ).map((entry) => {
85
- const hasValue = typeof entry.value === "string";
86
- if (!VALID_ENV_NAME.test(entry.name)) {
87
- throw new LunoraError(
88
- "INTERNAL",
89
- `registry.json "${itemName}": envVars["${entry.name}"].name must match ${VALID_ENV_NAME.source} (letters, digits, underscore; no "=" or newline)`
90
- );
91
- }
92
- if (hasValue && NEWLINE_PRESENT.test(entry.value)) {
93
- throw new LunoraError("INTERNAL", `registry.json "${itemName}": envVars["${entry.name}"].value must not contain a newline`);
94
- }
95
- if (typeof entry.description === "string" && NEWLINE_PRESENT.test(entry.description)) {
96
- throw new LunoraError("INTERNAL", `registry.json "${itemName}": envVars["${entry.name}"].description must not contain a newline`);
97
- }
98
- return {
99
- ...typeof entry.description === "string" ? { description: entry.description } : {},
100
- name: entry.name,
101
- // Default to secret unless a concrete value is provided.
102
- secret: typeof entry.secret === "boolean" ? entry.secret : !hasValue,
103
- ...hasValue ? { value: entry.value } : {}
104
- };
105
- }) : void 0;
106
- return {
107
- bindings,
108
- deps,
109
- description: typeof record.description === "string" ? record.description : void 0,
110
- devDependencies,
111
- docs: typeof record.docs === "string" ? record.docs : void 0,
112
- entrypointReexports,
113
- envVars: envVariables,
114
- files,
115
- name,
116
- requires,
117
- title: typeof record.title === "string" ? record.title : void 0
118
- };
119
- };
120
-
121
- export { parseManifest as default };
@@ -1,9 +0,0 @@
1
- class PromptCancelledError extends Error {
2
- constructor() {
3
- super("cancelled");
4
- this.name = "PromptCancelledError";
5
- }
6
- }
7
- const PROMPT_CANCEL_EXIT_CODE = 130;
8
-
9
- export { PromptCancelledError as P, PROMPT_CANCEL_EXIT_CODE as a };