@intelligo-dev/cli 1.0.0-beta.13 → 1.0.0-beta.15
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 +65 -2
- package/dist/args.d.ts +10 -0
- package/dist/args.d.ts.map +1 -0
- package/dist/args.js +20 -0
- package/dist/args.js.map +1 -0
- package/dist/bin.js +103 -22
- package/dist/bin.js.map +1 -1
- package/dist/commands/add.d.ts +4 -0
- package/dist/commands/add.d.ts.map +1 -1
- package/dist/commands/add.js +28 -2
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/create-flow.d.ts +8 -1
- package/dist/commands/create-flow.d.ts.map +1 -1
- package/dist/commands/create-flow.js +101 -34
- package/dist/commands/create-flow.js.map +1 -1
- package/dist/commands/create.d.ts +24 -4
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +57 -14
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +123 -35
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/migrate-check.d.ts +20 -1
- package/dist/commands/migrate-check.d.ts.map +1 -1
- package/dist/commands/migrate-check.js +35 -6
- package/dist/commands/migrate-check.js.map +1 -1
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +2 -8
- package/dist/commands/migrate.js.map +1 -1
- package/dist/commands/sync-messages.d.ts +37 -0
- package/dist/commands/sync-messages.d.ts.map +1 -0
- package/dist/commands/sync-messages.js +88 -0
- package/dist/commands/sync-messages.js.map +1 -0
- package/dist/commands/sync-scaffold.d.ts +36 -0
- package/dist/commands/sync-scaffold.d.ts.map +1 -0
- package/dist/commands/sync-scaffold.js +53 -0
- package/dist/commands/sync-scaffold.js.map +1 -0
- package/dist/commands/sync.d.ts +109 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +392 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/commands/upgrade-check.d.ts.map +1 -1
- package/dist/commands/upgrade-check.js +4 -1
- package/dist/commands/upgrade-check.js.map +1 -1
- package/dist/env-files.d.ts +11 -0
- package/dist/env-files.d.ts.map +1 -1
- package/dist/env-files.js +28 -9
- package/dist/env-files.js.map +1 -1
- package/dist/manifest.d.ts +27 -0
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.js +30 -3
- package/dist/manifest.js.map +1 -1
- package/dist/module-exports.d.ts +63 -0
- package/dist/module-exports.d.ts.map +1 -0
- package/dist/module-exports.js +231 -0
- package/dist/module-exports.js.map +1 -0
- package/dist/registry-bundle.d.ts +43 -0
- package/dist/registry-bundle.d.ts.map +1 -0
- package/dist/registry-bundle.js +74 -0
- package/dist/registry-bundle.js.map +1 -0
- package/dist/registry-items.d.ts +41 -13
- package/dist/registry-items.d.ts.map +1 -1
- package/dist/registry-items.js +117 -33
- package/dist/registry-items.js.map +1 -1
- package/package.json +1 -1
- package/src/args.ts +25 -0
- package/src/bin.ts +124 -22
- package/src/commands/add.ts +39 -12
- package/src/commands/create-flow.ts +119 -29
- package/src/commands/create.ts +82 -14
- package/src/commands/doctor.ts +156 -47
- package/src/commands/migrate-check.ts +51 -10
- package/src/commands/migrate.ts +2 -8
- package/src/commands/sync-messages.ts +114 -0
- package/src/commands/sync-scaffold.ts +83 -0
- package/src/commands/sync.ts +574 -0
- package/src/commands/upgrade-check.ts +4 -1
- package/src/env-files.ts +28 -7
- package/src/manifest.ts +57 -3
- package/src/module-exports.ts +266 -0
- package/src/registry-bundle.ts +103 -0
- package/src/registry-items.ts +141 -36
- package/templates/admin-page/admin-page.tsx.tpl +96 -24
- package/templates/app-scaffold/gitignore.tpl +25 -0
- package/templates/app-scaffold/intelligo.ts.tpl +6 -47
- package/templates/app-scaffold/next.config.mjs.tpl +31 -2
- package/templates/app-scaffold/package.json.tpl +2 -2
- package/templates/manifest.json +40 -3
- package/templates/pnpm-standalone/npmrc.tpl +6 -0
- package/templates/pnpm-standalone/pnpm-workspace.yaml.tpl +10 -0
- package/templates/registry/ai-agent-activity.json +23 -0
- package/templates/registry/ai-agent-progress.json +21 -0
- package/templates/registry/ai-approval-card.json +27 -0
- package/templates/registry/ai-artifact.json +22 -0
- package/templates/registry/ai-branch.json +21 -0
- package/templates/registry/ai-citations.json +24 -0
- package/templates/registry/ai-code-block.json +23 -0
- package/templates/registry/ai-composer-menu.json +19 -0
- package/templates/registry/ai-file-diff.json +25 -0
- package/templates/registry/ai-image-generation.json +23 -0
- package/templates/registry/ai-markdown.json +23 -0
- package/templates/registry/ai-message-bubble.json +23 -0
- package/templates/registry/ai-message-scroller.json +22 -0
- package/templates/registry/ai-message.json +21 -0
- package/templates/registry/ai-motion.json +19 -0
- package/templates/registry/ai-prompt-input.json +28 -0
- package/templates/registry/ai-reasoning-text.json +22 -0
- package/templates/registry/ai-reasoning.json +22 -0
- package/templates/registry/ai-shimmer-text.json +19 -0
- package/templates/registry/ai-sidebar.json +25 -0
- package/templates/registry/ai-speech-input.json +21 -0
- package/templates/registry/ai-streaming-response.json +24 -0
- package/templates/registry/ai-suggestion.json +19 -0
- package/templates/registry/ai-todo-list.json +22 -0
- package/templates/registry/ai-tool-approval.json +26 -0
- package/templates/registry/ai-tool-result.json +25 -0
- package/templates/registry/alert-dialog.json +23 -0
- package/templates/registry/animated-list.json +21 -0
- package/templates/registry/app-shell.json +93 -0
- package/templates/registry/artifacts.json +82 -0
- package/templates/registry/attachment.json +22 -0
- package/templates/registry/auth-email-verification.json +39 -0
- package/templates/registry/auth-login.json +72 -0
- package/templates/registry/auth-password-reset.json +53 -0
- package/templates/registry/auth-signup.json +41 -0
- package/templates/registry/billing-settings.json +66 -0
- package/templates/registry/button.json +22 -0
- package/templates/registry/chat-eve.json +19 -0
- package/templates/registry/chat-panel.json +30 -0
- package/templates/registry/chat-share.json +42 -0
- package/templates/registry/chat-widget.json +34 -0
- package/templates/registry/chat.json +326 -0
- package/templates/registry/checkbox.json +22 -0
- package/templates/registry/checkout.json +40 -0
- package/templates/registry/collapsible.json +19 -0
- package/templates/registry/command.json +23 -0
- package/templates/registry/copy-button.json +21 -0
- package/templates/registry/dashboard.json +69 -0
- package/templates/registry/dialog.json +24 -0
- package/templates/registry/document-viewer.json +22 -0
- package/templates/registry/dropdown-menu.json +23 -0
- package/templates/registry/expandable-tabs.json +22 -0
- package/templates/registry/feature-gating.json +73 -0
- package/templates/registry/file-upload.json +24 -0
- package/templates/registry/hold-action-button.json +22 -0
- package/templates/registry/input-group.json +23 -0
- package/templates/registry/input.json +19 -0
- package/templates/registry/intelligo.json +187 -0
- package/templates/registry/invitation-accept.json +64 -0
- package/templates/registry/language-switcher.json +29 -0
- package/templates/registry/morphing-modal.json +24 -0
- package/templates/registry/notification-stack.json +24 -0
- package/templates/registry/notifications.json +87 -0
- package/templates/registry/onboarding.json +83 -0
- package/templates/registry/otp-input.json +22 -0
- package/templates/registry/page-header.json +15 -0
- package/templates/registry/payment-poll.json +58 -0
- package/templates/registry/popover-morph.json +22 -0
- package/templates/registry/popover.json +22 -0
- package/templates/registry/pricing.json +117 -0
- package/templates/registry/privacy-settings.json +65 -0
- package/templates/registry/profile-settings.json +68 -0
- package/templates/registry/progress.json +19 -0
- package/templates/registry/radio-group.json +22 -0
- package/templates/registry/registry.json +2960 -0
- package/templates/registry/route-error.json +65 -0
- package/templates/registry/select-morph.json +23 -0
- package/templates/registry/select.json +23 -0
- package/templates/registry/settings-shell.json +47 -0
- package/templates/registry/sheet.json +24 -0
- package/templates/registry/sidebar.json +28 -0
- package/templates/registry/smoke.json +34 -0
- package/templates/registry/spinner.json +16 -0
- package/templates/registry/stat-card.json +18 -0
- package/templates/registry/status-badge.json +18 -0
- package/templates/registry/switch.json +20 -0
- package/templates/registry/tabs.json +23 -0
- package/templates/registry/team-settings.json +97 -0
- package/templates/registry/textarea.json +16 -0
- package/templates/registry/tooltip.json +22 -0
- package/templates/registry/trial-banner.json +43 -0
- package/templates/registry/usage.json +84 -0
- package/templates/registry/workspace-settings.json +71 -0
- package/templates/registry-items.json +3 -3
- package/templates/registry-requires.json +30 -4
- package/templates/vitest/server-only.ts.tpl +7 -0
- package/templates/vitest/vitest.config.ts.tpl +37 -0
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
* `migrate` can take it over.
|
|
38
38
|
*
|
|
39
39
|
* Beside `state` it carries `exitCode`, `chain`, `applied`, `pending`,
|
|
40
|
-
* `unknown`, `legacy` and `adoptable`.
|
|
40
|
+
* `unknown`, `legacy`, `legacyMissing` and `adoptable`.
|
|
41
41
|
*/
|
|
42
42
|
|
|
43
43
|
import { createHash } from "node:crypto";
|
|
@@ -64,6 +64,11 @@ export type MigrateCheckResult = {
|
|
|
64
64
|
legacy: string[];
|
|
65
65
|
/** Length of the pre-1.0 chain (0 when this checkout ships none). */
|
|
66
66
|
legacyChainLength: number;
|
|
67
|
+
/**
|
|
68
|
+
* Pre-1.0 migrations the database has not run, by tag, in chain
|
|
69
|
+
* order — empty unless it ran some of them.
|
|
70
|
+
*/
|
|
71
|
+
legacyMissing: string[];
|
|
67
72
|
/**
|
|
68
73
|
* The database ran the whole pre-1.0 chain and not the baseline:
|
|
69
74
|
* `migrate` records the baseline as applied without running it.
|
|
@@ -74,11 +79,11 @@ export type MigrateCheckResult = {
|
|
|
74
79
|
/** The pre-1.0 chain's tags and hashes, if this checkout ships them. */
|
|
75
80
|
export function readLegacyChain(
|
|
76
81
|
migrationsDir: string
|
|
77
|
-
): Array<{ tag: string; hash: string }> {
|
|
82
|
+
): Array<{ tag: string; hash: string; alternates?: string[] }> {
|
|
78
83
|
const file = path.join(migrationsDir, "legacy-chain.json");
|
|
79
84
|
if (!existsSync(file)) return [];
|
|
80
85
|
const parsed = JSON.parse(readFileSync(file, "utf8")) as {
|
|
81
|
-
entries?: Array<{ tag: string; hash: string }>;
|
|
86
|
+
entries?: Array<{ tag: string; hash: string; alternates?: string[] }>;
|
|
82
87
|
};
|
|
83
88
|
return parsed.entries ?? [];
|
|
84
89
|
}
|
|
@@ -118,7 +123,13 @@ export async function migrateCheck(
|
|
|
118
123
|
}
|
|
119
124
|
|
|
120
125
|
const legacyChain = readLegacyChain(migrationsDir);
|
|
121
|
-
|
|
126
|
+
// A migration can be recorded under more than one hash: npm's
|
|
127
|
+
// 1.0.0-beta.6 shipped different bytes for three of them.
|
|
128
|
+
const legacyByHash = new Map(
|
|
129
|
+
legacyChain.flatMap((e) =>
|
|
130
|
+
[e.hash, ...(e.alternates ?? [])].map((h) => [h, e.tag] as const)
|
|
131
|
+
)
|
|
132
|
+
);
|
|
122
133
|
|
|
123
134
|
const appliedHashes = new Set(rows.map((r) => r.hash));
|
|
124
135
|
const applied: string[] = [];
|
|
@@ -144,6 +155,10 @@ export async function migrateCheck(
|
|
|
144
155
|
unmanaged: tableMissing || appliedHashes.size === 0,
|
|
145
156
|
legacy,
|
|
146
157
|
legacyChainLength: legacyChain.length,
|
|
158
|
+
legacyMissing:
|
|
159
|
+
legacy.length > 0
|
|
160
|
+
? legacyChain.map((e) => e.tag).filter((t) => !legacy.includes(t))
|
|
161
|
+
: [],
|
|
147
162
|
adoptable:
|
|
148
163
|
legacyChain.length > 0 &&
|
|
149
164
|
legacy.length === legacyChain.length &&
|
|
@@ -185,12 +200,8 @@ export function formatMigrateCheck(
|
|
|
185
200
|
`already there), then applies what follows. Tables the old chain ` +
|
|
186
201
|
`created that the framework no longer owns are left untouched.`
|
|
187
202
|
);
|
|
188
|
-
} else if (r
|
|
189
|
-
lines.push(
|
|
190
|
-
`✗ This database ran ${r.legacy.length} of the ${r.legacyChainLength} ` +
|
|
191
|
-
`pre-1.0 migrations. Finish that chain with @intelligo-dev/core ` +
|
|
192
|
-
`1.0.0-beta.7 (\`intelligo migrate\`) before upgrading.`
|
|
193
|
-
);
|
|
203
|
+
} else if (isPartialLegacy(r)) {
|
|
204
|
+
lines.push(`✗ ${partialLegacyMessage(r)}`);
|
|
194
205
|
}
|
|
195
206
|
|
|
196
207
|
if (r.unknown.length > 0) {
|
|
@@ -221,6 +232,35 @@ export function isPartialLegacy(r: MigrateCheckResult): boolean {
|
|
|
221
232
|
return r.legacy.length > 0 && r.legacy.length < r.legacyChainLength;
|
|
222
233
|
}
|
|
223
234
|
|
|
235
|
+
/**
|
|
236
|
+
* The last pre-1.0 migration any published `@intelligo-dev/core`
|
|
237
|
+
* carries: 1.0.0-beta.6 shipped the chain through it, and the versions
|
|
238
|
+
* that carried the rest were never published.
|
|
239
|
+
*/
|
|
240
|
+
export const LAST_PUBLISHED_LEGACY_TAG = "0042_sessions_active_organization_id";
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Why a partial pre-1.0 chain is refused and where the way forward is
|
|
244
|
+
* written down. No published version finishes the chain, so the
|
|
245
|
+
* message names what is missing and points at the README's options
|
|
246
|
+
* instead of at a version to install.
|
|
247
|
+
*/
|
|
248
|
+
export function partialLegacyMessage(r: MigrateCheckResult): string {
|
|
249
|
+
const shown = r.legacyMissing.slice(0, 6);
|
|
250
|
+
const more = r.legacyMissing.length - shown.length;
|
|
251
|
+
return (
|
|
252
|
+
`This database ran ${r.legacy.length} of the ${r.legacyChainLength} ` +
|
|
253
|
+
`pre-1.0 migrations; it has not run ${shown.join(", ")}` +
|
|
254
|
+
`${more > 0 ? ` and ${more} more` : ""}. No published ` +
|
|
255
|
+
`@intelligo-dev/core finishes that chain: 1.0.0-beta.6 ships it ` +
|
|
256
|
+
`through ${LAST_PUBLISHED_LEGACY_TAG}, and the versions that carried ` +
|
|
257
|
+
`the rest never reached npm. Apply the missing migrations' SQL from ` +
|
|
258
|
+
`your own copy of it, or bring the schema to the baseline and record ` +
|
|
259
|
+
`it as applied — see "Databases from before 1.0" in README.md in ` +
|
|
260
|
+
`@intelligo-dev/core's src/db/migrations.`
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
|
|
224
264
|
export type MigrateState =
|
|
225
265
|
"up_to_date" | "pending" | "fresh" | "ahead" | "unmanaged" | "legacy";
|
|
226
266
|
|
|
@@ -252,6 +292,7 @@ export function formatMigrateCheckJson(
|
|
|
252
292
|
pending: r.pending,
|
|
253
293
|
unknown: r.unknown,
|
|
254
294
|
legacy: r.legacy,
|
|
295
|
+
legacyMissing: r.legacyMissing,
|
|
255
296
|
adoptable: r.adoptable,
|
|
256
297
|
});
|
|
257
298
|
}
|
package/src/commands/migrate.ts
CHANGED
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
hashMigration,
|
|
35
35
|
isPartialLegacy,
|
|
36
36
|
migrateCheck,
|
|
37
|
+
partialLegacyMessage,
|
|
37
38
|
type MigrateCheckResult,
|
|
38
39
|
} from "./migrate-check.js";
|
|
39
40
|
|
|
@@ -68,14 +69,7 @@ export function decideApply(
|
|
|
68
69
|
}
|
|
69
70
|
|
|
70
71
|
if (isPartialLegacy(check)) {
|
|
71
|
-
return {
|
|
72
|
-
action: "refuse",
|
|
73
|
-
reason:
|
|
74
|
-
`This database ran ${check.legacy.length} of the ` +
|
|
75
|
-
`${check.legacyChainLength} pre-1.0 migrations. Finish that chain ` +
|
|
76
|
-
`with @intelligo-dev/core 1.0.0-beta.7 (\`intelligo migrate\`) ` +
|
|
77
|
-
`before upgrading.`,
|
|
78
|
-
};
|
|
72
|
+
return { action: "refuse", reason: partialLegacyMessage(check) };
|
|
79
73
|
}
|
|
80
74
|
|
|
81
75
|
if (check.adoptable) {
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message files under `intelligo sync`: the registry's keys an app's
|
|
3
|
+
* copy lacks, the merge that keeps the app's values, and the other
|
|
4
|
+
* locales checked against the app's English copy.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
|
|
10
|
+
export type Json = Record<string, unknown>;
|
|
11
|
+
|
|
12
|
+
const isObject = (v: unknown): v is Json =>
|
|
13
|
+
typeof v === "object" && v !== null && !Array.isArray(v);
|
|
14
|
+
|
|
15
|
+
/** Dotted paths of every leaf in `registry` that `app` lacks. */
|
|
16
|
+
export function missingMessageKeys(
|
|
17
|
+
registry: Json,
|
|
18
|
+
app: Json,
|
|
19
|
+
prefix = ""
|
|
20
|
+
): string[] {
|
|
21
|
+
return Object.entries(registry).flatMap(([key, value]) => {
|
|
22
|
+
const at = prefix ? `${prefix}.${key}` : key;
|
|
23
|
+
if (!(key in app)) return [at];
|
|
24
|
+
const mine = app[key];
|
|
25
|
+
return isObject(value) && isObject(mine)
|
|
26
|
+
? missingMessageKeys(value, mine, at)
|
|
27
|
+
: [];
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The registry's messages with the app's copy laid over them: every key
|
|
33
|
+
* the registry has is present, every value the app set wins, and keys
|
|
34
|
+
* only the app has (its own nav entries, product copy) are kept.
|
|
35
|
+
*/
|
|
36
|
+
export function mergeMessages(registry: Json, app: Json): Json {
|
|
37
|
+
const out: Json = {};
|
|
38
|
+
for (const [key, value] of Object.entries(registry)) {
|
|
39
|
+
const mine = app[key];
|
|
40
|
+
out[key] =
|
|
41
|
+
key in app
|
|
42
|
+
? isObject(value) && isObject(mine)
|
|
43
|
+
? mergeMessages(value, mine)
|
|
44
|
+
: mine
|
|
45
|
+
: value;
|
|
46
|
+
}
|
|
47
|
+
for (const [key, value] of Object.entries(app)) {
|
|
48
|
+
if (!(key in out)) out[key] = value;
|
|
49
|
+
}
|
|
50
|
+
return out;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const isMessages = (target: string) =>
|
|
54
|
+
target.startsWith("messages/") && target.endsWith(".json");
|
|
55
|
+
|
|
56
|
+
/** The locale the registry ships messages in. */
|
|
57
|
+
const SOURCE_LOCALE = "en";
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The app's locales, from `locales: [...]` in i18n/routing.ts — the
|
|
61
|
+
* source locale alone when there is no such file or list.
|
|
62
|
+
*/
|
|
63
|
+
export function appLocales(appRoot: string): string[] {
|
|
64
|
+
const file = path.join(appRoot, "i18n", "routing.ts");
|
|
65
|
+
if (!existsSync(file)) return [SOURCE_LOCALE];
|
|
66
|
+
const list = /\blocales\s*:\s*\[([^\]]*)\]/.exec(readFileSync(file, "utf8"));
|
|
67
|
+
const locales = [...(list?.[1] ?? "").matchAll(/["'`]([^"'`]+)["'`]/g)].map(
|
|
68
|
+
(m) => m[1]!
|
|
69
|
+
);
|
|
70
|
+
return locales.length > 0 ? locales : [SOURCE_LOCALE];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export type LocaleEntry = {
|
|
74
|
+
item: string;
|
|
75
|
+
path: string;
|
|
76
|
+
state: "current" | "locale-behind";
|
|
77
|
+
missingKeys?: string[];
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Every other locale's copy of the namespaces the registry ships,
|
|
82
|
+
* against the app's English file on disk — the merged copy, product
|
|
83
|
+
* keys included, which is what the other locales translate. A missing
|
|
84
|
+
* file lacks every key.
|
|
85
|
+
*/
|
|
86
|
+
export function localeEntries(
|
|
87
|
+
appRoot: string,
|
|
88
|
+
files: readonly { item: string; target: string }[]
|
|
89
|
+
): LocaleEntry[] {
|
|
90
|
+
const others = appLocales(appRoot).filter((l) => l !== SOURCE_LOCALE);
|
|
91
|
+
if (others.length === 0) return [];
|
|
92
|
+
const prefix = `messages/${SOURCE_LOCALE}/`;
|
|
93
|
+
const entries: LocaleEntry[] = [];
|
|
94
|
+
for (const { item, target } of files) {
|
|
95
|
+
if (!target.startsWith(prefix) || !target.endsWith(".json")) continue;
|
|
96
|
+
const english = path.join(appRoot, target);
|
|
97
|
+
if (!existsSync(english)) continue;
|
|
98
|
+
const source = JSON.parse(readFileSync(english, "utf8")) as Json;
|
|
99
|
+
for (const locale of others) {
|
|
100
|
+
const rel = `messages/${locale}/${target.slice(prefix.length)}`;
|
|
101
|
+
const abs = path.join(appRoot, rel);
|
|
102
|
+
const missingKeys = missingMessageKeys(
|
|
103
|
+
source,
|
|
104
|
+
existsSync(abs) ? (JSON.parse(readFileSync(abs, "utf8")) as Json) : {}
|
|
105
|
+
);
|
|
106
|
+
entries.push(
|
|
107
|
+
missingKeys.length > 0
|
|
108
|
+
? { item, path: rel, state: "locale-behind", missingKeys }
|
|
109
|
+
: { item, path: rel, state: "current" }
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return entries;
|
|
114
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scaffold files a registry install replaces. `intelligo create`
|
|
3
|
+
* writes app/globals.css, the theme provider and lib/utils.ts; the
|
|
4
|
+
* design-system base and the items overwrite them, and the scaffold's
|
|
5
|
+
* record has to let go of them or `upgrade --check` reports them as
|
|
6
|
+
* the app's own edits forever.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
10
|
+
import path from "node:path";
|
|
11
|
+
|
|
12
|
+
import { readManifest } from "../manifest.js";
|
|
13
|
+
|
|
14
|
+
/** The `intelligo create` feature whose files an install may replace. */
|
|
15
|
+
export const SCAFFOLD_FEATURE = "app-scaffold";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Scaffold files the install extends in place rather than replaces:
|
|
19
|
+
* shadcn adds dependencies to package.json and style fields to
|
|
20
|
+
* components.json, and both stay the app's.
|
|
21
|
+
*/
|
|
22
|
+
const EDITED_IN_PLACE: ReadonlySet<string> = new Set([
|
|
23
|
+
"package.json",
|
|
24
|
+
"components.json",
|
|
25
|
+
]);
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The scaffold files an install has made the registry's: a file an
|
|
29
|
+
* installed item ships, the Tailwind stylesheet once the design-system
|
|
30
|
+
* base is in (it rewrites the tokens), or any scaffold file the install
|
|
31
|
+
* changed (shadcn's own `utils`, `sonner`). Seams stay the app's, and
|
|
32
|
+
* so do the files shadcn only extends. Left in the scaffold's record,
|
|
33
|
+
* each would read `customized` in `upgrade --check` forever.
|
|
34
|
+
*/
|
|
35
|
+
export function scaffoldHandover(input: {
|
|
36
|
+
scaffold: readonly string[];
|
|
37
|
+
changed: ReadonlySet<string>;
|
|
38
|
+
shipped: ReadonlySet<string>;
|
|
39
|
+
seams: Readonly<Record<string, string>>;
|
|
40
|
+
css: string | null;
|
|
41
|
+
}): string[] {
|
|
42
|
+
return input.scaffold.filter(
|
|
43
|
+
(file) =>
|
|
44
|
+
!(file in input.seams) &&
|
|
45
|
+
!EDITED_IN_PLACE.has(file) &&
|
|
46
|
+
(input.shipped.has(file) || file === input.css || input.changed.has(file))
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function readIfExists(file: string): string | null {
|
|
51
|
+
return existsSync(file) ? readFileSync(file, "utf8") : null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The scaffold's recorded files as they are before an install, and
|
|
56
|
+
* afterwards the ones the install made the registry's.
|
|
57
|
+
*/
|
|
58
|
+
export function snapshotScaffold(appRoot: string): {
|
|
59
|
+
handedOver: (input: {
|
|
60
|
+
shipped: ReadonlySet<string>;
|
|
61
|
+
seams: Readonly<Record<string, string>>;
|
|
62
|
+
css: string | null;
|
|
63
|
+
}) => string[];
|
|
64
|
+
} {
|
|
65
|
+
const scaffold = (
|
|
66
|
+
readManifest(appRoot)?.features[SCAFFOLD_FEATURE]?.files ?? []
|
|
67
|
+
).map((f) => f.path);
|
|
68
|
+
const before = new Map(
|
|
69
|
+
scaffold.map((f) => [f, readIfExists(path.join(appRoot, f))])
|
|
70
|
+
);
|
|
71
|
+
return {
|
|
72
|
+
handedOver: (input) =>
|
|
73
|
+
scaffoldHandover({
|
|
74
|
+
...input,
|
|
75
|
+
scaffold,
|
|
76
|
+
changed: new Set(
|
|
77
|
+
scaffold.filter(
|
|
78
|
+
(f) => readIfExists(path.join(appRoot, f)) !== before.get(f)
|
|
79
|
+
)
|
|
80
|
+
),
|
|
81
|
+
}),
|
|
82
|
+
};
|
|
83
|
+
}
|