create-ailk 0.9.0 → 0.10.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 (50) hide show
  1. package/README.md +3 -3
  2. package/dist/cli.js +12 -1
  3. package/dist/lib/module-license-gate.d.ts +29 -23
  4. package/dist/lib/module-license-gate.js +98 -0
  5. package/dist/module-architecture.js +5 -4
  6. package/dist/programmatic.js +12 -4
  7. package/dist/starter-grid.d.ts +4 -67
  8. package/dist/starter-grid.js +6 -84
  9. package/dist/template-manifest.d.ts +1 -1
  10. package/dist/template-manifest.js +5 -5
  11. package/package.json +4 -2
  12. package/release-scope.json +25 -0
  13. package/site-templates/designs/minimalism/sample/README.md +2 -2
  14. package/site-templates/designs/minimalism/sample/content/en/HomePage/home.mdx +1 -1
  15. package/templates/.claude/agents/web.md +10 -8
  16. package/templates/.claude/rules/architecture.md +10 -7
  17. package/templates/.claude/skills/add-auth/SKILL.md +142 -90
  18. package/templates/.claude/skills/add-auth/references/env-vars.md +9 -1
  19. package/templates/.claude/skills/add-auth/references/oauth-app-setup.md +14 -6
  20. package/templates/.claude/skills/add-page/references/page-types.md +9 -10
  21. package/templates/.claude/skills/check-site/SKILL.md +28 -18
  22. package/templates/.claude/skills/check-site/references/common-errors.md +12 -9
  23. package/templates/.claude/skills/check-site/references/findings-glossary.md +4 -4
  24. package/templates/.claude/skills/check-site/references/severity-levels.md +3 -3
  25. package/templates/.claude/skills/setup-deploy/SKILL.md +75 -38
  26. package/templates/.claude/skills/update-page/SKILL.md +1 -1
  27. package/templates/.env.example +23 -2
  28. package/templates/CLAUDE.md +1 -1
  29. package/templates/package.json +2 -0
  30. package/dist/modules/commerce/0.6.0.tar.gz +0 -0
  31. package/dist/modules/commerce/0.6.1.tar.gz +0 -0
  32. package/dist/modules/docs-blog/0.6.0.tar.gz +0 -0
  33. package/dist/modules/docs-blog/0.6.1.tar.gz +0 -0
  34. package/dist/modules/marketing-site/0.6.1.tar.gz +0 -0
  35. package/dist/modules/minimalism-site/0.6.1.tar.gz +0 -0
  36. package/dist/modules/multi-tenant/0.6.0.tar.gz +0 -0
  37. package/dist/modules/multi-tenant/0.6.1.tar.gz +0 -0
  38. package/dist/modules/saas-product/0.6.1.tar.gz +0 -0
  39. package/dist/modules/scheduling/0.6.0.tar.gz +0 -0
  40. package/dist/modules/scheduling/0.6.1.tar.gz +0 -0
  41. package/dist/modules/signal-collectors/0.6.0.tar.gz +0 -0
  42. package/dist/modules/signal-collectors/0.6.1.tar.gz +0 -0
  43. package/dist/modules/simple-service/0.6.1.tar.gz +0 -0
  44. package/dist/modules/workspace/0.6.0.tar.gz +0 -0
  45. package/dist/modules/workspace/0.6.1.tar.gz +0 -0
  46. package/site-templates/aliases/minimalism-site.TEMPLATE-MANIFEST.json +0 -538
  47. package/templates/.claude/skills/setup-deploy/references/env-vars-template.md +0 -192
  48. package/templates/apps/api/.ailk/inbox/2026-09-20T14-57-31.552Z-fallback-1789916251590-037e9005.json +0 -8
  49. package/templates/apps/api/.ailk/inbox/2026-09-20T14-57-33.840Z-fallback-1789916253842-b52659e9.json +0 -12
  50. package/templates/apps/api/.ailk/inbox/2026-09-20T14-57-33.844Z-fallback-1789916253845-6b266f8c.json +0 -12
package/README.md CHANGED
@@ -52,9 +52,9 @@ pnpm create ailk@latest my-site --shape organization-service --license <key>
52
52
 
