@orkestrel/scaffold 0.0.46 → 0.0.48

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.
@@ -2,6 +2,118 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  let _orkestrel_contract = require("@orkestrel/contract");
3
3
  let _orkestrel_template = require("@orkestrel/template");
4
4
  let _orkestrel_emitter = require("@orkestrel/emitter");
5
+ var package_default = {
6
+ name: "@orkestrel/scaffold",
7
+ version: "0.0.48",
8
+ description: "Scaffold workspaces with five commands: new, audit, repair, catalog, and overwrite.",
9
+ keywords: [
10
+ "audit",
11
+ "catalog",
12
+ "new",
13
+ "overwrite",
14
+ "repair"
15
+ ],
16
+ homepage: "https://github.com/orkestrel/scaffold#readme",
17
+ bugs: "https://github.com/orkestrel/scaffold/issues",
18
+ license: "MIT",
19
+ repository: {
20
+ "type": "git",
21
+ "url": "git+https://github.com/orkestrel/scaffold.git"
22
+ },
23
+ bin: { "scaffold": "dist/bin/main.js" },
24
+ files: [
25
+ "dist/src",
26
+ "dist/bin",
27
+ "dist/host",
28
+ "README.md"
29
+ ],
30
+ type: "module",
31
+ sideEffects: ["./src/bin/main.ts", "./dist/bin/main.js"],
32
+ main: "./dist/src/core/index.cjs",
33
+ module: "./dist/src/core/index.js",
34
+ exports: {
35
+ ".": {
36
+ "import": {
37
+ "types": "./dist/src/core/index.d.ts",
38
+ "default": "./dist/src/core/index.js"
39
+ },
40
+ "require": {
41
+ "types": "./dist/src/core/index.d.cts",
42
+ "default": "./dist/src/core/index.cjs"
43
+ }
44
+ },
45
+ "./server": {
46
+ "import": {
47
+ "types": "./dist/src/server/index.d.ts",
48
+ "default": "./dist/src/server/index.js"
49
+ },
50
+ "require": {
51
+ "types": "./dist/src/server/index.d.cts",
52
+ "default": "./dist/src/server/index.cjs"
53
+ }
54
+ },
55
+ "./package.json": "./package.json"
56
+ },
57
+ publishConfig: { "access": "public" },
58
+ scripts: {
59
+ "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
60
+ "copy": "node -e \"const fs=require('node:fs'),p=require('node:path'),a=process.argv[1],b=process.argv[2];fs.mkdirSync(p.dirname(b),{recursive:true});fs.cpSync(a,b,{force:true});console.log('Copied: '+a+' to '+b)\"",
61
+ "scaffold": "node ./dist/bin/main.js",
62
+ "lint": "oxlint --config .oxlintrc.json --fix --deny-warnings .",
63
+ "check": "tsc --noEmit --project tsconfig.json && npm run check:src",
64
+ "check:src": "npm run check:src:core && npm run check:src:server && npm run check:src:bin",
65
+ "check:src:core": "tsc --noEmit -p configs/src/tsconfig.core.json",
66
+ "check:src:server": "tsc --noEmit -p configs/src/tsconfig.server.json",
67
+ "check:src:bin": "tsc --noEmit -p configs/src/tsconfig.bin.json",
68
+ "format": "oxfmt --config .oxfmtrc.json --write .",
69
+ "format:check": "oxfmt --config .oxfmtrc.json --check .",
70
+ "lint:check": "oxlint --config .oxlintrc.json --deny-warnings .",
71
+ "test": "npm run test:src:core && npm run test:src:server && npm run test:src:bin && npm run test:policy && npm run test:config && npm run test:guides",
72
+ "test:src:core": "vitest run --config vite.config.ts --no-cache --reporter=dot --project src:core",
73
+ "test:src:server": "vitest run --config vite.config.ts --no-cache --reporter=dot --project src:server",
74
+ "test:src:bin": "vitest run --config vite.config.ts --no-cache --reporter=dot --project src:bin",
75
+ "test:policy": "vitest run --config vite.config.ts --no-cache --reporter=dot --project policy",
76
+ "test:config": "vitest run --config vite.config.ts --no-cache --reporter=dot --project config",
77
+ "test:guides": "vitest run --config vite.config.ts --no-cache --reporter=dot --project guides",
78
+ "test:distribution": "vitest run --config vite.config.ts --no-cache --reporter=dot --project distribution",
79
+ "test:probe": "vitest run --config vite.config.ts --no-cache --reporter=verbose --project probe",
80
+ "test:bench": "vitest bench --config vite.config.ts --no-cache --project probe",
81
+ "build": "npm run clean && npm run build:src && npm run build:host",
82
+ "build:src": "npm run build:src:core && npm run build:src:server && npm run build:src:bin",
83
+ "build:src:core": "vite build --config configs/src/vite.core.config.ts && npm run copy dist/src/core/index.d.ts dist/src/core/index.d.cts",
84
+ "build:src:server": "vite build --config configs/src/vite.server.config.ts && npm run copy dist/src/server/index.d.ts dist/src/server/index.d.cts",
85
+ "build:src:bin": "vite build --config configs/src/vite.bin.config.ts",
86
+ "build:host": "node -e \"import('./dist/src/server/index.js').then((m)=>{const n=m.stageHost(process.cwd(),'dist/host').length;console.log('build-host: staged '+n+' file(s) into dist/host')})\"",
87
+ "prepack": "npm run build",
88
+ "prepublishOnly": "npm run format:check && npm run lint:check && npm run check && npm run build && npm test && npm run test:distribution -- --mode release"
89
+ },
90
+ dependencies: {
91
+ "@orkestrel/console": "^0.0.9",
92
+ "@orkestrel/contract": "^0.0.13",
93
+ "@orkestrel/emitter": "^0.0.7",
94
+ "@orkestrel/markdown": "^0.0.9",
95
+ "@orkestrel/process": "^0.0.6",
96
+ "@orkestrel/template": "^0.0.4"
97
+ },
98
+ devDependencies: {
99
+ "@microsoft/api-extractor": "^7.59.0",
100
+ "@orkestrel/guide": "^0.0.12",
101
+ "@orkestrel/html": "^0.0.4",
102
+ "@orkestrel/probe": "^0.0.2",
103
+ "@orkestrel/test": "^0.0.9",
104
+ "@types/node": "^26.2.0",
105
+ "@vitest/browser-playwright": "^4.1.11",
106
+ "oxfmt": "^0.64.0",
107
+ "oxlint": "^1.79.0",
108
+ "playwright": "^1.62.1",
109
+ "typescript": "^6.0.3",
110
+ "vite": "^8.2.2",
111
+ "vite-plugin-dts": "^5.0.3",
112
+ "vitest": "^4.1.11"
113
+ },
114
+ engines: { "node": ">=22.12.0" }
115
+ };
116
+ //#endregion
5
117
  //#region src/core/constants.ts
