@orkestrel/scaffold 0.0.25 → 0.0.27

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.
@@ -140,6 +140,25 @@ var HOST_PATHS = Object.freeze([
140
140
  "guides/scaffold.md"
141
141
  ]);
142
142
  /**
143
+ * The vendored paths a target receives with its executable bit set, frozen.
144
+ *
145
+ * @remarks
146
+ * Declared rather than read from the staging host's filesystem, because that
147
+ * reading is not portable: Windows carries no executable bit, so a host staged
148
+ * there reports every file non-executable and every target receives hooks it
149
+ * cannot run. Declaring the set here makes one checkout stage one manifest on
150
+ * every host.
151
+ *
152
+ * Every entry is also a {@link HOST_PATHS} member or sits beneath one. A file
153
+ * that must run when a target invokes it belongs here the moment it is vendored.
154
+ */
155
+ var EXECUTABLE_PATHS = Object.freeze([
156
+ "scripts/codex.sh",
157
+ "scripts/cursor.sh",
158
+ "scripts/deps.sh",
159
+ "scripts/ollama.sh"
160
+ ]);
161
+ /**
143
162
  * The path prefixes whose contents instruct or wire an agent, frozen.
144
163
  *
145
164
  * @remarks
@@ -227,7 +246,7 @@ var ENGINES_PATTERN = /^>=(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/;
227
246
  var HEX_PATTERN = /^(?:[0-9a-f]{2})*$/;
228
247
  /** Unicode controls, formatting controls, and line and paragraph separators rejected in text. */
229
248
  var CONTROL_CHARACTER_PATTERN = /[\p{Cc}\p{Cf}\p{Zl}\p{Zp}]/u;