53
53
  `--design minimalism` picks the other look and needs a Pro or Pro Plus key;
54
54
  `standard` (the default) needs none. `--template <alias>` scaffolds one of the
55
- four named aliases (`marketing-site-free`, `marketing-site`, `saas-product`,
56
- `minimalism-site`) — each fixes a shape, a design and its own module list — and
57
- cannot be combined with `--shape` or `--design`.
55
+ three named aliases (`marketing-site-free`, `marketing-site`, `saas-product`) —
56
+ each fixes a shape, a design and its own module list — and cannot be combined
57
+ with `--shape` or `--design`.
58
58
 
59
59
  ### Add a purchased module to an existing site
60
60
 
package/dist/cli.js CHANGED
@@ -43,6 +43,7 @@ import { ADD_ROUTE_HELP, AddRouteRefusedError, addRouteToScaffold, formatAddRout
43
43
  import { APPLY_DESIGN_HELP, applyDesign, formatApplyDesignReport, parseApplyDesignArgs, } from "./apply-design.js";
44
44
  import { CLAUDE_MD_CHECK_PATH } from "./claude-md.js";
45
45
  import { buildScaffoldMarkers } from "./copy.js";
46
+ import { assertReleased } from "./lib/module-license-gate.js";
46
47
  import { FREE_PREREQUISITES_NOTE, LICENSED_PREREQUISITES_NOTE, isLicensedInstall, proCallout, } from "./lib/pro-callout.js";
47
48
  import { LICENSE_SET_HELP, runLicenseSet } from "./license-set.js";
48
49
  import { helpText, parseCliArgs, parseModules, resolveCliShape, toScaffoldOptions, } from "./parse-args.js";
@@ -207,7 +208,17 @@ async function main() {
207
208
  }
208
209
  // No silent default (#6754 D2/D3): a scaffold run naming neither --shape
209
210
  // nor --template asks for a shape on a terminal and is refused without one.
210
- const opts = await resolveCliShape(parseCliArgs(argv, { interactive: process.stdin.isTTY === true }), { input: process.stdin, output: process.stdout });
211
+ // A --design or --modules outside the release scope is refused before that
212
+ // prompt asks anything (#6984); scaffold() checks the full run again.
213
+ const parsed = parseCliArgs(argv, { interactive: process.stdin.isTTY === true });
214
+ if (parsed.needsShapePrompt && !parsed.help && !parsed.version) {
215
+ assertReleased("designs", [parsed.design]);
216
+ assertReleased("modules", parsed.modules ?? []);
217
+ }
218
+ const opts = await resolveCliShape(parsed, {
219
+ input: process.stdin,
220
+ output: process.stdout,
221
+ });
211
222
  // Deprecation notice for a retired `--surfaces` id (#5563 D2). `surfaces.ts`
212
223
  // stays pure — `canonicalizeSurface` only resolves the alias — so this is
213
224
  // the one place that prints: compare the raw `--surfaces` argv token
@@ -1,26 +1,3 @@
1
- /**
2
- * Paid-module license gate (K1, #5089 — Flavor 3). Orchestrates
3
- * `module-tier.ts`'s classification + `fetch-module.ts`'s authenticated
4
- * fetch into the three honest states the CLI must surface:
5
- *
6
- * (a) no key + a paid module requested → conversion hint, non-zero, ZERO
7
- * network (mirrors `install-skill.ts`'s free-tier short-circuit).
8
- * (b) a lapsed/invalid key + a paid module → "your licence does not cover
9
- * this", non-zero (the module distribution's own 401 — see
10
- * `fetch-module.ts`'s file doc for why there is no local JWT
11
- * pre-check here).
12
- * (c) a valid key → every requested paid module's bundle bytes, ready for
13
- * `extract-module-bundle.ts` to merge into the scaffold.
14
- *
15
- * A Free-only request (no paid modules) never reaches the key check at all —
16
- * `resolvePaidModules` returns immediately, before touching `process.env` or
17
- * the network, so a bare/all-Free scaffold is provably unaffected by this
18
- * gate (K1's regression floor).
19
- *
20
- * Also carries the design gate (#6760): `assertDesignAllowed` refuses a
21
- * non-`standard` design at the `free` level, naming the design and the
22
- * run's level, before `scaffold()`'s first disk write.
23
- */
24
1
  import type { ModuleName } from "../parse-args.js";
25
2
  import { type Level } from "./module-tier.js";
26
3
  /**
@@ -38,6 +15,35 @@ export declare const CONVERSION_HINT_URL = "https://ailaunchkit.ai/pricing";
38
15
  export declare class LicenseRequiredError extends Error {
39
16
  constructor(message: string);
40
17
  }
18
+ /** The five axes `release-scope.json` declares (spec 6977 D3). */
19
+ export type ReleaseAxis = "templates" | "shapes" | "designs" | "modules" | "levels";
20
+ /** `gated` and `deferred` are both refused; only a `gated` one gets negative checks. */
21
+ export type ReleaseStatus = "released" | "gated" | "deferred";
22
+ export type ReleaseScope = Readonly<Record<ReleaseAxis, Readonly<Record<string, ReleaseStatus>>>>;
23
+ /**
24
+ * The package-root `release-scope.json` (shipped in `files`). A static JSON
25
+ * import, not an `import.meta.url` read, for `fetch-module.ts`'s reason: jest
26
+ * loads this module directly. `release-scope.test.ts` pins every registry
27
+ * name to an entry here (R5).
28
+ */
29
+ export declare const RELEASE_SCOPE: ReleaseScope;
30
+ /** Thrown for a surface outside the release scope — a refusal, not a licence state. */
31
+ export declare class ReleaseScopeError extends Error {
32
+ constructor(message: string);
33
+ }
34
+ /**
35
+ * Refuse any of `names` that `scope[axis]` marks `gated` or `deferred`, with
36
+ * the not-available message `parse-args.ts` gives a reserved shape. A name
37
+ * the scope does not list (a customer's own design, say) is not refused.
38
+ * Bypassed when `AILK_RELEASE_SCOPE=ignore` — this package's jest setup and
39
+ * an operator's own run; a published CLI never sets it.
40
+ *
41
+ * Called on the scaffold path only (`scaffold()`, `cli.ts`, and the level
42
+ * check in `resolveModuleSet`) — never from `parseModules`, so `add-module`
43
+ * and `--sync-architecture` keep working on a site that already carries a
44
+ * gated module.
45
+ */
46
+ export declare function assertReleased(axis: ReleaseAxis, names: readonly (string | undefined)[], scope?: ReleaseScope): void;
41
47
  /**
42
48
  * Design names every level renders (#6760 D1). Anything else in
43
49
  * `STARTER_DESIGNS` is Pro and up. A path design's Free-ness is decided by
@@ -1,3 +1,31 @@
1
+ /**
2
+ * Paid-module license gate (K1, #5089 — Flavor 3). Orchestrates
3
+ * `module-tier.ts`'s classification + `fetch-module.ts`'s authenticated
4
+ * fetch into the three honest states the CLI must surface:
5
+ *
6
+ * (a) no key + a paid module requested → conversion hint, non-zero, ZERO
7
+ * network (mirrors `install-skill.ts`'s free-tier short-circuit).
8
+ * (b) a lapsed/invalid key + a paid module → "your licence does not cover
9
+ * this", non-zero (the module distribution's own 401 — see
10
+ * `fetch-module.ts`'s file doc for why there is no local JWT
11
+ * pre-check here).
12
+ * (c) a valid key → every requested paid module's bundle bytes, ready for
13
+ * `extract-module-bundle.ts` to merge into the scaffold.
14
+ *
15
+ * A Free-only request (no paid modules) never reaches the key check at all —
16
+ * `resolvePaidModules` returns immediately, before touching `process.env` or
17
+ * the network, so a bare/all-Free scaffold is provably unaffected by this
18
+ * gate (K1's regression floor).
19
+ *
20
+ * Also carries the design gate (#6760): `assertDesignAllowed` refuses a
21
+ * non-`standard` design at the `free` level, naming the design and the
22
+ * run's level, before `scaffold()`'s first disk write.
23
+ *
24
+ * And the release-scope gate (#6984, spec 6977 D3): `assertReleased` refuses
25
+ * a template, shape, design, module or level that `release-scope.json` marks
26
+ * `gated` or `deferred`, on the scaffold path only.
27
+ */
28
+ import releaseScopeJson from "../../release-scope.json" with { type: "json" };
1
29
  import { FetchModuleError, fetchModule } from "./fetch-module.js";
2
30
  import { assertLicenseKeyShape } from "./license-key-files.js";
3
31
  import { ADD_ONS, LEVEL_LABEL, LEVEL_MODULES, OPT_IN_MODULES, PAID_MODULES, classifyModules, composeModuleSet, levelOf, } from "./module-tier.js";
@@ -19,6 +47,74 @@ export class LicenseRequiredError extends Error {
19
47
  this.name = "LicenseRequiredError";
20
48
  }
21
49
  }
