create-ailk 0.8.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.
- package/README.md +71 -3
- package/component-catalog.json +279 -45
- package/dist/add-module.d.ts +20 -0
- package/dist/add-module.js +43 -7
- package/dist/add-route.d.ts +56 -0
- package/dist/add-route.js +286 -0
- package/dist/apply-design-md.d.ts +7 -0
- package/dist/apply-design-md.js +50 -0
- package/dist/apply-design.d.ts +64 -0
- package/dist/apply-design.js +273 -0
- package/dist/claude-md.d.ts +111 -0
- package/dist/claude-md.js +334 -0
- package/dist/cli.js +104 -5
- package/dist/derive-architecture.js +41 -36
- package/dist/design-compile.d.ts +71 -0
- package/dist/design-compile.js +98 -0
- package/dist/design-package.d.ts +83 -0
- package/dist/design-package.js +468 -0
- package/dist/design-presets.d.ts +86 -0
- package/dist/design-presets.js +642 -0
- package/dist/design-scaffold.d.ts +76 -0
- package/dist/design-scaffold.js +220 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +4 -1
- package/dist/legacy-nav-renderers.d.ts +45 -0
- package/dist/legacy-nav-renderers.js +545 -0
- package/dist/lib/auth-secret-file.d.ts +19 -0
- package/dist/lib/auth-secret-file.js +112 -0
- package/dist/lib/design-checks.d.ts +78 -0
- package/dist/lib/design-checks.js +174 -0
- package/dist/lib/license-key-files.d.ts +9 -0
- package/dist/lib/license-key-files.js +2 -2
- package/dist/lib/module-license-gate.d.ts +48 -32
- package/dist/lib/module-license-gate.js +117 -8
- package/dist/lib/render-verdict.d.ts +52 -0
- package/dist/lib/render-verdict.js +77 -0
- package/dist/lib/scaffold-render-sweep.d.ts +105 -0
- package/dist/lib/scaffold-render-sweep.js +236 -0
- package/dist/module-architecture.d.ts +19 -16
- package/dist/module-architecture.js +67 -23
- package/dist/parse-args.d.ts +12 -2
- package/dist/parse-args.js +74 -13
- package/dist/programmatic.d.ts +30 -6
- package/dist/programmatic.js +216 -19
- package/dist/site-chrome.d.ts +19 -9
- package/dist/site-chrome.js +23 -13
- package/dist/site-manifest.d.ts +25 -0
- package/dist/site-manifest.js +254 -0
- package/dist/site-roster.d.ts +41 -0
- package/dist/site-roster.js +141 -8
- package/dist/starter-grid.d.ts +16 -63
- package/dist/starter-grid.js +102 -84
- package/dist/surfaces.d.ts +41 -9
- package/dist/surfaces.js +200 -83
- package/dist/template-manifest.d.ts +30 -13
- package/dist/template-manifest.js +53 -28
- package/package.json +6 -3
- package/release-scope.json +25 -0
- package/site-templates/_base/content/en/UseCase/persona-1.mdx +7 -6
- package/site-templates/_base/content/en/UseCase/persona-2.mdx +7 -6
- package/site-templates/_base/content/en/UseCase/persona-3.mdx +7 -6
- package/site-templates/designs/minimalism/DESIGN.md +98 -6
- package/site-templates/designs/minimalism/sample/README.md +48 -0
- package/site-templates/{minimalism-site → designs/minimalism/sample}/content/en/HomePage/home.mdx +1 -1
- package/site-templates/designs/standard/DESIGN.md +98 -6
- package/site-templates/marketing-site/DESIGN.md +98 -6
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +60 -27
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +50 -30
- package/site-templates/marketing-site-free/DESIGN.md +98 -6
- package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.json +60 -24
- package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.md +44 -27
- package/site-templates/marketing-site-free/ailk-template.json +1 -1
- package/site-templates/saas-product/DESIGN.md +98 -6
- package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.json +127 -18
- package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.md +74 -20
- package/site-templates/shapes/local-business-service/ailk-template.json +1 -1
- package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.json +127 -18
- package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.md +74 -20
- package/site-templates/shapes/organization-service/ailk-template.json +1 -1
- package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.json +127 -18
- package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.md +75 -21
- package/site-templates/shapes/person-service/ailk-template.json +1 -1
- package/site-templates/shapes/person-service/content/en/AboutPage/about.mdx +1 -1
- package/site-templates/shapes/person-service/content/en/HomePage/home.mdx +2 -2
- package/site-templates/shapes/person-service/content/en/PortfolioList/portfolio.mdx +4 -2
- package/site-templates/shapes/person-service/content/en/ServicesList/services.mdx +1 -1
- package/templates/.claude/agents/web.md +10 -8
- package/templates/.claude/rules/architecture.md +17 -7
- package/templates/.claude/skills/README.md +3 -2
- package/templates/.claude/skills/add-auth/SKILL.md +142 -90
- package/templates/.claude/skills/add-auth/references/env-vars.md +32 -17
- package/templates/.claude/skills/add-auth/references/oauth-app-setup.md +17 -8
- package/templates/.claude/skills/add-page/SKILL.md +241 -238
- package/templates/.claude/skills/add-page/references/page-types.md +94 -86
- package/templates/.claude/skills/add-page/scripts/site-pages.mjs +87 -0
- package/templates/.claude/skills/add-page/templates/comparison-page.mdx.tmpl +99 -0
- package/templates/.claude/skills/add-page/templates/content.mdx.tmpl +8 -18
- package/templates/.claude/skills/add-page/templates/flow-landing-page.mdx.tmpl +43 -0
- package/templates/.claude/skills/add-page/templates/report-page.mdx.tmpl +52 -0
- package/templates/.claude/skills/add-page/templates/reports-list.mdx.tmpl +38 -0
- package/templates/.claude/skills/check-site/SKILL.md +51 -18
- package/templates/.claude/skills/check-site/references/common-errors.md +12 -9
- package/templates/.claude/skills/check-site/references/findings-glossary.md +4 -4
- package/templates/.claude/skills/check-site/references/severity-levels.md +3 -3
- package/templates/.claude/skills/fill-page/SKILL.md +26 -7
- package/templates/.claude/skills/fill-page/profiles/plumbing.yaml +1 -1
- package/templates/.claude/skills/setup-deploy/SKILL.md +75 -38
- package/templates/.claude/skills/update-page/SKILL.md +117 -0
- package/templates/.claude/skills/update-page/scripts/update-page.ts +640 -0
- package/templates/.claude/skills/update-page/templates/redirects.mjs.tmpl +31 -0
- package/templates/.claude/skills/upgrade-plan/SKILL.md +12 -8
- package/templates/.env.example +23 -2
- package/templates/.github/workflows/ci.yml +4 -0
- package/templates/.prettierignore +1 -0
- package/templates/CLAUDE.md +146 -103
- package/templates/DESIGN.md +98 -6
- package/templates/README.md +50 -38
- package/templates/apps/api/.env.example +2 -1
- package/templates/apps/api/src/__tests__/commerce-claim-registration.test.ts +2 -0
- package/templates/apps/api/src/__tests__/server.test.ts +116 -0
- package/templates/apps/api/src/lib/stripe.ts +9 -0
- package/templates/apps/api/src/middleware/__tests__/auth.optional-cookie.test.ts +140 -0
- package/templates/apps/api/src/middleware/auth.ts +54 -0
- package/templates/apps/api/src/routes/checkout/__tests__/session.test.ts +5 -2
- package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +628 -0
- package/templates/apps/api/src/routes/checkout/sessions.ts +222 -24
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-flow-checkout.test.ts +1 -1
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +5 -1
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +521 -20
- package/templates/apps/api/src/routes/webhooks/stripe.ts +124 -32
- package/templates/apps/api/src/server.ts +28 -0
- package/templates/apps/api/src/services/__tests__/revalidation.test.ts +90 -15
- package/templates/apps/api/src/services/checkout-buyer.ts +72 -0
- package/templates/apps/api/src/services/revalidation.ts +60 -15
- package/templates/apps/mcp/__tests__/tools/create_project.test.ts +30 -24
- package/templates/apps/mcp/src/tools/purchase.ts +4 -2
- package/templates/apps/web/.env.example +13 -0
- package/templates/apps/web/CLAUDE.md +22 -28
- package/templates/apps/web/app/[locale]/(auth)/layout.tsx +1 -1
- package/templates/apps/web/app/[locale]/(authed)/leads/__tests__/page.test.tsx +24 -0
- package/templates/apps/web/app/[locale]/(authed)/leads/page.tsx +17 -6
- package/templates/apps/web/app/[locale]/[slug]/[detail]/__tests__/page.test.tsx +110 -0
- package/templates/apps/web/app/[locale]/[slug]/[detail]/page.tsx +60 -0
- package/templates/apps/web/app/[locale]/[slug]/page.tsx +1 -1
- package/templates/apps/web/app/[locale]/alternatives/__tests__/page.test.tsx +161 -0
- package/templates/apps/web/app/[locale]/alternatives/page.tsx +104 -0
- package/templates/apps/web/app/[locale]/{use-cases → for}/[slug]/page.tsx +4 -3
- package/templates/apps/web/app/[locale]/for/__tests__/page-renderer-migration.test.tsx +73 -0
- package/templates/apps/web/app/[locale]/{use-cases → for}/page.tsx +8 -7
- package/templates/apps/web/app/[locale]/glossary/page.tsx +1 -1
- package/templates/apps/web/app/[locale]/layout.tsx +35 -19
- package/templates/apps/web/app/[locale]/newsletter/page.tsx +1 -1
- package/templates/apps/web/app/[locale]/portfolio/[slug]/page.tsx +1 -1
- package/templates/apps/web/app/[locale]/portfolio/page.tsx +1 -1
- package/templates/apps/web/app/[locale]/vs/[slug]/__tests__/page.test.tsx +112 -0
- package/templates/apps/web/app/[locale]/vs/[slug]/page.tsx +70 -0
- package/templates/apps/web/app/api/revalidate/__tests__/route.test.ts +236 -44
- package/templates/apps/web/app/api/revalidate/route.ts +78 -36
- package/templates/apps/web/lib/__tests__/site-brand.test.ts +79 -0
- package/templates/apps/web/lib/__tests__/site-theme.test.ts +104 -11
- package/templates/apps/web/lib/__tests__/structured-data.test.tsx +21 -4
- package/templates/apps/web/lib/locale-guard.ts +18 -0
- package/templates/apps/web/lib/meet-placeholder.ts +5 -0
- package/templates/apps/web/lib/nav-config.ts +14 -13
- package/templates/apps/web/lib/site-brand.tsx +13 -9
- package/templates/apps/web/lib/site-logo.tsx +36 -0
- package/templates/apps/web/lib/site-theme.ts +46 -26
- package/templates/apps/web/messages/en.json +23 -9
- package/templates/apps/web/middleware.ts +28 -4
- package/templates/content/en/BookCall/book-a-call.mdx +80 -0
- package/templates/content/en/BookCall/onsite-estimate.mdx +56 -0
- package/templates/content/en/BookCall/onsite-service.mdx +56 -0
- package/templates/content/en/BookCall/start-project.mdx +56 -0
- package/templates/content/en/ContactPage/contact.mdx +40 -1
- package/templates/content/en/HomePage/home.mdx +2 -6
- package/templates/content/en/LandingPage/meet.mdx +59 -0
- package/templates/content/en/UseCasesList/{use-cases.mdx → for.mdx} +19 -18
- package/templates/database/CHANGELOG.md +7 -0
- package/templates/database/package.json +1 -1
- package/templates/package.json +4 -1
- package/templates/tools/check-claude-md.ts +128 -0
- package/versions.json +33 -33
- package/dist/modules/commerce/0.6.0.tar.gz +0 -0
- package/dist/modules/commerce/0.6.1.tar.gz +0 -0
- package/dist/modules/docs-blog/0.6.0.tar.gz +0 -0
- package/dist/modules/docs-blog/0.6.1.tar.gz +0 -0
- package/dist/modules/marketing-site/0.6.1.tar.gz +0 -0
- package/dist/modules/minimalism-site/0.6.1.tar.gz +0 -0
- package/dist/modules/multi-tenant/0.6.0.tar.gz +0 -0
- package/dist/modules/multi-tenant/0.6.1.tar.gz +0 -0
- package/dist/modules/saas-product/0.6.1.tar.gz +0 -0
- package/dist/modules/scheduling/0.6.0.tar.gz +0 -0
- package/dist/modules/scheduling/0.6.1.tar.gz +0 -0
- package/dist/modules/signal-collectors/0.6.0.tar.gz +0 -0
- package/dist/modules/signal-collectors/0.6.1.tar.gz +0 -0
- package/dist/modules/simple-service/0.6.1.tar.gz +0 -0
- package/dist/modules/workspace/0.6.0.tar.gz +0 -0
- package/dist/modules/workspace/0.6.1.tar.gz +0 -0
- package/site-templates/_base/content/en/BookCall/book-call.mdx +0 -52
- package/site-templates/minimalism-site/DESIGN.md +0 -162
- package/site-templates/minimalism-site/TEMPLATE-MANIFEST.json +0 -506
- package/site-templates/minimalism-site/TEMPLATE-MANIFEST.md +0 -458
- package/site-templates/minimalism-site/ailk-template.json +0 -23
- package/site-templates/minimalism-site/content/en/AboutPage/about.mdx +0 -110
- package/site-templates/minimalism-site/content/en/BookCall/book-call.mdx +0 -52
- package/site-templates/minimalism-site/content/en/ContactPage/contact.mdx +0 -34
- package/site-templates/minimalism-site/content/en/FAQPage/faq.mdx +0 -57
- package/site-templates/minimalism-site/content/en/LandingPage/referral.mdx +0 -77
- package/site-templates/minimalism-site/content/en/LandingPage/reports.mdx +0 -73
- package/site-templates/minimalism-site/content/en/PurchasePolicyPage/purchase-policy.mdx +0 -123
- package/site-templates/minimalism-site/content/en/ReportPage/annual-letter-2024.mdx +0 -52
- package/site-templates/minimalism-site/content/en/ReportPage/field-notes-2023.mdx +0 -52
- package/site-templates/minimalism-site/content/en/ReportPage/platform-shift-2025.mdx +0 -52
- package/site-templates/minimalism-site/content/en/ReportPage/state-of-the-market-2026.mdx +0 -52
- package/site-templates/minimalism-site/content/en/Service/first-engagement.mdx +0 -38
- package/site-templates/minimalism-site/content/en/Service/second-engagement.mdx +0 -38
- package/site-templates/minimalism-site/content/en/Service/third-engagement.mdx +0 -38
- package/site-templates/minimalism-site/content/en/ServicesList/services.mdx +0 -73
- package/site-templates/minimalism-site/flows/referral.flow.json +0 -71
- package/site-templates/minimalism-site/provenance.json +0 -4
- package/templates/.claude/skills/add-page/templates/route.tsx.tmpl +0 -28
- package/templates/.claude/skills/setup-deploy/references/env-vars-template.md +0 -175
- package/templates/apps/api/.ailk/inbox/2026-09-20T14-57-31.552Z-fallback-1789916251590-037e9005.json +0 -8
- package/templates/apps/api/.ailk/inbox/2026-09-20T14-57-33.840Z-fallback-1789916253842-b52659e9.json +0 -12
- package/templates/apps/api/.ailk/inbox/2026-09-20T14-57-33.844Z-fallback-1789916253845-6b266f8c.json +0 -12
- package/templates/apps/web/app/[locale]/book-a-call/page.tsx +0 -50
- package/templates/apps/web/app/[locale]/use-cases/__tests__/page-renderer-migration.test.tsx +0 -72
- /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-1.svg +0 -0
- /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-2.svg +0 -0
- /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-3.svg +0 -0
- /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-4.svg +0 -0
- /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-5.svg +0 -0
- /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-6.svg +0 -0
- /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/hero-backdrop.svg +0 -0
- /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/logo-placeholder-1.svg +0 -0
- /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/logo-placeholder-2.svg +0 -0
- /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/logo-placeholder-3.svg +0 -0
- /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/wordmark-placeholder.svg +0 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { type CompiledDesignTheme } from "./design-compile.js";
|
|
2
|
+
import { type DesignPackage } from "./design-package.js";
|
|
3
|
+
import type { LayerOwnership } from "./lib/extract-module-bundle.js";
|
|
4
|
+
/** One resolved `--design` reference (D2). */
|
|
5
|
+
export interface ResolvedDesign {
|
|
6
|
+
/** "name" when the reference was a registry name, "path" when a directory. */
|
|
7
|
+
kind: "name" | "path";
|
|
8
|
+
/** Absolute directory holding the DESIGN.md. */
|
|
9
|
+
dir: string;
|
|
10
|
+
pkg: DesignPackage;
|
|
11
|
+
/** What the site records: the registry name when `pkg` deep-equals a shipped design's package, else `pkg.name`. */
|
|
12
|
+
recorded: string;
|
|
13
|
+
/** What a refusal names: the name, or the absolute directory. */
|
|
14
|
+
display: string;
|
|
15
|
+
/** True iff `recorded` is in `FREE_DESIGNS` by the identity rule below (D2). */
|
|
16
|
+
free: boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Resolve a design reference to its package (D2). Classification mirrors
|
|
20
|
+
* `parse-args.ts`'s `parseDesign` (D1) exactly, so a programmatic caller
|
|
21
|
+
* accepts the same inputs the CLI does: a value with no `/` or `\` that
|
|
22
|
+
* names a recognized design resolves to `<designsDir>/<name>`; otherwise, if
|
|
23
|
+
* it names an existing directory (relative to `opts.cwd`), it resolves as a
|
|
24
|
+
* path; otherwise it is refused. A value with a separator is always a path.
|
|
25
|
+
*
|
|
26
|
+
* A path's package is compared, by deep equality, against each shipped
|
|
27
|
+
* design's own package: a byte-identical copy of a shipped design IS that
|
|
28
|
+
* design (`recorded`/`free` follow the shipped name), and any authored
|
|
29
|
+
* change makes it a distinct, non-Free design named by its own `pkg.name`.
|
|
30
|
+
*
|
|
31
|
+
* @throws TemplateError on an unrecognized bare name or a missing directory.
|
|
32
|
+
* @throws DesignPackageError (from `readDesignPackage`, never caught here) on
|
|
33
|
+
* a malformed package — naming the file and the field.
|
|
34
|
+
*/
|
|
35
|
+
export declare function resolveDesign(ref: string, opts: {
|
|
36
|
+
designsDir: string;
|
|
37
|
+
cwd?: string;
|
|
38
|
+
}): ResolvedDesign;
|
|
39
|
+
/**
|
|
40
|
+
* Render a compiled theme's `theme:` frontmatter block (D5) — `theme:`, each
|
|
41
|
+
* treatment present as a bare `key: value`, then `colors:` with `light:`/
|
|
42
|
+
* `dark:` sub-blocks, each colour slot as `slot: <JSON.stringify(value)>` in
|
|
43
|
+
* `DESIGN_COLOR_MAP`'s order. Ends with a trailing newline.
|
|
44
|
+
*/
|
|
45
|
+
export declare function renderThemeBlock(theme: CompiledDesignTheme): string;
|
|
46
|
+
/**
|
|
47
|
+
* Splice a compiled theme into `text`'s frontmatter `theme:` block (D5),
|
|
48
|
+
* replacing an existing one in place or inserting a fresh one immediately
|
|
49
|
+
* before the closing `---` when the frontmatter carries none. Nothing
|
|
50
|
+
* outside the block moves — for every committed `_site.mdx` and its own
|
|
51
|
+
* design, this is the identity function (byte-identity floor, AC-4).
|
|
52
|
+
*
|
|
53
|
+
* @throws TemplateError when `text` carries no frontmatter to write into.
|
|
54
|
+
*/
|
|
55
|
+
export declare function spliceThemeBlock(text: string, theme: CompiledDesignTheme, file: string): string;
|
|
56
|
+
/**
|
|
57
|
+
* Install a design's `sample/` directory onto a scaffold (spec 6892 D4) — a
|
|
58
|
+
* FIXED, undeclared convention, not a design-package field: `sample/content/**`
|
|
59
|
+
* lands at the scaffold's `content/**`, `sample/public/**` at
|
|
60
|
+
* `apps/web/public/**`. A design with no `sample/` directory (e.g. `standard`)
|
|
61
|
+
* installs nothing.
|
|
62
|
+
*
|
|
63
|
+
* Refuses — before its first write, so a refused sample leaves `targetDir`
|
|
64
|
+
* untouched — any file outside those two roots, or any `.ts`/`.tsx`/`.js`/
|
|
65
|
+
* `.mjs` file (content only, the template §5.2 rule this design package
|
|
66
|
+
* amendment carries over). Every installed file's destination is recorded in
|
|
67
|
+
* `ownership` as `design:<name>` (`readDesignPackage(designDir).name`), the
|
|
68
|
+
* same call-scoped registry `installBundleTree` writes into.
|
|
69
|
+
*
|
|
70
|
+
* @throws Error on a file outside `content/`/`public/`, or a forbidden extension.
|
|
71
|
+
*/
|
|
72
|
+
export declare function installDesignSample(opts: {
|
|
73
|
+
designDir: string;
|
|
74
|
+
targetDir: string;
|
|
75
|
+
ownership: LayerOwnership;
|
|
76
|
+
}): void;
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve a `--design` reference (a shipped name, or a directory holding a
|
|
3
|
+
* `DESIGN.md`) to its design package, and splice the compiled theme it
|
|
4
|
+
* produces into a scaffold's `content/_site.mdx` (#6813, spec
|
|
5
|
+
* docs/specs/6813-design-accepts-a-package-path-spec.md D2/D5).
|
|
6
|
+
*
|
|
7
|
+
* `resolveDesign` is the one resolver every front door (the CLI, `scaffold()`,
|
|
8
|
+
* `verify-scaffold.mjs`) passes a design reference through, before any
|
|
9
|
+
* network request or write (D8). It never touches `import.meta.url` — every
|
|
10
|
+
* directory it reads is supplied by the caller — so it stays importable from
|
|
11
|
+
* Jest's CJS transform, unlike `programmatic.ts`.
|
|
12
|
+
*/
|
|
13
|
+
import { copyFileSync, existsSync, mkdirSync, readdirSync, statSync, } from "node:fs";
|
|
14
|
+
import { join, relative, resolve, sep } from "node:path";
|
|
15
|
+
import { isDeepStrictEqual } from "node:util";
|
|
16
|
+
import { DESIGN_COLOR_MAP } from "./design-compile.js";
|
|
17
|
+
import { readDesignPackage } from "./design-package.js";
|
|
18
|
+
import { FREE_DESIGNS } from "./lib/module-license-gate.js";
|
|
19
|
+
import { STARTER_DESIGNS, TemplateError } from "./template-manifest.js";
|
|
20
|
+
/** `path` is an existing DIRECTORY — a file at `path` is not (mirrors `parse-args.ts`'s own helper). */
|
|
21
|
+
function isExistingDir(path) {
|
|
22
|
+
try {
|
|
23
|
+
return statSync(path).isDirectory();
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Resolve a design reference to its package (D2). Classification mirrors
|
|
31
|
+
* `parse-args.ts`'s `parseDesign` (D1) exactly, so a programmatic caller
|
|
32
|
+
* accepts the same inputs the CLI does: a value with no `/` or `\` that
|
|
33
|
+
* names a recognized design resolves to `<designsDir>/<name>`; otherwise, if
|
|
34
|
+
* it names an existing directory (relative to `opts.cwd`), it resolves as a
|
|
35
|
+
* path; otherwise it is refused. A value with a separator is always a path.
|
|
36
|
+
*
|
|
37
|
+
* A path's package is compared, by deep equality, against each shipped
|
|
38
|
+
* design's own package: a byte-identical copy of a shipped design IS that
|
|
39
|
+
* design (`recorded`/`free` follow the shipped name), and any authored
|
|
40
|
+
* change makes it a distinct, non-Free design named by its own `pkg.name`.
|
|
41
|
+
*
|
|
42
|
+
* @throws TemplateError on an unrecognized bare name or a missing directory.
|
|
43
|
+
* @throws DesignPackageError (from `readDesignPackage`, never caught here) on
|
|
44
|
+
* a malformed package — naming the file and the field.
|
|
45
|
+
*/
|
|
46
|
+
export function resolveDesign(ref, opts) {
|
|
47
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
48
|
+
const hasSeparator = ref.includes("/") || ref.includes("\\");
|
|
49
|
+
if (!hasSeparator && STARTER_DESIGNS.includes(ref)) {
|
|
50
|
+
const dir = join(opts.designsDir, ref);
|
|
51
|
+
return {
|
|
52
|
+
kind: "name",
|
|
53
|
+
dir,
|
|
54
|
+
pkg: readDesignPackage(dir),
|
|
55
|
+
recorded: ref,
|
|
56
|
+
display: ref,
|
|
57
|
+
free: FREE_DESIGNS.includes(ref),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const dir = resolve(cwd, ref);
|
|
61
|
+
if (!isExistingDir(dir)) {
|
|
62
|
+
throw new TemplateError(hasSeparator
|
|
63
|
+
? `design directory "${ref}" does not exist`
|
|
64
|
+
: `unknown design "${ref}". Declared: ${STARTER_DESIGNS.join(", ")}`);
|
|
65
|
+
}
|
|
66
|
+
const pkg = readDesignPackage(dir);
|
|
67
|
+
for (const name of STARTER_DESIGNS) {
|
|
68
|
+
if (isDeepStrictEqual(pkg, readDesignPackage(join(opts.designsDir, name)))) {
|
|
69
|
+
return {
|
|
70
|
+
kind: "path",
|
|
71
|
+
dir,
|
|
72
|
+
pkg,
|
|
73
|
+
recorded: name,
|
|
74
|
+
display: dir,
|
|
75
|
+
free: FREE_DESIGNS.includes(name),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return { kind: "path", dir, pkg, recorded: pkg.name, display: dir, free: false };
|
|
80
|
+
}
|
|
81
|
+
/** The runtime colour slots, in `DESIGN_COLOR_MAP`'s light-mode row order — the order every committed `theme:` block uses. */
|
|
82
|
+
const RUNTIME_COLOR_SLOT_ORDER = DESIGN_COLOR_MAP.filter((row) => row.mode === "light").map((row) => row.runtime);
|
|
83
|
+
/**
|
|
84
|
+
* Render a compiled theme's `theme:` frontmatter block (D5) — `theme:`, each
|
|
85
|
+
* treatment present as a bare `key: value`, then `colors:` with `light:`/
|
|
86
|
+
* `dark:` sub-blocks, each colour slot as `slot: <JSON.stringify(value)>` in
|
|
87
|
+
* `DESIGN_COLOR_MAP`'s order. Ends with a trailing newline.
|
|
88
|
+
*/
|
|
89
|
+
export function renderThemeBlock(theme) {
|
|
90
|
+
const lines = ["theme:"];
|
|
91
|
+
if (theme.corners !== undefined)
|
|
92
|
+
lines.push(` corners: ${theme.corners}`);
|
|
93
|
+
if (theme.eyebrowCase !== undefined)
|
|
94
|
+
lines.push(` eyebrowCase: ${theme.eyebrowCase}`);
|
|
95
|
+
if (theme.placeholders !== undefined)
|
|
96
|
+
lines.push(` placeholders: ${theme.placeholders}`);
|
|
97
|
+
if (theme.checkmarks !== undefined)
|
|
98
|
+
lines.push(` checkmarks: ${theme.checkmarks}`);
|
|
99
|
+
lines.push(" colors:");
|
|
100
|
+
for (const mode of ["light", "dark"]) {
|
|
101
|
+
lines.push(` ${mode}:`);
|
|
102
|
+
const palette = theme.colors[mode];
|
|
103
|
+
for (const slot of RUNTIME_COLOR_SLOT_ORDER) {
|
|
104
|
+
lines.push(` ${slot}: ${JSON.stringify(palette[slot])}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return `${lines.join("\n")}\n`;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Splice a compiled theme into `text`'s frontmatter `theme:` block (D5),
|
|
111
|
+
* replacing an existing one in place or inserting a fresh one immediately
|
|
112
|
+
* before the closing `---` when the frontmatter carries none. Nothing
|
|
113
|
+
* outside the block moves — for every committed `_site.mdx` and its own
|
|
114
|
+
* design, this is the identity function (byte-identity floor, AC-4).
|
|
115
|
+
*
|
|
116
|
+
* @throws TemplateError when `text` carries no frontmatter to write into.
|
|
117
|
+
*/
|
|
118
|
+
export function spliceThemeBlock(text, theme, file) {
|
|
119
|
+
const lines = text.split("\n");
|
|
120
|
+
let closeIdx = -1;
|
|
121
|
+
if (lines[0] === "---") {
|
|
122
|
+
for (let i = 1; i < lines.length; i += 1) {
|
|
123
|
+
if (lines[i] === "---") {
|
|
124
|
+
closeIdx = i;
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (closeIdx === -1) {
|
|
130
|
+
throw new TemplateError(`${file}: no frontmatter to write the theme into`);
|
|
131
|
+
}
|
|
132
|
+
const rendered = renderThemeBlock(theme).split("\n");
|
|
133
|
+
rendered.pop(); // drop the trailing "" the render's final "\n" split off
|
|
134
|
+
let themeStart = -1;
|
|
135
|
+
let themeEnd = -1;
|
|
136
|
+
for (let i = 1; i < closeIdx; i += 1) {
|
|
137
|
+
if (lines[i] === "theme:") {
|
|
138
|
+
themeStart = i;
|
|
139
|
+
let j = i + 1;
|
|
140
|
+
while (j < closeIdx && (lines[j] === "" || lines[j].startsWith(" "))) {
|
|
141
|
+
j += 1;
|
|
142
|
+
}
|
|
143
|
+
themeEnd = j;
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const next = themeStart === -1
|
|
148
|
+
? [...lines.slice(0, closeIdx), ...rendered, ...lines.slice(closeIdx)]
|
|
149
|
+
: [...lines.slice(0, themeStart), ...rendered, ...lines.slice(themeEnd)];
|
|
150
|
+
return next.join("\n");
|
|
151
|
+
}
|
|
152
|
+
/** Forbidden extensions for a design sample's files (spec 6892 D4) — content only, never code. */
|
|
153
|
+
const SAMPLE_FORBIDDEN_EXTENSIONS = [".ts", ".tsx", ".js", ".mjs"];
|
|
154
|
+
function hasSampleForbiddenExtension(p) {
|
|
155
|
+
return SAMPLE_FORBIDDEN_EXTENSIONS.some((ext) => p.toLowerCase().endsWith(ext));
|
|
156
|
+
}
|
|
157
|
+
/** Every file under `dir`, as `/`-separated paths relative to `dir`. */
|
|
158
|
+
function listFiles(dir) {
|
|
159
|
+
const out = [];
|
|
160
|
+
const stack = [dir];
|
|
161
|
+
for (let cur = stack.pop(); cur !== undefined; cur = stack.pop()) {
|
|
162
|
+
for (const entry of readdirSync(cur, { withFileTypes: true })) {
|
|
163
|
+
const abs = join(cur, entry.name);
|
|
164
|
+
if (entry.isDirectory())
|
|
165
|
+
stack.push(abs);
|
|
166
|
+
else if (entry.isFile())
|
|
167
|
+
out.push(relative(dir, abs).split(sep).join("/"));
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return out;
|
|
171
|
+
}
|
|
172
|
+
/** Where one `sample/` file lands on a scaffold (spec 6892 D4's fixed convention). */
|
|
173
|
+
function sampleDestination(rel) {
|
|
174
|
+
if (rel.startsWith("content/"))
|
|
175
|
+
return rel;
|
|
176
|
+
return `apps/web/public/${rel.slice("public/".length)}`;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Install a design's `sample/` directory onto a scaffold (spec 6892 D4) — a
|
|
180
|
+
* FIXED, undeclared convention, not a design-package field: `sample/content/**`
|
|
181
|
+
* lands at the scaffold's `content/**`, `sample/public/**` at
|
|
182
|
+
* `apps/web/public/**`. A design with no `sample/` directory (e.g. `standard`)
|
|
183
|
+
* installs nothing.
|
|
184
|
+
*
|
|
185
|
+
* Refuses — before its first write, so a refused sample leaves `targetDir`
|
|
186
|
+
* untouched — any file outside those two roots, or any `.ts`/`.tsx`/`.js`/
|
|
187
|
+
* `.mjs` file (content only, the template §5.2 rule this design package
|
|
188
|
+
* amendment carries over). Every installed file's destination is recorded in
|
|
189
|
+
* `ownership` as `design:<name>` (`readDesignPackage(designDir).name`), the
|
|
190
|
+
* same call-scoped registry `installBundleTree` writes into.
|
|
191
|
+
*
|
|
192
|
+
* @throws Error on a file outside `content/`/`public/`, or a forbidden extension.
|
|
193
|
+
*/
|
|
194
|
+
export function installDesignSample(opts) {
|
|
195
|
+
const sampleDir = join(opts.designDir, "sample");
|
|
196
|
+
if (!existsSync(sampleDir))
|
|
197
|
+
return;
|
|
198
|
+
const name = readDesignPackage(opts.designDir).name;
|
|
199
|
+
const subject = `design:${name}`;
|
|
200
|
+
// README.md at the sample root is the ONE documented exception (spec 6892
|
|
201
|
+
// D5: "the narrative sections move to designs/<name>/sample/README.md,
|
|
202
|
+
// which is not installed") — every other file is real content and is
|
|
203
|
+
// validated against the two roots below.
|
|
204
|
+
const files = listFiles(sampleDir).filter((rel) => rel !== "README.md");
|
|
205
|
+
for (const rel of files) {
|
|
206
|
+
if (!rel.startsWith("content/") && !rel.startsWith("public/")) {
|
|
207
|
+
throw new Error(`${subject}: sample file "${rel}" is outside content/ and public/ (spec 6892 D4)`);
|
|
208
|
+
}
|
|
209
|
+
if (hasSampleForbiddenExtension(rel)) {
|
|
210
|
+
throw new Error(`${subject}: sample file "${rel}" is a code file — a design sample is content only (spec 6892 D4)`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
for (const rel of files) {
|
|
214
|
+
const destinationRel = sampleDestination(rel);
|
|
215
|
+
const destinationAbs = resolve(opts.targetDir, destinationRel);
|
|
216
|
+
mkdirSync(join(destinationAbs, ".."), { recursive: true });
|
|
217
|
+
copyFileSync(join(sampleDir, rel), destinationAbs);
|
|
218
|
+
opts.ownership.set(destinationRel, subject);
|
|
219
|
+
}
|
|
220
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,10 +5,11 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export { copyTemplate, type CopyTemplateOptions } from "./copy.js";
|
|
7
7
|
export { parseCliArgs, parseModules, ParseError, helpText, RECOGNIZED_MODULES, type ModuleName, type CliOptions, } from "./parse-args.js";
|
|
8
|
-
export { CATALOG_TARGET_PATH, FREE_MODULES, addModule, LicenseRequiredError, PAID_MODULES, classifyModules, formatSurfaceDrift, scaffold, scaffoldSync, syncArchitectureSync, syncCatalogSync, syncRoutesSync, type AddModuleOptions, type ResolvePaidModulesOptions, type ScaffoldOptions, type ScaffoldResult, type SyncArchitectureOptions, type SyncArchitectureResult, type SyncCatalogResult, type SyncRoutesSyncOptions, } from "./programmatic.js";
|
|
8
|
+
export { CATALOG_TARGET_PATH, FREE_MODULES, addModule, LicenseRequiredError, PAID_MODULES, classifyModules, formatSurfaceDrift, scaffold, scaffoldSync, syncArchitectureSync, syncCatalogSync, syncClaudeMdSync, syncRoutesSync, type AddModuleOptions, type ResolvePaidModulesOptions, type ScaffoldOptions, type ScaffoldResult, type SyncArchitectureOptions, type SyncArchitectureResult, type SyncCatalogResult, type SyncClaudeMdResult, type SyncRoutesSyncOptions, } from "./programmatic.js";
|
|
9
9
|
export { DEFAULT_AILK_MODULE_REGISTRY_URL, FetchModuleError, fetchModule, type FetchModuleOptions, } from "./lib/fetch-module.js";
|
|
10
10
|
export { extractModuleBundle, type ExistingFilePolicy, type ExtractModuleBundleOptions, type InstallReportRow, } from "./lib/extract-module-bundle.js";
|
|
11
11
|
export { ADD_MODULE_HELP, AddModuleRefusedError, applyModuleToScaffold, formatAddModuleReport, parseAddModuleArgs, type AddModuleReportRow, type AddModuleResult, type ApplyModuleOptions, } from "./add-module.js";
|
|
12
|
+
export { APPLY_DESIGN_HELP, applyDesign, formatApplyDesignReport, parseApplyDesignArgs, type ApplyDesignArgs, type ApplyDesignChange, type ApplyDesignOptions, type ApplyDesignResult, } from "./apply-design.js";
|
|
12
13
|
export { SITE_ROSTER_PATH, readSiteRoster, siteRosterProblems, } from "./site-roster.js";
|
|
13
14
|
export { SYNC_ROUTES_HELP, formatSyncRoutesReport, listTemplateRouteDirs, parseSyncRoutesArgs, syncRoutes, type RouteReport, type SyncRoutesOptions, type SyncRoutesResult, } from "./sync-routes.js";
|
|
14
15
|
export { deriveArchitecture } from "./derive-architecture.js";
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export { copyTemplate } from "./copy.js";
|
|
7
7
|
export { parseCliArgs, parseModules, ParseError, helpText, RECOGNIZED_MODULES, } from "./parse-args.js";
|
|
8
|
-
export { CATALOG_TARGET_PATH, FREE_MODULES, addModule, LicenseRequiredError, PAID_MODULES, classifyModules, formatSurfaceDrift, scaffold, scaffoldSync, syncArchitectureSync, syncCatalogSync, syncRoutesSync, } from "./programmatic.js";
|
|
8
|
+
export { CATALOG_TARGET_PATH, FREE_MODULES, addModule, LicenseRequiredError, PAID_MODULES, classifyModules, formatSurfaceDrift, scaffold, scaffoldSync, syncArchitectureSync, syncCatalogSync, syncClaudeMdSync, syncRoutesSync, } from "./programmatic.js";
|
|
9
9
|
// The paid-module fetch/extract primitives (K1, #5089 — Flavor 3). Exported
|
|
10
10
|
// so tooling (and this repo's own evidence-run scripts) can drive the fetch
|
|
11
11
|
// path directly without re-implementing its shape.
|
|
@@ -14,6 +14,9 @@ export { extractModuleBundle, } from "./lib/extract-module-bundle.js";
|
|
|
14
14
|
// `create-ailk add-module` (#6653) — apply a purchased module to an existing
|
|
15
15
|
// site in place. The pure core, beside `sync-routes`'s.
|
|
16
16
|
export { ADD_MODULE_HELP, AddModuleRefusedError, applyModuleToScaffold, formatAddModuleReport, parseAddModuleArgs, } from "./add-module.js";
|
|
17
|
+
// `create-ailk apply-design` (#6819) — make an existing site wear a design,
|
|
18
|
+
// changing only its look. The pure core, beside `add-module`'s.
|
|
19
|
+
export { APPLY_DESIGN_HELP, applyDesign, formatApplyDesignReport, parseApplyDesignArgs, } from "./apply-design.js";
|
|
17
20
|
// The site's page roster of record and its install-diff check (#6682).
|
|
18
21
|
export { SITE_ROSTER_PATH, readSiteRoster, siteRosterProblems, } from "./site-roster.js";
|
|
19
22
|
// `create-ailk sync-routes` (#4986) — the template-route drift check + copy.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Frozen, published-generator `renderNavConfig` bodies (#6908 D2) — one per
|
|
3
|
+
* era a create-ailk release ever shipped (E1–E4, `docs/specs/6908-add-module-
|
|
4
|
+
* treats-every-pre-spec.md` § 1.2). `surfaces.ts`'s own `renderNavConfig`
|
|
5
|
+
* self-hashes its output (D1) so a nav it wrote can always prove itself; a
|
|
6
|
+
* nav written before the stamp existed carries none, and this module is the
|
|
7
|
+
* only way `add-module` can still recognize it as unedited.
|
|
8
|
+
*
|
|
9
|
+
* Each `render` below is copied VERBATIM from the named tag's own
|
|
10
|
+
* `packages/create-ailk/src/surfaces.ts`, at the named commit, with exactly
|
|
11
|
+
* two changes from the original:
|
|
12
|
+
*
|
|
13
|
+
* - `GATEABLE_SURFACES` is replaced by a frozen `{ id, navLabelKey }` table
|
|
14
|
+
* of that tag's own entries, in that tag's own order (the era's own
|
|
15
|
+
* `<era>_SURFACES` constant below) — so a later change to today's
|
|
16
|
+
* `GATEABLE_SURFACES` can never move a byte of a legacy render.
|
|
17
|
+
* - the `@working-theory/ui` import line stays fragment-assembled, exactly
|
|
18
|
+
* as the original does, so THIS file never contains the literal import
|
|
19
|
+
* string either (`tools/lint-architecture.ts` matches source text; see
|
|
20
|
+
* the comment on each `navItemImport` below).
|
|
21
|
+
*
|
|
22
|
+
* The list is CLOSED (D2): after D1 ships, every published generator is
|
|
23
|
+
* unstamped only up to 0.8.0 (E4), so a future generator change never needs a
|
|
24
|
+
* fifth entry. Fixtures produced by each tag's own code (never by this
|
|
25
|
+
* vendored copy) pin these bodies exactly — see
|
|
26
|
+
* `__tests__/fixtures/legacy-nav/index.json`.
|
|
27
|
+
*/
|
|
28
|
+
/** One published nav-generator era, and the renderer that reproduces it byte-for-byte. */
|
|
29
|
+
export interface LegacyNavRenderer {
|
|
30
|
+
/** Era label, E1–E4 (spec § 1.2). */
|
|
31
|
+
era: string;
|
|
32
|
+
/** Every published create-ailk tag that shipped this exact `renderNavConfig` body. */
|
|
33
|
+
tags: readonly string[];
|
|
34
|
+
/** The representative tag commit the body and fixtures were taken from. */
|
|
35
|
+
commit: string;
|
|
36
|
+
/** Render this era's nav for an enabled surface set — no `options`; no published era before #6878 D6 took one. */
|
|
37
|
+
render(enabled: readonly string[]): string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The closed set of published, pre-stamp `renderNavConfig` bodies (D2).
|
|
41
|
+
* `add-module`'s `isUneditedNav` tries these, in order, against an unstamped
|
|
42
|
+
* nav (`surfaces.ts` `readNavConfigStamp` returning `"absent"`) before giving
|
|
43
|
+
* up and reporting it as customer-edited.
|
|
44
|
+
*/
|
|
45
|
+
export declare const LEGACY_NAV_RENDERERS: readonly LegacyNavRenderer[];
|