create-ailk 0.3.0 → 0.5.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 (155) hide show
  1. package/component-catalog.json +11939 -0
  2. package/component-catalog.md +176 -64
  3. package/dist/cli.js +48 -10
  4. package/dist/derive-architecture.js +5 -2
  5. package/dist/lib/extract-module-bundle.d.ts +88 -1
  6. package/dist/lib/extract-module-bundle.js +375 -80
  7. package/dist/lib/fetch-guard.d.ts +28 -0
  8. package/dist/lib/fetch-guard.js +101 -0
  9. package/dist/lib/fetch-module.js +4 -0
  10. package/dist/lib/fetch-template.d.ts +20 -0
  11. package/dist/lib/fetch-template.js +133 -0
  12. package/dist/lib/module-license-gate.d.ts +8 -0
  13. package/dist/lib/module-license-gate.js +12 -4
  14. package/dist/module-architecture.d.ts +116 -7
  15. package/dist/module-architecture.js +465 -94
  16. package/dist/parse-args.d.ts +8 -1
  17. package/dist/parse-args.js +49 -2
  18. package/dist/programmatic.d.ts +36 -1
  19. package/dist/programmatic.js +216 -5
  20. package/dist/site-chrome.d.ts +80 -0
  21. package/dist/site-chrome.js +135 -0
  22. package/dist/surfaces.d.ts +21 -6
  23. package/dist/surfaces.js +140 -23
  24. package/dist/template-manifest.d.ts +144 -0
  25. package/dist/template-manifest.js +337 -0
  26. package/dist/template-names.d.ts +41 -0
  27. package/dist/template-names.js +45 -0
  28. package/package.json +10 -2
  29. package/site-templates/_base/ailk-template.json +6 -0
  30. package/site-templates/_base/content/en/Pricing/pricing.mdx +169 -0
  31. package/site-templates/_base/content/en/PrivacyPage/privacy.mdx +79 -0
  32. package/site-templates/_base/content/en/TermsPage/terms.mdx +80 -0
  33. package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +331 -0
  34. package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +393 -0
  35. package/site-templates/marketing-site/ailk-template.json +11 -0
  36. package/site-templates/marketing-site/content/en/blog/05-this-vc-morning-routine-will-make-you-super-annoying.mdx +36 -0
  37. package/site-templates/marketing-site/provenance.json +4 -0
  38. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.json +288 -0
  39. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.md +285 -0
  40. package/site-templates/marketing-site-free/ailk-template.json +9 -0
  41. package/site-templates/marketing-site-free/provenance.json +4 -0
  42. package/site-templates/minimalism-site/TEMPLATE-MANIFEST.json +271 -0
  43. package/site-templates/minimalism-site/TEMPLATE-MANIFEST.md +324 -0
  44. package/site-templates/minimalism-site/ailk-template.json +21 -0
  45. package/site-templates/minimalism-site/assets/avatar-placeholder-1.svg +7 -0
  46. package/site-templates/minimalism-site/assets/avatar-placeholder-2.svg +7 -0
  47. package/site-templates/minimalism-site/assets/avatar-placeholder-3.svg +7 -0
  48. package/site-templates/minimalism-site/assets/avatar-placeholder-4.svg +7 -0
  49. package/site-templates/minimalism-site/assets/avatar-placeholder-5.svg +7 -0
  50. package/site-templates/minimalism-site/assets/avatar-placeholder-6.svg +7 -0
  51. package/site-templates/minimalism-site/assets/hero-backdrop.svg +17 -0
  52. package/site-templates/minimalism-site/assets/logo-placeholder-1.svg +6 -0
  53. package/site-templates/minimalism-site/assets/logo-placeholder-2.svg +6 -0
  54. package/site-templates/minimalism-site/assets/logo-placeholder-3.svg +6 -0
  55. package/site-templates/minimalism-site/content/en/AboutPage/about.mdx +110 -0
  56. package/site-templates/minimalism-site/content/en/ContactPage/contact.mdx +68 -0
  57. package/site-templates/minimalism-site/content/en/FAQPage/faq.mdx +57 -0
  58. package/site-templates/minimalism-site/content/en/HomePage/home.mdx +214 -0
  59. package/site-templates/minimalism-site/content/en/LandingPage/referral.mdx +77 -0
  60. package/site-templates/minimalism-site/content/en/LandingPage/reports.mdx +73 -0
  61. package/site-templates/minimalism-site/content/en/ReportPage/annual-letter-2024.mdx +52 -0
  62. package/site-templates/minimalism-site/content/en/ReportPage/field-notes-2023.mdx +52 -0
  63. package/site-templates/minimalism-site/content/en/ReportPage/platform-shift-2025.mdx +52 -0
  64. package/site-templates/minimalism-site/content/en/ReportPage/state-of-the-market-2026.mdx +52 -0
  65. package/site-templates/minimalism-site/content/en/Service/first-engagement.mdx +38 -0
  66. package/site-templates/minimalism-site/content/en/Service/second-engagement.mdx +38 -0
  67. package/site-templates/minimalism-site/content/en/Service/third-engagement.mdx +38 -0
  68. package/site-templates/minimalism-site/content/en/ServicesList/services.mdx +73 -0
  69. package/site-templates/minimalism-site/flows/referral.flow.json +71 -0
  70. package/site-templates/minimalism-site/provenance.json +4 -0
  71. package/site-templates/saas-product/TEMPLATE-MANIFEST.md +61 -0
  72. package/site-templates/saas-product/ailk-template.json +16 -0
  73. package/site-templates/saas-product/provenance.json +10 -0
  74. package/templates/.claude/skills/README.md +16 -25
  75. package/templates/.env.example +32 -7
  76. package/templates/.github/workflows/ci.yml +48 -0
  77. package/templates/README.md +3 -1
  78. package/templates/apps/api/CLAUDE.md +4 -1
  79. package/templates/apps/api/eslint.config.mjs +69 -0
  80. package/templates/apps/api/package.json +6 -2
  81. package/templates/apps/api/src/__tests__/module-exclusion.test.ts +6 -2
  82. package/templates/apps/api/src/__tests__/review-surface-registration.test.ts +167 -0
  83. package/templates/apps/api/src/__tests__/workspace-module-registration.test.ts +173 -0
  84. package/templates/apps/api/src/config/modules.ts +1 -1
  85. package/templates/apps/api/src/lib/__mocks__/prisma.ts +3 -0
  86. package/templates/apps/api/src/middleware/__tests__/default-tenant.test.ts +339 -0
  87. package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +108 -0
  88. package/templates/apps/api/src/middleware/default-tenant.ts +136 -0
  89. package/templates/apps/api/src/routes/leads/__tests__/list.test.ts +171 -0
  90. package/templates/apps/api/src/routes/leads/list.ts +104 -0
  91. package/templates/apps/api/src/server.ts +122 -3
  92. package/templates/apps/api/src/services/__tests__/lead-promotion.test.ts +408 -0
  93. package/templates/apps/api/src/services/__tests__/leads-inbox.test.ts +329 -0
  94. package/templates/apps/api/src/services/default-tenant.ts +261 -0
  95. package/templates/apps/api/src/services/lead-promotion.ts +161 -0
  96. package/templates/apps/api/src/services/leads-inbox.ts +263 -0
  97. package/templates/apps/api/src/services/owner-workspaces.ts +132 -0
  98. package/templates/apps/mcp/CLAUDE.md +1 -1
  99. package/templates/apps/mcp/__tests__/parity.test.ts +2 -2
  100. package/templates/apps/mcp/__tests__/tools/{scaffold.test.ts → create_project.test.ts} +23 -23
  101. package/templates/apps/mcp/eslint.config.mjs +69 -0
  102. package/templates/apps/mcp/package.json +6 -2
  103. package/templates/apps/mcp/src/server.ts +2 -2
  104. package/templates/apps/mcp/src/tools/{scaffold.ts → create_project.ts} +3 -3
  105. package/templates/apps/mcp/src/tools/index.ts +2 -2
  106. package/templates/apps/web/.env.example +3 -3
  107. package/templates/apps/web/CLAUDE.md +2 -0
  108. package/templates/apps/web/app/[locale]/(authed)/account/page.tsx +4 -6
  109. package/templates/apps/web/app/[locale]/(authed)/layout.tsx +1 -1
  110. package/templates/apps/web/app/[locale]/(authed)/leads/__tests__/page.test.tsx +181 -0
  111. package/templates/apps/web/app/[locale]/(authed)/leads/components/LeadsTable.tsx +137 -0
  112. package/templates/apps/web/app/[locale]/(authed)/leads/page.tsx +111 -0
  113. package/templates/apps/web/app/[locale]/(authed)/sign-in-gate.tsx +1 -1
  114. package/templates/apps/web/app/[locale]/[slug]/__tests__/page.test.tsx +111 -0
  115. package/templates/apps/web/app/[locale]/[slug]/page.tsx +65 -0
  116. package/templates/apps/web/app/[locale]/flows/[slug]/FlowStepperClient.tsx +1 -1
  117. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.permalink.test.tsx +1 -1
  118. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.test.tsx +6 -5
  119. package/templates/apps/web/app/[locale]/flows/[slug]/flow.actions.ts +1 -1
  120. package/templates/apps/web/app/[locale]/layout.tsx +214 -17
  121. package/templates/apps/web/app/[locale]/pricing/page.tsx +40 -0
  122. package/templates/apps/web/app/[locale]/privacy/page.tsx +40 -0
  123. package/templates/apps/web/app/[locale]/terms/page.tsx +40 -0
  124. package/templates/apps/web/components/google-analytics.tsx +18 -1
  125. package/templates/apps/web/eslint.config.mjs +69 -0
  126. package/templates/apps/web/jest.config.cjs +12 -15
  127. package/templates/apps/web/lib/__tests__/server-api.test.ts +61 -0
  128. package/templates/apps/web/lib/__tests__/structured-data.test.tsx +32 -5
  129. package/templates/apps/web/lib/nav-config.ts +27 -7
  130. package/templates/apps/web/lib/server-api.ts +29 -13
  131. package/templates/apps/web/lib/site-chrome.ts +29 -0
  132. package/templates/apps/web/lib/telemetry-scrub.ts +46 -0
  133. package/templates/apps/web/messages/en.json +86 -1
  134. package/templates/apps/web/next.config.mjs +20 -0
  135. package/templates/apps/web/package.json +6 -2
  136. package/templates/apps/web/sentry.client.config.ts +131 -0
  137. package/templates/apps/web/sentry.edge.config.ts +72 -0
  138. package/templates/apps/web/sentry.server.config.ts +72 -0
  139. package/templates/apps/web/src/lib/routes.ts +13 -18
  140. package/templates/brand_assets/README.md +24 -0
  141. package/templates/content/en/AboutPage/about.mdx +160 -15
  142. package/templates/content/en/ContactPage/contact.mdx +90 -13
  143. package/templates/content/en/FAQPage/faq.mdx +62 -22
  144. package/templates/content/en/HomePage/home.mdx +244 -20
  145. package/templates/content/en/LandingPage/blog.mdx +83 -0
  146. package/templates/content/en/LandingPage/features.mdx +103 -0
  147. package/templates/content/en/LandingPage/how-it-works.mdx +143 -0
  148. package/templates/database/CHANGELOG.md +21 -0
  149. package/templates/database/__tests__/seed.test.ts +1 -1
  150. package/templates/database/eslint.config.mjs +69 -0
  151. package/templates/database/package.json +7 -3
  152. package/templates/database/seed.ts +1 -1
  153. package/templates/package.json +1 -14
  154. package/versions.json +52 -0
  155. /package/templates/apps/web/{src/components → components}/SiteNav.tsx +0 -0
