create-ailk 0.9.0 → 0.11.0

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 (104) hide show
  1. package/README.md +10 -5
  2. package/dist/cli.js +17 -2
  3. package/dist/content-payloads.d.ts +37 -0
  4. package/dist/content-payloads.js +64 -0
  5. package/dist/lib/fetch-module.d.ts +3 -3
  6. package/dist/lib/fetch-module.js +11 -5
  7. package/dist/lib/fetch-template.d.ts +1 -1
  8. package/dist/lib/fetch-template.js +7 -4
  9. package/dist/lib/module-license-gate.d.ts +29 -23
  10. package/dist/lib/module-license-gate.js +98 -0
  11. package/dist/module-architecture.d.ts +9 -0
  12. package/dist/module-architecture.js +46 -14
  13. package/dist/parse-args.d.ts +2 -0
  14. package/dist/parse-args.js +7 -0
  15. package/dist/programmatic.js +12 -4
  16. package/dist/starter-grid.d.ts +4 -67
  17. package/dist/starter-grid.js +6 -84
  18. package/dist/surfaces.js +2 -3
  19. package/dist/template-manifest.d.ts +1 -1
  20. package/dist/template-manifest.js +5 -5
  21. package/package.json +6 -4
  22. package/release-scope.json +25 -0
  23. package/site-templates/designs/minimalism/sample/README.md +2 -2
  24. package/site-templates/designs/minimalism/sample/content/en/HomePage/home.mdx +1 -1
  25. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.md +4 -3
  26. package/templates/.claude/agents/web.md +10 -8
  27. package/templates/.claude/rules/architecture.md +10 -7
  28. package/templates/.claude/settings.json +12 -0
  29. package/templates/.env.example +24 -3
  30. package/templates/CLAUDE.md +38 -22
  31. package/templates/README.md +12 -12
  32. package/templates/apps/api/jest.config.cjs +1 -0
  33. package/templates/apps/api/package.json +1 -0
  34. package/templates/apps/mcp/CLAUDE.md +23 -10
  35. package/templates/apps/mcp/__tests__/catalog-drift.test.ts +160 -17
  36. package/templates/apps/mcp/__tests__/index.test.ts +118 -1
  37. package/templates/apps/mcp/__tests__/lib/commerce-claim.test.ts +425 -5
  38. package/templates/apps/mcp/__tests__/module-exclusion.test.ts +67 -3
  39. package/templates/apps/mcp/__tests__/server.test.ts +162 -1
  40. package/templates/apps/mcp/src/index.ts +35 -3
  41. package/templates/apps/mcp/src/lib/commerce-claim.ts +193 -24
  42. package/templates/apps/mcp/src/server.ts +77 -5
  43. package/templates/apps/mcp/src/tools/purchase.ts +1 -1
  44. package/templates/apps/web/app/.well-known/mcp.json/build-manifest.ts +15 -0
  45. package/templates/apps/web/app/.well-known/mcp.json/route.ts +10 -3
  46. package/templates/apps/web/src/lib/commerce-claim.ts +15 -6
  47. package/templates/content/_site.mdx +23 -4
  48. package/templates/database/CHANGELOG.md +7 -0
  49. package/templates/database/package.json +1 -1
  50. package/templates/package.json +2 -0
  51. package/versions.json +34 -33
  52. package/dist/modules/commerce/0.6.0.tar.gz +0 -0
  53. package/dist/modules/commerce/0.6.1.tar.gz +0 -0
  54. package/dist/modules/docs-blog/0.6.0.tar.gz +0 -0
  55. package/dist/modules/docs-blog/0.6.1.tar.gz +0 -0
  56. package/dist/modules/marketing-site/0.6.1.tar.gz +0 -0
  57. package/dist/modules/minimalism-site/0.6.1.tar.gz +0 -0
  58. package/dist/modules/multi-tenant/0.6.0.tar.gz +0 -0
  59. package/dist/modules/multi-tenant/0.6.1.tar.gz +0 -0
  60. package/dist/modules/saas-product/0.6.1.tar.gz +0 -0
  61. package/dist/modules/scheduling/0.6.0.tar.gz +0 -0
  62. package/dist/modules/scheduling/0.6.1.tar.gz +0 -0
  63. package/dist/modules/signal-collectors/0.6.0.tar.gz +0 -0
  64. package/dist/modules/signal-collectors/0.6.1.tar.gz +0 -0
  65. package/dist/modules/simple-service/0.6.1.tar.gz +0 -0
  66. package/dist/modules/workspace/0.6.0.tar.gz +0 -0
  67. package/dist/modules/workspace/0.6.1.tar.gz +0 -0
  68. package/site-templates/aliases/minimalism-site.TEMPLATE-MANIFEST.json +0 -538
  69. package/templates/.claude/skills/README.md +0 -37
  70. package/templates/.claude/skills/add-auth/SKILL.md +0 -261
  71. package/templates/.claude/skills/add-auth/references/env-vars.md +0 -98
  72. package/templates/.claude/skills/add-auth/references/oauth-app-setup.md +0 -172
  73. package/templates/.claude/skills/add-page/SKILL.md +0 -260
  74. package/templates/.claude/skills/add-page/references/page-types.md +0 -124
  75. package/templates/.claude/skills/add-page/scripts/site-pages.mjs +0 -87
  76. package/templates/.claude/skills/add-page/templates/comparison-page.mdx.tmpl +0 -99
  77. package/templates/.claude/skills/add-page/templates/content.mdx.tmpl +0 -18
  78. package/templates/.claude/skills/add-page/templates/flow-landing-page.mdx.tmpl +0 -43
  79. package/templates/.claude/skills/add-page/templates/report-page.mdx.tmpl +0 -52
  80. package/templates/.claude/skills/add-page/templates/reports-list.mdx.tmpl +0 -38
  81. package/templates/.claude/skills/check-site/SKILL.md +0 -235
  82. package/templates/.claude/skills/check-site/references/common-errors.md +0 -113
  83. package/templates/.claude/skills/check-site/references/findings-glossary.md +0 -140
  84. package/templates/.claude/skills/check-site/references/severity-levels.md +0 -114
  85. package/templates/.claude/skills/fill-page/SKILL.md +0 -199
  86. package/templates/.claude/skills/fill-page/profiles/plumbing.yaml +0 -80
  87. package/templates/.claude/skills/fill-page/references/section-sources.md +0 -41
  88. package/templates/.claude/skills/setup-database/SKILL.md +0 -156
  89. package/templates/.claude/skills/setup-database/scripts/verify-inbox.ts +0 -154
  90. package/templates/.claude/skills/setup-deploy/SKILL.md +0 -275
  91. package/templates/.claude/skills/setup-deploy/references/env-vars-template.md +0 -192
  92. package/templates/.claude/skills/setup-deploy/references/runbook-template.md +0 -204
  93. package/templates/.claude/skills/setup-deploy/references/vercel-json-template.md +0 -98
  94. package/templates/.claude/skills/update-page/SKILL.md +0 -117
  95. package/templates/.claude/skills/update-page/scripts/update-page.ts +0 -640
  96. package/templates/.claude/skills/update-page/templates/redirects.mjs.tmpl +0 -31
  97. package/templates/.claude/skills/upgrade-plan/SKILL.md +0 -121
  98. package/templates/.claude/skills/upgrade-plan/references/options.md +0 -24
  99. package/templates/.claude/skills/upgrade-plan/scripts/upgrade-plan.ts +0 -527
  100. package/templates/apps/api/.ailk/inbox/2026-09-20T14-57-31.552Z-fallback-1789916251590-037e9005.json +0 -8
  101. package/templates/apps/api/.ailk/inbox/2026-09-20T14-57-33.840Z-fallback-1789916253842-b52659e9.json +0 -12
  102. package/templates/apps/api/.ailk/inbox/2026-09-20T14-57-33.844Z-fallback-1789916253845-6b266f8c.json +0 -12
  103. package/templates/apps/mcp/__tests__/lib/require-paid-tier.test.ts +0 -75
  104. package/templates/apps/mcp/src/lib/require-paid-tier.ts +0 -44