6
118
  /**
7
119
  * The `Environment` values, frozen.
@@ -302,6 +414,24 @@ var MAX_AUDIT_FINDINGS = MAX_COLLECTION_ITEMS * 2;
302
414
  var MAX_ARTIFACT_BYTES = 5242880;
303
415
  /** Maximum length of the hexadecimal string carrying one artifact's bytes. */
304
416
  var MAX_ARTIFACT_HEX_LENGTH = MAX_ARTIFACT_BYTES * 2;
417
+ /**
418
+ * Maximum decoded bytes accepted from one registry response.
419
+ *
420
+ * @remarks
421
+ * The 2026-08-21 abbreviated-packument measurements were 8,647,138 bytes for
422
+ * TypeScript, 8,077,438 for Playwright, 2,315,360 for `@types/node`, 2,298,256
423
+ * for Vite, and 1,272,652 for Vitest. The bound leaves headroom above those
424
+ * registry answers.
425
+ */
426
+ var MAX_REGISTRY_BYTES = 33554432;
427
+ /**
428
+ * Maximum decoded bytes accepted across one registry-reading call.
429
+ *
430
+ * @remarks
431
+ * The 2026-08-21 browser-workspace registry set measured about 24 MiB. The
432
+ * bound leaves headroom for that set to grow without making a call unbounded.
433
+ */
434
+ var MAX_TOTAL_REGISTRY_BYTES = 100663296;
305
435
  /** Maximum bytes accepted for one package or vendored-host manifest. */
306
436
  var MAX_MANIFEST_BYTES = 1048576;
307
437
  /** Maximum bytes retained across one whole plan or audit. */
@@ -314,33 +444,33 @@ var DEFAULT_VERSION = "0.0.1";
314
444
  var DEFAULT_ENGINES = `>=${MINIMUM_NODE_VERSION}`;
