@metaobjectsdev/cli 0.11.6-rc.1 → 0.12.0-rc.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/README.md +17 -3
- package/dist/src/commands/gen.d.ts +2 -1
- package/dist/src/commands/gen.d.ts.map +1 -1
- package/dist/src/commands/gen.js +8 -4
- package/dist/src/commands/gen.js.map +1 -1
- package/dist/src/commands/migrate.d.ts +4 -3
- package/dist/src/commands/migrate.d.ts.map +1 -1
- package/dist/src/commands/migrate.js +304 -206
- package/dist/src/commands/migrate.js.map +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +182 -7
- package/dist/src/index.js.map +1 -1
- package/dist/src/lib/args.d.ts +8 -0
- package/dist/src/lib/args.d.ts.map +1 -1
- package/dist/src/lib/args.js +21 -0
- package/dist/src/lib/args.js.map +1 -1
- package/dist/src/lib/format.d.ts +8 -0
- package/dist/src/lib/format.d.ts.map +1 -0
- package/dist/src/lib/format.js +18 -0
- package/dist/src/lib/format.js.map +1 -0
- package/dist/src/lib/kysely.d.ts.map +1 -1
- package/dist/src/lib/kysely.js +5 -2
- package/dist/src/lib/kysely.js.map +1 -1
- package/dist/src/lib/output-json.d.ts +4 -0
- package/dist/src/lib/output-json.d.ts.map +1 -0
- package/dist/src/lib/output-json.js +8 -0
- package/dist/src/lib/output-json.js.map +1 -0
- package/dist/src/lib/output.d.ts +23 -0
- package/dist/src/lib/output.d.ts.map +1 -1
- package/dist/src/lib/output.js +88 -0
- package/dist/src/lib/output.js.map +1 -1
- package/dist/src/lib/pm-detect.d.ts +12 -0
- package/dist/src/lib/pm-detect.d.ts.map +1 -0
- package/dist/src/lib/pm-detect.js +52 -0
- package/dist/src/lib/pm-detect.js.map +1 -0
- package/package.json +17 -20
- package/src/commands/gen.ts +10 -4
- package/src/commands/migrate.ts +134 -10
- package/src/index.ts +183 -7
- package/src/lib/args.ts +34 -0
- package/src/lib/format.ts +23 -0
- package/src/lib/kysely.ts +5 -2
- package/src/lib/output-json.ts +10 -0
- package/src/lib/output.ts +100 -0
- package/src/lib/pm-detect.ts +53 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../../src/lib/output.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../../src/lib/output.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAG3C,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,OAAO,CAAC;CAChB;AAMD,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,QAAQ,GAAG,UAAU,GAAG,WAAW,GAAG,SAAS,CAAC;AAEpF,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,aAAa,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAkBD,wBAAgB,eAAe,CAAC,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,GAAG,MAAM,CAyCnF;AAMD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,MAAM,EAAE,OAAO,CAAC;IAChB,wGAAwG;IACxG,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,2DAA2D;IAC3D,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,kBAAkB,EAAE,KAAK,EAAE,aAAa,GAAG,MAAM,CAyC5F;AAMD,wBAAgB,eAAe,CAAC,MAAM,EAAE,cAAc,GAAG;IACvD,GAAG,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,aAAa,CAAA;KAAE,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAC;CACjF,CAkBA;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAElE;AAMD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,kBAAkB,GAAG;IAC/D,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC3C,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB,CAkDA;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAE1E"}
|
package/dist/src/lib/output.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
//
|
|
3
3
|
// TTY-gated glyphs: unicode (✓ ↺ ✗ = ⚠) when stdout is a TTY, plain words
|
|
4
4
|
// (NEW MERGED CONFLICT UNCHANGED REFUSED) otherwise. Per SP5 §5.1.
|
|
5
|
+
import { toonEncode } from "./format.js";
|
|
5
6
|
const GEN_GLYPHS = {
|
|
6
7
|
new: "✓",
|
|
7
8
|
merged: "↺",
|
|
@@ -93,4 +94,91 @@ export function formatMigrateResult(result, _opts) {
|
|
|
93
94
|
}
|
|
94
95
|
return lines.join("\n");
|
|
95
96
|
}
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
// gen TOON/JSON formatters (axi)
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
export function genResultToData(result) {
|
|
101
|
+
const counts = result.files.reduce((a, f) => ((a[f.status] = (a[f.status] ?? 0) + 1), a), { new: 0, merged: 0, conflict: 0, unchanged: 0, refused: 0 });
|
|
102
|
+
const parts = [];
|
|
103
|
+
if (counts.new)
|
|
104
|
+
parts.push(`${counts.new} written`);
|
|
105
|
+
if (counts.merged)
|
|
106
|
+
parts.push(`${counts.merged} merged`);
|
|
107
|
+
if (counts.conflict)
|
|
108
|
+
parts.push(`${counts.conflict} conflict`);
|
|
109
|
+
if (counts.unchanged)
|
|
110
|
+
parts.push(`${counts.unchanged} unchanged`);
|
|
111
|
+
if (counts.refused)
|
|
112
|
+
parts.push(`${counts.refused} refused`);
|
|
113
|
+
const summary = result.files.length === 0
|
|
114
|
+
? `no entities to generate in ${result.outDir}`
|
|
115
|
+
: parts.join(", ");
|
|
116
|
+
const help = result.files.length === 0
|
|
117
|
+
? ["author entities under metaobjects/ then re-run `meta gen`"]
|
|
118
|
+
: ["typecheck the generated code with `npx tsc`", "run schema with `meta migrate --db <url> --slug <name>`"];
|
|
119
|
+
return { gen: result.files.map((f) => ({ file: f.path, status: f.status })), summary, help };
|
|
120
|
+
}
|
|
121
|
+
export function formatGenResultToon(result) {
|
|
122
|
+
return toonEncode(genResultToData(result));
|
|
123
|
+
}
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
// migrate TOON/JSON formatters (axi)
|
|
126
|
+
// ---------------------------------------------------------------------------
|
|
127
|
+
export function migrateResultToData(result) {
|
|
128
|
+
const changeEntries = Object.entries(result.changeCounts).filter(([, v]) => v > 0);
|
|
129
|
+
const changes = changeEntries.map(([kind, count]) => ({ kind, count }));
|
|
130
|
+
const isBlocked = result.blocked.length > 0 || result.ambiguous.length > 0;
|
|
131
|
+
const changeSummary = changeEntries.map(([k, v]) => `${v} ${k}`).join(", ");
|
|
132
|
+
const applied = result.applied ?? [];
|
|
133
|
+
const applyFailed = result.applyFailed ?? false;
|
|
134
|
+
// `--apply` also applies previously-written-but-unapplied ledger files, so
|
|
135
|
+
// `applied` can be non-empty even when there is no fresh metadata diff.
|
|
136
|
+
const hasChanges = changeEntries.length > 0 || isBlocked;
|
|
137
|
+
const prefix = changeSummary.length > 0 ? `${changeSummary}; ` : "";
|
|
138
|
+
// Summary + help reflect what ACTUALLY happened, computed from the real signals
|
|
139
|
+
// (dry-run, blocked/ambiguous, files written, files applied) rather than
|
|
140
|
+
// short-circuiting on the presence of a fresh diff: a dry-run wrote nothing, a
|
|
141
|
+
// generate-only run wrote files but applied nothing, and `--apply` can apply a
|
|
142
|
+
// pending ledger file even with no new diff. The `--rollback` hint appears only
|
|
143
|
+
// when something was actually applied.
|
|
144
|
+
let summary;
|
|
145
|
+
let help;
|
|
146
|
+
if (isBlocked) {
|
|
147
|
+
summary = `${changeSummary}; not applied`;
|
|
148
|
+
help = [
|
|
149
|
+
...result.blocked.map((b) => `re-run with --allow ${b.allowFlag} to apply: ${b.description}`),
|
|
150
|
+
...result.ambiguous.map((a) => `re-run with --on-ambiguous to resolve: ${a.hint}`),
|
|
151
|
+
];
|
|
152
|
+
}
|
|
153
|
+
else if (result.dryRun) {
|
|
154
|
+
summary = hasChanges ? `${changeSummary}; preview only (nothing written)` : "no schema changes";
|
|
155
|
+
help = hasChanges
|
|
156
|
+
? ["re-run without --dry-run to write the migration"]
|
|
157
|
+
: ["metadata and schema are in sync — nothing to do"];
|
|
158
|
+
}
|
|
159
|
+
else if (applyFailed) {
|
|
160
|
+
summary = `${prefix}apply failed`;
|
|
161
|
+
help = ["resolve the apply error above, then re-run `meta migrate --apply`"];
|
|
162
|
+
}
|
|
163
|
+
else if (applied.length > 0) {
|
|
164
|
+
summary = `${prefix}applied ${applied.length} migration(s)`;
|
|
165
|
+
help = ["roll back with `meta migrate --rollback <target>`"];
|
|
166
|
+
}
|
|
167
|
+
else if (result.writtenPaths.length > 0) {
|
|
168
|
+
summary = `${prefix}wrote ${result.writtenPaths.length} migration file(s)`;
|
|
169
|
+
help = ["apply with `meta migrate --db <url> --apply`"];
|
|
170
|
+
}
|
|
171
|
+
else if (!hasChanges) {
|
|
172
|
+
summary = "no schema changes";
|
|
173
|
+
help = ["metadata and schema are in sync — nothing to do"];
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
summary = `${changeSummary}; not written`;
|
|
177
|
+
help = ["re-run with --slug <name> to write the migration"];
|
|
178
|
+
}
|
|
179
|
+
return { changes, written: result.writtenPaths, summary, help };
|
|
180
|
+
}
|
|
181
|
+
export function formatMigrateResultToon(result) {
|
|
182
|
+
return toonEncode(migrateResultToData(result));
|
|
183
|
+
}
|
|
96
184
|
//# sourceMappingURL=output.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../../src/lib/output.ts"],"names":[],"mappings":"AAAA,mDAAmD;AACnD,EAAE;AACF,0EAA0E;AAC1E,mEAAmE;
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../../src/lib/output.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type PackageManager = "npm" | "pnpm" | "yarn" | "bun";
|
|
2
|
+
/**
|
|
3
|
+
* Detect the package manager in use by looking for the lockfile closest to
|
|
4
|
+
* `dir`. Walks up to the root. Returns "bun" as the default when no lockfile
|
|
5
|
+
* is found.
|
|
6
|
+
*/
|
|
7
|
+
export declare function detectPackageManager(dir: string): Promise<PackageManager>;
|
|
8
|
+
/**
|
|
9
|
+
* Returns the install command for a missing package, using the detected PM.
|
|
10
|
+
*/
|
|
11
|
+
export declare function installCommand(pkg: string, dir: string): Promise<string>;
|
|
12
|
+
//# sourceMappingURL=pm-detect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pm-detect.d.ts","sourceRoot":"","sources":["../../../src/lib/pm-detect.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;AAE7D;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAyB/E;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAY9E"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { access } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
/**
|
|
4
|
+
* Detect the package manager in use by looking for the lockfile closest to
|
|
5
|
+
* `dir`. Walks up to the root. Returns "bun" as the default when no lockfile
|
|
6
|
+
* is found.
|
|
7
|
+
*/
|
|
8
|
+
export async function detectPackageManager(dir) {
|
|
9
|
+
// Check in the given dir first, then parent dirs up to the FS root.
|
|
10
|
+
let current = dir;
|
|
11
|
+
while (true) {
|
|
12
|
+
const candidates = [
|
|
13
|
+
[join(current, "package-lock.json"), "npm"],
|
|
14
|
+
[join(current, "pnpm-lock.yaml"), "pnpm"],
|
|
15
|
+
[join(current, "yarn.lock"), "yarn"],
|
|
16
|
+
[join(current, "bun.lockb"), "bun"],
|
|
17
|
+
[join(current, "bun.lock"), "bun"],
|
|
18
|
+
];
|
|
19
|
+
for (const [path, pm] of candidates) {
|
|
20
|
+
try {
|
|
21
|
+
await access(path);
|
|
22
|
+
return pm;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
// not found, try next
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const parent = join(current, "..");
|
|
29
|
+
if (parent === current)
|
|
30
|
+
break; // reached root
|
|
31
|
+
current = parent;
|
|
32
|
+
}
|
|
33
|
+
// Default: bun (most common for this toolchain)
|
|
34
|
+
return "bun";
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Returns the install command for a missing package, using the detected PM.
|
|
38
|
+
*/
|
|
39
|
+
export async function installCommand(pkg, dir) {
|
|
40
|
+
const pm = await detectPackageManager(dir);
|
|
41
|
+
switch (pm) {
|
|
42
|
+
case "npm":
|
|
43
|
+
return `npm install ${pkg}`;
|
|
44
|
+
case "pnpm":
|
|
45
|
+
return `pnpm add ${pkg}`;
|
|
46
|
+
case "yarn":
|
|
47
|
+
return `yarn add ${pkg}`;
|
|
48
|
+
case "bun":
|
|
49
|
+
return `bun add ${pkg}`;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=pm-detect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pm-detect.js","sourceRoot":"","sources":["../../../src/lib/pm-detect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAIjC;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,GAAW;IACpD,oEAAoE;IACpE,IAAI,OAAO,GAAG,GAAG,CAAC;IAClB,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,UAAU,GAA+B;YAC7C,CAAC,IAAI,CAAC,OAAO,EAAE,mBAAmB,CAAC,EAAE,KAAK,CAAC;YAC3C,CAAC,IAAI,CAAC,OAAO,EAAE,gBAAgB,CAAC,EAAE,MAAM,CAAC;YACzC,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC;YACpC,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,EAAE,KAAK,CAAC;YACnC,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,KAAK,CAAC;SACnC,CAAC;QACF,KAAK,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,UAAU,EAAE,CAAC;YACpC,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;gBACnB,OAAO,EAAE,CAAC;YACZ,CAAC;YAAC,MAAM,CAAC;gBACP,sBAAsB;YACxB,CAAC;QACH,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACnC,IAAI,MAAM,KAAK,OAAO;YAAE,MAAM,CAAC,eAAe;QAC9C,OAAO,GAAG,MAAM,CAAC;IACnB,CAAC;IACD,gDAAgD;IAChD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,GAAW,EAAE,GAAW;IAC3D,MAAM,EAAE,GAAG,MAAM,oBAAoB,CAAC,GAAG,CAAC,CAAC;IAC3C,QAAQ,EAAE,EAAE,CAAC;QACX,KAAK,KAAK;YACR,OAAO,eAAe,GAAG,EAAE,CAAC;QAC9B,KAAK,MAAM;YACT,OAAO,YAAY,GAAG,EAAE,CAAC;QAC3B,KAAK,MAAM;YACT,OAAO,YAAY,GAAG,EAAE,CAAC;QAC3B,KAAK,KAAK;YACR,OAAO,WAAW,GAAG,EAAE,CAAC;IAC5B,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metaobjectsdev/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0-rc.1",
|
|
4
4
|
"description": "CLI for MetaObjects: scaffold, codegen, migrate, and drift-detection commands.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/src/index.js",
|
|
@@ -48,38 +48,35 @@
|
|
|
48
48
|
"drift-detection"
|
|
49
49
|
],
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@
|
|
52
|
-
"@metaobjectsdev/
|
|
53
|
-
"@metaobjectsdev/
|
|
54
|
-
"@metaobjectsdev/codegen-ts": "0.
|
|
55
|
-
"@metaobjectsdev/
|
|
56
|
-
"@metaobjectsdev/
|
|
57
|
-
"@metaobjectsdev/
|
|
58
|
-
"@metaobjectsdev/runtime-ts": "0.
|
|
51
|
+
"@libsql/kysely-libsql": "^0.4.0",
|
|
52
|
+
"@metaobjectsdev/codegen-ts": "0.12.0-rc.1",
|
|
53
|
+
"@metaobjectsdev/codegen-ts-react": "0.12.0-rc.1",
|
|
54
|
+
"@metaobjectsdev/codegen-ts-tanstack": "0.12.0-rc.1",
|
|
55
|
+
"@metaobjectsdev/metadata": "0.12.0-rc.1",
|
|
56
|
+
"@metaobjectsdev/migrate-ts": "0.12.0-rc.1",
|
|
57
|
+
"@metaobjectsdev/render": "0.12.0-rc.1",
|
|
58
|
+
"@metaobjectsdev/runtime-ts": "0.12.0-rc.1",
|
|
59
|
+
"@metaobjectsdev/sdk": "0.12.0-rc.1",
|
|
60
|
+
"@toon-format/toon": "^2.3.0",
|
|
59
61
|
"jiti": "^2.4.0"
|
|
60
62
|
},
|
|
61
63
|
"peerDependencies": {
|
|
62
64
|
"kysely": ">=0.27.0",
|
|
63
|
-
"pg": ">=8.0.0"
|
|
64
|
-
"@libsql/kysely-libsql": ">=0.4.0"
|
|
65
|
+
"pg": ">=8.0.0"
|
|
65
66
|
},
|
|
66
67
|
"peerDependenciesMeta": {
|
|
67
68
|
"pg": {
|
|
68
69
|
"optional": true
|
|
69
|
-
},
|
|
70
|
-
"@libsql/kysely-libsql": {
|
|
71
|
-
"optional": true
|
|
72
70
|
}
|
|
73
71
|
},
|
|
74
72
|
"devDependencies": {
|
|
75
|
-
"bun-types": "latest",
|
|
76
|
-
"typescript": "^5.6.0",
|
|
77
|
-
"@types/node": "^22.0.0",
|
|
78
|
-
"@libsql/kysely-libsql": "^0.4.1",
|
|
79
73
|
"@libsql/client": "^0.14.0",
|
|
74
|
+
"@types/node": "^22.0.0",
|
|
75
|
+
"@types/pg": "^8.0.0",
|
|
76
|
+
"bun-types": "latest",
|
|
80
77
|
"kysely": "^0.27.0",
|
|
81
78
|
"pg": "^8.0.0",
|
|
82
|
-
"
|
|
83
|
-
"
|
|
79
|
+
"pg-mem": "^3.0.4",
|
|
80
|
+
"typescript": "^5.6.0"
|
|
84
81
|
}
|
|
85
82
|
}
|
package/src/commands/gen.ts
CHANGED
|
@@ -3,7 +3,9 @@ import { existsSync } from "node:fs";
|
|
|
3
3
|
import { parseGenArgs } from "../lib/args.js";
|
|
4
4
|
import { resolveGenConfig } from "../lib/config.js";
|
|
5
5
|
import { loadMetaobjectsConfig } from "../lib/load-metaobjects-config.js";
|
|
6
|
-
import { formatGenResult, type GenFileEntry, type GenFileStatus } from "../lib/output.js";
|
|
6
|
+
import { formatGenResult, formatGenResultToon, type GenFileEntry, type GenFileStatus } from "../lib/output.js";
|
|
7
|
+
import { formatGenResultJson } from "../lib/output-json.js";
|
|
8
|
+
import type { OutputFormat } from "../lib/format.js";
|
|
7
9
|
import { log } from "../lib/log.js";
|
|
8
10
|
import { warnIfAgentContextStale } from "../lib/agent-context-staleness.js";
|
|
9
11
|
import { loadMemory, DEFAULT_METADATA_DIR } from "@metaobjectsdev/sdk";
|
|
@@ -22,7 +24,7 @@ function mapStatus(s: WriteStatus): GenFileStatus {
|
|
|
22
24
|
}
|
|
23
25
|
}
|
|
24
26
|
|
|
25
|
-
export async function genCommand(args: string[], cwd: string): Promise<number> {
|
|
27
|
+
export async function genCommand(args: string[], cwd: string, fmt: OutputFormat = "text"): Promise<number> {
|
|
26
28
|
let flags;
|
|
27
29
|
try { flags = parseGenArgs(args); }
|
|
28
30
|
catch (err) { log.error((err as Error).message); return 2; }
|
|
@@ -97,13 +99,17 @@ export async function genCommand(args: string[], cwd: string): Promise<number> {
|
|
|
97
99
|
(forgeConfig.targets ? Object.values(forgeConfig.targets).map((t) => t.outDir) : [])
|
|
98
100
|
.concat([forgeConfig.outDir]),
|
|
99
101
|
));
|
|
100
|
-
const
|
|
102
|
+
const genResult = {
|
|
101
103
|
files,
|
|
102
104
|
outDir: targetDirs.length > 1 ? targetDirs.join(", ") : forgeConfig.outDir,
|
|
103
105
|
dialect: forgeConfig.dialect,
|
|
104
106
|
dryRun: cliConfig.dryRun,
|
|
105
107
|
warnings: [],
|
|
106
|
-
}
|
|
108
|
+
};
|
|
109
|
+
const output =
|
|
110
|
+
fmt === "toon" ? formatGenResultToon(genResult)
|
|
111
|
+
: fmt === "json" ? formatGenResultJson(genResult)
|
|
112
|
+
: formatGenResult(genResult, { isTTY: !!process.stdout.isTTY });
|
|
107
113
|
|
|
108
114
|
log.info(output);
|
|
109
115
|
|
package/src/commands/migrate.ts
CHANGED
|
@@ -4,7 +4,10 @@ import { spawn } from "node:child_process";
|
|
|
4
4
|
import { parseMigrateArgs } from "../lib/args.js";
|
|
5
5
|
import { resolveMigrateConfig, MIGRATE_DEFAULT_OUT_DIR } from "../lib/config.js";
|
|
6
6
|
import type { ResolvedMigrateConfig } from "../lib/config.js";
|
|
7
|
-
import { formatMigrateResult, type BlockedEntry, type AmbiguousEntry } from "../lib/output.js";
|
|
7
|
+
import { formatMigrateResult, formatMigrateResultToon, type BlockedEntry, type AmbiguousEntry } from "../lib/output.js";
|
|
8
|
+
import { formatMigrateResultJson } from "../lib/output-json.js";
|
|
9
|
+
import type { OutputFormat } from "../lib/format.js";
|
|
10
|
+
import { toonEncode } from "../lib/format.js";
|
|
8
11
|
import { buildKyselyFromUrl } from "../lib/kysely.js";
|
|
9
12
|
import { log } from "../lib/log.js";
|
|
10
13
|
import { loadMemory } from "@metaobjectsdev/sdk";
|
|
@@ -44,6 +47,64 @@ import {
|
|
|
44
47
|
import { buildProjectionViews } from "@metaobjectsdev/codegen-ts";
|
|
45
48
|
import { tokensToAllowOptions, describeChange } from "../lib/allow.js";
|
|
46
49
|
|
|
50
|
+
const MIGRATE_HELP_TEXT = `meta migrate — diff metadata vs live DB; emit migration SQL files
|
|
51
|
+
|
|
52
|
+
USAGE:
|
|
53
|
+
meta migrate [baseline] [flags]
|
|
54
|
+
|
|
55
|
+
SUBCOMMANDS:
|
|
56
|
+
baseline Seed the committed reference snapshot (no migration emitted).
|
|
57
|
+
Required before the first offline generate.
|
|
58
|
+
|
|
59
|
+
MIGRATE FLAGS:
|
|
60
|
+
--db <url> DB connection URL (required for live-introspect / --apply / --rollback)
|
|
61
|
+
Supports: file:, libsql:, postgres:, postgresql:
|
|
62
|
+
--dialect sqlite|postgres|d1
|
|
63
|
+
Optional dialect override (auto-detected from URL scheme)
|
|
64
|
+
--out-dir <path> Migration directory (default: ./.metaobjects/migrations)
|
|
65
|
+
--slug <name> Required when changes are present (e.g., --slug add-user-shipping)
|
|
66
|
+
--allow <csv> Comma-separated destructive-change permissions:
|
|
67
|
+
drop-column,drop-table,type-change,drop-index,drop-fk,nullable-to-not-null
|
|
68
|
+
--on-ambiguous abort|rename|drop-add
|
|
69
|
+
How to handle ambiguous renames (default: abort)
|
|
70
|
+
--from-db Introspect live DB instead of using the committed snapshot
|
|
71
|
+
--apply Run pending migration files against the DB after writing
|
|
72
|
+
--rollback <target> Roll back applied migrations newer than <target>
|
|
73
|
+
--d1 <binding> D1 binding name from wrangler.toml (only with --dialect d1)
|
|
74
|
+
--remote Target remote D1 instead of local (only with --dialect d1)
|
|
75
|
+
--yes Skip the --remote --apply confirmation pause
|
|
76
|
+
--dry-run Print SQL to stdout, don't write
|
|
77
|
+
--help, -h Print this help
|
|
78
|
+
|
|
79
|
+
EXAMPLES:
|
|
80
|
+
meta migrate baseline --dialect sqlite
|
|
81
|
+
meta migrate --dialect sqlite --slug add-users
|
|
82
|
+
meta migrate --db file:local.db --slug add-orders
|
|
83
|
+
meta migrate --db postgresql://localhost/mydb --slug add-index --apply
|
|
84
|
+
`;
|
|
85
|
+
|
|
86
|
+
/** Emit a structured error on stdout (not stderr) in the active format, per axi. */
|
|
87
|
+
function emitStructuredError(error: string, hint: string, fmt: OutputFormat): void {
|
|
88
|
+
const payload = { error, hint };
|
|
89
|
+
if (fmt === "json") {
|
|
90
|
+
log.info(JSON.stringify(payload, null, 2));
|
|
91
|
+
} else if (fmt === "toon") {
|
|
92
|
+
log.info(toonEncode(payload));
|
|
93
|
+
}
|
|
94
|
+
// text format: errors go to stderr via log.error() — the caller handles that path
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Sentinel thrown by sub-functions that have already emitted a structured error
|
|
99
|
+
* via emitStructuredError(). The top-level catch in migrateCommand re-throws
|
|
100
|
+
* this as-is without double-emitting.
|
|
101
|
+
*/
|
|
102
|
+
class AlreadyEmittedError extends Error {
|
|
103
|
+
constructor(public readonly exitCode: number) {
|
|
104
|
+
super("already-emitted");
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
47
108
|
function mapOnAmbiguous(v: "abort" | "rename" | "drop-add"): AmbiguousResolution {
|
|
48
109
|
return v === "drop-add" ? "drop+add" : v;
|
|
49
110
|
}
|
|
@@ -98,48 +159,78 @@ export async function migrateCommand(
|
|
|
98
159
|
cwd: string,
|
|
99
160
|
/** Injectable wrangler runner — tests pass a mock; production uses the default. */
|
|
100
161
|
wranglerRunner?: WranglerRunner,
|
|
162
|
+
fmt: OutputFormat = "text",
|
|
101
163
|
): Promise<number> {
|
|
164
|
+
// Intercept --help / -h before parseMigrateArgs (parseArgs strict mode rejects them).
|
|
165
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
166
|
+
log.info(MIGRATE_HELP_TEXT);
|
|
167
|
+
return 0;
|
|
168
|
+
}
|
|
169
|
+
|
|
102
170
|
let flags;
|
|
103
171
|
try {
|
|
104
172
|
flags = parseMigrateArgs(args);
|
|
105
173
|
} catch (err) {
|
|
106
|
-
|
|
174
|
+
const msg = (err as Error).message;
|
|
175
|
+
log.error(`migrate: ${msg}`);
|
|
176
|
+
emitStructuredError(`migrate: ${msg}`, "run `meta migrate --help` for usage", fmt);
|
|
107
177
|
return 2;
|
|
108
178
|
}
|
|
109
179
|
|
|
110
180
|
const metaRoot = cwd;
|
|
111
181
|
const config = await resolveMigrateConfig(flags, metaRoot);
|
|
112
182
|
|
|
183
|
+
try {
|
|
113
184
|
if (config.dialect === "d1") {
|
|
114
185
|
if (config.baseline) {
|
|
115
186
|
log.error(`migrate baseline is not supported for dialect 'd1' (snapshots are a postgres/sqlite concept)`);
|
|
187
|
+
emitStructuredError(
|
|
188
|
+
`migrate baseline is not supported for dialect 'd1'`,
|
|
189
|
+
"drop 'baseline' for d1 — snapshots are a postgres/sqlite concept",
|
|
190
|
+
fmt,
|
|
191
|
+
);
|
|
116
192
|
return 2;
|
|
117
193
|
}
|
|
118
194
|
if (config.databaseUrl !== undefined) {
|
|
119
195
|
log.error(`migrate: --db / DATABASE_URL is not used for dialect 'd1' — wrangler.toml owns connection`);
|
|
196
|
+
emitStructuredError(
|
|
197
|
+
`migrate: --db / DATABASE_URL is not used for dialect 'd1'`,
|
|
198
|
+
"remove --db / DATABASE_URL for d1 — wrangler.toml owns the connection",
|
|
199
|
+
fmt,
|
|
200
|
+
);
|
|
120
201
|
return 2;
|
|
121
202
|
}
|
|
122
203
|
if (config.rollback !== undefined) {
|
|
123
204
|
log.error(`migrate: --rollback is not supported for dialect 'd1' (use 'wrangler d1 migrations' tooling)`);
|
|
205
|
+
emitStructuredError(
|
|
206
|
+
`migrate: --rollback is not supported for dialect 'd1'`,
|
|
207
|
+
"use 'wrangler d1 migrations' tooling to roll back d1",
|
|
208
|
+
fmt,
|
|
209
|
+
);
|
|
124
210
|
return 2;
|
|
125
211
|
}
|
|
126
|
-
return await runD1Migrate(config, metaRoot, wranglerRunner ?? defaultWranglerRunner);
|
|
212
|
+
return await runD1Migrate(config, metaRoot, wranglerRunner ?? defaultWranglerRunner, fmt);
|
|
127
213
|
}
|
|
128
214
|
|
|
129
215
|
// `migrate baseline` — seed the committed reference snapshot, emit no migration.
|
|
130
216
|
if (config.baseline) {
|
|
131
|
-
return await runBaseline(config, metaRoot);
|
|
217
|
+
return await runBaseline(config, metaRoot, fmt);
|
|
132
218
|
}
|
|
133
219
|
|
|
134
220
|
// Default = offline snapshot generation. The live-introspection path runs only
|
|
135
221
|
// when explicitly requested via --from-db, when --apply needs a connection, or
|
|
136
222
|
// for --rollback (which runs hand-authored down.sql against the live DB).
|
|
137
223
|
if (!config.fromDb && !config.apply && config.rollback === undefined) {
|
|
138
|
-
return await runOfflineGenerate(config, metaRoot);
|
|
224
|
+
return await runOfflineGenerate(config, metaRoot, fmt);
|
|
139
225
|
}
|
|
140
226
|
|
|
141
227
|
if (config.databaseUrl === undefined) {
|
|
142
228
|
log.error(`migrate: --db <url> required (or set DATABASE_URL, or add migrate.databaseUrl to .metaobjects/config.json)`);
|
|
229
|
+
emitStructuredError(
|
|
230
|
+
`migrate: --db <url> required`,
|
|
231
|
+
"pass --db <url>, set DATABASE_URL, or add migrate.databaseUrl to .metaobjects/config.json",
|
|
232
|
+
fmt,
|
|
233
|
+
);
|
|
143
234
|
return 2;
|
|
144
235
|
}
|
|
145
236
|
|
|
@@ -187,6 +278,7 @@ export async function migrateCommand(
|
|
|
187
278
|
let exitCode = 0;
|
|
188
279
|
let writtenPaths: string[] = [];
|
|
189
280
|
let appliedNames: string[] = [];
|
|
281
|
+
let applyFailed = false;
|
|
190
282
|
let blocked: BlockedEntry[] = [];
|
|
191
283
|
let ambiguous: AmbiguousEntry[] = [];
|
|
192
284
|
let changeCounts: Record<string, number> = {};
|
|
@@ -240,7 +332,7 @@ export async function migrateCommand(
|
|
|
240
332
|
// with the collected ambiguity list.
|
|
241
333
|
if ((err as Error).message.includes("aborted by onAmbiguous")) {
|
|
242
334
|
ambiguous = ambiguousToEntries(collectedAmbiguous);
|
|
243
|
-
const
|
|
335
|
+
const migrateResult = {
|
|
244
336
|
dialect: kysely.dialect,
|
|
245
337
|
displayUrl: kysely.displayUrl,
|
|
246
338
|
changeCounts: {},
|
|
@@ -248,7 +340,13 @@ export async function migrateCommand(
|
|
|
248
340
|
ambiguous,
|
|
249
341
|
writtenPaths: [],
|
|
250
342
|
dryRun: config.dryRun,
|
|
251
|
-
|
|
343
|
+
applied: [],
|
|
344
|
+
applyFailed: false,
|
|
345
|
+
};
|
|
346
|
+
const output =
|
|
347
|
+
fmt === "toon" ? formatMigrateResultToon(migrateResult)
|
|
348
|
+
: fmt === "json" ? formatMigrateResultJson(migrateResult)
|
|
349
|
+
: formatMigrateResult(migrateResult, { isTTY: !!process.stdout.isTTY });
|
|
252
350
|
log.info(output);
|
|
253
351
|
await kysely.close();
|
|
254
352
|
return 1;
|
|
@@ -326,6 +424,7 @@ export async function migrateCommand(
|
|
|
326
424
|
} catch (err) {
|
|
327
425
|
log.error(`migrate: apply failed: ${(err as Error).message}`);
|
|
328
426
|
exitCode = 1;
|
|
427
|
+
applyFailed = true;
|
|
329
428
|
}
|
|
330
429
|
}
|
|
331
430
|
} finally {
|
|
@@ -336,7 +435,7 @@ export async function migrateCommand(
|
|
|
336
435
|
}
|
|
337
436
|
}
|
|
338
437
|
|
|
339
|
-
const
|
|
438
|
+
const migrateResult = {
|
|
340
439
|
dialect: kysely.dialect,
|
|
341
440
|
displayUrl: kysely.displayUrl,
|
|
342
441
|
changeCounts,
|
|
@@ -344,7 +443,13 @@ export async function migrateCommand(
|
|
|
344
443
|
ambiguous,
|
|
345
444
|
writtenPaths,
|
|
346
445
|
dryRun: config.dryRun,
|
|
347
|
-
|
|
446
|
+
applied: appliedNames,
|
|
447
|
+
applyFailed,
|
|
448
|
+
};
|
|
449
|
+
const output =
|
|
450
|
+
fmt === "toon" ? formatMigrateResultToon(migrateResult)
|
|
451
|
+
: fmt === "json" ? formatMigrateResultJson(migrateResult)
|
|
452
|
+
: formatMigrateResult(migrateResult, { isTTY: !!process.stdout.isTTY });
|
|
348
453
|
|
|
349
454
|
log.info(output);
|
|
350
455
|
if (config.apply && exitCode === 0) {
|
|
@@ -355,6 +460,16 @@ export async function migrateCommand(
|
|
|
355
460
|
}
|
|
356
461
|
}
|
|
357
462
|
return exitCode;
|
|
463
|
+
} catch (err) {
|
|
464
|
+
// AlreadyEmittedError: sub-function already called emitStructuredError — just
|
|
465
|
+
// propagate the exit code without double-emitting.
|
|
466
|
+
if (err instanceof AlreadyEmittedError) return err.exitCode;
|
|
467
|
+
// Unexpected error: emit structured error on stdout in the active format, then exit 1.
|
|
468
|
+
const msg = (err as Error).message ?? String(err);
|
|
469
|
+
log.error(`migrate: unexpected error: ${msg}`);
|
|
470
|
+
emitStructuredError(`migrate: unexpected error: ${msg}`, "run `meta migrate --help` for usage", fmt);
|
|
471
|
+
return 1;
|
|
472
|
+
}
|
|
358
473
|
}
|
|
359
474
|
|
|
360
475
|
/**
|
|
@@ -365,6 +480,7 @@ export async function migrateCommand(
|
|
|
365
480
|
export async function runBaseline(
|
|
366
481
|
config: ResolvedMigrateConfig,
|
|
367
482
|
metaRoot: string,
|
|
483
|
+
_fmt: OutputFormat = "text",
|
|
368
484
|
): Promise<number> {
|
|
369
485
|
if (config.dialect === undefined) {
|
|
370
486
|
log.error(`migrate baseline: --dialect required (or set migrate.dialect in .metaobjects/config.json)`);
|
|
@@ -431,6 +547,7 @@ export async function runBaseline(
|
|
|
431
547
|
export async function runOfflineGenerate(
|
|
432
548
|
config: ResolvedMigrateConfig,
|
|
433
549
|
metaRoot: string,
|
|
550
|
+
fmt: OutputFormat = "text",
|
|
434
551
|
): Promise<number> {
|
|
435
552
|
if (config.dialect === undefined) {
|
|
436
553
|
log.error(`migrate: --dialect required for offline generation (or use --from-db)`);
|
|
@@ -454,7 +571,13 @@ export async function runOfflineGenerate(
|
|
|
454
571
|
return 2;
|
|
455
572
|
}
|
|
456
573
|
if (snapshot === null) {
|
|
457
|
-
log.error(`migrate: no schema snapshot at ${path}; run
|
|
574
|
+
log.error(`migrate: no schema snapshot at ${path}; run \`meta migrate baseline --dialect ${config.dialect}\` first`);
|
|
575
|
+
// Structured next-step on stdout so callers / agents can parse it, in the active format.
|
|
576
|
+
emitStructuredError(
|
|
577
|
+
"no schema snapshot",
|
|
578
|
+
`first run \`meta migrate baseline --dialect ${config.dialect}\``,
|
|
579
|
+
fmt,
|
|
580
|
+
);
|
|
458
581
|
return 2;
|
|
459
582
|
}
|
|
460
583
|
|
|
@@ -587,6 +710,7 @@ async function runD1Migrate(
|
|
|
587
710
|
config: ResolvedMigrateConfig,
|
|
588
711
|
metaRoot: string,
|
|
589
712
|
runner: WranglerRunner,
|
|
713
|
+
_fmt: OutputFormat = "text",
|
|
590
714
|
): Promise<number> {
|
|
591
715
|
// 1. Resolve wrangler.toml + binding.
|
|
592
716
|
const wranglerConfigPath = config.d1.wranglerConfigPath
|