@@ -31,7 +31,7 @@ import { writeAuthSecretFile } from "./lib/auth-secret-file.js";
31
31
  import { extractModuleBundle, installBundleTree, } from "./lib/extract-module-bundle.js";
32
32
  import { fetchTemplate } from "./lib/fetch-template.js";
33
33
  import { assertLicenseKeyShape, writeLicenseKeyFiles, } from "./lib/license-key-files.js";
34
- import { assertDesignAllowed, deriveLevel, resolveModuleSet, resolvePaidModules, } from "./lib/module-license-gate.js";
34
+ import { assertDesignAllowed, assertReleased, deriveLevel, resolveModuleSet, resolvePaidModules, } from "./lib/module-license-gate.js";
35
35
  import { classifyModules } from "./lib/module-tier.js";
36
36
  import { normalizeModules } from "./module-architecture.js";
37
37
  import { RECOGNIZED_SHAPES, RESERVED_SHAPES, } from "./parse-args.js";
@@ -235,11 +235,16 @@ export async function scaffold(opts) {
235
235
  if (opts.template !== undefined && opts.shape !== undefined) {
236
236
  throw new TemplateError("pass a template or a shape, not both");
237
237
  }
238
+ // #6984 — a surface `release-scope.json` does not release is refused here,
239
+ // after parsing and before the licence gate, fetch or write (spec 6977 D3).
240
+ assertReleased("templates", [opts.template]);
241
+ assertReleased("shapes", [opts.shape]);
238
242
  const template = opts.template !== undefined
239
243
  ? resolveTemplate(opts.template)
240
244
  : opts.shape !== undefined
241
245
  ? resolveShapeTemplate(opts.shape)
242
246
  : undefined;
247
+ assertReleased("modules", [...(opts.modules ?? []), ...(template?.requires ?? [])]);
243
248
  // #6813 D8 step 3 — the design this scaffold renders, resolved from its
244
249
  // package ONCE, before any fetch or write: the caller's override, else the
245
250
  // template's own. Unset for a scaffold naming neither. Replaces the
@@ -250,6 +255,8 @@ export async function scaffold(opts) {
250
255
  const resolvedDesign = designRef !== undefined
251
256
  ? resolveDesign(designRef, { designsDir: DESIGNS_DIR })
252
257
  : undefined;
258
+ // By registry name, so a byte-identical copy of a gated design is refused too.
259
+ assertReleased("designs", [resolvedDesign?.recorded]);
253
260
  // #6816 D6 step 3b — a design's section presets are validated here, before
254
261
  // any fetch or write, against the look groups the shipped catalog carries
255
262
  // (D2): a non-look field or unknown variant throws `DesignPackageError`
@@ -313,8 +320,8 @@ export async function scaffold(opts) {
313
320
  // answers, never a key claim (D2) — only when the caller CHOSE a
314
321
  // non-Free design alongside the template (`opts.design`, #6813 D7). An
315
322
  // alias's own declared design is never gated (#6778 option (c)), so a
316
- // plain `--template minimalism-site` run makes no extra network call and
317
- // is never refused on its design.
323
+ // plain `--template <alias>` run makes no extra network call and is
324
+ // never refused on its design.
318
325
  if (chosenDesign !== undefined && !chosenDesign.free) {
319
326
  ({ level } = await deriveLevel({
320
327
  licenseKey,
@@ -557,7 +564,8 @@ export async function scaffold(opts) {
557
564
  writeFileSync(join(result.targetDir, NAV_CONFIG_PATH), renderNavConfig(result.surfaces, { serviceSlugs }));
558
565
  pruneUnrosteredSeeds(result.targetDir, mergeRoster(template, template.requires), result.surfaces, ownership);
559
566
  // spec 6892 D4 — the resolved design's own sample (the minimalism design's
560
- // nine-slide deck home + its SVGs today), installed AFTER the template
567
+ // nine-slide deck home + its SVGs; no template declares `minimalism`
568
+ // since #6976, so none installs it today), installed AFTER the template
561
569
  // layer so it wins over the shape's `HomePage/home.mdx`, and ONLY when
562
570
  // the resolved design is the template's OWN declared design: a caller
563
571
  // combination like `--shape organization-product --design minimalism`
@@ -31,9 +31,8 @@ export interface AliasDifferences {
31
31
  /**
32
32
  * Further positioned groups (#6757 D7): each group's rows go before its
33
33
  * own `before` route, applied group by group in array order, AFTER `add`
34
- * is placed. The one alias that needs more than one anchor
35
- * (`minimalism-site`, which interleaves rows at two separate points in the
36
- * shape's row order) uses this; every other alias leaves it unset.
34
+ * is placed — for an alias that interleaves rows at more than one point
35
+ * in the shape's row order. No alias in the table below needs it today.
37
36
  */
38
37
  readonly insert?: readonly {
39
38
  readonly before: string;
@@ -58,8 +57,8 @@ export interface TemplateAlias {
58
57
  readonly differences?: AliasDifferences;
59
58
  /**
60
59
  * Whether this alias ships its own `site-templates/<name>/` tree (spec 6892
61
- * D1). Absent means `true` — every alias but `minimalism-site` keeps its
62
- * own directory. `false` declares that the alias resolves purely from the
60
+ * D1). Absent means `true` — every alias today keeps its own directory.
61
+ * `false` declares that the alias resolves purely from the
63
62
  * grid: its seed layer is its shape's tree (`templateTreeDir`), and its
64
63
  * generated roster record lives under `site-templates/aliases/` rather
65
64
  * than a directory of its own (`shippedManifestPath`).
@@ -152,68 +151,6 @@ export declare const ALIASES: Readonly<{
152
151
  readonly before: "/portfolio";
153
152
  };
154
153
  };
155
- /**
156
- * The second Pro template (#5589) — the reports-first, scroll-snap deck
157
- * site. NOT `marketing-site` plus a module: its `modules` omit `docs-blog`,
158
- * so the two Pro templates are siblings under `_base` (#5618 D2), never a
159
- * lineage. Level still derives from `modules`: `scheduling` and
160
- * `signal-collectors` are paid, so `templateDelivery` returns `"paid"`
161
- * exactly as it does for `marketing-site`.
162
- *
163
- * It composes the `organization-service` shape roster (#6757) rather than
164
- * the organization-product one: the deck home replaces the document-scroll
165
- * home, and `/how-it-works`, the product page, `/pricing` and `/sign-in`
166
- * are not pages this site has. The roster is what the
167
- * template IS, so an unrostered page has neither a route directory
168
- * (`rosterSurfaces`) nor its `_base`/overlay seed (#6646 D1).
169
- *
170
- * It declares NO `layout` block (#6638): the deck home, mark-only nav and
171
- * centered footer are the `minimalism` design's own `layout` (its
172
- * `DESIGN.md`, resolved by `resolveDesign` off `design:` — #6813 D4) — the
173
- * look any shape can wear. This alias ships no tree of its own (`ownTree:
174
- * false`, spec 6892 D1); its GENERATED roster record (no narrative `.md`,
175
- * D5) lives at `site-templates/aliases/minimalism-site.TEMPLATE-MANIFEST.json`.
176
- *
177
- * `/reports` (a `ReportsList` hub over `ReportPage`) and `/referral` (a
178
- * flow landing page) are signal-collectors module samples (spec 6892 D3);
179
- * neither carries a `GATEABLE_SURFACES` entry: `/referral` is a
180
- * single-segment `LandingPage` slug served by the generic `[slug]` route
181
- * (#5469 D2), the same mechanism Free's `/how-it-works` uses, and `/reports`
182
- * is its own routes-map row. `/reports/[slug]` (the reader) is the
183
- * signal-collectors module's own contributed row.
184
- *
185
- * `/services/[slug]` declares its seed DIRECTORY as `contentDir`
186
- * (`content/en/Service`, as `routes-map.ts` records it). The three
187
- * samples ride the template tree unmapped, landing at that directory.
188
- *
189
- * Since #6757, `organization-service` carries a real standard roster
190
- * (D1), so this alias's `differences` is additions and drops only: it
191
- * drops the `/blog` teaser (a Pro alias does not upsell its own level,
192
- * D8), the portfolio pair (the reports are the proof, not a
193
- * portfolio) and the two auth code routes the shape rosters (#6797 —
194
- * this site has no `/sign-in`, above), adds the signal-collectors
195
- * samples, and INSERTS its two own
196
- * rows — `/reports` before `/about`, `/referral` before `/faq` (D7) — to
197
- * reproduce its pre-#6757 row order (§ 1.2) exactly.
198
- */
199
- readonly "minimalism-site": {
200
- readonly shape: "organization-service";
201
- readonly design: "minimalism";
202
- readonly modules: readonly ["marketing", "scheduling", "signal-collectors"];
203
- readonly categories: readonly ["real-estate", "technology", "legal"];
204
- readonly ownTree: false;
205
- readonly differences: {
206
- readonly drop: readonly ["/sign-in", "/sign-up", "/blog", "/meet", "/meet/[slug]", "/portfolio", "/portfolio/[slug]"];
207
- readonly add: readonly import("./module-architecture.js").PageRosterRow[];
208
- readonly insert: readonly [{
209
- readonly before: "/about";
210
- readonly rows: readonly [import("./module-architecture.js").PageRosterRow];
211
- }, {
212
- readonly before: "/faq";
213
- readonly rows: readonly [import("./module-architecture.js").PageRosterRow];
214
- }];
215
- };
216
- };
217
154
  }>;
218
155
  /**
219
156
  * The coordinates a keyless `--shape S` builds (#6757 D5) — the composed
@@ -171,14 +171,10 @@ const PORTFOLIO_ROWS = [
171
171
  { route: "/portfolio/[slug]", contentDir: "content/en/PortfolioItem" },
172
172
  ];
173
173
  /**
174
- * `minimalism-site`'s two OWN rows (#5589, shrunk from its own 17-row roster
175
- * by #6757 once the `organization-service` shape carried a standard roster of
176
- * its own): the deck's two `LandingPage` slugs, positioned by `insert` (D7)
177
- * at the two points this alias interleaves them into the shape's row order
178
- * (§ 1.2) — `/reports` before `/about`, `/referral` before `/faq`. Neither
179
- * carries a `GATEABLE_SURFACES` entry: both are single-segment slugs served
180
- * by the generic `[slug]` route (#5469 D2), the same mechanism Free's
181
- * `/how-it-works` used.
174
+ * The two report/referral sample rows. Neither carries a `GATEABLE_SURFACES`
175
+ * entry: `/referral` is a single-segment `LandingPage` slug served by the
176
+ * generic `[slug]` route (#5469 D2), the same mechanism Free's
177
+ * `/how-it-works` used, and `/reports` is its own routes-map row.
182
178
  */
183
179
  const REPORTS_ROW = {
184
180
  route: "/reports",
@@ -193,8 +189,7 @@ const REFERRAL_ROW = {
193
189
  * `/reports`, a `ReportsList` hub over the module's four `ReportPage` seeds,
194
190
  * and `/referral`, a sample flow landing page. `marketing-site` and
195
191
  * `saas-product` add these before `/portfolio`, alongside
196
- * `SIGNAL_COLLECTORS_SAMPLE_ROWS`; `minimalism-site` keeps its own two
197
- * `insert` groups instead (its pre-existing row order, D1).
192
+ * `SIGNAL_COLLECTORS_SAMPLE_ROWS`.
198
193
  */
199
194
  const SIGNAL_COLLECTORS_REPORT_ROWS = [
200
195
  REPORTS_ROW,
@@ -206,8 +201,7 @@ const SIGNAL_COLLECTORS_REPORT_ROWS = [
206
201
  * --registry packages/schema/src/registry/entries.ts` at harness commit
207
202
  * `7bdaf148e1b0e639cd90a80008955e55cc4aa2b5`, edited only by the deviations
208
203
  * `site-templates/shapes/organization-service/TEMPLATE-MANIFEST.md` § 3a
209
- * records with their reasons. Row order matches `minimalism-site`'s (D3), so
210
- * that alias's `differences` are additions and drops only.
204
+ * records with their reasons.
211
205
  */
212
206
  const ORGANIZATION_SERVICE_ROWS = [
213
207
  { route: "/", content: ["content/en/HomePage/home.mdx"] },
@@ -429,78 +423,6 @@ export const ALIASES = Object.freeze({
429
423
  before: "/portfolio",
430
424
  },
431
425
  },
432
- /**
433
- * The second Pro template (#5589) — the reports-first, scroll-snap deck
434
- * site. NOT `marketing-site` plus a module: its `modules` omit `docs-blog`,
435
- * so the two Pro templates are siblings under `_base` (#5618 D2), never a
436
- * lineage. Level still derives from `modules`: `scheduling` and
437
- * `signal-collectors` are paid, so `templateDelivery` returns `"paid"`
438
- * exactly as it does for `marketing-site`.
439
- *
440
- * It composes the `organization-service` shape roster (#6757) rather than
441
- * the organization-product one: the deck home replaces the document-scroll
442
- * home, and `/how-it-works`, the product page, `/pricing` and `/sign-in`
443
- * are not pages this site has. The roster is what the
444
- * template IS, so an unrostered page has neither a route directory
445
- * (`rosterSurfaces`) nor its `_base`/overlay seed (#6646 D1).
446
- *
447
- * It declares NO `layout` block (#6638): the deck home, mark-only nav and
448
- * centered footer are the `minimalism` design's own `layout` (its
449
- * `DESIGN.md`, resolved by `resolveDesign` off `design:` — #6813 D4) — the
450
- * look any shape can wear. This alias ships no tree of its own (`ownTree:
451
- * false`, spec 6892 D1); its GENERATED roster record (no narrative `.md`,
452
- * D5) lives at `site-templates/aliases/minimalism-site.TEMPLATE-MANIFEST.json`.
453
- *
454
- * `/reports` (a `ReportsList` hub over `ReportPage`) and `/referral` (a
455
- * flow landing page) are signal-collectors module samples (spec 6892 D3);
456
- * neither carries a `GATEABLE_SURFACES` entry: `/referral` is a
457
- * single-segment `LandingPage` slug served by the generic `[slug]` route
458
- * (#5469 D2), the same mechanism Free's `/how-it-works` uses, and `/reports`
459
- * is its own routes-map row. `/reports/[slug]` (the reader) is the
460
- * signal-collectors module's own contributed row.
461
- *
462
- * `/services/[slug]` declares its seed DIRECTORY as `contentDir`
463
- * (`content/en/Service`, as `routes-map.ts` records it). The three
464
- * samples ride the template tree unmapped, landing at that directory.
465
- *
466
- * Since #6757, `organization-service` carries a real standard roster
467
- * (D1), so this alias's `differences` is additions and drops only: it
468
- * drops the `/blog` teaser (a Pro alias does not upsell its own level,
469
- * D8), the portfolio pair (the reports are the proof, not a
470
- * portfolio) and the two auth code routes the shape rosters (#6797 —
471
- * this site has no `/sign-in`, above), adds the signal-collectors
472
- * samples, and INSERTS its two own
473
- * rows — `/reports` before `/about`, `/referral` before `/faq` (D7) — to
474
- * reproduce its pre-#6757 row order (§ 1.2) exactly.
475
- */
476
- "minimalism-site": {
477
- shape: "organization-service",
478
- design: "minimalism",
479
- modules: ["marketing", "scheduling", "signal-collectors"],
480
- categories: ["real-estate", "technology", "legal"],
481
- // Spec 6892 D1 — this alias ships no `site-templates/minimalism-site/`
482
- // tree of its own: it resolves purely from the grid. Its seed layer is
483
- // its shape's tree (`templateTreeDir`), its deck home + SVGs are a
484
- // sample the `minimalism` design installs (D4), and its `/reports` +
485
- // `/referral` rows are signal-collectors module samples (D3).
486
- ownTree: false,
487
- differences: {
488
- drop: [
489
- "/sign-in",
490
- "/sign-up",
491
- "/blog",
492
- "/meet",
493
- "/meet/[slug]",
494
- "/portfolio",
495
- "/portfolio/[slug]",
496
- ],
497
- add: SIGNAL_COLLECTORS_SAMPLE_ROWS,
498
- insert: [
499
- { before: "/about", rows: [REPORTS_ROW] },
500
- { before: "/faq", rows: [REFERRAL_ROW] },
501
- ],
502
- },
503
- },
504
426
  });
505
427
  /**
506
428
  * The coordinates a keyless `--shape S` builds (#6757 D5) — the composed
package/dist/surfaces.js CHANGED
@@ -20,8 +20,7 @@
20
20
  *
21
21
  * The default (`--modules marketing`) enables NO gateable surface: every one of
22
22
  * them is a claim about the business that the scaffolder cannot make. The path
23
- * from there is the `add-page` skill that already ships in
24
- * `templates/.claude/skills/`.
23
+ * from there is the `/ailk:add-page` skill in the `ailk` Claude Code plugin.
25
24
  *
26
25
  * Zero runtime dependencies — create-ailk is a published, standalone CLI.
27
26
  *
@@ -1047,7 +1046,7 @@ export function renderNavConfig(enabled, options) {
1047
1046
  // below it, the nav is yours and add-module reports the change it wanted
1048
1047
  // instead.
1049
1048
  //
1050
- // Adding a link: scaffold the page (the \`add-page\` skill), then add an
1049
+ // Adding a link: scaffold the page (the \`/ailk:add-page\` skill), then add an
1051
1050
  // entry below with a \`labelKey\` that exists in the \`nav\` namespace of
1052
1051
  // \`apps/web/messages/<locale>.json\`. Paths are locale-agnostic — Nav prefixes
1053
1052
  // them with the active locale at render.
@@ -183,7 +183,7 @@ export declare function templateTreeDir(name: string): string;
183
183
  /**
184
184
  * Whether `name` ships its own `site-templates/<name>/` directory (spec 6892
185
185
  * D1) — `false` only for a declared `--template` alias whose `ownTree` is
186
- * `false` (`minimalism-site` today). A `SHAPE_STARTERS` key owns its
186
+ * `false` (none today). A `SHAPE_STARTERS` key owns its
187
187
  * `shapes/<name>` tree outright, so it is never treeless by this predicate
188
188
  * even though `templateTreeDir` also renames its directory.
189
189
  *
@@ -60,10 +60,10 @@ export class TemplateError extends Error {
60
60
  * shape's standard roster, minus the alias's `drop` routes, with its `add`
61
61
  * rows inserted before the `before` route (appended when there is none),
62
62
  * then each `insert` group's rows spliced before ITS OWN `before` route, in
63
- * array order — the one alias with more than one anchor point
64
- * (`minimalism-site`) uses this to interleave its own rows into the shape's
65
- * row order. Rows are pushed by reference, never cloned, so
66
- * `manifest.roster.includes(row)` identity checks downstream keep working.
63
+ * array order — for an alias that interleaves its own rows into the shape's
64
+ * row order at more than one anchor point. Rows are pushed by reference,
65
+ * never cloned, so `manifest.roster.includes(row)` identity checks
66
+ * downstream keep working.
67
67
  * Every refusal names the alias, so a malformed table fails at load — the
68
68
  * shipped one — or in the test that injected it.
69
69
  *
@@ -178,7 +178,7 @@ export function templateTreeDir(name) {
178
178
  /**
179
179
  * Whether `name` ships its own `site-templates/<name>/` directory (spec 6892
180
180
  * D1) — `false` only for a declared `--template` alias whose `ownTree` is
181
- * `false` (`minimalism-site` today). A `SHAPE_STARTERS` key owns its
181
+ * `false` (none today). A `SHAPE_STARTERS` key owns its
182
182
  * `shapes/<name>` tree outright, so it is never treeless by this predicate
183
183
  * even though `templateTreeDir` also renames its directory.
184
184
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-ailk",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "description": "Scaffolder for AI Launch Kit — `pnpm create ailk@latest <dir>` produces a starter repo consuming @working-theory/* from npm (per ADR 0007).",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -10,9 +10,11 @@
10
10
  },
11
11
  "files": [
12
12
  "dist",
13
+ "!dist/modules",
13
14
  "templates",
14
15
  "site-templates",
15
16
  "versions.json",
17
+ "release-scope.json",
16
18
  "component-catalog.json",
17
19
  "component-catalog.md",
18
20
  "README.md",
@@ -25,8 +27,8 @@
25
27
  "tar": "^7.5.21"
26
28
  },
27
29
  "devDependencies": {
28
- "@working-theory/schema": "0.29.0",
29
- "@working-theory/templates": "0.29.0"
30
+ "@working-theory/schema": "0.30.0",
31
+ "@working-theory/templates": "0.30.0"
30
32
  },
31
33
  "repository": {
32
34
  "type": "git",
@@ -58,7 +60,7 @@
58
60
  "build-catalog": "node scripts/build-component-catalog.mjs",
59
61
  "check-catalog": "node scripts/build-component-catalog.mjs --check",
60
62
  "manifest:build": "node scripts/build-template-manifest.mjs --template marketing-site-free",
61
- "manifest:check": "node scripts/build-template-manifest.mjs --template marketing-site-free --check && node scripts/build-template-manifest.mjs --template marketing-site --check && node scripts/build-template-manifest.mjs --template minimalism-site --check",
63
+ "manifest:check": "node scripts/build-template-manifest.mjs --template marketing-site-free --check && node scripts/build-template-manifest.mjs --template marketing-site --check",
62
64
  "design:gen": "tsc -b && node scripts/build-design-md.mjs",
63
65
  "page-types:build": "tsx scripts/generate-page-types-reference.ts",
64
66
  "page-types:check": "tsx scripts/generate-page-types-reference.ts --check"
@@ -0,0 +1,25 @@
1
+ {
2
+ "templates": {
3
+ "marketing-site-free": "released",
4
+ "marketing-site": "released",
5
+ "saas-product": "gated"
6
+ },
7
+ "shapes": {
8
+ "organization-product": "released",
9
+ "organization-service": "released",
10
+ "local-business-service": "released",
11
+ "person-service": "released",
12
+ "local-business-product": "deferred"
13
+ },
14
+ "designs": { "standard": "released", "minimalism": "gated" },
15
+ "modules": {
16
+ "marketing": "released",
17
+ "docs-blog": "released",
18
+ "scheduling": "released",
19
+ "signal-collectors": "released",
20
+ "workspace": "gated",
21
+ "multi-tenant": "gated",
22
+ "commerce": "gated"
23
+ },
24
+ "levels": { "free": "released", "pro": "released", "pro-plus": "gated" }
25
+ }
@@ -1,7 +1,7 @@
1
1
  # The `minimalism` design's home-deck sample
2
2
 
3
- > Narrative moved here from the retired `site-templates/minimalism-site/TEMPLATE-MANIFEST.md`
4
- > when that tree retired (spec 6892 D4/D5) — `minimalism` is a design, not a template, so it
3
+ > Narrative moved here from the retired minimalism template's `TEMPLATE-MANIFEST.md` when
4
+ > that tree retired (spec 6892 D4/D5) — `minimalism` is a design, not a template, so it
5
5
  > carries no generated manifest of its own. This file is NOT installed onto a scaffold
6
6
  > (`installDesignSample` copies only `content/**` and `public/**`); it documents the sample for
7
7
  > maintainers of this design.
@@ -2,7 +2,7 @@
2
2
  type: "HomePage"
3
3
  slug: "home"
4
4
  title: "Your Company"
5
- description: "Placeholder home for the minimalism-site template — a nine-slide scroll-snap deck. Replace every line before you launch."
5
+ description: "Placeholder home for the minimalism design — a nine-slide scroll-snap deck. Replace every line before you launch."
6
6
  sections:
7
7
  [
8
8
  {
@@ -366,10 +366,11 @@ Every content route emits one `application/ld+json` script whose `@graph` carrie
366
366
  | Node | `@id` | Built from | Links |
367
367
  | ------------------------------------------------------ | --------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
368
368
  | Identity (`Organization` · `Person` · `LocalBusiness`) | `<origin>/#organization` (`#person` for a Person) | `siteIdentity` `name` · `url` · `logo`/`image` · `description` · `sameAs` | — |
369
+ | Identity (`SoftwareApplication`) | `<origin>/#product` | `siteIdentity` fields; `logo` emitted as `image` | `publisher` → the maker's own `@id` (`siteIdentity.publisher`), never a node here; takes no secondary |
369
370
  | Secondary (optional) | `<origin>/#product` (a `SoftwareApplication`) · `<origin>/#organization` (a Person's company) | `siteIdentity.secondary` | product `publisher` → `#organization`, `featureList` from the product page's (`/software/product`) feature items; a Person `worksFor` its company, which has the Person as `founder` |
370
- | `WebSite` | `<origin>/#website` | `siteName` · `baseUrl` · the render locale | `publisher` → the identity node |
371
+ | `WebSite` | `<origin>/#website` | `siteName` · `baseUrl` · the render locale | `publisher` → the identity node (the maker, for a `SoftwareApplication` identity) |
371
372
 
372
- Each page's primary node is `isPartOf` the `WebSite`; the home page's `mainEntity` is the secondary when declared, else the identity. A testimonials `Review` points its `itemReviewed` at the identity node, declared in the same graph. Free declares no secondary, so a fresh site emits the Organization and the WebSite. `/sign-in` emits no JSON-LD.
373
+ Each page's primary node is `isPartOf` the `WebSite`; the home page's `mainEntity` is the secondary when declared, else the identity (`#product` for a `SoftwareApplication` identity, #7103). A testimonials `Review` points its `itemReviewed` at the identity node, declared in the same graph. Free declares no secondary, so a fresh site emits the Organization and the WebSite. `/sign-in` emits no JSON-LD.
373
374
 
374
375
  ## 2a. State and persistence (every interactive element)
375
376
 
@@ -466,7 +467,7 @@ reversed (`docs/decisions/starter-roster-page-set.md` D4, D7).
466
467
 
467
468
  ### 3b. Site entity (operator-disposed 2026-09-24)
468
469
 
469
- `derive-roster.py` names `SoftwareApplication` as the main entity for this template's inputs. The template deliberately declares the **Organization** as the site's primary node and the software as its **secondary** node (`siteIdentity.secondary`, kind `SoftwareApplication`, #6597): the Free template is a company's own site about its product, so the entity the site is _about_ is the maker. The inverse — `SoftwareApplication` primary — is for a product whose canonical site is elsewhere (Positionary, whose maker has its own site). A fresh Free scaffold declares no `secondary` until the owner names the product; the overlay `_site.mdx` documents the field.
470
+ `derive-roster.py` names `SoftwareApplication` as the main entity for this template's inputs. The template deliberately declares the **Organization** as the site's primary node and the software as its **secondary** node (`siteIdentity.secondary`, kind `SoftwareApplication`, #6597): the Free template is a company's own site about its product, so the entity the site is _about_ is the maker. The inverse — `SoftwareApplication` primary — is for a product whose maker has its own site (Positionary): express it as `siteIdentity.kind: SoftwareApplication` with a required `publisher` naming the maker's stable `@id` on that site (e.g. `https://salessmyth.com/#organization`, #7103), so the product is `<origin>/#product` and the maker is a reference, never a second Organization node here. A fresh Free scaffold declares no `secondary` until the owner names the product; the overlay `_site.mdx` documents the field.
470
471
 
471
472
  ## 4. Component inventory (Free, by tier)
472
473
 
@@ -22,8 +22,8 @@ upstream packages; don't try to edit them locally.
22
22
  ## Read before edit
23
23
 
24
24
  1. `.claude/rules/architecture.md` — confirm what `apps/web` may
25
- import. NextAuth handlers are the only API-shaped code allowed in
26
- `apps/web`; everything else server-side goes through `apps/api`.
25
+ import, including its one database exception (the Better Auth
26
+ adapter). Everything else server-side goes through `apps/api`.
27
27
  2. The page or component you're modifying, plus any sibling files in
28
28
  the same directory.
29
29
  3. Any project-local theme override file before touching styles —
@@ -46,7 +46,8 @@ Run `pnpm preflight` before opening a PR.
46
46
  - Need a new content type? Add it under `content/<TypeName>/` and
47
47
  reference the schema from `@working-theory/schema`.
48
48
  - Need a database read? Wrong layer — `apps/web` does not read the
49
- database. Route through `apps/api`.
49
+ database outside the one exception `.claude/rules/architecture.md`
50
+ names. Route through `apps/api`.
50
51
 
51
52
  ## Domain conventions
52
53
 
@@ -55,23 +56,24 @@ Run `pnpm preflight` before opening a PR.
55
56
  Adding `'use client'` to a file that just renders JSX is the
56
57
  default failure mode — resist it.
57
58
  - **Tailwind tokens only.** No raw hex, rgb, or arbitrary colors.
58
- Use semantic tokens from `@working-theory/theme` (`bg-canvas`, `text-fg`,
59
+ Use semantic tokens from `@working-theory/theme` (`bg-surface`, `text-fg`,
59
60
  `border-border`, etc.). If a token doesn't exist, extend the theme;
60
61
  don't bypass.
61
62
  - **Mobile-first responsive.** Default styles target mobile;
62
63
  `md:`/`lg:` modifiers for larger viewports.
63
64
  - **MDX rendering** uses `next-mdx-remote/rsc`, never `@next/mdx`
64
65
  (the latter requires runtime config that fights Server Components).
65
- - **NextAuth handlers** are the only API-shaped code in `apps/web`
66
- — they live at `apps/web/app/api/auth/[...nextauth]/route.ts`.
66
+ - **Better Auth's route handler** is the only API-shaped code in
67
+ `apps/web` — it lives at `apps/web/app/api/auth/[...all]/route.ts`.
67
68
  Everything else goes to `apps/api`.
68
69
 
69
70
  ## Forbidden
70
71
 
71
72
  - Importing from `apps/api` or `apps/mcp` — these are peer apps;
72
73
  speak to the API via `@working-theory/api-client`.
73
- - Importing `@working-theory/database` — `apps/web` does not touch the DB;
74
- route through `apps/api`.
74
+ - Importing `@working-theory/database` outside the Better Auth adapter
75
+ (the exception `.claude/rules/architecture.md` names) — route through
76
+ `apps/api`.
75
77
  - Importing `resend`, `@react-email/*` directly — wrap through
76
78
  `@working-theory/email`, server-side via `apps/api`.
77
79
  - Adding a `utils.ts`, `helpers.ts`, `common.ts`, or `misc.ts` file
@@ -25,13 +25,16 @@ other.
25
25
  or `@working-theory/schema` (schema.org types).
26
26
  - Need an HTTP call from `apps/web` to `apps/api`? Use
27
27
  `@working-theory/api-client`. Don't import API route handlers directly.
28
- - Need database access? Only `apps/api` and `apps/mcp` import
29
- `@working-theory/database`. `apps/web` never reads the database directly — it
30
- goes through the HTTP API.
31
- - Cross-cutting integrations (auth, email, analytics) go through their
32
- wrapper packages: `@working-theory/auth-client`, `@working-theory/email`,
33
- `@working-theory/analytics`. Never import `next-auth`, `resend`, etc.
34
- directly.
28
+ - Need database access? `apps/api` and `apps/mcp` import
29
+ `@working-theory/database`. `apps/web` does not read the database — it goes
30
+ through `apps/api` via the published HTTP client. The one exception is the
31
+ Better Auth adapter (`apps/web/lib/prisma-for-auth.ts`, typed in
32
+ `apps/web/auth.ts`).
33
+ - Cross-cutting integrations (email, analytics) go through their
34
+ wrapper packages: `@working-theory/email`, `@working-theory/analytics`.
35
+ Never import `resend`, etc. directly. Auth has no wrapper package: it is
36
+ Better Auth, configured in `apps/web/auth.ts` and mounted at
37
+ `apps/web/app/api/auth/[...all]/route.ts`.
35
38
 
36
39
  ## What you can verify, what you can't
37
40
 
@@ -11,5 +11,17 @@
11
11
  ]
12
12
  }
13
13
  ]
14
+ },
15
+ "extraKnownMarketplaces": {
16
+ "working-theory": {
17
+ "source": {
18
+ "source": "github",
19
+ "repo": "working-theory-labs/claude-plugins"
20
+ },
21
+ "autoUpdate": true
22
+ }
23
+ },
24
+ "enabledPlugins": {
25
+ "ailk@working-theory": true
14
26
  }
15
27
  }
@@ -40,6 +40,8 @@ CONTENT_ADAPTER=mdx
40
40
 
41
41
  # ── Database (optional in standalone mode) ───────────────────────────────────
42
42
  # DATABASE_URL=postgres://user:pass@host:5432/db
43
+ # Direct (non-pooled) URL that `prisma migrate` uses (database/prisma.config.ts).
44
+ # DATABASE_URL_NON_POOLED=
43
45
 
44
46
  # ── Stripe (sandbox keys only — never sk_live_/pk_live_) ─────────────────────
45
47
  # STRIPE_SECRET_KEY=sk_test_...
@@ -57,6 +59,23 @@ CONTENT_ADAPTER=mdx
57
59
  # BETTER_AUTH_URL=http://localhost:3000
58
60
  # BETTER_AUTH_SECRET=
59
61
 
62
+ # ── API origin checks + checkout gate (apps/api) ─────────────────────────────
63
+ # Unset in production, either one makes the API log a startup warning; the
64
+ # API keeps running.
65
+ # FRONTEND_URL is the site the browser loads (no trailing slash). Set it on the
66
+ # API project: unset in production, CORS, cookie origin checks and the
67
+ # billing-portal return URLs fall back to http://localhost:3000, and checkout
68
+ # answers 500 to a caller without X-Internal-Auth.
69
+ # FRONTEND_URL=https://your-domain.com
70
+ # OSS_API_INTERNAL_SECRET gates POST /v1/checkout/sessions. Unset, the route
71
+ # admits every caller. Set, it answers 401 to any caller that does not send it
72
+ # as X-Internal-Auth — including the MCP start_purchase tool and a browser
73
+ # calling the API directly — so set it only when every checkout caller is a
74
+ # server that sends the header. Use the same value on the API and on each such
75
+ # caller.
76
+ # Generate with: openssl rand -hex 32
77
+ # OSS_API_INTERNAL_SECRET=
78
+
60
79
  # ── Single-tenant operator pin (apps/api) ────────────────────────────────────
61
80
  # REQUIRED on a build WITHOUT the multi-tenant module — for the submissions
62
81
  # review dashboard AND for the `workspace` module's settings surface.
@@ -295,7 +314,7 @@ CONTENT_ADAPTER=mdx
295
314
  # AILK_LICENSE_KEY=
296
315
  # Override the daily refresh upstream (self-hosters point at their own server
297
316
  # implementing the @working-theory/validation refresh contract).
298
- # Default: https://ailaunchkit.ai/api/license/refresh
317
+ # Default: https://api.ailaunchkit.ai/v1/licenses/refresh
299
318
  # AILK_LICENSE_REFRESH_URL=
300
319
  # Self-host override — replaces the bundled public key with a PEM-encoded one.
301
320
  # Only set this if you operate your own license-signing infrastructure.
@@ -351,8 +370,10 @@ CONTENT_ADAPTER=mdx
351
370
  # AILK_TEST_AUTH_USER_ALLOWLIST=
352
371
 
353
372
  # ── Lead capture file store ───────────────────────────────────────────────────
354
- # Always-on JSONL write path — every successful submission appends a line.
355
- # Default output: apps/api/leads.jsonl (relative to process cwd).
373
+ # Outside production, every successful submission appends one JSONL line here,
374
+ # whichever destination delivered it. In production the write is skipped unless
375
+ # LEAD_CAPTURE_FILE is set, and then it is a side copy, never the delivery.
376
+ # Default: apps/api/leads.jsonl (relative to process cwd).
356
377
  # LEAD_CAPTURE_FILE=apps/api/leads.jsonl
357
378
  # Set to "true" to disable file writes (leads go to DB only; requires DATABASE_URL).
358
379
  # LEAD_CAPTURE_FILE_DISABLED=false