315
445
  /** The tooling versions scaffold and every generated workspace share. */
316
446
  var BASE_DEV_DEPENDENCIES = Object.freeze({
317
- "@orkestrel/guide": "^0.0.12",
318
- "@orkestrel/probe": "^0.0.1",
319
- "@orkestrel/scaffold": "^0.0.46",
320
- "@orkestrel/test": "^0.0.7",
321
- "@types/node": "^26.2.0",
322
- oxfmt: "^0.64.0",
323
- oxlint: "^1.79.0",
324
- typescript: "^6.0.3",
325
- vite: "~8.2.1",
326
- vitest: "^4.1.11"
447
+ "@orkestrel/guide": package_default.devDependencies["@orkestrel/guide"],
448
+ "@orkestrel/probe": package_default.devDependencies["@orkestrel/probe"],
449
+ "@orkestrel/scaffold": `^${package_default.version}`,
450
+ "@orkestrel/test": package_default.devDependencies["@orkestrel/test"],
451
+ "@types/node": package_default.devDependencies["@types/node"],
452
+ oxfmt: package_default.devDependencies.oxfmt,
453
+ oxlint: package_default.devDependencies.oxlint,
454
+ typescript: package_default.devDependencies.typescript,
455
+ vite: package_default.devDependencies.vite,
456
+ vitest: package_default.devDependencies.vitest
327
457
  });
328
458
  /** The development dependencies that emit declarations for published source or an executable. */
329
459
  var DECLARATION_DEV_DEPENDENCIES = Object.freeze({
330
- "@microsoft/api-extractor": "^7.58.12",
331
- "vite-plugin-dts": "^5.0.3"
460
+ "@microsoft/api-extractor": package_default.devDependencies["@microsoft/api-extractor"],
461
+ "vite-plugin-dts": package_default.devDependencies["vite-plugin-dts"]
332
462
  });
333
463
  /** The development dependencies a published browser `src` environment adds. */
334
464
  var SOURCE_BROWSER_DEV_DEPENDENCIES = Object.freeze({
335
- "@vitest/browser-playwright": "^4.1.11",
336
- playwright: "^1.62.1"
465
+ "@vitest/browser-playwright": package_default.devDependencies["@vitest/browser-playwright"],
466
+ playwright: package_default.devDependencies.playwright
337
467
  });
338
468
  /** The development dependency every private `app` environment adds. */
339
- var APP_DEV_DEPENDENCIES = Object.freeze({ "@orkestrel/contract": "^0.0.12" });
469
+ var APP_DEV_DEPENDENCIES = Object.freeze({ "@orkestrel/contract": package_default.dependencies["@orkestrel/contract"] });
340
470
  /** The development dependencies a private Vue browser application adds. */