package/dist/cli.js CHANGED
@@ -9,8 +9,9 @@
9
9
  * 2. on --help: print helpText, exit 0
10
10
  * 3. on --version: print version, exit 0
11
11
  * 4. delegate to scaffold() in programmatic.ts — gates + fetches any
12
- * requested paid module (K1, #5089 — Flavor 3), then validates + copies
13
- * the local template, then merges each fetched bundle in
12
+ * requested paid module (K1, #5089 — Flavor 3) and any named site
13
+ * template's own bundle (#5481), then validates + copies the local
14
+ * template, then merges each fetched bundle in, the site template last
14
15
  * 5. when --install: spawn `pnpm install` (cwd = target, hard-coded argv)
15
16
  * 6. print next-steps message
16
17
  *
@@ -32,7 +33,7 @@ import { fileURLToPath } from "node:url";
32
33
  import { proCallout } from "./lib/pro-callout.js";
33
34
  import { helpText, parseCliArgs, parseModules } from "./parse-args.js";
34
35
  import { formatSurfaceDrift, scaffold, syncArchitectureSync, syncCatalogSync, syncRoutesSync, } from "./programmatic.js";
35
- import { CORE_SURFACE_PATHS } from "./surfaces.js";
36
+ import { CORE_SURFACE_PATHS, SURFACE_ALIASES } from "./surfaces.js";
36
37
  import { SYNC_ROUTES_HELP, formatSyncRoutesReport, parseSyncRoutesArgs, } from "./sync-routes.js";
37
38
  const PKG_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
38
39
  const PKG_JSON = resolve(PKG_ROOT, "package.json");
@@ -40,6 +41,17 @@ function readPackageVersion() {
40
41
  const raw = readFileSync(PKG_JSON, "utf8");
41
42
  return JSON.parse(raw).version;
42
43
  }
44
+ /** Raw value of a `--flag <value>` or `--flag=<value>` argv entry, if present. */
45
+ function readRawFlagValue(argv, flag) {
46
+ for (let i = 0; i < argv.length; i++) {
47
+ const arg = argv[i];
48
+ if (arg === flag)
49
+ return argv[i + 1];
50
+ if (arg?.startsWith(`${flag}=`))
51
+ return arg.slice(flag.length + 1);
52
+ }
53
+ return undefined;
54
+ }
43
55
  async function main() {
44
56
  const argv = process.argv.slice(2);
45
57
  // Subcommand dispatch, ahead of the flag parser: `sync-routes` has its own
@@ -59,6 +71,23 @@ async function main() {
59
71
  process.exit(!args.apply && result.missing.length > 0 ? 1 : 0);
60
72
  }
61
73
  const opts = parseCliArgs(argv);
74
+ // Deprecation notice for a retired `--surfaces` id (#5563 D2). `surfaces.ts`
75
+ // stays pure — `canonicalizeSurface` only resolves the alias — so this is
76
+ // the one place that prints: compare the raw `--surfaces` argv token
77
+ // against SURFACE_ALIASES rather than diffing the (already-canonical)
78
+ // parsed result.
79
+ const rawSurfaces = readRawFlagValue(argv, "--surfaces");
80
+ if (rawSurfaces !== undefined) {
81
+ for (const token of rawSurfaces
82
+ .split(",")
83
+ .map((s) => s.trim().toLowerCase())
84
+ .filter(Boolean)) {
85
+ const canonical = SURFACE_ALIASES[token];
86
+ if (canonical !== undefined) {
87
+ process.stdout.write(`[create-ailk] "--surfaces ${token}" is retired; using "${canonical}" (#5563).\n`);
88
+ }
89
+ }
90
+ }
62
91
  if (opts.help) {
63
92
  process.stdout.write(helpText + "\n" + SYNC_ROUTES_HELP);
64
93
  process.exit(0);
@@ -100,17 +129,24 @@ async function main() {
100
129
  process.stdout.write(drift);
101
130
  process.exit(0);
102
131
  }
103
- // scaffold() gates + fetches any requested paid module (K1, #5089), then
104
- // validates and copies the local template — throws ValidationError or
105
- // LicenseRequiredError on rejection (caught at top level below). Neither
106
- // AILK_LICENSE_KEY nor AILK_MODULE_REGISTRY_URL is read, and no network
107
- // call is made, when `opts.modules` names no paid module — the regression
108
- // floor (see `resolvePaidModules` in `lib/module-license-gate.ts`).
132
+ // scaffold() gates + fetches any requested paid module (K1, #5089) and any
133
+ // named site template's own bundle (#5481), then validates and copies the
134
+ // local template — throws ValidationError or LicenseRequiredError on
135
+ // rejection (caught at top level below). Neither AILK_LICENSE_KEY nor
136
+ // either registry URL is read, and no network call is made, when the
137
+ // effective module set names no paid module — the regression floor, which
138
+ // `--template marketing-site-free` deliberately rides (record D11): its
139
+ // `requires` is all-free, so it installs from the shipped
140
+ // `site-templates/` tree with no key and no request.
109
141
  const { targetDir: targetAbs, surfaces } = await scaffold({
110
142
  targetDir: opts.target,
111
143
  modules: opts.modules,
112
144
  surfaces: opts.surfaces,
113
145
  withCatalog: opts.withCatalog,
146
+ // Spread rather than passed as `undefined` so a run naming no template
147
+ // hands `scaffold()` exactly the option object it got before the flag
148
+ // existed (spec 5481 § 3 DD3's byte-identity floor).
149
+ ...(opts.template !== undefined ? { template: opts.template } : {}),
114
150
  });
115
151
  if (opts.install) {
116
152
  // Hard-coded argv. User input only flows through `cwd`, never the command.
@@ -126,7 +162,9 @@ async function main() {
126
162
  // Next-steps message.
127
163
  const lines = [
128
164
  "",
129
- "Scaffolded AI Launch Kit starter.",
165
+ opts.template !== undefined
166
+ ? `Scaffolded AI Launch Kit starter from the "${opts.template}" template.`
167
+ : "Scaffolded AI Launch Kit starter.",
130
168
  "",
131
169
  "Next steps:",
132
170
  ` cd ${targetAbs}`,
@@ -181,11 +181,14 @@ export function deriveArchitecture(modules = ["marketing"], surfaces) {
181
181
  forbidden_patterns: ARCHITECTURE_BASE.web.forbidden_patterns.map(forbiddenToYaml),
182
182
  },
183
183
  };
184
- // Additional apps (api, mcp, workspace) in canonical order.
184
+ // Additional apps (api, mcp, admin) in canonical order. `admin` was
185
+ // `workspace` until #5637 renamed the owner surface; the slice's key was
186
+ // renamed there and this list was not, which dropped the Admin app from
187
+ // every derived architecture without failing anything but its own test.
185
188
  const extraApps = {};
186
189
  for (const s of slices)
187
190
  Object.assign(extraApps, s.apps ?? {});
188
- for (const key of ["api", "mcp", "workspace"]) {
191
+ for (const key of ["api", "mcp", "admin"]) {
189
192
  const a = extraApps[key];
190
193
  if (a)
191
194
  apps[key] = appToYaml(a);
@@ -1,4 +1,23 @@
1
+ import { type TemplateLayout } from "../site-chrome.js";
1
2
  import type { WorkspaceVersionMap } from "../substitute.js";
3
+ /** Exported for `fetch-template.ts`/`fetch-module.ts`'s Content-Length guard (#5514) — one cap, not two literals. */
4
+ export declare const MAX_TOTAL_SIZE_BYTES: number;
5
+ /**
6
+ * The file-grain ownership registry (#5618 D4): scaffold-relative destination
7
+ * → the layer that wrote it (a `subject` string — `template "_base"`,
8
+ * `module "docs-blog"`, `template "marketing-site"`). Caller-owned and
9
+ * CALL-SCOPED: `scaffold()` constructs one per call and threads it through
10
+ * every `installBundleTree` of that scaffold, so two `scaffold()` calls in
11
+ * one process share no state (the frozen-registry posture of #5507). It is
12
+ * the third ownership view beside `ownedFiles` (which repo file a module
13
+ * physically owns) and `pageContributions` (which route+content it brings):
14
+ * which scaffold destination a LAYER wrote at install time.
15
+ *
16
+ * Layer 0 — the `templates/` snapshot — is deliberately outside it: the
17
+ * registry starts empty at the base-layer boundary, so a destination it does
18
+ * not hold is the snapshot's, which a module may freely add to and patch.
19
+ */
20
+ export type LayerOwnership = Map<string, string>;
2
21
  export interface ExtractModuleBundleOptions {
3
22
  /** The fetched bundle bytes (a gzipped tar archive). */
4
23
  bytes: Uint8Array;
@@ -13,6 +32,16 @@ export interface ExtractModuleBundleOptions {
13
32
  * (a bundle with no `patches`, or none using `workspace:*`, needs nothing).
14
33
  */
15
34
  versions?: WorkspaceVersionMap;
35
+ /**
36
+ * Present ⟹ `moduleName` names a SITE TEMPLATE, not a module, and the
37
+ * archive's root manifest is `ailk-template.json` cross-checked against
38
+ * this list (record D10, DD4). See `InstallBundleTreeOptions`.
39
+ */
40
+ templateRequires?: readonly string[];
41
+ /** The registry's `extends` for this template (#5618 D2). See `InstallBundleTreeOptions`. */
42
+ templateExtends?: string;
43
+ /** The call-scoped ownership registry (#5618 D4). See `InstallBundleTreeOptions`. */
44
+ ownership?: LayerOwnership;
16
45
  }
17
46
  /**
18
47
  * Extract a fetched module bundle into `targetDir`, merging its files onto
@@ -22,4 +51,62 @@ export interface ExtractModuleBundleOptions {
22
51
  * those cases: validation AND patch computation both complete before any
23
52
  * file is copied or written into place.
24
53
  */
25
- export declare function extractModuleBundle(options: ExtractModuleBundleOptions): Promise<void>;
54
+ export declare function extractModuleBundle(options: ExtractModuleBundleOptions): Promise<InstallBundleTreeResult>;
55
+ export interface InstallBundleTreeOptions {
56
+ /**
57
+ * The validated tree whose files land in the scaffold. Two source roots,
58
+ * one install step (spec 5481 § 3 DD7): the staging dir
59
+ * `extractModuleBundle` above produced, or `site-templates/<name>/` read
60
+ * straight off disk on the keyless Free path.
61
+ */
62
+ sourceRoot: string;
63
+ /** The already-scaffolded target directory the files land in. */
64
+ targetDir: string;
65
+ /** The module or template name — error messages and nothing else. */
66
+ name: string;
67
+ /**
68
+ * Present ⟹ this tree is a SITE TEMPLATE's: the root manifest is
69
+ * `ailk-template.json`, it MUST be present and parseable, and its
70
+ * `requires` must agree with this list — the client registry's own
71
+ * (record D10, DD4). Absent ⟹ a module bundle, read exactly as before.
72
+ */
73
+ templateRequires?: readonly string[];
74
+ /**
75
+ * Template trees only (#5618 D2): the client registry's `extends` for this
76
+ * template, which the tree's `ailk-template.json` must declare verbatim —
77
+ * the sibling of the `requires` cross-check above. Absent for the base
78
+ * layer itself (the chain's terminus declares no parent) and for a module.
79
+ */
80
+ templateExtends?: string;
81
+ /**
82
+ * The call-scoped ownership registry (#5618 D4) — destination → the layer
83
+ * that wrote it. Present ⟹ this install is one layer of a composed
84
+ * scaffold: a MODULE tree is refused (before its first write) for any
85
+ * destination an earlier layer owns unless it is a declared `patches`
86
+ * target, and every layer records its destinations on success. Absent ⟹
87
+ * the pre-#5618 single-tree behaviour, unchecked and unrecorded.
88
+ */
89
+ ownership?: LayerOwnership;
90
+ /** Canonical `@working-theory/*` versions for `workspace:*` substitution in patch targets. */
91
+ versions?: WorkspaceVersionMap;
92
+ }
93
+ /** `installBundleTree`'s result — presently only the template-only `layout` knobs. */
94
+ export interface InstallBundleTreeResult {
95
+ /**
96
+ * The installed template's validated `layout` block (#5612 D1), unresolved
97
+ * (defaults NOT filled — `resolveSiteChrome` does that). `undefined` for a
98
+ * module install, or a template whose manifest declares no `layout`.
99
+ */
100
+ layout?: TemplateLayout;
101
+ }
102
+ /**
103
+ * Apply one resolved manifest's `installMap`, plain content and `patches`
104
+ * from `sourceRoot` into `targetDir`.
105
+ *
106
+ * Extracted from `extractModuleBundle` so the Free template path — which has
107
+ * no archive to unpack, only a local tree — runs the SAME step (DD7). The
108
+ * atomicity guarantee is this function's, not its callers': validation AND
109
+ * patch computation both complete before the first byte is written, so a
110
+ * rejected tree leaves `targetDir` exactly as it was.
111
+ */
112
+ export declare function installBundleTree(options: InstallBundleTreeOptions): InstallBundleTreeResult;