50
+ /**
51
+ * The package-root `release-scope.json` (shipped in `files`). A static JSON
52
+ * import, not an `import.meta.url` read, for `fetch-module.ts`'s reason: jest
53
+ * loads this module directly. `release-scope.test.ts` pins every registry
54
+ * name to an entry here (R5).
55
+ */
56
+ export const RELEASE_SCOPE = releaseScopeJson;
57
+ const AXIS_NOUN = {
58
+ templates: "template",
59
+ shapes: "shape",
60
+ designs: "design",
61
+ modules: "module",
62
+ levels: "level",
63
+ };
64
+ /** Thrown for a surface outside the release scope — a refusal, not a licence state. */
65
+ export class ReleaseScopeError extends Error {
66
+ constructor(message) {
67
+ super(message);
68
+ this.name = "ReleaseScopeError";
69
+ }
70
+ }
71
+ const RELEASE_STATUSES = ["released", "gated", "deferred"];
72
+ /**
73
+ * Refuse a scope carrying a status other than `released`, `gated` or
74
+ * `deferred` — fail closed: a misspelled status never reads as released.
75
+ */
76
+ function assertValidScope(scope) {
77
+ for (const [axis, statuses] of Object.entries(scope)) {
78
+ for (const [name, status] of Object.entries(statuses)) {
79
+ if (!RELEASE_STATUSES.includes(status)) {
80
+ throw new ReleaseScopeError(`release-scope.json ${axis}."${name}" is "${String(status)}" — expected one of: ${RELEASE_STATUSES.join(", ")}`);
81
+ }
82
+ }
83
+ }
84
+ }
85
+ /**
86
+ * Refuse any of `names` that `scope[axis]` marks `gated` or `deferred`, with
87
+ * the not-available message `parse-args.ts` gives a reserved shape. A name
88
+ * the scope does not list (a customer's own design, say) is not refused.
89
+ * Bypassed when `AILK_RELEASE_SCOPE=ignore` — this package's jest setup and
90
+ * an operator's own run; a published CLI never sets it.
91
+ *
92
+ * Called on the scaffold path only (`scaffold()`, `cli.ts`, and the level
93
+ * check in `resolveModuleSet`) — never from `parseModules`, so `add-module`
94
+ * and `--sync-architecture` keep working on a site that already carries a
95
+ * gated module.
96
+ */
97
+ export function assertReleased(axis, names, scope = RELEASE_SCOPE) {
98
+ if (process.env["AILK_RELEASE_SCOPE"] === "ignore")
99
+ return;
100
+ assertValidScope(scope);
101
+ const statuses = scope[axis];
102
+ for (const name of names) {
103
+ if (name === undefined)
104
+ continue;
105
+ const status = statuses[name];
106
+ if (status !== "gated" && status !== "deferred")
107
+ continue;
108
+ const released = Object.keys(statuses).filter((n) => statuses[n] === "released");
109
+ // A level comes from the key, never a flag — so it points at what the run CAN choose.
110
+ const choose = axis === "levels"
111
+ ? `Your licence key's level is ${name}; name the modules you want with --modules (one of: ${Object.keys(scope.modules)
112
+ .filter((m) => scope.modules[m] === "released")
113
+ .join(", ")}).`
114
+ : `Choose one of: ${released.join(", ")}.`;
115
+ throw new ReleaseScopeError(`${AXIS_NOUN[axis]} "${name}" is not available yet. ${choose}`);
116
+ }
117
+ }
22
118
  /**
23
119
  * Design names every level renders (#6760 D1). Anything else in
24
120
  * `STARTER_DESIGNS` is Pro and up. A path design's Free-ness is decided by
@@ -223,6 +319,8 @@ export async function resolveModuleSet(options) {
223
319
  return { modules, bundles };
224
320
  }
225
321
  const { level, bundles } = await deriveLevel(options);
322
+ // #6984 — a gated level (Pro Plus) is refused before its defaults compose.
323
+ assertReleased("levels", [level]);
226
324
  const modules = composeModuleSet(namedList, level);
227
325
  const { paid } = classifyModules(modules);
228
326
  const missing = paid.filter((m) => !bundles.has(m));
@@ -1503,8 +1503,8 @@ export const MODULE_SLICES = {
1503
1503
  // module's own `pageContributions`/`starter-grid.ts` rows respectively,
1504
1504
  // so this module installs its own seeds for them directly, unlike the
1505
1505
  // sample rows above. `/referral`'s seed and flow move here the same way,
1506
- // moved out of the retired `minimalism-site` tree (spec 6892 D3), which
1507
- // owned no code of its own for either route.
1506
+ // moved out of a retired template tree (spec 6892 D3), which owned no
1507
+ // code of its own for either route.
1508
1508
  // `generate-sample-report.py` keeps its root-level destination
1509
1509
  // (finding 1 — AC7 forbids changing the Pro file set).
1510
1510
  installMap: {
@@ -1661,7 +1661,7 @@ export const MODULE_SLICES = {
1661
1661
  // it sits outside build-templates.mjs's SNAPSHOT_DIRS/overlay, so
1662
1662
  // ownedFiles/paidModuleTemplateExclusions cannot reach it) to
1663
1663
  // `module-templates/commerce/.claude/skills/scaffold-commerce/`, and
1664
- // delivered into a keyed scaffold by `installMap` instead. Ten literal
1664
+ // delivered into a keyed scaffold by `installMap` instead. Eleven literal
1665
1665
  // entries, not one directory entry: `extractModuleBundle`'s
1666
1666
  // `validateInstallMap` requires every source to be a FILE the bundle
1667
1667
  // produced (`extract-module-bundle.ts`'s `!sourceStat.isFile()` check) —
@@ -1677,10 +1677,11 @@ export const MODULE_SLICES = {
1677
1677
  "packages/create-ailk/module-templates/commerce/.claude/skills/scaffold-commerce/templates/portal-route.template.ts": ".claude/skills/scaffold-commerce/templates/portal-route.template.ts",
1678
1678
  "packages/create-ailk/module-templates/commerce/.claude/skills/scaffold-commerce/templates/stripe-config.template.ts": ".claude/skills/scaffold-commerce/templates/stripe-config.template.ts",
1679
1679
  "packages/create-ailk/module-templates/commerce/.claude/skills/scaffold-commerce/templates/subscription-route.template.ts": ".claude/skills/scaffold-commerce/templates/subscription-route.template.ts",
1680
+ "packages/create-ailk/module-templates/commerce/.claude/skills/scaffold-commerce/scripts/stripe-catalog.ts": ".claude/skills/scaffold-commerce/scripts/stripe-catalog.ts",
1680
1681
  // The commerce-boundary rule (#6039/#6070, this entry #6041): ships to
1681
1682
  // a commerce-keyed scaffold's project root so an agent working there
1682
1683
  // reads the money/live-mode/personal-data classification before it
1683
- // acts. One more literal entry alongside the ten scaffold-commerce
1684
+ // acts. One more literal entry alongside the eleven scaffold-commerce
1684
1685
  // skill entries above, for the same reason — a directory source is
1685
1686
  // rejected by `validateInstallMap`.
1686
1687
  "packages/create-ailk/module-templates/commerce/.claude/rules/commerce-boundary.md": ".claude/rules/commerce-boundary.md",
@@ -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
@@ -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.10.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",
@@ -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
  {