341
471
  var APP_BROWSER_DEV_DEPENDENCIES = Object.freeze({
342
472
  ...SOURCE_BROWSER_DEV_DEPENDENCIES,
343
- "@orkestrel/html": "^0.0.4",
473
+ "@orkestrel/html": package_default.devDependencies["@orkestrel/html"],
344
474
  "@vitejs/plugin-vue": "^6.0.8",
345
475
  vue: "^3.5.40",
346
476
  "vue-tsc": "^3.3.7"
@@ -352,13 +482,13 @@ var APP_BROWSER_DEV_DEPENDENCIES = Object.freeze({
352
482
  * ```ts
353
483
  * import { SHOWCASE_DEV_DEPENDENCIES } from '@orkestrel/scaffold'
354
484
  *
355
- * SHOWCASE_DEV_DEPENDENCIES['vite-plugin-singlefile'] // '^2.3.3'
485
+ * SHOWCASE_DEV_DEPENDENCIES['vite-plugin-singlefile'] // the showcase plugin range
356
486
  * ```
357
487
  */
358
488
  var SHOWCASE_DEV_DEPENDENCIES = Object.freeze({ "vite-plugin-singlefile": "^2.3.3" });
359
489
  /** The development dependencies a private server application adds. */
360
490
  var APP_SERVER_DEV_DEPENDENCIES = Object.freeze({
361
- "@orkestrel/emitter": "^0.0.7",
491
+ "@orkestrel/emitter": package_default.dependencies["@orkestrel/emitter"],
362
492
  "@orkestrel/middleware": "^0.0.16",
363
493
  "@orkestrel/router": "^0.0.10",
364
494
  "@orkestrel/server": "^0.0.14"
@@ -794,7 +924,11 @@ export const service = (options?: UserConfig): UserConfig =>
794
924
  options ?? {},
795
925
  )
796
926
  `,
797
- probe: `// A workbench, not a proof. No gate selects this project.
927
+ probe: `// A workbench, not a proof. No gate selects this project. Run in test mode by the
928
+ // \`test:probe\` script, it collects \`tmp/probe/**/*.test.ts\`. Run in benchmark mode by the
929
+ // \`test:bench\` script, the same workbench also collects \`tests/**/*.test.ts\` for a \`bench\` block,
930
+ // so a suite may carry a bench beside its ordinary tests without a second project. The mode
931
+ // guard around each \`bench\` call keeps it out of test mode, so it never executes there.
798
932
  export const probe = (options?: UserConfig): UserConfig =>
799
933
  mergeConfig(
800
934
  {
@@ -805,6 +939,9 @@ export const probe = (options?: UserConfig): UserConfig =>
805
939
  setupFiles: ['./tests/setup.ts'],
806
940
  environment: 'node',
807
941
  browser: { enabled: false },
942
+ fileParallelism: false,
943
+ pool: 'threads',
944
+ benchmark: { include: ['tmp/probe/**/*.test.ts', 'tests/**/*.test.ts'] },
808
945
  },
809
946
  },
810
947
  options ?? {},
@@ -2692,6 +2829,32 @@ function extractVersion(version) {
2692
2829
  ];
2693
2830
  }
2694
2831
  /**
2832
+ * Extract the major component of an admitted dependency range.
2833
+ *
2834
+ * @param range - The candidate range text.
2835
+ * @returns The major number, or `undefined` when the text is not a canonical
2836
+ * major caret or an admitted full-version form.
2837
+ *
2838
+ * @remarks
2839
+ * A canonical toolchain range is `^MAJOR`. Existing consumer declarations may
2840
+ * instead carry an exact `major.minor.patch` version or that version under a
2841
+ * caret or tilde. The projection reads those forms without deciding whether a
2842
+ * version satisfies them; {@link matchesRange} owns that separate question.
2843
+ *
2844
+ * @example
2845
+ * ```ts
2846
+ * import { extractRangeMajor } from '@orkestrel/scaffold'
2847
+ *
2848
+ * extractRangeMajor('^6') // the declared major
2849
+ * extractRangeMajor('>=6.0.0') // undefined
2850
+ * ```
2851
+ */
2852
+ function extractRangeMajor(range) {
2853
+ const match = /^(?:\^(0|[1-9]\d*)|(?:\^|~)?(0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*)?)$/.exec(range);
2854
+ const major = match?.[1] ?? match?.[2];
2855
+ return major === void 0 ? void 0 : Number(major);
2856
+ }
2857
+ /**
2695
2858
  * Compare two versions by their numeric components.
2696
2859
  *
2697
2860
  * @param left - The version ordered first when it compares lower.
@@ -3171,6 +3334,7 @@ function blueprintToScripts(blueprint) {
3171
3334
  if (blueprint.guides) scripts["test:guides"] = `${vitest} --project guides`;
3172
3335
  if (blueprint.conformance) scripts["test:conformance"] = `${vitest} --project conformance`;
3173
3336
  scripts["test:probe"] = "vitest run --config vite.config.ts --no-cache --reporter=verbose --project probe";
3337
+ scripts["test:bench"] = "vitest bench --config vite.config.ts --no-cache --project probe";
3174
3338
  if (distributes) scripts["test:distribution"] = `${vitest} --project distribution`;
3175
3339
  if (integrates) scripts["test:integration"] = `${vitest} --project integration`;
3176
3340
  if (blueprint.service) scripts["test:service"] = `${vitest} --project service`;
@@ -3203,11 +3367,14 @@ function blueprintToScripts(blueprint) {
3203
3367
  scripts.serve = "node dist/app/server/main.cjs";
3204
3368
  scripts["serve:build"] = "npm run build:app:server && npm run serve";
3205
3369
  }
3206
- if (publishes) scripts.prepublishOnly = [
3207
- "npm run format:check && npm run lint:check && npm run check && npm run build && npm test",
3208
- ...distributes ? ["npm run test:distribution -- --mode release"] : [],
3209
- ...blueprint.service ? ["npm run test:service"] : []
3210
- ].join(" && ");
3370
+ if (publishes) {
3371
+ scripts.prepack = scripts.build;
3372
+ scripts.prepublishOnly = [
3373
+ "npm run format:check && npm run lint:check && npm run check && npm run build && npm test",
3374
+ ...distributes ? ["npm run test:distribution -- --mode release"] : [],
3375
+ ...blueprint.service ? ["npm run test:service"] : []
3376
+ ].join(" && ");
3377
+ }
3211
3378
  return scripts;
3212
3379
  }
3213
3380
  /**
@@ -4014,6 +4181,230 @@ function applyOverrides(artifacts, overrides) {
4014
4181
  });
4015
4182
  }
4016
4183
  /**
4184
+ * Replace declared dependency ranges in package manifest text.
4185
+ *
4186
+ * @param manifest - The manifest text to compile.
4187
+ * @param dependencies - The declared names and replacement ranges.
4188
+ * @returns The manifest with every matching dependency-section value replaced,
4189
+ * or `undefined` when any name has no quoted declaration in those sections.
4190
+ *
4191
+ * @remarks
4192
+ * The compiler replaces values in place instead of serializing the manifest,
4193
+ * so description, keywords, scripts, key order, indentation, and every byte
4194
+ * outside the named ranges survive. Every occurrence in `dependencies`,
4195
+ * `devDependencies`, and `peerDependencies` moves, which keeps duplicate
4196
+ * declarations aligned until the manifest's own validation reports the
4197
+ * duplicate. An override or resolution with the same name stays untouched.
4198
+ *
4199
+ * @example
4200
+ * ```ts
4201
+ * import { replaceManifestRanges } from '@orkestrel/scaffold'
4202
+ *
4203
+ * const manifest = '{"devDependencies":{"typescript":"^6"}}\n'
4204
+ * replaceManifestRanges(manifest, [{ name: 'typescript', range: '^7' }])
4205
+ * // the manifest with the declared range replaced
4206
+ * ```
4207
+ */
4208
+ function replaceManifestRanges(manifest, dependencies) {
4209
+ if (dependencies.length === 0) return manifest;
4210
+ const sectionNames = /* @__PURE__ */ new Set([
4211
+ "dependencies",
4212
+ "devDependencies",
4213
+ "peerDependencies"
4214
+ ]);
4215
+ const sections = [];
4216
+ let depth = 0;
4217
+ let cursor = 0;
4218
+ while (cursor < manifest.length) {
4219
+ const character = manifest.charAt(cursor);
4220
+ if (character === "{") {
4221
+ depth += 1;
4222
+ cursor += 1;
4223
+ continue;
4224
+ }
4225
+ if (character === "}") {
4226
+ depth -= 1;
4227
+ cursor += 1;
4228
+ continue;
4229
+ }
4230
+ if (character !== "\"") {
4231
+ cursor += 1;
4232
+ continue;
4233
+ }
4234
+ const start = cursor;
4235
+ cursor += 1;
4236
+ while (cursor < manifest.length) {
4237
+ if (manifest.charAt(cursor) === "\\") {
4238
+ cursor += 2;
4239
+ continue;
4240
+ }
4241
+ if (manifest.charAt(cursor) === "\"") break;
4242
+ cursor += 1;
4243
+ }
4244
+ if (cursor >= manifest.length) return void 0;
4245
+ const end = cursor + 1;
4246
+ if (depth === 1) {
4247
+ const key = (0, _orkestrel_contract.parseJSON)(manifest.slice(start, end));
4248
+ let value = end;
4249
+ while (value < manifest.length && /\s/u.test(manifest.charAt(value))) value += 1;
4250
+ if (manifest.charAt(value) === ":") {
4251
+ value += 1;
4252
+ while (value < manifest.length && /\s/u.test(manifest.charAt(value))) value += 1;
4253
+ if (typeof key === "string" && sectionNames.has(key) && manifest.charAt(value) === "{") {
4254
+ let sectionDepth = 0;
4255
+ let sectionCursor = value;
4256
+ while (sectionCursor < manifest.length) {
4257
+ const sectionCharacter = manifest.charAt(sectionCursor);
4258
+ if (sectionCharacter === "\"") {
4259
+ sectionCursor += 1;
4260
+ while (sectionCursor < manifest.length) {
4261
+ if (manifest.charAt(sectionCursor) === "\\") {
4262
+ sectionCursor += 2;
4263
+ continue;
4264
+ }
4265
+ if (manifest.charAt(sectionCursor) === "\"") break;
4266
+ sectionCursor += 1;
4267
+ }
4268
+ if (sectionCursor >= manifest.length) return void 0;
4269
+ } else if (sectionCharacter === "{") sectionDepth += 1;
4270
+ else if (sectionCharacter === "}") {
4271
+ sectionDepth -= 1;
4272
+ if (sectionDepth === 0) {
4273
+ sections.push({
4274
+ start: value,
4275
+ end: sectionCursor + 1
4276
+ });
4277
+ break;
4278
+ }
4279
+ }
4280
+ sectionCursor += 1;
4281
+ }
4282
+ }
4283
+ }
4284
+ }
4285
+ cursor = end;
4286
+ }
4287
+ const replacements = new Map(dependencies.map(({ name, range }) => [name, range]));
4288
+ const declared = /* @__PURE__ */ new Set();
4289
+ let compiled = manifest;
4290
+ for (const bounds of sections.reverse()) {
4291
+ let section = compiled.slice(bounds.start, bounds.end);
4292
+ let sectionDepth = 0;
4293
+ let sectionCursor = 0;
4294
+ while (sectionCursor < section.length) {
4295
+ const character = section.charAt(sectionCursor);
4296
+ if (character === "{") {
4297
+ sectionDepth += 1;
4298
+ sectionCursor += 1;
4299
+ continue;
4300
+ }
4301
+ if (character === "}") {
4302
+ sectionDepth -= 1;
4303
+ sectionCursor += 1;
4304
+ continue;
4305
+ }
4306
+ if (character !== "\"") {
4307
+ sectionCursor += 1;
4308
+ continue;
4309
+ }
4310
+ const keyStart = sectionCursor;
4311
+ sectionCursor += 1;
4312
+ while (sectionCursor < section.length) {
4313
+ if (section.charAt(sectionCursor) === "\\") {
4314
+ sectionCursor += 2;
4315
+ continue;
4316
+ }
4317
+ if (section.charAt(sectionCursor) === "\"") break;
4318
+ sectionCursor += 1;
4319
+ }
4320
+ if (sectionCursor >= section.length) return void 0;
4321
+ const keyEnd = sectionCursor + 1;
4322
+ const key = (0, _orkestrel_contract.parseJSON)(section.slice(keyStart, keyEnd));
4323
+ let valueStart = keyEnd;
4324
+ while (valueStart < section.length && /\s/u.test(section.charAt(valueStart))) valueStart += 1;
4325
+ if (sectionDepth !== 1 || section.charAt(valueStart) !== ":") {
4326
+ sectionCursor = keyEnd;
4327
+ continue;
4328
+ }
4329
+ valueStart += 1;
4330
+ while (valueStart < section.length && /\s/u.test(section.charAt(valueStart))) valueStart += 1;
4331
+ if (typeof key !== "string" || section.charAt(valueStart) !== "\"") {
4332
+ sectionCursor = keyEnd;
4333
+ continue;
4334
+ }
4335
+ const replacement = replacements.get(key);
4336
+ if (replacement === void 0) {
4337
+ sectionCursor = keyEnd;
4338
+ continue;
4339
+ }
4340
+ let valueEnd = valueStart + 1;
4341
+ while (valueEnd < section.length) {
4342
+ if (section.charAt(valueEnd) === "\\") {
4343
+ valueEnd += 2;
4344
+ continue;
4345
+ }
4346
+ if (section.charAt(valueEnd) === "\"") break;
4347
+ valueEnd += 1;
4348
+ }
4349
+ if (valueEnd >= section.length) return void 0;
4350
+ const range = JSON.stringify(replacement);
4351
+ section = section.slice(0, valueStart) + range + section.slice(valueEnd + 1);
4352
+ declared.add(key);
4353
+ sectionCursor = valueStart + range.length;
4354
+ }
4355
+ compiled = compiled.slice(0, bounds.start) + section + compiled.slice(bounds.end);
4356
+ }
4357
+ return dependencies.every(({ name }) => declared.has(name)) ? compiled : void 0;
4358
+ }
4359
+ /**
4360
+ * Replace dependency ranges in a plan's manifest and recompute its identity.
4361
+ *
4362
+ * @param plan - The plan carrying the manifest artifact to compile.
4363
+ * @param dependencies - The declared names and replacement ranges.
4364
+ * @returns A plan with replaced manifest ranges and a matching hash, or
4365
+ * `undefined` when the manifest or its identity cannot be compiled.
4366
+ *
4367
+ * @remarks
4368
+ * The blueprint remains the workspace specification that produced the plan.
4369
+ * Registry answers alter only the manifest artifact that materialization will
4370
+ * write. Recomputing the hash in the same compiler keeps the plan's identity
4371
+ * tied to those final bytes rather than to the unresolved floor.
4372
+ *
4373
+ * @example
4374
+ * ```ts
4375
+ * import { replacePlanRanges } from '@orkestrel/scaffold'
4376
+ *
4377
+ * replacePlanRanges(plan, releases) // the plan carrying the resolved manifest ranges
4378
+ * ```
4379
+ */
4380
+ function replacePlanRanges(plan, dependencies) {
4381
+ let replaced = false;
4382
+ let refused = false;
4383
+ const artifacts = plan.artifacts.map((artifact) => {
4384
+ if (artifact.path !== "package.json" || artifact.origin === "host") return artifact;
4385
+ const content = replaceManifestRanges(artifact.content, dependencies);
4386
+ if (content === void 0) {
4387
+ refused = true;
4388
+ return artifact;
4389
+ }
4390
+ replaced = true;
4391
+ return {
4392
+ ...artifact,
4393
+ content
4394
+ };
4395
+ });
4396
+ if (!replaced || refused) return void 0;
4397
+ const compiled = {
4398
+ ...plan,
4399
+ artifacts
4400
+ };
4401
+ const hash = planToHash(compiled);
4402
+ return hash === void 0 ? void 0 : {
4403
+ ...compiled,
4404
+ hash
4405
+ };
4406
+ }
4407
+ /**
4017
4408
  * Compute a plan's content identity.
4018
4409
  *
4019
4410
  * @param plan - The plan to identify.
@@ -4884,7 +5275,9 @@ exports.MAX_MANIFEST_BYTES = MAX_MANIFEST_BYTES;
4884
5275
  exports.MAX_NAME_LENGTH = MAX_NAME_LENGTH;
4885
5276
  exports.MAX_PATH_LENGTH = MAX_PATH_LENGTH;
4886
5277
  exports.MAX_RANGE_LENGTH = MAX_RANGE_LENGTH;
5278
+ exports.MAX_REGISTRY_BYTES = MAX_REGISTRY_BYTES;
4887
5279
  exports.MAX_TOTAL_ARTIFACT_BYTES = MAX_TOTAL_ARTIFACT_BYTES;
5280
+ exports.MAX_TOTAL_REGISTRY_BYTES = MAX_TOTAL_REGISTRY_BYTES;
4888
5281
  exports.MINIMUM_NODE_VERSION = MINIMUM_NODE_VERSION;
4889
5282
  exports.NAME_PATTERN = NAME_PATTERN;
4890
5283
  exports.ORCHESTRATION_PATH_NAMES = ORCHESTRATION_PATH_NAMES;
@@ -4928,6 +5321,7 @@ exports.computeHash = computeHash;
4928
5321
  exports.contentToHex = contentToHex;
4929
5322
  exports.createBlueprint = createBlueprint;
4930
5323
  exports.dependenciesToQuestions = dependenciesToQuestions;
5324
+ exports.extractRangeMajor = extractRangeMajor;
4931
5325
  exports.extractVersion = extractVersion;
4932
5326
  exports.inferDrift = inferDrift;
4933
5327
  exports.inferGroup = inferGroup;
@@ -4972,6 +5366,8 @@ exports.pathToCondition = pathToCondition;
4972
5366
  exports.planToFindings = planToFindings;
4973
5367
  exports.planToHash = planToHash;
4974
5368
  exports.planToSummary = planToSummary;
5369
+ exports.replaceManifestRanges = replaceManifestRanges;
5370
+ exports.replacePlanRanges = replacePlanRanges;
4975
5371
  exports.selectGroups = selectGroups;
4976
5372
  exports.selectHostPaths = selectHostPaths;
4977
5373
  exports.serializeTypeScriptString = serializeTypeScriptString;