cronus-ui 0.7.0 → 0.7.2

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 CHANGED
@@ -49,7 +49,7 @@ Notes that match the commander surface:
49
49
  `packages/cli/scripts/build-registry.ts` — each item carries its source, its npm
50
50
  `dependencies`, and its `registryDependencies` (other components it imports),
51
51
  derived by parsing imports.
52
- - The default registry is pinned to the CLI package version (`v0.7.0` here), not
52
+ - The default registry is pinned to the CLI package version (`v0.7.2` here), not
53
53
  mutable `main`, so a published CLI reads the registry snapshot it was released
54
54
  with. Use `-r, --registry ./registry` when testing local registry changes before
55
55
  a release tag exists.
@@ -80,7 +80,7 @@ Notes that match the commander surface:
80
80
  "lib": "lib",
81
81
  "blocks": "components/blocks"
82
82
  },
83
- "registry": "https://raw.githubusercontent.com/pedrogbraz/cronus-ui/v0.7.0/registry"
83
+ "registry": "https://raw.githubusercontent.com/pedrogbraz/cronus-ui/v0.7.2/registry"
84
84
  }
85
85
  ```
86
86
 
@@ -19,8 +19,8 @@
19
19
  * inherited wholesale from the shared renderer.
20
20
  */
21
21
  import { existsSync } from "node:fs";
22
- import { rm } from "node:fs/promises";
23
- import { goldPatchAppShellChrome, goldPatchHomePage, goldPatchShellLayout, goldPatchTeamPage, isGoldPathTemplate, } from "../compose/gold-path.js";
22
+ import { readFile, rm } from "node:fs/promises";
23
+ import { GOLD_PATH_AUTH_SPLIT_FILES, goldPatchAppShellChrome, goldPatchHomePage, goldPatchShellLayout, goldPatchTeamPage, isGoldPathTemplate, patchGoldPathAuthSplit, } from "../compose/gold-path.js";
24
24
  import { blockRefParts } from "../compose/manifest.js";
25
25
  import { buildComposePlan, ComposePlanError, } from "../compose/plan.js";
26
26
  import { baseSnapshotDir, reloadManifest } from "../compose/reload.js";
@@ -306,6 +306,21 @@ export async function addPage(options) {
306
306
  generatedFiles.push(rel);
307
307
  }
308
308
  }
309
+ if (isGoldPathTemplate(appName)) {
310
+ for (const file of GOLD_PATH_AUTH_SPLIT_FILES) {
311
+ const rel = `${config.paths.blocks}/${file}`;
312
+ const dest = resolveSafeDest(targetDir, ".", rel);
313
+ if (!existsSync(dest))
314
+ continue;
315
+ const current = await readFile(dest, "utf8");
316
+ const patched = patchGoldPathAuthSplit(current);
317
+ if (patched === undefined || patched === current)
318
+ continue;
319
+ await writeFileEnsured(dest, patched);
320
+ if (!generatedFiles.includes(rel))
321
+ generatedFiles.push(rel);
322
+ }
323
+ }
309
324
  // --- Grow composed{} (pages union + files union) + persist ----------------
310
325
  const nextPages = [...new Set([...composedRecord.choices.pages, options.route])];
311
326
  // Preserve manifest order of the routes the app actually has.
@@ -5,7 +5,7 @@ import { tmpdir } from "node:os";
5
5
  import { join } from "node:path";
6
6
  import { createInterface } from "node:readline/promises";
7
7
  import pc from "picocolors";
8
- import { goldPatchAppShellChrome, goldPatchHomePage, goldPatchShellLayout, goldPatchTeamPage, isGoldPathTemplate, reemitGoldPathOwned, } from "../compose/gold-path.js";
8
+ import { GOLD_PATH_AUTH_SPLIT_FILES, goldPatchAppShellChrome, goldPatchHomePage, goldPatchShellLayout, goldPatchTeamPage, goldPathLayout, isGoldPathTemplate, patchGoldPathAccountIssuer, patchGoldPathAuthSplit, reemitGoldPathOwned, } from "../compose/gold-path.js";
9
9
  import { buildComposePlan } from "../compose/plan.js";
10
10
  import { baseSnapshotDest, filterManifestToComposedPages, listBaseSnapshotRels, readBaseSnapshot, reloadManifest, } from "../compose/reload.js";
11
11
  import { renderPlan } from "../compose/render.js";
@@ -484,7 +484,12 @@ async function repatchGoldPathSurfaces(cwd, config, composed) {
484
484
  if (!Object.keys(composed).some((key) => isGoldPathTemplate(key)))
485
485
  return;
486
486
  const authImport = `${config.aliases.lib}/auth`;
487
- await repatchGoldPathFile(cwd, join(config.paths.blocks, "app-shell-chrome.tsx"), goldPatchAppShellChrome, "WorkspaceMenu / InviteMember / SessionUser / nav");
487
+ const layout = goldPathLayout(config);
488
+ await repatchGoldPathFile(cwd, `${layout.dbDir}/schema.ts`, patchGoldPathAccountIssuer, "account.issuer nullable");
489
+ await repatchGoldPathFile(cwd, join(config.paths.blocks, "app-shell-chrome.tsx"), goldPatchAppShellChrome, "WorkspaceMenu / InviteMember / SessionUser / nav / notifications");
490
+ for (const file of GOLD_PATH_AUTH_SPLIT_FILES) {
491
+ await repatchGoldPathFile(cwd, join(config.paths.blocks, file), patchGoldPathAuthSplit, "auth split without Dana Reyes");
492
+ }
488
493
  for (const rel of goldPathSurfaceRels(cwd, composed)) {
489
494
  if (/(^|\/)\(shell\)\/layout\.tsx$/.test(rel)) {
490
495
  await repatchGoldPathFile(cwd, rel, (source) => goldPatchShellLayout(source, authImport), "session gate");
@@ -6,11 +6,14 @@ import type { CronusUIConfig } from "../config.js";
6
6
  export declare const GOLD_PATH_TEMPLATES: Set<string>;
7
7
  export declare function isGoldPathTemplate(name: string): boolean;
8
8
  /**
9
- * Re-apply WorkspaceMenu / InviteMember / SessionUser onto catalog app-shell-chrome
10
- * and drop catalog demo routes from APP_NAV. Idempotent. Used by add-page --nav
11
- * and upgrade so neither restores Mara nor Analytics/Billing/Settings in the nav.
9
+ * Re-apply WorkspaceMenu / InviteMember / SessionUser onto catalog app-shell-chrome,
10
+ * drop catalog demo routes from APP_NAV, and remove the dead Notifications button.
11
+ * Idempotent. Used by add-page --nav and upgrade so neither restores Mara,
12
+ * Analytics/Billing/Settings in the nav, nor a no-op Bell.
12
13
  */
13
14
  export declare function goldPatchAppShellChrome(source: string): string | undefined;
15
+ /** Installed split-auth copies compose writes for saas/admin. */
16
+ export declare const GOLD_PATH_AUTH_SPLIT_FILES: readonly ["login-split.tsx", "signup-split.tsx", "forgot-password-split.tsx"];
14
17
  /**
15
18
  * Re-apply the session gate onto a catalog shell layout.
16
19
  * Idempotent. Used by add-page (new shell group) and upgrade.
@@ -49,6 +52,21 @@ export interface ApplyGoldPathResult {
49
52
  skipped: string[];
50
53
  }
51
54
  export declare function goldPathLayout(config: CronusUIConfig): GoldPathLayout;
55
+ /**
56
+ * Drop the catalog Dana Reyes / Northwind testimonial column from a split auth
57
+ * block. Idempotent. Returns undefined when the quote is missing and the file
58
+ * is not an already-stripped gold-path split.
59
+ */
60
+ export declare function patchGoldPathAuthSplit(source: string): string | undefined;
61
+ /**
62
+ * Drop `.notNull()` on `account.issuer`. Better Auth 1.7.3 never writes the
63
+ * column and refuses a required one (`SCHEMA_MISMATCH`). Idempotent. Does not
64
+ * rewrite the rest of a user-owned schema — used by compose and `upgrade --all`
65
+ * so 0.7.1 apps pick up the fix without losing hand edits.
66
+ */
67
+ export declare function patchGoldPathAccountIssuer(source: string): string | undefined;
68
+ /** Remove the no-op Notifications Bell from gold-path chrome. Idempotent. */
69
+ export declare function patchGoldPathChromeNotifications(source: string): string | undefined;
52
70
  /**
53
71
  * Drop catalog demo hrefs from `const APP_NAV`. Idempotent. Keeps Items, Team,
54
72
  * and any user-added link. Returns undefined when the const is missing.
@@ -20,13 +20,20 @@ const GOLD_AUTH_IMPORT = "@/lib/auth";
20
20
  const GOLD_MEMBERS_IMPORT = "@/components/members-panel";
21
21
  const GOLD_ITEMS_IMPORT = "@/components/items-panel";
22
22
  /**
23
- * Re-apply WorkspaceMenu / InviteMember / SessionUser onto catalog app-shell-chrome
24
- * and drop catalog demo routes from APP_NAV. Idempotent. Used by add-page --nav
25
- * and upgrade so neither restores Mara nor Analytics/Billing/Settings in the nav.
23
+ * Re-apply WorkspaceMenu / InviteMember / SessionUser onto catalog app-shell-chrome,
24
+ * drop catalog demo routes from APP_NAV, and remove the dead Notifications button.
25
+ * Idempotent. Used by add-page --nav and upgrade so neither restores Mara,
26
+ * Analytics/Billing/Settings in the nav, nor a no-op Bell.
26
27
  */
27
28
  export function goldPatchAppShellChrome(source) {
28
29
  return patchChromeSource(source, GOLD_WORKSPACE_IMPORT, GOLD_INVITE_IMPORT, GOLD_SESSION_IMPORT);
29
30
  }
31
+ /** Installed split-auth copies compose writes for saas/admin. */
32
+ export const GOLD_PATH_AUTH_SPLIT_FILES = [
33
+ "login-split.tsx",
34
+ "signup-split.tsx",
35
+ "forgot-password-split.tsx",
36
+ ];
30
37
  /**
31
38
  * Re-apply the session gate onto a catalog shell layout.
32
39
  * Idempotent. Used by add-page (new shell group) and upgrade.
@@ -180,7 +187,7 @@ export const session = sqliteTable("session", {
180
187
 
181
188
  export const account = sqliteTable("account", {
182
189
  id: text("id").primaryKey(),
183
- issuer: text("issuer").notNull(),
190
+ issuer: text("issuer"),
184
191
  accountId: text("account_id").notNull(),
185
192
  providerId: text("provider_id").notNull(),
186
193
  userId: text("user_id")
@@ -1125,6 +1132,76 @@ function serializeGoldPathAppNav(links) {
1125
1132
  .join("\n");
1126
1133
  return `const APP_NAV = [\n${rows}\n];`;
1127
1134
  }
1135
+ /**
1136
+ * Drop the catalog Dana Reyes / Northwind testimonial column from a split auth
1137
+ * block. Idempotent. Returns undefined when the quote is missing and the file
1138
+ * is not an already-stripped gold-path split.
1139
+ */
1140
+ export function patchGoldPathAuthSplit(source) {
1141
+ const hasQuote = source.includes("Dana Reyes") || source.includes("Northwind Labs");
1142
+ if (!hasQuote) {
1143
+ if (source.includes("lg:grid-cols-2"))
1144
+ return undefined;
1145
+ if (source.includes("Sign in to your Cronus workspace") ||
1146
+ source.includes("Create your Cronus workspace") ||
1147
+ source.includes("Join the workspace") ||
1148
+ source.includes("Check your inbox")) {
1149
+ return source;
1150
+ }
1151
+ return undefined;
1152
+ }
1153
+ let out = source.replace(/(?:\n\s*\{\/\* Brand panel \*\/\})?\s*<div className="relative overflow-hidden bg-gradient-primary-strong[\s\S]*?Head of Growth, Northwind Labs[\s\S]*?<\/figure>\s*<\/div>\s*<\/div>/, "");
1154
+ if (out === source)
1155
+ return undefined;
1156
+ out = out.replace(" lg:grid-cols-2", "");
1157
+ out = out.replace(" max-w-4xl", " max-w-md");
1158
+ out = out.replace(" lg:order-2", "");
1159
+ out = out.replace(" lg:order-1", "");
1160
+ out = dropUnusedFromImport(out, "lucide-react");
1161
+ out = dropUnusedFromImport(out, "@cronus-ui/ui");
1162
+ return out;
1163
+ }
1164
+ /**
1165
+ * Drop `.notNull()` on `account.issuer`. Better Auth 1.7.3 never writes the
1166
+ * column and refuses a required one (`SCHEMA_MISMATCH`). Idempotent. Does not
1167
+ * rewrite the rest of a user-owned schema — used by compose and `upgrade --all`
1168
+ * so 0.7.1 apps pick up the fix without losing hand edits.
1169
+ */
1170
+ export function patchGoldPathAccountIssuer(source) {
1171
+ const next = source.replace(/(issuer:\s*(?:text|varchar)\([^)]*\))\s*\.notNull\(\)/g, "$1");
1172
+ if (next === source)
1173
+ return undefined;
1174
+ return next;
1175
+ }
1176
+ /** Remove the no-op Notifications Bell from gold-path chrome. Idempotent. */
1177
+ export function patchGoldPathChromeNotifications(source) {
1178
+ if (!source.includes('aria-label="Notifications"'))
1179
+ return undefined;
1180
+ let out = source.replace(/\n\s*<Button variant="ghost" size="icon-sm" aria-label="Notifications">\s*<Bell className="size-4" aria-hidden="true" \/>\s*<\/Button>/, "");
1181
+ if (out === source)
1182
+ return undefined;
1183
+ out = dropUnusedFromImport(out, "lucide-react");
1184
+ return out;
1185
+ }
1186
+ function dropUnusedFromImport(source, fromModule) {
1187
+ const escaped = fromModule.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1188
+ const re = new RegExp(`import \\{([^}]+)\\} from "${escaped}";\\n`);
1189
+ const match = source.match(re);
1190
+ if (!match || match.index === undefined)
1191
+ return source;
1192
+ const names = (match[1] ?? "")
1193
+ .split(",")
1194
+ .map((part) => part.trim())
1195
+ .filter(Boolean);
1196
+ const rest = source.slice(0, match.index) + source.slice(match.index + match[0].length);
1197
+ const kept = names.filter((name) => new RegExp(`(?:<|{)${name}\\b`).test(rest));
1198
+ if (kept.length === names.length)
1199
+ return source;
1200
+ if (kept.length === 0) {
1201
+ return source.slice(0, match.index) + source.slice(match.index + match[0].length);
1202
+ }
1203
+ return `${source.slice(0, match.index)}import { ${kept.join(", ")} } from "${fromModule}";\n${source.slice(match.index + match[0].length)}`;
1204
+ }
1128
1205
  /**
1129
1206
  * Drop catalog demo hrefs from `const APP_NAV`. Idempotent. Keeps Items, Team,
1130
1207
  * and any user-added link. Returns undefined when the const is missing.
@@ -1207,9 +1284,12 @@ export function patchChromeSource(source, workspaceImport, inviteImport, session
1207
1284
  const navPatched = patchGoldPathAppNav(out);
1208
1285
  if (navPatched !== undefined)
1209
1286
  out = navPatched;
1287
+ const notifyPatched = patchGoldPathChromeNotifications(out);
1288
+ if (notifyPatched !== undefined)
1289
+ out = notifyPatched;
1210
1290
  if (out !== source)
1211
1291
  return out;
1212
- if (widgetsTouched || navPatched !== undefined)
1292
+ if (widgetsTouched || (navPatched !== undefined && navPatched === source))
1213
1293
  return source;
1214
1294
  return undefined;
1215
1295
  }
@@ -1485,6 +1565,20 @@ export async function applyGoldPath(options) {
1485
1565
  for (const file of files) {
1486
1566
  await writeRel(targetDir, file.rel, file.content, overwrite, file.always === true, written, skipped);
1487
1567
  }
1568
+ const schemaRel = `${layout.dbDir}/schema.ts`;
1569
+ const schemaDest = resolveSafeDest(targetDir, ".", schemaRel);
1570
+ if (existsSync(schemaDest)) {
1571
+ const current = await readFile(schemaDest, "utf8");
1572
+ const patched = patchGoldPathAccountIssuer(current);
1573
+ if (patched !== undefined && patched !== current) {
1574
+ await writeFileEnsured(schemaDest, patched);
1575
+ if (!written.includes(schemaRel))
1576
+ written.push(schemaRel);
1577
+ const skipAt = skipped.indexOf(schemaRel);
1578
+ if (skipAt >= 0)
1579
+ skipped.splice(skipAt, 1);
1580
+ }
1581
+ }
1488
1582
  const chromeDest = resolveSafeDest(targetDir, ".", chromeRel);
1489
1583
  if (existsSync(chromeDest)) {
1490
1584
  const current = await readFile(chromeDest, "utf8");
@@ -1500,6 +1594,20 @@ export async function applyGoldPath(options) {
1500
1594
  }
1501
1595
  }
1502
1596
  }
1597
+ const blocksDir = posix(config.paths.blocks);
1598
+ for (const file of GOLD_PATH_AUTH_SPLIT_FILES) {
1599
+ const rel = `${blocksDir}/${file}`;
1600
+ const dest = resolveSafeDest(targetDir, ".", rel);
1601
+ if (!existsSync(dest))
1602
+ continue;
1603
+ const current = await readFile(dest, "utf8");
1604
+ const patched = patchGoldPathAuthSplit(current);
1605
+ if (patched === undefined || patched === current)
1606
+ continue;
1607
+ await writeFileEnsured(dest, patched);
1608
+ if (!written.includes(rel))
1609
+ written.push(rel);
1610
+ }
1503
1611
  const layoutRel = shellLayoutRel(appDir, generatedFiles);
1504
1612
  if (layoutRel !== undefined) {
1505
1613
  const dest = resolveSafeDest(targetDir, ".", layoutRel);
package/dist/config.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export declare const CONFIG_FILE = "cronus-ui.json";
2
- export declare const CLI_VERSION = "0.7.0";
3
- export declare const DEFAULT_REGISTRY = "https://raw.githubusercontent.com/pedrogbraz/cronus-ui/v0.7.0/registry";
2
+ export declare const CLI_VERSION = "0.7.2";
3
+ export declare const DEFAULT_REGISTRY = "https://raw.githubusercontent.com/pedrogbraz/cronus-ui/v0.7.2/registry";
4
4
  /** Manifest entry `add`/`upgrade` record per installed registry item. */
5
5
  export interface InstalledRecord {
6
6
  /** Registry release the files came from (git tag without the leading "v"). */
package/dist/config.js CHANGED
@@ -2,7 +2,7 @@ import { existsSync } from "node:fs";
2
2
  import { readFile, writeFile } from "node:fs/promises";
3
3
  import { join } from "node:path";
4
4
  export const CONFIG_FILE = "cronus-ui.json";
5
- export const CLI_VERSION = "0.7.0";
5
+ export const CLI_VERSION = "0.7.2";
6
6
  export const DEFAULT_REGISTRY = `https://raw.githubusercontent.com/pedrogbraz/cronus-ui/v${CLI_VERSION}/registry`;
7
7
  export const DEFAULT_CONFIG = {
8
8
  aliases: { ui: "@/components/ui", lib: "@/lib", blocks: "@/components/blocks" },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cronus-ui",
3
- "version": "0.7.0",
3
+ "version": "0.7.2",
4
4
  "description": "cronus-ui — add Cronus UI components to your project, shadcn-style (copy-paste registry).",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -54,7 +54,7 @@
54
54
  "registry:check": "bun run scripts/check-registry.ts"
55
55
  },
56
56
  "dependencies": {
57
- "@cronus-ui/ai-kit": "0.7.0",
57
+ "@cronus-ui/ai-kit": "0.7.2",
58
58
  "commander": "^15.0.0",
59
59
  "picocolors": "^1.1.1"
60
60
  },
@@ -4,7 +4,7 @@
4
4
  "planVersion": 1,
5
5
  "manifest": {
6
6
  "title": "Admin",
7
- "description": "An admin console: split login/signup, password reset, an (app) shell, overview, users, analytics, a sprint board and an audit trail — composed from validated blocks.",
7
+ "description": "Authenticated gold path: split login/signup, password reset, Items in a sidebar shell. Catalog demo pages (users, analytics, board, audit) ship as files, not in the nav — composed from validated blocks.",
8
8
  "chrome": {
9
9
  "shell": { "block": "app-shell-chrome" },
10
10
  "bare": {}
@@ -4,7 +4,7 @@
4
4
  "planVersion": 1,
5
5
  "manifest": {
6
6
  "title": "SaaS",
7
- "description": "A complete multi-page SaaS app: split login/signup, password reset, a sidebar-shell dashboard, analytics, team, billing and settings, plus welcome, setup wizard and checklist — all from validated blocks.",
7
+ "description": "Authenticated gold path: split login/signup, password reset, Items and Team in a sidebar shell. Catalog demo pages (analytics, billing, settings, welcome, setup wizard, checklist) ship as files, not in the nav — all from validated blocks.",
8
8
  "chrome": {
9
9
  "shell": { "block": "app-shell-chrome" },
10
10
  "bare": {}