230
- /** Visible characters a portable path and a Markdown path cell both forbid. */
249
+ /** Visible characters a target-relative path and a Markdown path cell both forbid. */
231
250
  var INVALID_PATH_CHARACTER_PATTERN = /[<>:"|?*\\]/;
232
251
  /**
233
252
  * Maximum bare workspace name length.
@@ -245,6 +264,8 @@ var MAX_RANGE_LENGTH = 2048;
245
264
  var MAX_PATH_LENGTH = 32767;
246
265
  /** Maximum items accepted in one public collection. */
247
266
  var MAX_COLLECTION_ITEMS = 1e3;
267
+ /** Maximum findings one audit can produce from a bounded plan and snapshot. */
268
+ var MAX_AUDIT_FINDINGS = MAX_COLLECTION_ITEMS * 2;
248
269
  /** Maximum bytes accepted for one artifact. */
249
270
  var MAX_ARTIFACT_BYTES = 5242880;
250
271
  /** Maximum length of the hexadecimal string carrying one artifact's bytes. */
@@ -262,8 +283,8 @@ var DEFAULT_ENGINES = `>=${MINIMUM_NODE_VERSION}`;
262
283
  /** The tooling versions scaffold and every generated workspace share. */
263
284
  var BASE_DEV_DEPENDENCIES = Object.freeze({
264
285
  "@microsoft/api-extractor": "^7.58.12",
265
- "@orkestrel/guide": "^0.0.9",
266
- "@orkestrel/scaffold": "^0.0.25",
286
+ "@orkestrel/guide": "^0.0.10",
287
+ "@orkestrel/scaffold": "^0.0.27",
267
288
  "@types/node": "^26.2.0",
268
289
  oxfmt: "^0.62.0",
269
290
  oxlint: "^1.77.0",
@@ -278,11 +299,11 @@ var SOURCE_BROWSER_DEV_DEPENDENCIES = Object.freeze({
278
299
  playwright: "^1.62.1"
279
300
  });
280
301
  /** The development dependency every private `app` environment adds. */
281
- var APP_DEV_DEPENDENCIES = Object.freeze({ "@orkestrel/contract": "^0.0.10" });
302
+ var APP_DEV_DEPENDENCIES = Object.freeze({ "@orkestrel/contract": "^0.0.11" });
282
303
  /** The development dependencies a private Vue browser application adds. */
283
304
  var APP_BROWSER_DEV_DEPENDENCIES = Object.freeze({
284
305
  ...SOURCE_BROWSER_DEV_DEPENDENCIES,
285
- "@orkestrel/html": "^0.0.2",
306
+ "@orkestrel/html": "^0.0.3",
286
307
  "@vitejs/plugin-vue": "^6.0.8",
287
308
  vue: "^3.5.40",
288
309
  "vue-tsc": "^3.3.7"
@@ -300,10 +321,10 @@ var APP_BROWSER_DEV_DEPENDENCIES = Object.freeze({
300
321
  var SHOWCASE_DEV_DEPENDENCIES = Object.freeze({ "vite-plugin-singlefile": "^2.3.3" });
301
322
  /** The development dependencies a private server application adds. */
302
323
  var APP_SERVER_DEV_DEPENDENCIES = Object.freeze({
303
- "@orkestrel/emitter": "^0.0.5",
304
- "@orkestrel/middleware": "^0.0.9",
305
- "@orkestrel/router": "^0.0.8",
306
- "@orkestrel/server": "^0.0.10"
324
+ "@orkestrel/emitter": "^0.0.6",
325
+ "@orkestrel/middleware": "^0.0.10",
326
+ "@orkestrel/router": "^0.0.9",
327
+ "@orkestrel/server": "^0.0.11"
307
328
  });
308
329
  //#endregion
309
330
  //#region src/core/templates.ts
@@ -356,12 +377,10 @@ var CONFIG_TEMPLATES = Object.freeze({
356
377
  "exclude": ["node_modules", "dist", "tmp"]
357
378
  }
358
379
  `,
359
- vite: `import type { UserConfig } from 'vite'
360
- {{imports}}
361
- import { defineConfig, mergeConfig } from 'vitest/config'
380
+ vite: `import type { {{viteTypes}} } from 'vite'
381
+ {{imports}}import { defineConfig, mergeConfig } from 'vitest/config'
362
382
  import tsconfig from './tsconfig.json' with { type: 'json' }
363
- import { environmentBoundary, outputBoundary } from './configs/helpers.js'
364
- import { lstatSync, readdirSync, realpathSync } from 'node:fs'
383
+ {{helpers}}import { lstatSync, readdirSync, realpathSync } from 'node:fs'
365
384
  import { basename, join, parse, relative, resolve as resolvePath, sep } from 'node:path'
366
385
  import { fileURLToPath, URL } from 'node:url'
367
386
 
@@ -553,14 +572,9 @@ const resolve = {
553
572
  `,
554
573
  browser: `function applicationBrowser(showcase: boolean): UserConfig {
555
574
  const output = showcase ? 'dist/showcase' : 'dist/app/browser'
556
- return {
575
+ {{showcasePlugins}} return {
557
576
  resolve,
558
- plugins: [
559
- outputBoundary(output),
560
- environmentBoundary('app/browser'),
561
- vue(),
562
- {{showcasePlugin}} ],
563
- root: resolveWorkspacePath('app/browser'),
577
+ {{plugins}} root: resolveWorkspacePath('app/browser'),
564
578
  publicDir: false,
565
579
  build: {
566
580
  {{showcaseBuild}} emptyOutDir: true,
@@ -943,9 +957,13 @@ export default defineConfig(appShowcase())
943
957
  *
944
958
  * @remarks
945
959
  * Builders in `compilers.ts` fill every varying span through
946
- * `@orkestrel/template`. Empty barrels and setup modules are intentional: the
947
- * generated workspace starts with no sample domain API, while each selected
948
- * Vitest project gets a real test that proves its barrel has no starter exports.
960
+ * `@orkestrel/template`. Empty barrels, entries, and setup modules are
961
+ * intentional: the generated workspace starts with no sample domain API, while
962
+ * each selected Vitest project gets a real test that proves its barrel has no
963
+ * starter exports. An entry starts empty for the same reason its barrel does,
964
+ * and because the vendored lint config refuses an unassigned import outside a
965
+ * stylesheet, so a starter `import './index.js'` would fail the workspace's own
966
+ * `lint:check` on the day it is written.
949
967
  *
950
968
  * @example
951
969
  * ```ts
@@ -957,8 +975,6 @@ export default defineConfig(appShowcase())
957
975
  var ARTIFACT_TEMPLATES = Object.freeze({
958
976
  source: Object.freeze({
959
977
  empty: "",
960
- main: `import './index.js'
961
- `,
962
978
  browser: `<!doctype html>
963
979
  <html lang="en">
964
980
  <head>
@@ -1143,16 +1159,20 @@ printf '%s\\n' \\
1143
1159
  * The one error this package throws, carrying the coded reason it was raised.
1144
1160
  *
1145
1161
  * @remarks
1146
- * A throw is reserved for a caller the package cannot serve: `INVALID` for
1147
- * off-contract input, `DESTROYED` for any call made after teardown, `TARGET`
1148
- * for a destination that is not what the caller's observation said it was,
1149
- * `WRITE` for a mutation that could not be completed, and `FETCH` for an
1150
- * upstream read that produced no answer the caller can be given.
1151
- *
1152
- * A refused blueprint is not one of these. The gate fails closed and returns
1153
- * the questions that closed it, and `BLOCKED` is the code those stage records
1154
- * carry, so a caller reads a refusal from the value it asked for rather than
1155
- * from a stack.
1162
+ * Each code names one cause: `INVALID` for off-contract input, `DESTROYED` for
1163
+ * any call made after teardown, `TARGET` for a destination that is not what the
1164
+ * caller's observation said it was, `WRITE` for a mutation that could not be
1165
+ * completed, `FETCH` for an upstream read that produced no answer the caller can
1166
+ * be given, and `BLOCKED` for a refused blueprint.
1167
+ *
1168
+ * `BLOCKED` covers both refusals a blueprint can meet, because they are one fact
1169
+ * this blueprint will not be built and the questions say which. The compiler
1170
+ * answers its refusal rather than throwing it: the gate fails closed, returns the
1171
+ * questions that closed it, and records `BLOCKED` on its stage, so a caller reads
1172
+ * that refusal from the value it asked for. A verb that creates a workspace
1173
+ * throws it, because it chose the shape and has nothing to hand back. A blocking
1174
+ * question closed the gate; a non-blocking one is a shape this package can
1175
+ * describe and declines to create.
1156
1176
  *
1157
1177
  * `context` carries whatever the raising site can say about the failure. It is
1158
1178
  * `unknown` because nothing narrows it usefully at the catch site; read it for
@@ -1206,19 +1226,20 @@ function isScaffoldError(value) {
1206
1226
  //#endregion
1207
1227
  //#region src/core/validators.ts
1208
1228
  /**
1209
- * Narrow a value to a portable target-relative path.
1229
+ * Narrow a value to a logical target-relative path.
1210
1230
  *
1211
1231
  * @param value - The candidate path.
1212
1232
  * @returns `true` for a bounded relative path with no traversal, empty segment,
1213
- * control character, or non-portable visible character.
1233
+ * control character, or reserved syntax character.
1214
1234
  *
1215
1235
  * @remarks
1216
1236
  * Every path this package reads or writes passes here, so one law covers a
1217
1237
  * planned artifact, an override target, an audit finding, a guide mirror, and a
1218
1238
  * snapshot key. Rejecting `..`, a leading `/`, and a backslash at the guard is
1219
1239
  * what stops a caller-supplied path from naming a destination outside the
1220
- * target, and rejecting the non-portable visible characters is what keeps a
1221
- * generated workspace checkable out on every supported filesystem.
1240
+ * target. Host-location validation is a separate server boundary: this guard
1241
+ * does not reject a device spelling, a trailing dot or space, or a segment that
1242
+ * exceeds a host filesystem's byte ceiling.
1222
1243
  *
1223
1244
  * @example
1224
1245
  * ```ts
@@ -1496,20 +1517,34 @@ var isQuestion = (0, _orkestrel_contract.recordOf)({
1496
1517
  * @remarks
1497
1518
  * `observed` is required exactly where the mutation it precedes is held to it,
1498
1519
  * absent where the destination had no bytes to record, and optional where the
1499
- * comparison may not have been made.
1520
+ * comparison may not have been made. Planned findings require `ownership`;
1521
+ * foreign findings forbid it because no artifact was planned for their path.
1522
+ *
1523
+ * That is the whole claim. This guard proves the shape a reader may destructure
1524
+ * and nothing about whether the verdict is one an audit could have reached: the
1525
+ * correlation between `ownership`, `drift`, and `observed` belongs to
1526
+ * {@link inferDrift}, and it is re-derived at the verb that acts on the finding.
1500
1527
  */
1501
1528
  var isFinding = (0, _orkestrel_contract.unionOf)((0, _orkestrel_contract.recordOf)({
1502
1529
  path: isPath,
1503
1530
  group: isGroup,
1504
- drift: (0, _orkestrel_contract.literalOf)("stale", "foreign"),
1531
+ ownership: (0, _orkestrel_contract.literalOf)("content", "presence", "birth"),
1532
+ drift: (0, _orkestrel_contract.literalOf)("stale"),
1533
+ observed: isHex
1534
+ }), (0, _orkestrel_contract.recordOf)({
1535
+ path: isPath,
1536
+ group: isGroup,
1537
+ drift: (0, _orkestrel_contract.literalOf)("foreign"),
1505
1538
  observed: isHex
1506
1539
  }), (0, _orkestrel_contract.recordOf)({
1507
1540
  path: isPath,
1508
1541
  group: isGroup,
1542
+ ownership: (0, _orkestrel_contract.literalOf)("content", "presence", "birth"),
1509
1543
  drift: (0, _orkestrel_contract.literalOf)("missing")
1510
1544
  }), (0, _orkestrel_contract.recordOf)({
1511
1545
  path: isPath,
1512
1546
  group: isGroup,
1547
+ ownership: (0, _orkestrel_contract.literalOf)("content", "presence", "birth"),
1513
1548
  drift: (0, _orkestrel_contract.literalOf)("aligned"),
1514
1549
  observed: isHex
1515
1550
  }, ["observed"]));
@@ -1518,10 +1553,11 @@ var isFinding = (0, _orkestrel_contract.unionOf)((0, _orkestrel_contract.recordO
1518
1553
  *
1519
1554
  * @remarks
1520
1555
  * An audit reaches the writer and the destructive verb, so it is guarded as
1521
- * strictly as the plan beside it.
1556
+ * strictly as the plan beside it. Findings use the sum of the two producer
1557
+ * bounds: one per planned artifact, then one per unplanned snapshot path.
1522
1558
  */
1523
1559
  var isAudit = (0, _orkestrel_contract.recordOf)({
1524
- findings: (0, _orkestrel_contract.andOf)(isCollection, (0, _orkestrel_contract.arrayOf)(isFinding)),
1560
+ findings: (0, _orkestrel_contract.andOf)((value) => (0, _orkestrel_contract.holds)(() => (0, _orkestrel_contract.isArray)(value) && value.length <= 2e3), (0, _orkestrel_contract.arrayOf)(isFinding)),
1525
1561
  questions: (0, _orkestrel_contract.andOf)(isCollection, (0, _orkestrel_contract.arrayOf)(isQuestion))
1526
1562
  });
1527
1563
  /**
@@ -1555,7 +1591,8 @@ var isMirror = (0, _orkestrel_contract.unionOf)((0, _orkestrel_contract.recordOf
1555
1591
  var isCatalogEntry = (0, _orkestrel_contract.unionOf)((0, _orkestrel_contract.recordOf)({
1556
1592
  name: isDependencyName,
1557
1593
  lookup: (0, _orkestrel_contract.literalOf)("found"),
1558
- version: _orkestrel_contract.isString
1594
+ version: _orkestrel_contract.isString,
1595
+ dependencies: (0, _orkestrel_contract.andOf)(isCollection, (0, _orkestrel_contract.arrayOf)(isDependency))
1559
1596
  }), (0, _orkestrel_contract.recordOf)({
1560
1597
  name: isDependencyName,
1561
1598
  lookup: (0, _orkestrel_contract.literalOf)("missing", "failed"),
@@ -2111,6 +2148,71 @@ function inferDrift(artifact, observed) {
2111
2148
  return observed === artifactToHex(artifact) ? "aligned" : "stale";
2112
2149
  }
2113
2150
  /**
2151
+ * Test whether {@link inferDrift} could have produced a finding for an ownership.
2152
+ *
2153
+ * @param ownership - What scaffold claims at the planned path.
2154
+ * @param finding - The audit verdict to test.
2155
+ * @returns Whether the ownership and verdict are reachable through {@link inferDrift}.
2156
+ *
2157
+ * @remarks
2158
+ * This predicate keeps the comparison law beside the reachability law it
2159
+ * restates. A mutation uses it so a refusal can distinguish an impossible
2160
+ * verdict from a target that genuinely moved after its audit.
2161
+ */
2162
+ function matchesDriftReachability(ownership, finding) {
2163
+ if (finding.drift === "aligned") return ownership === "birth" || finding.observed !== void 0;
2164
+ if (finding.drift === "missing") return ownership !== "birth";
2165
+ return finding.drift === "stale" && ownership === "content";
2166
+ }
2167
+ /**
2168
+ * Project a catalog into the layers it publishes in.
2169
+ *
2170
+ * @param entries - The catalog rows to order.
2171
+ * @returns One layer per round, each holding the names publishable together,
2172
+ * sorted within the layer; a name whose edges never resolve is omitted.
2173
+ *
2174
+ * @remarks
2175
+ * A layer is a deterministic function of the catalog's own edges, so it is
2176
+ * computed here rather than stored on a row that could disagree with them.
2177
+ * Only RUNTIME edges between catalogued packages count: a development
2178
+ * dependency reaches no consumer, so it constrains nothing about publish order,
2179
+ * and an edge leaving the fleet is a package this catalog does not publish.
2180
+ *
2181
+ * The order matters because these packages are `0.0.x`, where a caret pins one
2182
+ * exact release. Publishing a dependent before its dependency leaves the
2183
+ * dependent pinned to the older release, and two ranges that disagree install
2184
+ * two copies of one package that the compiler reads as two distinct types.
2185
+ *
2186
+ * A cycle cannot be published in rounds, so its members are omitted rather than
2187
+ * placed in an order that would be wrong. An absent name is the report: compare
2188
+ * the returned names against the catalog to find one.
2189
+ *
2190
+ * @example
2191
+ * ```ts
2192
+ * import { catalogToLayers } from '@orkestrel/scaffold'
2193
+ *
2194
+ * catalogToLayers(entries)[0] // the names that depend on nothing in the fleet
2195
+ * ```
2196
+ */
2197
+ function catalogToLayers(entries) {
2198
+ const published = new Set(entries.filter((entry) => entry.lookup === "found").map((entry) => entry.name));
2199
+ const pending = /* @__PURE__ */ new Map();
2200
+ for (const entry of entries) {
2201
+ if (entry.lookup !== "found") continue;
2202
+ const edges = entry.dependencies.map((dependency) => dependency.name);
2203
+ pending.set(entry.name, new Set(edges.filter((name) => published.has(name))));
2204
+ }
2205
+ const layers = [];
2206
+ while (pending.size > 0) {
2207
+ const ready = [...pending].filter(([, edges]) => edges.size === 0).map(([name]) => name);
2208
+ if (ready.length === 0) break;
2209
+ for (const name of ready) pending.delete(name);
2210
+ for (const edges of pending.values()) for (const name of ready) edges.delete(name);
2211
+ layers.push(ready.sort());
2212
+ }
2213
+ return layers;
2214
+ }
2215
+ /**
2114
2216
  * Project a plan into its tally by artifact origin.
2115
2217
  *
2116
2218
  * @param plan - The plan to summarize.
@@ -2538,10 +2640,9 @@ function srcToExports(src) {
2538
2640
  *
2539
2641
  * @example
2540
2642
  * ```ts
2541
- * import type { Blueprint } from '@orkestrel/scaffold'
2542
- * import { blueprintToDevDependencies } from '@orkestrel/scaffold'
2643
+ * import { blueprintToDevDependencies, createBlueprint } from '@orkestrel/scaffold'
2543
2644
  *
2544
- * declare const blueprint: Blueprint
2645
+ * const blueprint = createBlueprint('router', { src: ['core'] })
2545
2646
  *
2546
2647
  * blueprintToDevDependencies(blueprint).typescript // the shared TypeScript pin
2547
2648
  * ```
@@ -2552,7 +2653,7 @@ function blueprintToDevDependencies(blueprint) {
2552
2653
  ...blueprint.src.includes("browser") ? SOURCE_BROWSER_DEV_DEPENDENCIES : {},
2553
2654
  ...blueprint.app.length > 0 ? APP_DEV_DEPENDENCIES : {},
2554
2655
  ...blueprint.app.includes("browser") ? APP_BROWSER_DEV_DEPENDENCIES : {},
2555
- ...blueprint.showcase ? SHOWCASE_DEV_DEPENDENCIES : {},
2656
+ ...blueprint.showcase && blueprint.app.includes("browser") ? SHOWCASE_DEV_DEPENDENCIES : {},
2556
2657
  ...blueprint.app.includes("server") ? APP_SERVER_DEV_DEPENDENCIES : {}
2557
2658
  };
2558
2659
  for (const extra of blueprint.extras) merged[extra.name] = extra.range;
@@ -2581,10 +2682,9 @@ function blueprintToDevDependencies(blueprint) {
2581
2682
  *
2582
2683
  * @example
2583
2684
  * ```ts
2584
- * import type { Blueprint } from '@orkestrel/scaffold'
2585
- * import { blueprintToScripts } from '@orkestrel/scaffold'
2685
+ * import { blueprintToScripts, createBlueprint } from '@orkestrel/scaffold'
2586
2686
  *
2587
- * declare const blueprint: Blueprint
2687
+ * const blueprint = createBlueprint('router', { src: ['core'] })
2588
2688
  *
2589
2689
  * blueprintToScripts(blueprint)['format:check'] // 'oxfmt --config .oxfmtrc.json --check .'
2590
2690
  * ```
@@ -2700,10 +2800,9 @@ function blueprintToScripts(blueprint) {
2700
2800
  *
2701
2801
  * @example
2702
2802
  * ```ts
2703
- * import type { Blueprint } from '@orkestrel/scaffold'
2704
- * import { blueprintToManifest } from '@orkestrel/scaffold'
2803
+ * import { blueprintToManifest, createBlueprint } from '@orkestrel/scaffold'
2705
2804
  *
2706
- * declare const blueprint: Blueprint
2805
+ * const blueprint = createBlueprint('router', { src: ['core'] })
2707
2806
  *
2708
2807
  * blueprintToManifest(blueprint).endsWith('}\n') // true
2709
2808
  * ```
@@ -2779,12 +2878,11 @@ function blueprintToManifest(blueprint) {
2779
2878
  *
2780
2879
  * @example
2781
2880
  * ```ts
2782
- * import type { Blueprint } from '@orkestrel/scaffold'
2783
- * import { blueprintToMachinery } from '@orkestrel/scaffold'
2881
+ * import { blueprintToMachinery, createBlueprint } from '@orkestrel/scaffold'
2784
2882
  *
2785
- * declare const blueprint: Blueprint
2883
+ * const blueprint = createBlueprint('router', { app: ['browser'] })
2786
2884
  *
2787
- * blueprintToMachinery(blueprint).vue // true when the app declares browser
2885
+ * blueprintToMachinery(blueprint).vue // true
2788
2886
  * ```
2789
2887
  */
2790
2888
  function blueprintToMachinery(blueprint) {
@@ -2804,10 +2902,9 @@ function blueprintToMachinery(blueprint) {
2804
2902
  *
2805
2903
  * @example
2806
2904
  * ```ts
2807
- * import type { Blueprint } from '@orkestrel/scaffold'
2808
- * import { blueprintToRootTsconfig } from '@orkestrel/scaffold'
2905
+ * import { blueprintToRootTsconfig, createBlueprint } from '@orkestrel/scaffold'
2809
2906
  *
2810
- * declare const blueprint: Blueprint
2907
+ * const blueprint = createBlueprint('router', { src: ['core'] })
2811
2908
  *
2812
2909
  * blueprintToRootTsconfig(blueprint).startsWith('{') // true
2813
2910
  * ```
@@ -2832,10 +2929,9 @@ function blueprintToRootTsconfig(blueprint) {
2832
2929
  *
2833
2930
  * @example
2834
2931
  * ```ts
2835
- * import type { Blueprint } from '@orkestrel/scaffold'
2836
- * import { blueprintToRootVite } from '@orkestrel/scaffold'
2932
+ * import { blueprintToRootVite, createBlueprint } from '@orkestrel/scaffold'
2837
2933
  *
2838
- * declare const blueprint: Blueprint
2934
+ * const blueprint = createBlueprint('router', { src: ['core'] })
2839
2935
  *
2840
2936
  * blueprintToRootVite(blueprint).includes('defineConfig') // true
2841
2937
  * ```
@@ -2865,8 +2961,7 @@ function blueprintToRootVite(blueprint) {
2865
2961
  const core = blueprint.src.includes("core");
2866
2962
  factories.push((0, _orkestrel_template.fillTemplate)(CONFIG_TEMPLATES.factories.src.server, {
2867
2963
  external: core ? `external: (id: string) =>
2868
- id === '@src/core' || id.startsWith('node:') || id.startsWith('@orkestrel/'),` : `external: (id: string) =>
2869
- id.startsWith('node:') || id.startsWith('@orkestrel/'),`,
2964
+ id === '@src/core' || id.startsWith('node:') || id.startsWith('@orkestrel/'),` : "external: (id: string) => id.startsWith('node:') || id.startsWith('@orkestrel/'),",
2870
2965
  output: core ? `\t\t\t\t\toutput: [
2871
2966
  {
2872
2967
  format: 'es',
@@ -2892,28 +2987,35 @@ function blueprintToRootVite(blueprint) {
2892
2987
  projects.push("appCore");
2893
2988
  }
2894
2989
  if (blueprint.app.includes("browser")) {
2895
- const showcasePlugin = machinery.showcase ? `\t\t\t...(showcase
2896
- ? [
2897
- viteSingleFile({
2898
- removeViteModuleLoader: true,
2899
- useRecommendedBuildConfig: true,
2900
- }),
2901
- {
2902
- name: 'orkestrel-showcase-html',
2903
- transformIndexHtml: {
2904
- order: 'post',
2905
- handler(html) {
2906
- const stamp = new Date().toISOString()
2907
- return html.replace(
2908
- '</head>',
2909
- '\t\t<meta name="build-id" content="' + stamp + '" />\\n\t</head>',
2910
- )
2911
- },
2912
- },
2990
+ const showcasePlugins = machinery.showcase ? ` const showcasePlugins: PluginOption[] = showcase
2991
+ ? [
2992
+ viteSingleFile({
2993
+ removeViteModuleLoader: true,
2994
+ useRecommendedBuildConfig: true,
2995
+ }),
2996
+ {
2997
+ name: 'orkestrel-showcase-html',
2998
+ transformIndexHtml: {
2999
+ order: 'post',
3000
+ handler(html) {
3001
+ const stamp = new Date().toISOString()
3002
+ return html.replace(
3003
+ '</head>',
3004
+ '\t\t<meta name="build-id" content="' + stamp + '" />\\n\t</head>',
3005
+ )
2913
3006
  },
2914
- ]
2915
- : []),
3007
+ },
3008
+ },
3009
+ ]
3010
+ : []
2916
3011
  ` : "";
3012
+ const plugins = machinery.showcase ? `\t\tplugins: [
3013
+ outputBoundary(output),
3014
+ environmentBoundary('app/browser'),
3015
+ vue(),
3016
+ ...showcasePlugins,
3017
+ ],
3018
+ ` : " plugins: [outputBoundary(output), environmentBoundary('app/browser'), vue()],\n";
2917
3019
  const showcaseBuild = machinery.showcase ? `\t\t\t...(showcase
2918
3020
  ? {
2919
3021
  cssMinify: 'lightningcss',
@@ -2932,11 +3034,12 @@ export function appShowcase(...options: never[]): UserConfig {
2932
3034
  }
2933
3035
  ` : "";
2934
3036
  factories.push((0, _orkestrel_template.fillTemplate)(CONFIG_TEMPLATES.factories.app.browser, {
2935
- showcasePlugin,
3037
+ plugins,
3038
+ showcasePlugins,
2936
3039
  showcaseBuild,
2937
3040
  showcaseFactory
2938
3041
  }));
2939
- projects.push("appBrowser");
3042
+ projects.push("appBrowser()");
2940
3043
  }
2941
3044
  if (blueprint.app.includes("server")) {
2942
3045
  factories.push(CONFIG_TEMPLATES.factories.app.server);
@@ -2957,9 +3060,13 @@ export function appShowcase(...options: never[]): UserConfig {
2957
3060
  const projectRows = `\t\tprojects: [
2958
3061
  ${projects.map((project) => `\t\t\t${project},`).join("\n")}
2959
3062
  \t],`;
3063
+ const body = `${factories.join("\n")}\n`;
3064
+ const boundaries = ["environmentBoundary", "outputBoundary"].filter((boundary) => body.includes(boundary));
2960
3065
  return (0, _orkestrel_template.fillTemplate)(CONFIG_TEMPLATES.root.vite, {
3066
+ viteTypes: machinery.showcase ? "PluginOption, UserConfig" : "UserConfig",
2961
3067
  imports: imports.length === 0 ? "" : `${imports.join("\n")}\n`,
2962
- factories: `${factories.join("\n")}\n`,
3068
+ helpers: boundaries.length === 0 ? "" : `import { ${boundaries.join(", ")} } from './configs/helpers.js'\n`,
3069
+ factories: body,
2963
3070
  projects: projectRows
2964
3071
  });
2965
3072
  }
@@ -2971,10 +3078,9 @@ ${projects.map((project) => `\t\t\t${project},`).join("\n")}
2971
3078
  *
2972
3079
  * @example
2973
3080
  * ```ts
2974
- * import type { Blueprint } from '@orkestrel/scaffold'
2975
- * import { blueprintToConfigArtifacts } from '@orkestrel/scaffold'
3081
+ * import { blueprintToConfigArtifacts, createBlueprint } from '@orkestrel/scaffold'
2976
3082
  *
2977
- * declare const blueprint: Blueprint
3083
+ * const blueprint = createBlueprint('router', { src: ['core'] })
2978
3084
  *
2979
3085
  * blueprintToConfigArtifacts(blueprint)[0]?.path // 'tsconfig.json'
2980
3086
  * ```
@@ -3000,7 +3106,8 @@ function blueprintToConfigArtifacts(blueprint) {
3000
3106
  else if (path === "configs/src/tsconfig.browser.json") content = CONFIG_TEMPLATES.tsconfigs.src.browser;
3001
3107
  else if (path === "configs/src/vite.server.config.ts") {
3002
3108
  const packageName = serializeTypeScriptString(`@orkestrel/${blueprint.name}`);
3003
- const replacement = packageName.length <= 36 ? `\t\t\t\t\t\t? content.replaceAll(/(?:\\.\\.\\/)+core\\/index\\.ts/g, ${packageName})` : [
3109
+ const joined = `\t\t\t\t\t\t? content.replaceAll(/(?:\\.\\.\\/)+core\\/index\\.ts/g, ${packageName})`;
3110
+ const replacement = joined.replaceAll(" ", " ").length <= 100 ? joined : [
3004
3111
  " ? content.replaceAll(",
3005
3112
  " /(?:\\.\\.\\/)+core\\/index\\.ts/g,",
3006
3113
  `\t\t\t\t\t\t\t\t${packageName},`,
@@ -3065,7 +3172,7 @@ ${paths.join("\n")}
3065
3172
  content
3066
3173
  });
3067
3174
  }
3068
- if (blueprint.showcase) artifacts.push({
3175
+ if (blueprint.showcase && blueprint.app.includes("browser")) artifacts.push({
3069
3176
  path: SHOWCASE_CONFIG_PATH,
3070
3177
  group: "configs",
3071
3178
  ownership: "content",
@@ -3082,16 +3189,18 @@ ${paths.join("\n")}
3082
3189
  * @returns Empty published barrels, selected application entries, and the optional bin entry.
3083
3190
  *
3084
3191
  * @remarks
3085
- * The barrels and bin entry intentionally export nothing. A generated sample
3086
- * entity is too easy to mistake for package implementation, so the scaffold
3087
- * establishes only the selected environment boundaries.
3192
+ * The barrels and every runtime entry intentionally hold nothing. A generated
3193
+ * sample entity is too easy to mistake for package implementation, so the
3194
+ * scaffold establishes only the selected environment boundaries. An application
3195
+ * entry is empty for the same reason the bin entry is, and because the vendored
3196
+ * lint config refuses an unassigned import outside a stylesheet, so the entry
3197
+ * cannot start by importing its barrel for effect either.
3088
3198
  *
3089
3199
  * @example
3090
3200
  * ```ts
3091
- * import type { Blueprint } from '@orkestrel/scaffold'
3092
- * import { blueprintToSourceArtifacts } from '@orkestrel/scaffold'
3201
+ * import { blueprintToSourceArtifacts, createBlueprint } from '@orkestrel/scaffold'
3093
3202
  *
3094
- * declare const blueprint: Blueprint
3203
+ * const blueprint = createBlueprint('router', { src: ['core'] })
3095
3204
  *
3096
3205
  * blueprintToSourceArtifacts(blueprint).every(({ group }) => group === 'source') // true
3097
3206
  * ```
@@ -3121,7 +3230,7 @@ function blueprintToSourceArtifacts(blueprint) {
3121
3230
  ownership: "birth",
3122
3231
  origin: "template",
3123
3232
  environment,
3124
- content: ARTIFACT_TEMPLATES.source.main
3233
+ content: ARTIFACT_TEMPLATES.source.empty
3125
3234
  }, {
3126
3235
  path: "app/browser/index.html",
3127
3236
  group: "source",
@@ -3136,7 +3245,7 @@ function blueprintToSourceArtifacts(blueprint) {
3136
3245
  ownership: "birth",
3137
3246
  origin: "template",
3138
3247
  environment,
3139
- content: ARTIFACT_TEMPLATES.source.main
3248
+ content: ARTIFACT_TEMPLATES.source.empty
3140
3249
  });
3141
3250
  }
3142
3251
  if (blueprint.bin) artifacts.push({
@@ -3164,10 +3273,9 @@ function blueprintToSourceArtifacts(blueprint) {
3164
3273
  *
3165
3274
  * @example
3166
3275
  * ```ts
3167
- * import type { Blueprint } from '@orkestrel/scaffold'
3168
- * import { blueprintToTestArtifacts } from '@orkestrel/scaffold'
3276
+ * import { blueprintToTestArtifacts, createBlueprint } from '@orkestrel/scaffold'
3169
3277
  *
3170
- * declare const blueprint: Blueprint
3278
+ * const blueprint = createBlueprint('router', { src: ['core'] })
3171
3279
  *
3172
3280
  * blueprintToTestArtifacts(blueprint)[0]?.path // 'tests/setup.ts'
3173
3281
  * ```
@@ -3377,10 +3485,9 @@ function nameToHostArtifacts(name) {
3377
3485
  *
3378
3486
  * @example
3379
3487
  * ```ts
3380
- * import type { Artifact } from '@orkestrel/scaffold'
3381
- * import { applyOverrides } from '@orkestrel/scaffold'
3488
+ * import { applyOverrides, blueprintToConfigArtifacts, createBlueprint } from '@orkestrel/scaffold'
3382
3489
  *
3383
- * declare const artifacts: readonly Artifact[]
3490
+ * const artifacts = blueprintToConfigArtifacts(createBlueprint('router', { src: ['core'] }))
3384
3491
  *
3385
3492
  * applyOverrides(artifacts, [{ path: 'README.md', content: '# Title\n' }])
3386
3493
  * ```
@@ -3418,12 +3525,11 @@ function applyOverrides(artifacts, overrides) {
3418
3525
  *
3419
3526
  * @example
3420
3527
  * ```ts
3421
- * import type { Plan } from '@orkestrel/scaffold'
3422
- * import { planToHash } from '@orkestrel/scaffold'
3528
+ * import { createBlueprint, createCompiler, planToHash } from '@orkestrel/scaffold'
3423
3529
  *
3424
- * declare const plan: Plan
3530
+ * const { plan } = createCompiler().compile(createBlueprint('router', { src: ['core'] }))
3425
3531
  *
3426
- * planToHash(plan)?.length // 16
3532
+ * plan === undefined ? undefined : planToHash(plan)?.length // 16
3427
3533
  * ```
3428
3534
  */
3429
3535
  function planToHash(plan) {
@@ -3441,13 +3547,16 @@ function planToHash(plan) {
3441
3547
  * @param artifact - The planned artifact.
3442
3548
  * @param observed - The destination's exact bytes as hexadecimal; absent when
3443
3549
  * the destination holds no file.
3444
- * @returns The finding, carrying `observed` exactly where bytes were read.
3550
+ * @returns The finding, carrying the artifact's ownership and `observed`
3551
+ * exactly where bytes were read.
3445
3552
  *
3446
3553
  * @remarks
3447
3554
  * The comparison itself is {@link inferDrift}'s, so ownership decides it here
3448
3555
  * exactly as it does everywhere else. This adds only the shape: a missing
3449
3556
  * destination has no bytes to record, and every other verdict records the bytes
3450
3557
  * it was given, which is the precondition the mutation that follows is held to.
3558
+ * Ownership is copied rather than inferred from drift because aligned findings
3559
+ * span all three ownership tiers.
3451
3560
  *
3452
3561
  * `foreign` is not answerable here, because it describes a path no artifact was
3453
3562
  * planned for.
@@ -3459,29 +3568,34 @@ function planToHash(plan) {
3459
3568
  * artifactToFinding(
3460
3569
  * { path: 'README.md', group: 'docs', ownership: 'content', origin: 'computed', content: 'hi\n' },
3461
3570
  * '6279650a',
3462
- * ) // { path: 'README.md', group: 'docs', drift: 'stale', observed: '6279650a' }
3571
+ * ) // { path: 'README.md', group: 'docs', ownership: 'content', drift: 'stale', observed: '6279650a' }
3463
3572
  * ```
3464
3573
  */
3465
3574
  function artifactToFinding(artifact, observed) {
3466
3575
  const path = artifact.path;
3467
3576
  const group = artifact.group;
3577
+ const ownership = artifact.ownership;
3468
3578
  if (observed === void 0) return inferDrift(artifact) === "aligned" ? {
3469
3579
  path,
3470
3580
  group,
3581
+ ownership,
3471
3582
  drift: "aligned"
3472
3583
  } : {
3473
3584
  path,
3474
3585
  group,
3586
+ ownership,
3475
3587
  drift: "missing"
3476
3588
  };
3477
3589
  return inferDrift(artifact, observed) === "stale" ? {
3478
3590
  path,
3479
3591
  group,
3592
+ ownership,
3480
3593
  drift: "stale",
3481
3594
  observed
3482
3595
  } : {
3483
3596
  path,
3484
3597
  group,
3598
+ ownership,
3485
3599
  drift: "aligned",
3486
3600
  observed
3487
3601
  };
@@ -3505,12 +3619,11 @@ function artifactToFinding(artifact, observed) {
3505
3619
  *
3506
3620
  * @example
3507
3621
  * ```ts
3508
- * import type { Plan } from '@orkestrel/scaffold'
3509
- * import { planToFindings } from '@orkestrel/scaffold'
3622
+ * import { createBlueprint, createCompiler, planToFindings } from '@orkestrel/scaffold'
3510
3623
  *
3511
- * declare const plan: Plan
3624
+ * const { plan } = createCompiler().compile(createBlueprint('router', { src: ['core'] }))
3512
3625
  *
3513
- * planToFindings(plan, { 'AGENTS.md': '68690a' })
3626
+ * plan === undefined ? [] : planToFindings(plan, { 'AGENTS.md': '68690a' })
3514
3627
  * ```
3515
3628
  */
3516
3629
  function planToFindings(plan, current) {
@@ -3594,8 +3707,8 @@ function dependenciesToQuestions(dependencies, field, name, range) {
3594
3707
  * Measure a blueprint against every law its own fields decide.
3595
3708
  *
3596
3709
  * @param blueprint - The workspace specification.
3597
- * @returns One blocking question per rejected field, in blueprint field order,
3598
- * with the rules that span several fields last.
3710
+ * @returns One question per rejected field, in blueprint field order, with the
3711
+ * rules that span several fields last.
3599
3712
  *
3600
3713
  * @remarks
3601
3714
  * Only the laws a blueprint answers alone are here. The structural record and
@@ -3606,19 +3719,25 @@ function dependenciesToQuestions(dependencies, field, name, range) {
3606
3719
  * a drafted plan belong to {@link artifactsToQuestions} and
3607
3720
  * {@link overridesToQuestions}.
3608
3721
  *
3609
- * Every question is blocking, because each one describes a workspace this
3610
- * package cannot generate rather than one it can generate imperfectly. An
3611
- * environment question carries `ENVIRONMENTS` as its candidates, so a caller
3612
- * reads the accepted values from the refusal instead of from the documentation.
3722
+ * A question blocks when it describes a workspace this package cannot generate.
3723
+ * Three do not, because each describes a workspace it can describe honestly and
3724
+ * should not create: a published axis of several environments without core, whose
3725
+ * manifest names a core build the workspace never runs, and a structural flag
3726
+ * whose required axis is absent, which emits nothing. Blocking those closed the
3727
+ * gate for every verb, and the verbs that read an existing workspace need the
3728
+ * plan the gate refused. The caller that chooses the shape refuses the advisory;
3729
+ * the callers that read one report it.
3730
+ *
3731
+ * An environment question carries `ENVIRONMENTS` as its candidates, so a caller
3732
+ * reads the accepted values from the question instead of from the documentation.
3613
3733
  *
3614
3734
  * @example
3615
3735
  * ```ts
3616
- * import type { Blueprint } from '@orkestrel/scaffold'
3617
- * import { blueprintToQuestions } from '@orkestrel/scaffold'
3736
+ * import { blueprintToQuestions, createBlueprint } from '@orkestrel/scaffold'
3618
3737
  *
3619
- * declare const blueprint: Blueprint
3738
+ * const blueprint = createBlueprint('router', { src: ['core'] })
3620
3739
  *
3621
- * blueprintToQuestions(blueprint).length === 0 // true when the gate passes
3740
+ * blueprintToQuestions(blueprint).length === 0 // true
3622
3741
  * ```
3623
3742
  */
3624
3743
  function blueprintToQuestions(blueprint) {
@@ -3644,6 +3763,12 @@ function blueprintToQuestions(blueprint) {
3644
3763
  blocking: true,
3645
3764
  candidates: ENVIRONMENTS
3646
3765
  });
3766
+ if (blueprint.src.length > 1 && !blueprint.src.includes("core")) questions.push({
3767
+ field: "src",
3768
+ message: "Several published environments put core at the package root, so this manifest names a core build the workspace never runs. Declare core on src, or publish one environment.",
3769
+ blocking: false,
3770
+ candidates: ENVIRONMENTS
3771
+ });
3647
3772
  for (const environment of ENVIRONMENTS) {
3648
3773
  if (blueprint.src.filter((declared) => declared === environment).length > 1) questions.push({
3649
3774
  field: "src",
@@ -3658,11 +3783,10 @@ function blueprintToQuestions(blueprint) {
3658
3783
  candidates: ENVIRONMENTS
3659
3784
  });
3660
3785
  }
3661
- if (blueprint.showcase && !blueprint.app.includes("browser")) questions.push({
3662
- field: "showcase",
3663
- message: "A showcase projects the browser application, which app does not declare.",
3664
- blocking: true,
3665
- candidates: ENVIRONMENTS
3786
+ if (blueprint.integration && blueprint.src.length === 0) questions.push({
3787
+ field: "integration",
3788
+ message: "integration projects a published src, and this workspace declares none, so it emits nothing.",
3789
+ blocking: false
3666
3790
  });
3667
3791
  const services = /* @__PURE__ */ new Set();
3668
3792
  for (const service of blueprint.services) {
@@ -3678,6 +3802,11 @@ function blueprintToQuestions(blueprint) {
3678
3802
  });
3679
3803
  services.add(service);
3680
3804
  }
3805
+ if (blueprint.showcase && !blueprint.app.includes("browser")) questions.push({
3806
+ field: "showcase",
3807
+ message: "showcase projects a browser app, and this workspace declares none, so it emits nothing.",
3808
+ blocking: false
3809
+ });
3681
3810
  questions.push(...dependenciesToQuestions(blueprint.dependencies, "dependencies", DEPENDENCY_NAME_PATTERN, ORKESTREL_RANGE_PATTERN), ...dependenciesToQuestions(blueprint.peers, "peers", DEPENDENCY_NAME_PATTERN, ORKESTREL_RANGE_PATTERN), ...dependenciesToQuestions(blueprint.extras, "extras", EXTRA_NAME_PATTERN, EXTRA_RANGE_PATTERN));
3682
3811
  const lists = [
3683
3812
  ["dependencies", blueprint.dependencies],
@@ -3726,12 +3855,11 @@ function blueprintToQuestions(blueprint) {
3726
3855
  *
3727
3856
  * @example
3728
3857
  * ```ts
3729
- * import type { Artifact } from '@orkestrel/scaffold'
3730
- * import { artifactsToQuestions } from '@orkestrel/scaffold'
3858
+ * import { artifactsToQuestions, blueprintToConfigArtifacts, createBlueprint } from '@orkestrel/scaffold'
3731
3859
  *
3732
- * declare const artifacts: readonly Artifact[]
3860
+ * const artifacts = blueprintToConfigArtifacts(createBlueprint('router', { src: ['core'] }))
3733
3861
  *
3734
- * artifactsToQuestions(artifacts).length === 0 // true when the draft is sound
3862
+ * artifactsToQuestions(artifacts).length === 0 // true
3735
3863
  * ```
3736
3864
  */
3737
3865
  function artifactsToQuestions(artifacts) {
@@ -3783,10 +3911,9 @@ function artifactsToQuestions(artifacts) {
3783
3911
  *
3784
3912
  * @example
3785
3913
  * ```ts
3786
- * import type { Artifact } from '@orkestrel/scaffold'
3787
- * import { overridesToQuestions } from '@orkestrel/scaffold'
3914
+ * import { blueprintToConfigArtifacts, createBlueprint, overridesToQuestions } from '@orkestrel/scaffold'
3788
3915
  *
3789
- * declare const artifacts: readonly Artifact[]
3916
+ * const artifacts = blueprintToConfigArtifacts(createBlueprint('router', { src: ['core'] }))
3790
3917
  *
3791
3918
  * overridesToQuestions([{ path: 'package.json', content: '{}\n' }], artifacts).length // 1
3792
3919
  * ```
@@ -3913,12 +4040,19 @@ var Compiler = class {
3913
4040
  * carries no plan, then `compile` with the whole outcome either way, so an
3914
4041
  * observer reads every compile from one event and the refusals from the other.
3915
4042
  *
4043
+ * A plan says the blueprint can be built. It does not say the blueprint should
4044
+ * be created, and the questions beside it are what this compiler could not
4045
+ * settle. A caller creating a fresh workspace answers them first and writes
4046
+ * nothing while any remains, which is the rule the `new` verb applies; a caller
4047
+ * describing or repairing an existing target carries them through instead.
4048
+ * Nothing downstream repeats that check, because only the caller knows which of
4049
+ * the two it is.
4050
+ *
3916
4051
  * @example
3917
4052
  * ```ts
3918
- * import type { Blueprint } from '@orkestrel/scaffold'
3919
- * import { createCompiler } from '@orkestrel/scaffold'
4053
+ * import { createBlueprint, createCompiler } from '@orkestrel/scaffold'
3920
4054
  *
3921
- * declare const blueprint: Blueprint
4055
+ * const blueprint = createBlueprint('router', { src: ['core'] })
3922
4056
  *
3923
4057
  * createCompiler().compile(blueprint, ['manifest']).plan?.artifacts.length // 1
3924
4058
  * ```
@@ -3946,14 +4080,19 @@ var Compiler = class {
3946
4080
  * reports no findings and carries the questions instead. Emits `block` in that
3947
4081
  * case, then `audit` with the verdict either way.
3948
4082
  *
4083
+ * Ownership decides each verdict, not absence. A birth-owned path is never
4084
+ * compared and reads `aligned` against a target holding nothing, while a
4085
+ * content-owned path with no bytes to read is `missing`. An empty snapshot
4086
+ * therefore produces both verdicts rather than one.
4087
+ *
3949
4088
  * @example
3950
4089
  * ```ts
3951
- * import type { Blueprint } from '@orkestrel/scaffold'
3952
- * import { createCompiler } from '@orkestrel/scaffold'
4090
+ * import { createBlueprint, createCompiler } from '@orkestrel/scaffold'
3953
4091
  *
3954
- * declare const blueprint: Blueprint
4092
+ * const blueprint = createBlueprint('router', { src: ['core'] })
3955
4093
  *
3956
- * createCompiler().audit(blueprint, {}).findings.every(({ drift }) => drift === 'missing') // true
4094
+ * createCompiler().audit(blueprint, {}, ['manifest']).findings[0]?.drift // 'aligned'
4095
+ * createCompiler().audit(blueprint, {}, ['configs']).findings[0]?.drift // 'missing'
3957
4096
  * ```
3958
4097
  */
3959
4098
  audit(blueprint, current, groups) {
@@ -3991,7 +4130,10 @@ var Compiler = class {
3991
4130
  }
3992
4131
  #scaffold(blueprint, groups) {
3993
4132
  const stages = [];
3994
- const artifacts = this.#draft(blueprint, groups);
4133
+ const draft = this.#draft(blueprint);
4134
+ const selected = [];
4135
+ for (const group of groups) for (const artifact of draft) if (artifact.group === group) selected.push(artifact);
4136
+ const artifacts = applyOverrides(selected, blueprint.overrides);
3995
4137
  stages.push({
3996
4138
  stage: "draft",
3997
4139
  input: {
@@ -4000,7 +4142,7 @@ var Compiler = class {
4000
4142
  },
4001
4143
  output: artifacts
4002
4144
  });
4003
- const questions = this.#gate(blueprint, artifacts);
4145
+ const questions = this.#gate(blueprint, draft, artifacts);
4004
4146
  const blocking = questions.filter((question) => question.blocking);
4005
4147
  if (blocking.length > 0) {
4006
4148
  stages.push({
@@ -4069,8 +4211,8 @@ var Compiler = class {
4069
4211
  stages
4070
4212
  };
4071
4213
  }
4072
- #draft(blueprint, groups) {
4073
- const drafted = [
4214
+ #draft(blueprint) {
4215
+ return [
4074
4216
  {
4075
4217
  path: "package.json",
4076
4218
  group: "manifest",
@@ -4086,14 +4228,11 @@ var Compiler = class {
4086
4228
  ...blueprintToOrchestrationArtifacts(blueprint),
4087
4229
  ...nameToHostArtifacts(blueprint.name)
4088
4230
  ];
4089
- const covered = [];
4090
- for (const group of groups) for (const artifact of drafted) if (artifact.group === group) covered.push(artifact);
4091
- return applyOverrides(covered, blueprint.overrides);
4092
4231
  }
4093
- #gate(blueprint, artifacts) {
4232
+ #gate(blueprint, draft, artifacts) {
4094
4233
  return [
4095
4234
  ...blueprintToQuestions(blueprint),
4096
- ...overridesToQuestions(blueprint.overrides, artifacts),
4235
+ ...overridesToQuestions(blueprint.overrides, draft),
4097
4236
  ...artifactsToQuestions(artifacts)
4098
4237
  ];
4099
4238
  }
@@ -4215,6 +4354,7 @@ exports.DEFAULT_VERSION = DEFAULT_VERSION;
4215
4354
  exports.DEPENDENCY_NAME_PATTERN = DEPENDENCY_NAME_PATTERN;
4216
4355
  exports.ENGINES_PATTERN = ENGINES_PATTERN;
4217
4356
  exports.ENVIRONMENTS = ENVIRONMENTS;
4357
+ exports.EXECUTABLE_PATHS = EXECUTABLE_PATHS;
4218
4358
  exports.EXTRA_NAME_PATTERN = EXTRA_NAME_PATTERN;
4219
4359
  exports.EXTRA_RANGE_PATTERN = EXTRA_RANGE_PATTERN;
4220
4360
  exports.GLOBAL_SETUP_PATH = GLOBAL_SETUP_PATH;
@@ -4226,6 +4366,7 @@ exports.INTEGRATION_TEST_PATH = INTEGRATION_TEST_PATH;
4226
4366
  exports.INVALID_PATH_CHARACTER_PATTERN = INVALID_PATH_CHARACTER_PATTERN;
4227
4367
  exports.MAX_ARTIFACT_BYTES = MAX_ARTIFACT_BYTES;
4228
4368
  exports.MAX_ARTIFACT_HEX_LENGTH = MAX_ARTIFACT_HEX_LENGTH;
4369
+ exports.MAX_AUDIT_FINDINGS = MAX_AUDIT_FINDINGS;
4229
4370
  exports.MAX_COLLECTION_ITEMS = MAX_COLLECTION_ITEMS;
4230
4371
  exports.MAX_DEPENDENCY_NAME_LENGTH = MAX_DEPENDENCY_NAME_LENGTH;
4231
4372
  exports.MAX_MANIFEST_BYTES = MAX_MANIFEST_BYTES;
@@ -4263,6 +4404,7 @@ exports.blueprintToScripts = blueprintToScripts;
4263
4404
  exports.blueprintToSourceArtifacts = blueprintToSourceArtifacts;
4264
4405
  exports.blueprintToTestArtifacts = blueprintToTestArtifacts;
4265
4406
  exports.bytesToHex = bytesToHex;
4407
+ exports.catalogToLayers = catalogToLayers;
4266
4408
  exports.cloneValue = cloneValue;
4267
4409
  exports.compareVersions = compareVersions;
4268
4410
  exports.computeBytes = computeBytes;
@@ -4298,6 +4440,7 @@ exports.isScaffoldError = isScaffoldError;
4298
4440
  exports.isSnapshot = isSnapshot;
4299
4441
  exports.manifestToDependencies = manifestToDependencies;
4300
4442
  exports.manifestToName = manifestToName;
4443
+ exports.matchesDriftReachability = matchesDriftReachability;
4301
4444
  exports.matchesEngines = matchesEngines;
4302
4445
  exports.matchesOrchestrationPath = matchesOrchestrationPath;
4303
4446
  exports.matchesRange = matchesRange;