@orkestrel/scaffold 0.0.47 → 0.0.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin/main.js CHANGED
@@ -3,8 +3,8 @@ import { align, renderTable, strip, stripControls, width } from "@orkestrel/cons
3
3
  import { attempt, isRecord, isString, parseJSON } from "@orkestrel/contract";
4
4
  import { createMarkdown, flattenText, isTableNode } from "@orkestrel/markdown";
5
5
  import { executeSync } from "@orkestrel/process/server";
6
- import { BIN_ENTRY_PATH, CATALOG_AGENT_PATH, CONFORMANCE_TEST_PATH, Compiler, DEPENDENCY_NAME_PATTERN, DISTRIBUTION_TEST_PATH, ENVIRONMENTS, GLOBAL_SETUP_PATH, GROUPS, GUIDES_TEST_PATH, INTEGRATION_TEST_PATH, MAX_MANIFEST_BYTES, SERVICE_SETUP_PATH, SHOWCASE_CONFIG_PATH, ScaffoldError, blueprintToDevDependencies, blueprintToRootVite, blueprintToScripts, compareVersions, createBlueprint, extractRangeMajor, extractVersion, isScaffoldError, manifestToDependencies, manifestToName, nameToGuide, replacePlanRanges } from "../src/core/index.js";
7
- import { Materializer, Upstream, isExactCaseFile, isPhysicalDirectory, isRepository, listFiles, readFileText, readSnapshot, resolveContainedPath } from "../src/server/index.js";
6
+ import { BIN_ENTRY_PATH, CATALOG_AGENT_PATH, CONFORMANCE_TEST_PATH, Compiler, DEPENDENCY_NAME_PATTERN, DISTRIBUTION_TEST_PATH, ENVIRONMENTS, GLOBAL_SETUP_PATH, GROUPS, GUIDES_TEST_PATH, INTEGRATION_TEST_PATH, MAX_MANIFEST_BYTES, SERVICE_SETUP_PATH, SHOWCASE_CONFIG_PATH, ScaffoldError, blueprintToDevDependencies, blueprintToRootVite, blueprintToScripts, compareVersions, createBlueprint, extractRangeMajor, extractVersion, isDeferredPath, isScaffoldError, manifestToDependencies, manifestToName, nameToGuide, replacePlanRanges } from "../src/core/index.js";
7
+ import { Materializer, Upstream, filesToHost, isExactCaseFile, isPhysicalDirectory, isWorktree, listFiles, readFileText, readHostFloor, readSnapshot, resolveContainedPath } from "../src/server/index.js";
8
8
  import { parseArgs } from "node:util";
9
9
  //#region src/bin/constants.ts
10
10
  /**
@@ -86,6 +86,7 @@ var COMMAND_OPTIONS = Object.freeze({
86
86
  groups: Object.freeze({ type: "string" }),
87
87
  all: Object.freeze({ type: "boolean" }),
88
88
  dirty: Object.freeze({ type: "boolean" }),
89
+ offline: Object.freeze({ type: "boolean" }),
89
90
  from: Object.freeze({
90
91
  type: "string",
91
92
  multiple: true
@@ -109,10 +110,12 @@ var OPTION_SUMMARY = Object.freeze({
109
110
  "--groups <list>": "the artifact groups to cover; every group when absent",
110
111
  "--all": "fetch a guide for every package the organization publishes, not the declared ones alone",
111
112
  "--dirty": "delete from a tree carrying uncommitted changes",
113
+ "--offline": "use the distributed dependency and vendored-host floors without reading upstream",
112
114
  "--from <path>": "read the data root from a local path instead of the bundled one; catalog alone accepts it more than once",
113
115
  "--target <path>": "the directory the verb operates on; the working directory when absent",
114
116
  "--json": "emit one machine-readable value instead of a report",
115
- ORKESTREL_SCAFFOLD_REGISTRY: "the registry base mapped to upstream.registry.base"
117
+ ORKESTREL_SCAFFOLD_REGISTRY: "the registry base mapped to upstream.registry.base",
118
+ ORKESTREL_SCAFFOLD_REPOSITORY: "the repository base mapped to upstream.repository.base"
116
119
  });
117
120
  /**
118
121
  * The options each verb takes, in usage order, frozen.
@@ -129,18 +132,21 @@ var VERB_OPTIONS = Object.freeze({
129
132
  "--app <list>",
130
133
  "--bin",
131
134
  "--deps <list>",
135
+ "--offline",
132
136
  "--from <path>",
133
137
  "--target <path>",
134
138
  "--json"
135
139
  ]),
136
140
  audit: Object.freeze([
137
141
  "--groups <list>",
142
+ "--offline",
138
143
  "--from <path>",
139
144
  "--target <path>",
140
145
  "--json"
141
146
  ]),
142
147
  repair: Object.freeze([
143
148
  "--groups <list>",
149
+ "--offline",
144
150
  "--from <path>",
145
151
  "--target <path>",
146
152
  "--json"
@@ -154,6 +160,7 @@ var VERB_OPTIONS = Object.freeze({
154
160
  overwrite: Object.freeze([
155
161
  "--groups <list>",
156
162
  "--dirty",
163
+ "--offline",
157
164
  "--from <path>",
158
165
  "--target <path>",
159
166
  "--json"
@@ -256,6 +263,22 @@ function optionToName(option) {
256
263
  return token.startsWith("--") ? token.slice(2) : token;
257
264
  }
258
265
  /**
266
+ * Project process environment endpoints into upstream reader options.
267
+ *
268
+ * @param environment - The process environment to read.
269
+ * @returns The configured endpoint groups, or `undefined` when neither endpoint
270
+ * is configured.
271
+ */
272
+ function environmentToUpstream(environment) {
273
+ const registry = environment.ORKESTREL_SCAFFOLD_REGISTRY;
274
+ const repository = environment.ORKESTREL_SCAFFOLD_REPOSITORY;
275
+ if (registry === void 0 && repository === void 0) return void 0;
276
+ return {
277
+ ...registry === void 0 ? {} : { registry: { base: registry } },
278
+ ...repository === void 0 ? {} : { repository: { base: repository } }
279
+ };
280
+ }
281
+ /**
259
282
  * Render one verb's synopsis.
260
283
  *
261
284
  * @param verb - The verb to describe.
@@ -355,6 +378,7 @@ function argvToCommand(argv) {
355
378
  const src = typeof values.src === "string" ? values.src : void 0;
356
379
  const app = typeof values.app === "string" ? values.app : void 0;
357
380
  const bin = values.bin === true;
381
+ const offline = values.offline === true;
358
382
  const dependencies = typeof values.deps === "string" ? values.deps : void 0;
359
383
  const target = typeof values.target === "string" ? values.target : void 0;
360
384
  const json = values.json === true;
@@ -374,6 +398,7 @@ function argvToCommand(argv) {
374
398
  ...src === void 0 ? {} : { src },
375
399
  ...app === void 0 ? {} : { app },
376
400
  ...bin ? { bin } : {},
401
+ ...offline ? { offline } : {},
377
402
  ...dependencies === void 0 ? {} : { dependencies }
378
403
  };
379
404
  case "audit": return {
@@ -381,14 +406,16 @@ function argvToCommand(argv) {
381
406
  json,
382
407
  ...location,
383
408
  ...source,
384
- ...selection
409
+ ...selection,
410
+ ...offline ? { offline } : {}
385
411
  };
386
412
  case "repair": return {
387
413
  verb,
388
414
  json,
389
415
  ...location,
390
416
  ...source,
391
- ...selection
417
+ ...selection,
418
+ ...offline ? { offline } : {}
392
419
  };
393
420
  case "catalog": return {
394
421
  verb,
@@ -401,6 +428,7 @@ function argvToCommand(argv) {
401
428
  verb,
402
429
  json,
403
430
  dirty: values.dirty === true,
431
+ ...offline ? { offline } : {},
404
432
  ...location,
405
433
  ...source,
406
434
  ...selection
@@ -467,6 +495,26 @@ function dependenciesToFleet(dependencies) {
467
495
  return dependencies.filter((dependency) => dependency.name.startsWith("@orkestrel/"));
468
496
  }
469
497
  /**
498
+ * Project declared concrete ranges to their distributed release floors.
499
+ *
500
+ * @param dependencies - The declarations whose floor versions to read.
501
+ * @returns One found floor per declaration, or `undefined` when any range names
502
+ * no concrete version.
503
+ */
504
+ function dependenciesToFloors(dependencies) {
505
+ const releases = [];
506
+ for (const dependency of dependencies) {
507
+ const version = dependency.range.startsWith("^") || dependency.range.startsWith("~") ? dependency.range.slice(1) : dependency.range;
508
+ if (extractVersion(version) === void 0) return void 0;
509
+ releases.push({
510
+ ...dependency,
511
+ lookup: "found",
512
+ latest: version
513
+ });
514
+ }
515
+ return releases;
516
+ }
517
+ /**
470
518
  * Read the exit code registry release evidence earns.
471
519
  *
472
520
  * @param releases - The release verdicts to measure.
@@ -682,48 +730,64 @@ var CLI = class CLI {
682
730
  const plan = this.#compile(blueprint);
683
731
  const manifest = plan.artifacts.find((artifact) => artifact.path === "package.json" && artifact.origin !== "host");
684
732
  if (manifest === void 0 || manifest.origin === "host") throw new ScaffoldError("BLOCKED", "The compiled plan carries no replaceable manifest.");
685
- const releases = await this.#lookup(dependenciesToFleet(manifestToDependencies(manifest.content)));
686
- const resolved = replacePlanRanges(plan, this.#pin(releases));
733
+ const versions = await this.#versions(dependenciesToFleet(manifestToDependencies(manifest.content)), command.offline === true);
734
+ this.#assertVersions(versions);
735
+ const resolved = replacePlanRanges(plan, versions.pins);
687
736
  if (resolved === void 0) throw new ScaffoldError("BLOCKED", "The compiled plan ranges could not be replaced.");
688
- const materializer = new Materializer(command.from === void 0 ? void 0 : { host: command.from });
737
+ const host = await this.#host(command.from, void 0, command.offline === true);
689
738
  try {
690
- const result = materializer.materialize(resolved, target);
691
- if (command.json === true) this.#report(result);
739
+ const result = host.materializer.materialize(resolved, target);
740
+ const outcome = {
741
+ ...result,
742
+ provenance: {
743
+ ...versions.baseline === void 0 ? {} : { versions: versions.baseline },
744
+ ...host.baseline === void 0 ? {} : { host: host.baseline }
745
+ }
746
+ };
747
+ if (command.json === true) this.#report(outcome);
692
748
  else {
693
749
  this.#say(`Scaffolded ${blueprint.name} into ${result.target}.`);
694
750
  this.#say(this.#tally(result));
695
751
  }
752
+ if (versions.forced || host.forced) this.#reportBaselines(outcome.provenance);
696
753
  return 0;
697
754
  } finally {
698
- materializer.destroy();
755
+ host.materializer.destroy();
699
756
  }
700
757
  }
701
758
  async #inspect(command) {
702
759
  const target = command.target ?? ".";
703
760
  const manifest = this.#manifest(target);
704
761
  const blueprint = this.#derive(target);
762
+ const groups = this.#groups(command.groups);
705
763
  const declared = manifestToPlannedDependencies(manifest, blueprint);
706
- const releases = await this.#lookup(declared);
707
- const questions = [...this.#targetQuestions(target, blueprint), ...releasesToQuestions(releases)];
708
- const materializer = new Materializer(command.from === void 0 ? void 0 : { host: command.from });
764
+ const versions = await this.#versions(declared, command.offline === true);
765
+ const questions = [...this.#targetQuestions(target, blueprint), ...releasesToQuestions(versions.releases)];
766
+ const host = await this.#host(command.from, target, command.offline === true);
709
767
  try {
710
- const [measured] = this.#survey(materializer, blueprint, target, this.#groups(command.groups));
768
+ const [measured] = this.#survey(host.materializer, blueprint, target, groups);
711
769
  const audit = questions.length === 0 ? measured : {
712
770
  ...measured,
713
771
  questions: [...measured.questions, ...questions]
714
772
  };
715
773
  const outcome = {
716
774
  ...audit,
717
- releases
775
+ releases: versions.releases,
776
+ provenance: {
777
+ ...versions.baseline === void 0 ? {} : { versions: versions.baseline },
778
+ ...host.baseline === void 0 ? {} : { host: host.baseline }
779
+ }
718
780
  };
719
781
  if (command.json === true) this.#report(outcome);
720
782
  else {
721
783
  this.#present(audit);
722
- this.#reportReleases(releases);
784
+ if (command.offline !== true) this.#reportReleases(versions.releases);
723
785
  }
724
- return Math.max(auditToExit(audit), releasesToExit(releases));
786
+ if (versions.forced || host.forced) this.#reportBaselines(outcome.provenance);
787
+ if (command.offline === true) return auditToExit(audit);
788
+ return Math.max(auditToExit(audit), releasesToExit(versions.releases), versions.forced || host.forced ? 1 : 0);
725
789
  } finally {
726
- materializer.destroy();
790
+ host.materializer.destroy();
727
791
  }
728
792
  }
729
793
  async #restore(command) {
@@ -731,22 +795,29 @@ var CLI = class CLI {
731
795
  const groups = this.#groups(command.groups);
732
796
  const blueprint = this.#derive(target);
733
797
  this.#assertTarget(target, blueprint);
734
- const materializer = new Materializer(command.from === void 0 ? void 0 : { host: command.from });
798
+ const host = await this.#host(command.from, target, command.offline === true);
735
799
  try {
736
- const [audit, plan] = this.#survey(materializer, blueprint, target, groups);
800
+ const [audit, plan] = this.#survey(host.materializer, blueprint, target, groups);
737
801
  if (plan === void 0) {
738
- if (command.json === true) this.#report(audit);
802
+ if (command.json === true) this.#report({
803
+ ...audit,
804
+ provenance: { ...host.baseline === void 0 ? {} : { host: host.baseline } }
805
+ });
739
806
  else this.#present(audit);
740
807
  return 1;
741
808
  }
742
- const releases = await this.#lookup(manifestToPlannedDependencies(this.#manifest(target), blueprint));
743
- const pins = this.#pin(releases);
744
- const result = this.#merge(materializer.repair(plan, audit, target), materializer.declare(pins, target));
745
- const [terminal] = this.#survey(materializer, this.#derive(target), target, groups);
809
+ const versions = await this.#versions(manifestToPlannedDependencies(this.#manifest(target), blueprint), command.offline === true);
810
+ this.#assertVersions(versions);
811
+ const result = this.#merge(host.materializer.repair(plan, audit, target), host.materializer.declare(versions.pins, target));
812
+ const [terminal] = this.#survey(host.materializer, this.#derive(target), target, groups);
746
813
  const outcome = {
747
814
  ...result,
748
815
  audit: terminal,
749
- releases
816
+ releases: versions.releases,
817
+ provenance: {
818
+ ...versions.baseline === void 0 ? {} : { versions: versions.baseline },
819
+ ...host.baseline === void 0 ? {} : { host: host.baseline }
820
+ }
750
821
  };
751
822
  if (command.json === true) this.#report(outcome);
752
823
  else {
@@ -754,9 +825,11 @@ var CLI = class CLI {
754
825
  this.#reportReplacements(audit, terminal);
755
826
  this.#say(this.#tally(result));
756
827
  }
828
+ if (versions.forced || host.forced) this.#reportBaselines(outcome.provenance);
829
+ if (command.offline !== true && (versions.forced || host.forced)) return 1;
757
830
  return auditToExit(terminal);
758
831
  } finally {
759
- materializer.destroy();
832
+ host.materializer.destroy();
760
833
  }
761
834
  }
762
835
  async #refresh(command) {
@@ -768,7 +841,8 @@ var CLI = class CLI {
768
841
  const releases = this.#catalogReleases(dependenciesToFleet(manifestToDependencies(this.#manifest(target))), fetched.entries);
769
842
  const pins = this.#pin(releases);
770
843
  this.#assertFetched(fetched.entries, fetched.mirrors);
771
- const materializer = new Materializer(host === void 0 ? void 0 : { host });
844
+ const guides = fetched.mirrors.length === 0 ? void 0 : fetched.mirrors.some((mirror) => mirror.lookup === "failed") ? "floor" : "live";
845
+ const materializer = new Materializer({ host: host ?? readHostFloor() });
772
846
  let result;
773
847
  try {
774
848
  result = this.#merge(this.#publish(materializer, target, fetched.entries, fetched.mirrors), materializer.declare(pins, target));
@@ -780,38 +854,46 @@ var CLI = class CLI {
780
854
  entries: fetched.entries,
781
855
  mirrors: fetched.mirrors,
782
856
  dropped: previous.filter((name) => !fetched.entries.some((entry) => entry.name === name)),
783
- releases
857
+ releases,
858
+ provenance: {
859
+ versions: "live",
860
+ ...guides === void 0 ? {} : { guides }
861
+ }
784
862
  };
785
863
  if (command.json === true) this.#report(outcome);
786
864
  else this.#recount(outcome);
787
- return 0;
865
+ return guides === "floor" ? 1 : 0;
788
866
  }
789
867
  async #replace(command) {
790
868
  const target = command.target ?? ".";
791
869
  const groups = this.#groups(command.groups);
792
870
  const blueprint = this.#derive(target);
793
871
  this.#assertTarget(target, blueprint);
794
- const repository = this.#repository(target);
795
- if (repository.dirty.length > 0 && command.dirty !== true) throw new ScaffoldError("TARGET", `The target at ${target} carries ${String(repository.dirty.length)} uncommitted change${repository.dirty.length === 1 ? "" : "s"}. Commit them, or pass --dirty to waive the refusal.`, {
872
+ const worktree = this.#worktree(target);
873
+ if (worktree.dirty.length > 0 && command.dirty !== true) throw new ScaffoldError("TARGET", `The target at ${target} carries ${String(worktree.dirty.length)} uncommitted change${worktree.dirty.length === 1 ? "" : "s"}. Commit them, or pass --dirty to waive the refusal.`, {
796
874
  target,
797
- dirty: repository.dirty.length
875
+ dirty: worktree.dirty.length
798
876
  });
799
- const materializer = new Materializer(command.from === void 0 ? void 0 : { host: command.from });
877
+ const host = await this.#host(command.from, target, command.offline === true);
800
878
  try {
801
- const [audit, plan] = this.#survey(materializer, blueprint, target, groups);
879
+ const [audit, plan] = this.#survey(host.materializer, blueprint, target, groups);
802
880
  if (plan === void 0) {
803
- if (command.json === true) this.#report(audit);
881
+ if (command.json === true) this.#report({
882
+ ...audit,
883
+ provenance: { ...host.baseline === void 0 ? {} : { host: host.baseline } }
884
+ });
804
885
  else this.#present(audit);
805
886
  return 1;
806
887
  }
807
- const repaired = materializer.repair(plan, audit, target);
808
- const removed = materializer.remove(plan, audit, command.dirty === true ? {
809
- tracked: repository.tracked,
888
+ const declared = manifestToPlannedDependencies(this.#manifest(target), blueprint);
889
+ const repaired = host.materializer.repair(plan, audit, target);
890
+ const removed = host.materializer.remove(plan, audit, command.dirty === true ? {
891
+ tracked: worktree.tracked,
810
892
  dirty: []
811
- } : repository, target);
893
+ } : worktree, target);
812
894
  const offline = this.#merge(repaired, removed);
813
- const online = await this.#reconcile(materializer, target, manifestToPlannedDependencies(this.#manifest(target), blueprint));
814
- const [terminal] = this.#survey(materializer, blueprint, target, groups);
895
+ const online = command.offline === true ? await this.#offline(host.materializer, target, declared, host.baseline) : await this.#reconcile(host.materializer, target, declared, host.baseline, host.forced);
896
+ const [terminal] = this.#survey(host.materializer, blueprint, target, groups);
815
897
  const outcome = {
816
898
  ...online,
817
899
  ...this.#merge(offline, online),
@@ -827,23 +909,58 @@ var CLI = class CLI {
827
909
  if (online.note !== void 0) return 1;
828
910
  return auditToExit(terminal);
829
911
  } finally {
830
- materializer.destroy();
912
+ host.materializer.destroy();
831
913
  }
832
914
  }
833
- async #reconcile(materializer, target, declared) {
915
+ async #offline(materializer, target, declared, host) {
916
+ const versions = await this.#versions(declared, true);
917
+ this.#assertVersions(versions);
918
+ return {
919
+ ...materializer.declare(versions.pins, target),
920
+ entries: [],
921
+ mirrors: [],
922
+ dropped: [],
923
+ releases: versions.releases,
924
+ provenance: {
925
+ ...versions.baseline === void 0 ? {} : { versions: versions.baseline },
926
+ ...host === void 0 ? {} : { host }
927
+ },
928
+ note: "The catalog step did not complete: USAGE: 'catalog' does not take --offline."
929
+ };
930
+ }
931
+ async #reconcile(materializer, target, declared, host, hostForced) {
834
932
  const previous = this.#previous(target);
835
933
  let releases = [];
934
+ let provenance = { ...host === void 0 ? {} : { host } };
836
935
  try {
837
- releases = await this.#lookup(declared);
838
- const pins = this.#pin(releases);
936
+ const versions = await this.#versions(declared, false);
937
+ releases = versions.releases;
938
+ provenance = {
939
+ ...versions.baseline === void 0 ? {} : { versions: versions.baseline },
940
+ ...host === void 0 ? {} : { host }
941
+ };
942
+ this.#assertVersions(versions);
839
943
  const fetched = await this.#fetch(target, false);
840
944
  this.#assertFetched(fetched.entries, fetched.mirrors);
945
+ const guides = fetched.mirrors.length === 0 ? void 0 : fetched.mirrors.some((mirror) => mirror.lookup === "failed") ? "floor" : "live";
946
+ provenance = {
947
+ ...versions.baseline === void 0 ? {} : { versions: versions.baseline },
948
+ ...guides === void 0 ? {} : { guides },
949
+ ...host === void 0 ? {} : { host }
950
+ };
951
+ const written = this.#merge(this.#publish(materializer, target, fetched.entries, fetched.mirrors), materializer.declare(versions.pins, target));
952
+ const floors = [];
953
+ if (hostForced) floors.push("host");
954
+ if (versions.forced) floors.push("versions");
955
+ if (guides === "floor") floors.push("guides");
841
956
  return {
842
- ...this.#merge(this.#publish(materializer, target, fetched.entries, fetched.mirrors), materializer.declare(pins, target)),
957
+ ...written,
843
958
  entries: fetched.entries,
844
959
  mirrors: fetched.mirrors,
845
960
  dropped: previous.filter((name) => !fetched.entries.some((entry) => entry.name === name)),
846
- releases
961
+ releases,
962
+ provenance,
963
+ ...floors.length === 0 ? {} : { note: `The ${floors.join(", ")} step used the distributed floor after its upstream read did not complete.` }
847
964
  };
848
965
  } catch (error) {
849
966
  return {
@@ -855,10 +972,104 @@ var CLI = class CLI {
855
972
  mirrors: [],
856
973
  dropped: [],
857
974
  releases,
975
+ provenance,
858
976
  note: `The catalog step did not complete: ${errorToEnvelope(error).error.message}`
859
977
  };
860
978
  }
861
979
  }
980
+ async #host(from, target, offline) {
981
+ if (from !== void 0) return {
982
+ materializer: new Materializer({ host: from }),
983
+ forced: false
984
+ };
985
+ const floor = readHostFloor();
986
+ if (offline) return {
987
+ materializer: new Materializer({ host: floor }),
988
+ baseline: "floor",
989
+ forced: false
990
+ };
991
+ const paths = floor.manifest.entries.filter((entry) => !isDeferredPath(entry.destination)).map((entry) => entry.destination);
992
+ const current = target === void 0 ? floor.bytes : readSnapshot(target, paths);
993
+ const upstream = new Upstream(this.#upstream);
994
+ try {
995
+ const files = await upstream.read(paths, current);
996
+ const live = filesToHost(files, floor);
997
+ return {
998
+ materializer: new Materializer({ host: live ?? floor }),
999
+ baseline: live === void 0 ? "floor" : "live",
1000
+ forced: live === void 0
1001
+ };
1002
+ } finally {
1003
+ upstream.destroy();
1004
+ }
1005
+ }
1006
+ async #versions(declared, offline) {
1007
+ if (declared.length === 0) return {
1008
+ releases: [],
1009
+ pins: [],
1010
+ forced: false,
1011
+ complete: true
1012
+ };
1013
+ const floors = dependenciesToFloors(declared);
1014
+ if (offline) {
1015
+ if (floors === void 0) return {
1016
+ releases: [],
1017
+ pins: [],
1018
+ baseline: "floor",
1019
+ forced: false,
1020
+ complete: false
1021
+ };
1022
+ return {
1023
+ releases: floors,
1024
+ pins: floors.map((release) => ({
1025
+ name: release.name,
1026
+ range: release.range
1027
+ })),
1028
+ baseline: "floor",
1029
+ forced: false,
1030
+ complete: true
1031
+ };
1032
+ }
1033
+ const releases = await this.#lookup(declared);
1034
+ if (releases.filter((release) => release.lookup === "missing" || release.lookup === "unmatched").length > 0) return {
1035
+ releases,
1036
+ pins: [],
1037
+ baseline: "live",
1038
+ forced: false,
1039
+ complete: false
1040
+ };
1041
+ if (releases.some((release) => release.lookup === "failed")) {
1042
+ if (floors === void 0) return {
1043
+ releases,
1044
+ pins: [],
1045
+ baseline: "floor",
1046
+ forced: true,
1047
+ complete: false
1048
+ };
1049
+ return {
1050
+ releases,
1051
+ pins: floors.map((release) => ({
1052
+ name: release.name,
1053
+ range: release.range
1054
+ })),
1055
+ baseline: "floor",
1056
+ forced: true,
1057
+ complete: true
1058
+ };
1059
+ }
1060
+ return {
1061
+ releases,
1062
+ pins: this.#pin(releases),
1063
+ baseline: "live",
1064
+ forced: false,
1065
+ complete: true
1066
+ };
1067
+ }
1068
+ #assertVersions(versions) {
1069
+ if (versions.complete) return;
1070
+ const names = versions.releases.filter((release) => release.lookup !== "found").map((release) => release.name);
1071
+ throw new ScaffoldError("FETCH", names.length === 0 ? "A declared dependency names no concrete floor." : `The registry named no release for ${names.join(", ")}.`, { names: names.length });
1072
+ }
862
1073
  async #lookup(declared) {
863
1074
  if (declared.length === 0) return [];
864
1075
  const upstream = new Upstream(this.#upstream);
@@ -921,7 +1132,7 @@ var CLI = class CLI {
921
1132
  });
922
1133
  }
923
1134
  #assertFetched(entries, mirrors) {
924
- const failed = [...entries.filter((entry) => entry.lookup !== "found").map((entry) => entry.name), ...mirrors.filter((mirror) => mirror.lookup !== "found").map((mirror) => mirror.name)];
1135
+ const failed = [...entries.filter((entry) => entry.lookup !== "found").map((entry) => entry.name), ...mirrors.filter((mirror) => mirror.lookup !== "found" && mirror.lookup !== "failed").map((mirror) => mirror.name)];
925
1136
  if (failed.length === 0) return;
926
1137
  throw new ScaffoldError("FETCH", `Upstream produced no complete catalog answer for ${failed.join(", ")}.`, { names: failed.length });
927
1138
  }
@@ -1255,7 +1466,7 @@ var CLI = class CLI {
1255
1466
  }
1256
1467
  return names;
1257
1468
  }
1258
- #repository(target) {
1469
+ #worktree(target) {
1259
1470
  const tracked = this.#inventory(target, ["ls-files", "-z"]);
1260
1471
  const dirty = this.#inventory(target, [
1261
1472
  "status",
@@ -1267,7 +1478,7 @@ var CLI = class CLI {
1267
1478
  tracked,
1268
1479
  dirty
1269
1480
  };
1270
- if (!isRepository(state)) throw new ScaffoldError("TARGET", `The git state at ${target} is not a readable inventory.`, {
1481
+ if (!isWorktree(state)) throw new ScaffoldError("TARGET", `The git state at ${target} is not a readable inventory.`, {
1271
1482
  target,
1272
1483
  tracked: tracked.length,
1273
1484
  dirty: dirty.length
@@ -1315,6 +1526,13 @@ var CLI = class CLI {
1315
1526
  removed: [...first.removed, ...second.removed]
1316
1527
  };
1317
1528
  }
1529
+ #reportBaselines(provenance) {
1530
+ const baselines = [];
1531
+ if (provenance.versions !== void 0) baselines.push(`versions=${provenance.versions}`);
1532
+ if (provenance.guides !== void 0) baselines.push(`guides=${provenance.guides}`);
1533
+ if (provenance.host !== void 0) baselines.push(`host=${provenance.host}`);
1534
+ this.#warn(`Upstream fallback selected the distributed baseline: ${baselines.join(", ")}.`);
1535
+ }
1318
1536
  #present(audit) {
1319
1537
  for (const question of audit.questions) this.#warn(`${question.field}: ${question.message}`);
1320
1538
  const rows = audit.findings.filter((finding) => finding.drift !== "aligned").map((finding) => [
@@ -1393,7 +1611,7 @@ process.stdout.on("error", (error) => {
1393
1611
  if ("code" in error && error.code === "EPIPE") return;
1394
1612
  throw error;
1395
1613
  });
1396
- process.exitCode = await new CLI(process.env.ORKESTREL_SCAFFOLD_REGISTRY === void 0 ? void 0 : { upstream: { registry: { base: process.env.ORKESTREL_SCAFFOLD_REGISTRY } } }).execute(process.argv.slice(2));
1614
+ process.exitCode = await new CLI({ upstream: environmentToUpstream(process.env) }).execute(process.argv.slice(2));
1397
1615
  //#endregion
1398
1616
 
1399
1617
  //# sourceMappingURL=main.js.map