@wairon/cli 5.1.1-dev.72 → 5.1.1-dev.73

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/index.js CHANGED
@@ -2497,7 +2497,7 @@ var require_dist = __commonJS({
2497
2497
  scaffoldPack: () => scaffoldPack2
2498
2498
  });
2499
2499
  module2.exports = __toCommonJS2(src_exports2);
2500
- var path28 = __toESM2(require("path"));
2500
+ var path29 = __toESM2(require("path"));
2501
2501
  var import_js_yaml3 = require("js-yaml");
2502
2502
  var import_js_yaml = require("js-yaml");
2503
2503
  var import_crypto = require("crypto");
@@ -3061,7 +3061,7 @@ var require_dist = __commonJS({
3061
3061
  return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
3062
3062
  }
3063
3063
  var fs18 = __toESM2(require("fs"));
3064
- var path29 = __toESM2(require("path"));
3064
+ var path30 = __toESM2(require("path"));
3065
3065
  var import_fflate = require_node();
3066
3066
  var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", ".hg", ".svn"]);
3067
3067
  function listEntries(archive) {
@@ -3099,8 +3099,8 @@ var require_dist = __commonJS({
3099
3099
  }
3100
3100
  function writeTree(destDir, files) {
3101
3101
  for (const file of files) {
3102
- const absolute = path29.join(destDir, file.path);
3103
- fs18.mkdirSync(path29.dirname(absolute), { recursive: true });
3102
+ const absolute = path30.join(destDir, file.path);
3103
+ fs18.mkdirSync(path30.dirname(absolute), { recursive: true });
3104
3104
  fs18.writeFileSync(absolute, file.contents);
3105
3105
  }
3106
3106
  }
@@ -3113,10 +3113,10 @@ var require_dist = __commonJS({
3113
3113
  for (const entry of fs18.readdirSync(current2, { withFileTypes: true })) {
3114
3114
  if (entry.isDirectory()) {
3115
3115
  if (SKIP_DIRS.has(entry.name)) continue;
3116
- walkPackDir(root, path29.join(current2, entry.name), out);
3116
+ walkPackDir(root, path30.join(current2, entry.name), out);
3117
3117
  } else if (entry.isFile()) {
3118
- const absolute = path29.join(current2, entry.name);
3119
- const relative22 = path29.relative(root, absolute).split(path29.sep).join("/");
3118
+ const absolute = path30.join(current2, entry.name);
3119
+ const relative22 = path30.relative(root, absolute).split(path30.sep).join("/");
3120
3120
  out.push({ path: relative22, contents: fs18.readFileSync(absolute) });
3121
3121
  }
3122
3122
  }
@@ -3167,7 +3167,7 @@ var require_dist = __commonJS({
3167
3167
  function scaffoldPack(request) {
3168
3168
  const files = render(request);
3169
3169
  writeTree(request.targetDir, files);
3170
- return files.map((file) => path28.join(request.targetDir, file.path));
3170
+ return files.map((file) => path29.join(request.targetDir, file.path));
3171
3171
  }
3172
3172
  function buildPack(sourceDir) {
3173
3173
  const files = readPackDir(sourceDir);
@@ -3224,7 +3224,7 @@ var require_dist = __commonJS({
3224
3224
  }
3225
3225
  const manifest = parseManifest(decode(envelope.contents));
3226
3226
  verifyIntegrity2(manifest, files);
3227
- const directory = path28.resolve(destDir);
3227
+ const directory = path29.resolve(destDir);
3228
3228
  writeTree(directory, files);
3229
3229
  const result = {
3230
3230
  directory,
@@ -3302,7 +3302,7 @@ var require_dist = __commonJS({
3302
3302
  }
3303
3303
  const manifest = parseTreeManifest(decode(envelope.contents));
3304
3304
  verifyTreeIntegrity(manifest, files);
3305
- const directory = path28.resolve(destDir);
3305
+ const directory = path29.resolve(destDir);
3306
3306
  writeTree(directory, files);
3307
3307
  const result = {
3308
3308
  destDir: directory,
@@ -3317,7 +3317,7 @@ var require_dist = __commonJS({
3317
3317
  return normalized === "." ? ".wai/" : `${normalized}/.wai/`;
3318
3318
  }
3319
3319
  function normalizeRootPath(relativePath) {
3320
- const posix2 = relativePath.split(path28.sep).join("/").replace(/^\.\//, "").replace(/\/+$/, "");
3320
+ const posix2 = relativePath.split(path29.sep).join("/").replace(/^\.\//, "").replace(/\/+$/, "");
3321
3321
  return posix2 === "" || posix2 === "." ? "." : posix2;
3322
3322
  }
3323
3323
  function slugify(projectName) {
@@ -3511,13 +3511,17 @@ __export(src_exports, {
3511
3511
  ambiguityMessage: () => ambiguityMessage,
3512
3512
  approvalRecord: () => approvalRecord,
3513
3513
  approvalVerdict: () => approvalVerdict,
3514
+ assertContainedProjectPath: () => assertContainedProjectPath,
3514
3515
  assertProjectInitialized: () => assertProjectInitialized,
3515
3516
  backendCommand: () => backendCommand,
3517
+ backfillChainedSubprojectConfigs: () => backfillChainedSubprojectConfigs,
3516
3518
  buildCanvasDataModel: () => buildCanvasDataModel,
3517
3519
  buildProjectGraph: () => buildProjectGraph,
3518
3520
  buildRuleContext: () => buildRuleContext,
3519
3521
  callSitesOf: () => callSitesOf,
3520
3522
  captureApprovedSpecs: () => captureApprovedSpecs,
3523
+ checkDeclarativePack: () => checkDeclarativePack,
3524
+ clearLoaderIssues: () => clearLoaderIssues,
3521
3525
  cognitiveScore: () => cognitiveScore,
3522
3526
  complexityLevel: () => complexityLevel,
3523
3527
  composeAgentBrief: () => composeAgentBrief,
@@ -3532,6 +3536,7 @@ __export(src_exports, {
3532
3536
  createEmptyTopologyConfig: () => createEmptyTopologyConfig,
3533
3537
  createProjectConfig: () => createProjectConfig,
3534
3538
  currentChildPins: () => currentChildPins,
3539
+ currentRootBinding: () => currentRootBinding,
3535
3540
  declaredPackNames: () => declaredPackNames,
3536
3541
  declaredProfileIds: () => declaredProfileIds,
3537
3542
  declaresGlobalPacks: () => declaresGlobalPacks,
@@ -3544,6 +3549,7 @@ __export(src_exports, {
3544
3549
  deriveExecutionProfile: () => deriveExecutionProfile,
3545
3550
  derivedDocPaths: () => derivedDocPaths,
3546
3551
  detectDomainCandidates: () => detectDomainCandidates,
3552
+ diagnoseProjectPacks: () => diagnoseProjectPacks,
3547
3553
  diagramSetIndex: () => diagramSetIndex,
3548
3554
  diffAgainstApproval: () => diffAgainstApproval,
3549
3555
  diffSize: () => diffSize,
@@ -3559,6 +3565,9 @@ __export(src_exports, {
3559
3565
  factsFor: () => factsFor,
3560
3566
  fieldTypeRefs: () => fieldTypeRefs,
3561
3567
  fieldTypesOf: () => fieldTypesOf,
3568
+ findChainingParent: () => findChainingParent,
3569
+ findChainingSubprojectsMissingConfig: () => findChainingSubprojectsMissingConfig,
3570
+ findLegacySpecFiles: () => findLegacySpecFiles,
3562
3571
  findProjectRoot: () => findProjectRoot,
3563
3572
  findSystemRoot: () => findSystemRoot,
3564
3573
  fromProjectRoot: () => fromProjectRoot,
@@ -3568,6 +3577,7 @@ __export(src_exports, {
3568
3577
  generateDiagramSet: () => generateDiagramSet,
3569
3578
  generateSequenceDiagram: () => generateSequenceDiagram,
3570
3579
  getExporter: () => getExporter,
3580
+ getLoaderIssues: () => getLoaderIssues,
3571
3581
  getProjectRoot: () => getProjectRoot,
3572
3582
  getProjectRootOverride: () => getProjectRootOverride,
3573
3583
  getRequestParentReach: () => getRequestParentReach,
@@ -3575,6 +3585,7 @@ __export(src_exports, {
3575
3585
  getStatusReport: () => getStatusReport,
3576
3586
  globalGuideFilePath: () => globalGuideFilePath,
3577
3587
  globalPacksDir: () => globalPacksDir,
3588
+ globalPacksEnabled: () => globalPacksEnabled,
3578
3589
  globalTemplatesDir: () => globalTemplatesDir,
3579
3590
  hasContext: () => hasContext,
3580
3591
  hasFunctionBody: () => hasFunctionBody,
@@ -3605,8 +3616,9 @@ __export(src_exports, {
3605
3616
  loadImplementationSpecs: () => loadImplementationSpecs,
3606
3617
  loadInterfaceSpec: () => loadInterfaceSpec,
3607
3618
  loadInterfaceSpecs: () => loadInterfaceSpecs,
3608
- loadProjectConfig: () => loadProjectConfig4,
3619
+ loadProjectConfig: () => loadProjectConfig2,
3609
3620
  loadProjectExtensions: () => loadProjectExtensions,
3621
+ loadProjectVariants: () => loadProjectVariants,
3610
3622
  loadRegistry: () => loadRegistry,
3611
3623
  loadSpec: () => loadSpec,
3612
3624
  loadSpecGraph: () => loadSpecGraph,
@@ -3630,12 +3642,16 @@ __export(src_exports, {
3630
3642
  moveSubsystemProject: () => moveSubsystemProject,
3631
3643
  movedChildren: () => movedChildren,
3632
3644
  narrativeStepForeignFields: () => narrativeStepForeignFields,
3645
+ packDirEntry: () => packDirEntry,
3646
+ packEntryLabel: () => packEntryLabel,
3647
+ packEntryRef: () => packEntryRef,
3633
3648
  packStoreDir: () => packStoreDir,
3634
3649
  parseDeclaredCall: () => parseDeclaredCall,
3635
3650
  parseYaml: () => parseYaml,
3636
3651
  passesIntentFloor: () => passesIntentFloor,
3637
3652
  pathExists: () => pathExists,
3638
3653
  pathKey: () => pathKey,
3654
+ pinInstalledPacksAsSelections: () => pinInstalledPacksAsSelections,
3639
3655
  projectConfigExists: () => projectConfigExists,
3640
3656
  provisionProject: () => provisionProject,
3641
3657
  qualifiedTypeId: () => qualifiedTypeId,
@@ -3663,12 +3679,14 @@ __export(src_exports, {
3663
3679
  resolveImport: () => resolveImport,
3664
3680
  resolveInstalledPack: () => resolveInstalledPack,
3665
3681
  resolveSubprojectForNamespace: () => resolveSubprojectForNamespace,
3682
+ resolveVariantGuidance: () => resolveVariantGuidance,
3666
3683
  retireSpecialists: () => retireSpecialists,
3667
3684
  runWithProjectBinding: () => runWithProjectBinding,
3668
3685
  runWithProjectRoot: () => runWithProjectRoot,
3669
3686
  sameContract: () => sameContract,
3670
3687
  saveSpec: () => saveSpec,
3671
3688
  saveTopologyConfig: () => saveTopologyConfig,
3689
+ scanAllSpecs: () => scanAllSpecs,
3672
3690
  serializeYaml: () => serializeYaml,
3673
3691
  setExecutionTier: () => setExecutionTier,
3674
3692
  setLogLevel: () => setLogLevel,
@@ -3701,7 +3719,7 @@ module.exports = __toCommonJS(src_exports);
3701
3719
 
3702
3720
  // src/config/project-config.ts
3703
3721
  var fs2 = __toESM(require("fs"));
3704
- var path2 = __toESM(require("path"));
3722
+ var path3 = __toESM(require("path"));
3705
3723
  var import_zod4 = require("zod");
3706
3724
 
3707
3725
  // src/utils/fs.ts
@@ -3754,6 +3772,9 @@ function listFilesRecursive(dirPath, ext) {
3754
3772
  }
3755
3773
  var projectRootOverride = null;
3756
3774
  var requestRootStore = new import_node_async_hooks.AsyncLocalStorage();
3775
+ function currentRootBinding() {
3776
+ return requestRootStore.getStore();
3777
+ }
3757
3778
  function runWithProjectRoot(dir, fn) {
3758
3779
  return requestRootStore.run({ ...requestRootStore.getStore(), root: path.resolve(dir) }, fn);
3759
3780
  }
@@ -3898,6 +3919,7 @@ var BundleNotFoundError = class extends WaironError {
3898
3919
  };
3899
3920
 
3900
3921
  // src/models/project.ts
3922
+ var path2 = __toESM(require("path"));
3901
3923
  var import_zod3 = require("zod");
3902
3924
 
3903
3925
  // src/models/agent.ts
@@ -4485,16 +4507,28 @@ function activeTargetTypes(config) {
4485
4507
  const targets = config.targets;
4486
4508
  return targets.filter((t) => typeof t === "string" || t.enabled !== false).map((t) => typeof t === "string" ? t : t.type);
4487
4509
  }
4510
+ var PACK_EXT_RE = /\.(ya?ml|cjs|js)$/i;
4511
+ function declaredPackNames(config) {
4512
+ const selection = config.profileSelection;
4513
+ return [.../* @__PURE__ */ new Set([
4514
+ ...(config.extensions?.packs ?? []).map((entry) => typeof entry === "string" ? path2.basename(entry).replace(PACK_EXT_RE, "") : entry.name),
4515
+ ...selection?.requiredPackNames ?? [],
4516
+ ...selection?.defaultPackNames ?? []
4517
+ ])];
4518
+ }
4519
+ function declaredProfileIds(config) {
4520
+ return [...new Set(config.profileSelection?.profileIds ?? [])];
4521
+ }
4488
4522
 
4489
4523
  // src/config/project-config.ts
4490
4524
  function waiDirAt(root) {
4491
- const wai = path2.join(root, ".wai");
4492
- const legacy = path2.join(root, ".wairon");
4525
+ const wai = path3.join(root, ".wai");
4526
+ const legacy = path3.join(root, ".wairon");
4493
4527
  return !fs2.existsSync(wai) && fs2.existsSync(legacy) ? legacy : wai;
4494
4528
  }
4495
4529
  function projectConfigFsAdapterAt(rootDir) {
4496
- const root = path2.resolve(rootDir);
4497
- const file = () => path2.join(waiDirAt(root), "project.yaml");
4530
+ const root = path3.resolve(rootDir);
4531
+ const file = () => path3.join(waiDirAt(root), "project.yaml");
4498
4532
  return {
4499
4533
  readDocument() {
4500
4534
  return readYamlFile(file());
@@ -4703,15 +4737,15 @@ function indexOver(store, root) {
4703
4737
  specsDir() {
4704
4738
  try {
4705
4739
  const declared = store.readField("paths.specsDir");
4706
- if (declared) return path2.resolve(root, declared);
4740
+ if (declared) return path3.resolve(root, declared);
4707
4741
  } catch {
4708
4742
  }
4709
- return path2.join(waiDirAt(root), "specs");
4743
+ return path3.join(waiDirAt(root), "specs");
4710
4744
  }
4711
4745
  };
4712
4746
  }
4713
4747
  function projectConfigRepositoryOver(adapter, rootDir) {
4714
- const root = path2.resolve(rootDir);
4748
+ const root = path3.resolve(rootDir);
4715
4749
  const store = storeOver(adapter, root);
4716
4750
  const index = indexOver(store, root);
4717
4751
  const registry = registryOver(store, root);
@@ -4808,36 +4842,24 @@ var projectConfigRepository = {
4808
4842
  bound().pinGlobalPacksAsSelections(selections);
4809
4843
  }
4810
4844
  };
4811
- var PACK_EXT_RE = /\.(ya?ml|cjs|js)$/i;
4812
- function declaredPackNames(config) {
4813
- const selection = config.profileSelection;
4814
- return [.../* @__PURE__ */ new Set([
4815
- ...(config.extensions?.packs ?? []).map((entry) => typeof entry === "string" ? path2.basename(entry).replace(PACK_EXT_RE, "") : entry.name),
4816
- ...selection?.requiredPackNames ?? [],
4817
- ...selection?.defaultPackNames ?? []
4818
- ])];
4819
- }
4820
- function declaredProfileIds(config) {
4821
- return [...new Set(config.profileSelection?.profileIds ?? [])];
4822
- }
4823
4845
 
4824
4846
  // src/core/domain_projector.ts
4825
4847
  var path16 = __toESM(require("path"));
4826
4848
 
4827
4849
  // src/core/specs.ts
4828
- var fs12 = __toESM(require("fs"));
4850
+ var fs11 = __toESM(require("fs"));
4829
4851
  var path15 = __toESM(require("path"));
4830
4852
 
4831
4853
  // src/config/paths.ts
4832
4854
  var fs3 = __toESM(require("fs"));
4833
- var path3 = __toESM(require("path"));
4855
+ var path4 = __toESM(require("path"));
4834
4856
  function aiPathsAt(rootDir) {
4835
- const resolvedRoot = path3.resolve(rootDir);
4857
+ const resolvedRoot = path4.resolve(rootDir);
4836
4858
  const aiDirAt2 = (...segments) => {
4837
- const waiPath = path3.join(resolvedRoot, ".wai");
4838
- const waironPath = path3.join(resolvedRoot, ".wairon");
4859
+ const waiPath = path4.join(resolvedRoot, ".wai");
4860
+ const waironPath = path4.join(resolvedRoot, ".wairon");
4839
4861
  const base = !fs3.existsSync(waiPath) && fs3.existsSync(waironPath) ? waironPath : waiPath;
4840
- return path3.join(base, ...segments);
4862
+ return path4.join(base, ...segments);
4841
4863
  };
4842
4864
  const specsDir = () => projectConfigRepositoryAt(resolvedRoot).specsDir();
4843
4865
  return {
@@ -4854,12 +4876,12 @@ function aiPathsAt(rootDir) {
4854
4876
  contextDomainsMd: () => aiDirAt2("context", "domains.md"),
4855
4877
  contextWaironGuideMd: () => aiDirAt2("context", "wairon-guide.md"),
4856
4878
  specsDir,
4857
- specsSystem: () => path3.join(specsDir(), ".index.yaml"),
4858
- specsSubsystemsDir: () => path3.join(specsDir(), "subsystems"),
4859
- specsComponentsDir: () => path3.join(specsDir(), "components"),
4860
- specsInterfacesDir: () => path3.join(specsDir(), "interfaces"),
4861
- specsImplementationsDir: () => path3.join(specsDir(), "implementations"),
4862
- specsTypesDir: () => path3.join(specsDir(), "types")
4879
+ specsSystem: () => path4.join(specsDir(), ".index.yaml"),
4880
+ specsSubsystemsDir: () => path4.join(specsDir(), "subsystems"),
4881
+ specsComponentsDir: () => path4.join(specsDir(), "components"),
4882
+ specsInterfacesDir: () => path4.join(specsDir(), "interfaces"),
4883
+ specsImplementationsDir: () => path4.join(specsDir(), "implementations"),
4884
+ specsTypesDir: () => path4.join(specsDir(), "types")
4863
4885
  };
4864
4886
  }
4865
4887
  var AI_PATHS = {
@@ -4940,7 +4962,7 @@ function stateIdEquals(a, b) {
4940
4962
 
4941
4963
  // src/core/lockfile.ts
4942
4964
  var fs4 = __toESM(require("fs"));
4943
- var path4 = __toESM(require("path"));
4965
+ var path5 = __toESM(require("path"));
4944
4966
  function lockPath() {
4945
4967
  return aiDir("lock.json");
4946
4968
  }
@@ -4972,7 +4994,7 @@ function normalizeRecord(raw) {
4972
4994
  }
4973
4995
  function writeLockRecord(record) {
4974
4996
  const p = lockPath();
4975
- fs4.mkdirSync(path4.dirname(p), { recursive: true });
4997
+ fs4.mkdirSync(path5.dirname(p), { recursive: true });
4976
4998
  const tmp = `${p}.tmp`;
4977
4999
  fs4.writeFileSync(tmp, JSON.stringify(withSortedMaps(record), null, 2) + "\n");
4978
5000
  fs4.renameSync(tmp, p);
@@ -4995,7 +5017,7 @@ function withSortedMaps(record) {
4995
5017
 
4996
5018
  // src/core/spec-files.ts
4997
5019
  var fs5 = __toESM(require("fs"));
4998
- var path5 = __toESM(require("path"));
5020
+ var path6 = __toESM(require("path"));
4999
5021
  var SPEC_FILE_EXTENSION = ".yaml";
5000
5022
  function readSpecFile(filePath) {
5001
5023
  return readYamlFile(filePath);
@@ -5009,7 +5031,7 @@ function listSpecFiles(specsDir) {
5009
5031
  function removeSpecFile(filePath, specsRoot) {
5010
5032
  if (!fs5.existsSync(filePath)) return false;
5011
5033
  fs5.unlinkSync(filePath);
5012
- pruneEmptyDirs(path5.dirname(filePath), path5.resolve(specsRoot));
5034
+ pruneEmptyDirs(path6.dirname(filePath), path6.resolve(specsRoot));
5013
5035
  return true;
5014
5036
  }
5015
5037
  function pruneEmptyDirs(dir, specsRoot) {
@@ -5017,7 +5039,7 @@ function pruneEmptyDirs(dir, specsRoot) {
5017
5039
  while (at !== specsRoot && at.startsWith(specsRoot)) {
5018
5040
  if (!fs5.existsSync(at) || fs5.readdirSync(at).length > 0) return;
5019
5041
  fs5.rmdirSync(at);
5020
- at = path5.dirname(at);
5042
+ at = path6.dirname(at);
5021
5043
  }
5022
5044
  }
5023
5045
 
@@ -6575,7 +6597,7 @@ function jumpFieldsOf(s) {
6575
6597
  }
6576
6598
 
6577
6599
  // src/models/code-model.ts
6578
- var path6 = __toESM(require("path"));
6600
+ var path7 = __toESM(require("path"));
6579
6601
  function pathKey(sourcePath) {
6580
6602
  return sourcePath.replace(/\\/g, "/").replace(/^\.\//, "");
6581
6603
  }
@@ -6610,7 +6632,7 @@ function hasFunctionBody(facts, symbol) {
6610
6632
  }
6611
6633
  function resolveImport(fromFile, specifier, knownPaths) {
6612
6634
  if (!specifier.startsWith(".")) return void 0;
6613
- const joined = pathKey(path6.posix.normalize(path6.posix.join(path6.posix.dirname(fromFile), specifier)));
6635
+ const joined = pathKey(path7.posix.normalize(path7.posix.join(path7.posix.dirname(fromFile), specifier)));
6614
6636
  const candidates = [
6615
6637
  joined,
6616
6638
  joined.replace(/\.js$/, ".ts"),
@@ -6706,7 +6728,7 @@ function resolveNarrativeLabels(methodName, steps) {
6706
6728
 
6707
6729
  // src/core/canvas.ts
6708
6730
  var fs6 = __toESM(require("fs"));
6709
- var path7 = __toESM(require("path"));
6731
+ var path8 = __toESM(require("path"));
6710
6732
 
6711
6733
  // src/core/canvas-layout.ts
6712
6734
  function computeLayout(model, collapsed) {
@@ -7365,9 +7387,9 @@ function embedJson(value) {
7365
7387
  }
7366
7388
  function loadCytoscapeLib() {
7367
7389
  const candidates = [
7368
- path7.resolve(__dirname, "..", "templates", "canvas", "cytoscape.min.js"),
7390
+ path8.resolve(__dirname, "..", "templates", "canvas", "cytoscape.min.js"),
7369
7391
  // src/core & dist/cli
7370
- path7.resolve(__dirname, "templates", "canvas", "cytoscape.min.js")
7392
+ path8.resolve(__dirname, "templates", "canvas", "cytoscape.min.js")
7371
7393
  // dist (library entry)
7372
7394
  ];
7373
7395
  for (const p of candidates) {
@@ -11539,10 +11561,47 @@ var MODEL = __MODEL_JSON__;
11539
11561
  </html>
11540
11562
  `;
11541
11563
 
11564
+ // src/core/surfaces.ts
11565
+ var fs7 = __toESM(require("fs"));
11566
+ var path9 = __toESM(require("path"));
11567
+
11568
+ // src/core/openapi.ts
11569
+ var yaml2 = __toESM(require("js-yaml"));
11570
+
11571
+ // src/core/surfaces.ts
11572
+ var SURFACES_DIRNAME = "surfaces";
11573
+ function surfacesDir(rootDir) {
11574
+ return path9.join(rootDir, ".wai", SURFACES_DIRNAME);
11575
+ }
11576
+ function listSnapshots(rootDir = getProjectRoot()) {
11577
+ const dir = surfacesDir(rootDir);
11578
+ if (!fs7.existsSync(dir)) return [];
11579
+ const out = [];
11580
+ for (const file of fs7.readdirSync(dir)) {
11581
+ if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue;
11582
+ try {
11583
+ out.push(SurfaceSnapshotSchema.parse(readYamlFile(path9.join(dir, file))));
11584
+ } catch {
11585
+ }
11586
+ }
11587
+ return out;
11588
+ }
11589
+ function listMountSnapshots(mounts) {
11590
+ const bound2 = path9.resolve(getProjectRoot());
11591
+ const out = [];
11592
+ for (const namespace of mounts) {
11593
+ const dir = resolveSubprojectForNamespace(namespace);
11594
+ if (!dir || path9.resolve(dir) === bound2) continue;
11595
+ const snapshots = listSnapshots(dir);
11596
+ if (snapshots.length > 0) out.push({ namespace, snapshots });
11597
+ }
11598
+ return out;
11599
+ }
11600
+
11542
11601
  // src/core/extensions.ts
11543
- var fs8 = __toESM(require("fs"));
11602
+ var fs9 = __toESM(require("fs"));
11544
11603
  var os2 = __toESM(require("os"));
11545
- var path10 = __toESM(require("path"));
11604
+ var path12 = __toESM(require("path"));
11546
11605
  var import_module = require("module");
11547
11606
  var import_zod9 = require("zod");
11548
11607
 
@@ -11570,12 +11629,12 @@ function isNewerVersion(current2, candidate) {
11570
11629
 
11571
11630
  // src/core/packstore.ts
11572
11631
  var crypto2 = __toESM(require("crypto"));
11573
- var fs7 = __toESM(require("fs"));
11574
- var path9 = __toESM(require("path"));
11632
+ var fs8 = __toESM(require("fs"));
11633
+ var path11 = __toESM(require("path"));
11575
11634
 
11576
11635
  // src/config/defaults.ts
11577
11636
  var os = __toESM(require("os"));
11578
- var path8 = __toESM(require("path"));
11637
+ var path10 = __toESM(require("path"));
11579
11638
  var DEFAULT_TARGET_DIRS = {
11580
11639
  claude: ".claude/agents",
11581
11640
  gemini: ".gemini/agents",
@@ -11591,7 +11650,7 @@ function defaultTargetConfig(type) {
11591
11650
  enabled: true
11592
11651
  };
11593
11652
  }
11594
- var WAIRON_VERSION = "5.1.1-dev.72";
11653
+ var WAIRON_VERSION = "5.1.1-dev.73";
11595
11654
  var GITHUB_REPO = "SYW-Apps/Waffle-AIron";
11596
11655
  var ARCHITECT_AGENT_ID = "agent-architect";
11597
11656
  var ARCHITECT_TEMPLATE_ID = "architect";
@@ -11602,7 +11661,7 @@ function globalTemplatesDir(projectOverride) {
11602
11661
  if (projectOverride) {
11603
11662
  return projectOverride;
11604
11663
  }
11605
- return path8.join(os.homedir(), ".wairon", "templates");
11664
+ return path10.join(os.homedir(), ".wairon", "templates");
11606
11665
  }
11607
11666
  var BACKEND_COMMANDS = {
11608
11667
  claude: "claude",
@@ -11638,7 +11697,7 @@ function packStoreDir() {
11638
11697
  function packFiles(dir, prefix = "") {
11639
11698
  let entries;
11640
11699
  try {
11641
- entries = fs7.readdirSync(dir, { withFileTypes: true });
11700
+ entries = fs8.readdirSync(dir, { withFileTypes: true });
11642
11701
  } catch {
11643
11702
  return [];
11644
11703
  }
@@ -11646,25 +11705,25 @@ function packFiles(dir, prefix = "") {
11646
11705
  for (const e of entries) {
11647
11706
  if (DIGEST_EXCLUDED.has(e.name)) continue;
11648
11707
  const rel2 = prefix ? `${prefix}/${e.name}` : e.name;
11649
- if (e.isDirectory()) out.push(...packFiles(path9.join(dir, e.name), rel2));
11708
+ if (e.isDirectory()) out.push(...packFiles(path11.join(dir, e.name), rel2));
11650
11709
  else if (e.isFile()) out.push(rel2);
11651
11710
  }
11652
11711
  return out.sort();
11653
11712
  }
11654
11713
  function computePackDigest(packDir) {
11655
11714
  const hash = crypto2.createHash("sha256");
11656
- const abs = path9.resolve(packDir);
11715
+ const abs = path11.resolve(packDir);
11657
11716
  let isFile = false;
11658
11717
  try {
11659
- isFile = fs7.statSync(abs).isFile();
11718
+ isFile = fs8.statSync(abs).isFile();
11660
11719
  } catch {
11661
11720
  }
11662
- const entries = isFile ? [[path9.basename(abs), abs]] : packFiles(abs).map((rel2) => [rel2, path9.join(abs, rel2)]);
11721
+ const entries = isFile ? [[path11.basename(abs), abs]] : packFiles(abs).map((rel2) => [rel2, path11.join(abs, rel2)]);
11663
11722
  for (const [rel2, full] of entries) {
11664
11723
  hash.update(rel2);
11665
11724
  hash.update("\0");
11666
11725
  try {
11667
- hash.update(fs7.readFileSync(full));
11726
+ hash.update(fs8.readFileSync(full));
11668
11727
  } catch {
11669
11728
  }
11670
11729
  hash.update("\0");
@@ -11673,7 +11732,7 @@ function computePackDigest(packDir) {
11673
11732
  }
11674
11733
  function readInstallRecord(packPath) {
11675
11734
  try {
11676
- const raw = readYamlFile(path9.join(packPath, INSTALL_RECORD));
11735
+ const raw = readYamlFile(path11.join(packPath, INSTALL_RECORD));
11677
11736
  return raw && typeof raw === "object" ? raw : {};
11678
11737
  } catch {
11679
11738
  return {};
@@ -11704,14 +11763,14 @@ function installedFrom(location, name, version) {
11704
11763
  function versionedEntries(nameDir, fallbackName) {
11705
11764
  let versions;
11706
11765
  try {
11707
- versions = fs7.readdirSync(nameDir, { withFileTypes: true });
11766
+ versions = fs8.readdirSync(nameDir, { withFileTypes: true });
11708
11767
  } catch {
11709
11768
  return [];
11710
11769
  }
11711
11770
  const out = [];
11712
11771
  for (const v of versions) {
11713
11772
  if (!v.isDirectory()) continue;
11714
- const versionDir = path9.join(nameDir, v.name);
11773
+ const versionDir = path11.join(nameDir, v.name);
11715
11774
  const entryFile = packDirEntry(versionDir);
11716
11775
  if (!entryFile) continue;
11717
11776
  out.push(installedFrom(versionDir, declaredName(entryFile) ?? fallbackName, v.name));
@@ -11719,7 +11778,7 @@ function versionedEntries(nameDir, fallbackName) {
11719
11778
  return out;
11720
11779
  }
11721
11780
  function storeEntryPacks(store, entry) {
11722
- const full = path9.join(store, entry.name);
11781
+ const full = path11.join(store, entry.name);
11723
11782
  if (entry.isFile()) {
11724
11783
  if (!PACK_FILE_RE.test(entry.name)) return [];
11725
11784
  const name = declaredName(full) ?? entry.name.replace(PACK_FILE_RE, "");
@@ -11734,7 +11793,7 @@ function listInstalledPacks() {
11734
11793
  const store = packStoreDir();
11735
11794
  let entries;
11736
11795
  try {
11737
- entries = fs7.readdirSync(store, { withFileTypes: true });
11796
+ entries = fs8.readdirSync(store, { withFileTypes: true });
11738
11797
  } catch {
11739
11798
  return [];
11740
11799
  }
@@ -11751,17 +11810,17 @@ function resolveInstalledPack(name, version) {
11751
11810
  return candidates[0];
11752
11811
  }
11753
11812
  function installPackFromDirectory(sourceDir, origin) {
11754
- const abs = path9.resolve(sourceDir);
11813
+ const abs = path11.resolve(sourceDir);
11755
11814
  const entryFile = packDirEntry(abs);
11756
11815
  if (!entryFile) {
11757
11816
  throw new Error(`"${sourceDir}" is not a pack directory (no pack.yaml | pack.cjs | index.cjs | \u2026).`);
11758
11817
  }
11759
- const manifest = readManifest(entryFile, path9.dirname(entryFile));
11818
+ const manifest = readManifest(entryFile, path11.dirname(entryFile));
11760
11819
  const version = manifest.version && manifest.version.length > 0 ? manifest.version : UNVERSIONED;
11761
- const dest = path9.join(packStoreDir(), manifest.name, version);
11762
- fs7.rmSync(dest, { recursive: true, force: true });
11763
- fs7.mkdirSync(path9.dirname(dest), { recursive: true });
11764
- fs7.cpSync(abs, dest, { recursive: true });
11820
+ const dest = path11.join(packStoreDir(), manifest.name, version);
11821
+ fs8.rmSync(dest, { recursive: true, force: true });
11822
+ fs8.mkdirSync(path11.dirname(dest), { recursive: true });
11823
+ fs8.cpSync(abs, dest, { recursive: true });
11765
11824
  const digest2 = computePackDigest(dest);
11766
11825
  const record = {
11767
11826
  origin,
@@ -11769,7 +11828,7 @@ function installPackFromDirectory(sourceDir, origin) {
11769
11828
  waironVersion: WAIRON_VERSION,
11770
11829
  installedAt: (/* @__PURE__ */ new Date()).toISOString()
11771
11830
  };
11772
- writeYamlFile(path9.join(dest, INSTALL_RECORD), record);
11831
+ writeYamlFile(path11.join(dest, INSTALL_RECORD), record);
11773
11832
  return {
11774
11833
  name: manifest.name,
11775
11834
  version,
@@ -11784,11 +11843,11 @@ function uninstallPack(name, version) {
11784
11843
  const targets = listInstalledPacks().filter((p) => p.name === name && (!version || p.version === version));
11785
11844
  if (targets.length === 0) return false;
11786
11845
  for (const target of targets) {
11787
- fs7.rmSync(target.path, { recursive: true, force: true });
11788
- const parent = path9.dirname(target.path);
11789
- if (path9.resolve(parent) === path9.resolve(packStoreDir())) continue;
11846
+ fs8.rmSync(target.path, { recursive: true, force: true });
11847
+ const parent = path11.dirname(target.path);
11848
+ if (path11.resolve(parent) === path11.resolve(packStoreDir())) continue;
11790
11849
  try {
11791
- if (fs7.readdirSync(parent).length === 0) fs7.rmdirSync(parent);
11850
+ if (fs8.readdirSync(parent).length === 0) fs8.rmdirSync(parent);
11792
11851
  } catch {
11793
11852
  }
11794
11853
  }
@@ -11939,6 +11998,10 @@ function skillExtendErrors(skills) {
11939
11998
  return skills.filter((s) => s.extends !== void 0 && !EXTENDABLE_BUILTIN_SKILLS.includes(s.extends)).map((s) => `Extension pack "${s.pack}" declares a skill extending "${s.extends}", which is not a builtin skill (extendable: ${EXTENDABLE_BUILTIN_SKILLS.join(", ")}).`);
11940
11999
  }
11941
12000
  var GLOBAL_PACKS_DEFAULT = false;
12001
+ function checkDeclarativePack(manifest) {
12002
+ const result = DeclarativePackSchema.safeParse(manifest);
12003
+ return result.success ? null : result.error.issues[0]?.message ?? "shape mismatch";
12004
+ }
11942
12005
  function globalPacksEnabled(config) {
11943
12006
  return config.extensions?.useGlobalPacks ?? GLOBAL_PACKS_DEFAULT;
11944
12007
  }
@@ -11946,27 +12009,27 @@ function emptyExtensions() {
11946
12009
  return { packNames: [], packs: [], rules: [], profiles: {}, languages: {}, skills: [], patterns: [], guarantees: [], assertions: [], instructions: [], errors: [], selectionFailures: [] };
11947
12010
  }
11948
12011
  function globalPacksDir() {
11949
- return process.env.WAIRON_PACKS_DIR ?? path10.join(os2.homedir(), ".wairon", "packs");
12012
+ return process.env.WAIRON_PACKS_DIR ?? path12.join(os2.homedir(), ".wairon", "packs");
11950
12013
  }
11951
12014
  var PACK_DIR_ENTRIES = ["pack.yaml", "pack.yml", "pack.cjs", "pack.js", "index.cjs", "index.js"];
11952
12015
  function packDirEntry(dir) {
11953
12016
  for (const name of PACK_DIR_ENTRIES) {
11954
- const p = path10.join(dir, name);
11955
- if (fs8.existsSync(p)) return p;
12017
+ const p = path12.join(dir, name);
12018
+ if (fs9.existsSync(p)) return p;
11956
12019
  }
11957
12020
  return null;
11958
12021
  }
11959
12022
  function latestVersionDir(nameDir) {
11960
12023
  let versions;
11961
12024
  try {
11962
- versions = fs8.readdirSync(nameDir, { withFileTypes: true });
12025
+ versions = fs9.readdirSync(nameDir, { withFileTypes: true });
11963
12026
  } catch {
11964
12027
  return null;
11965
12028
  }
11966
12029
  let best = null;
11967
12030
  for (const v of versions) {
11968
12031
  if (!v.isDirectory()) continue;
11969
- const dir = path10.join(nameDir, v.name);
12032
+ const dir = path12.join(nameDir, v.name);
11970
12033
  if (!packDirEntry(dir)) continue;
11971
12034
  if (!best || isNewerVersion(best.version, v.name)) best = { version: v.name, dir };
11972
12035
  }
@@ -11975,13 +12038,13 @@ function latestVersionDir(nameDir) {
11975
12038
  function discoverPacks(dir) {
11976
12039
  let entries;
11977
12040
  try {
11978
- entries = fs8.readdirSync(dir, { withFileTypes: true });
12041
+ entries = fs9.readdirSync(dir, { withFileTypes: true });
11979
12042
  } catch {
11980
12043
  return [];
11981
12044
  }
11982
12045
  const refs = [];
11983
12046
  for (const e of entries.sort((a, b) => compareOrdinal(a.name, b.name))) {
11984
- const full = path10.join(dir, e.name);
12047
+ const full = path12.join(dir, e.name);
11985
12048
  if (e.isDirectory()) {
11986
12049
  if (packDirEntry(full)) refs.push(full);
11987
12050
  else {
@@ -12011,7 +12074,7 @@ function mergePack(out, pack, ref, scope, packDir) {
12011
12074
  foreignBuiltins: [.../* @__PURE__ */ new Set([...existing.foreignBuiltins, ...def.foreignBuiltins])]
12012
12075
  } : def;
12013
12076
  }
12014
- for (const s of pack.skills) out.skills.push({ ...s, pack: pack.name, packVersion: pack.version, sourcePath: path10.resolve(packDir, s.source) });
12077
+ for (const s of pack.skills) out.skills.push({ ...s, pack: pack.name, packVersion: pack.version, sourcePath: path12.resolve(packDir, s.source) });
12015
12078
  for (const p of pack.patterns) out.patterns.push({ ...p, pack: pack.name });
12016
12079
  out.guarantees = [.../* @__PURE__ */ new Set([...out.guarantees, ...pack.guarantees])];
12017
12080
  for (const a of pack.assertions) out.assertions.push({ ...a, pack: pack.name, fullCode: assertionFullCode(pack.name, a.code) });
@@ -12019,10 +12082,10 @@ function mergePack(out, pack, ref, scope, packDir) {
12019
12082
  }
12020
12083
  var isYamlPath = (p) => /\.ya?ml$/i.test(p);
12021
12084
  function resolvePackRef(ref, projectRoot) {
12022
- const pathLike = ref.startsWith(".") || path10.isAbsolute(ref) || isYamlPath(ref);
12085
+ const pathLike = ref.startsWith(".") || path12.isAbsolute(ref) || isYamlPath(ref);
12023
12086
  if (!pathLike) return ref;
12024
- const resolved = path10.resolve(projectRoot, ref);
12025
- if (fs8.existsSync(resolved) && fs8.statSync(resolved).isDirectory()) {
12087
+ const resolved = path12.resolve(projectRoot, ref);
12088
+ if (fs9.existsSync(resolved) && fs9.statSync(resolved).isDirectory()) {
12026
12089
  const entry = packDirEntry(resolved);
12027
12090
  if (!entry) throw new Error(`directory pack has no entry file (${PACK_DIR_ENTRIES.join(" | ")})`);
12028
12091
  return entry;
@@ -12035,7 +12098,7 @@ function readManifest(target, projectRoot) {
12035
12098
  if (raw == null) throw new Error("file not found or empty");
12036
12099
  return { ...DeclarativePackSchema.parse(raw), rules: [] };
12037
12100
  }
12038
- const req = (0, import_module.createRequire)(path10.join(projectRoot, "package.json"));
12101
+ const req = (0, import_module.createRequire)(path12.join(projectRoot, "package.json"));
12039
12102
  const modRaw = req(target);
12040
12103
  const mod = modRaw?.default ?? modRaw;
12041
12104
  const parsed = DeclarativePackSchema.parse({
@@ -12063,7 +12126,7 @@ function loadExtensionPacks(refs, projectRoot) {
12063
12126
  try {
12064
12127
  const target = resolvePackRef(ref, projectRoot);
12065
12128
  const manifest = readManifest(target, projectRoot);
12066
- mergePack(out, manifest, ref, scope, path10.dirname(target));
12129
+ mergePack(out, manifest, ref, scope, path12.dirname(target));
12067
12130
  for (const r of manifest.rules) out.rules.push(r);
12068
12131
  } catch (e) {
12069
12132
  out.errors.push(`Extension pack "${ref}" failed to load: ${e instanceof Error ? e.message : String(e)}`);
@@ -12109,7 +12172,7 @@ function defaultPackSelections() {
12109
12172
  const entry = packDirEntry(pack.path) ?? pack.path;
12110
12173
  let manifest;
12111
12174
  try {
12112
- manifest = readManifest(entry, path10.dirname(entry));
12175
+ manifest = readManifest(entry, path12.dirname(entry));
12113
12176
  } catch {
12114
12177
  continue;
12115
12178
  }
@@ -12125,6 +12188,66 @@ function defaultPackSelections() {
12125
12188
  return [];
12126
12189
  }
12127
12190
  }
12191
+ function diagnoseProjectPacks() {
12192
+ const empty = { globalsUndeclared: false, notApplied: [], unresolved: [], globalsApplied: [] };
12193
+ try {
12194
+ const config = projectConfigRepository.load();
12195
+ if (!config) return empty;
12196
+ const globalsUndeclared = !projectConfigRepository.declaresGlobalPacks();
12197
+ const projectRoot = getProjectRoot();
12198
+ const entries = config.extensions?.packs ?? [];
12199
+ const unresolved = [];
12200
+ const selectedNames = /* @__PURE__ */ new Set();
12201
+ for (const entry of entries) {
12202
+ if (typeof entry === "string") continue;
12203
+ selectedNames.add(entry.name);
12204
+ const resolution = resolveSelection(entry, projectRoot);
12205
+ if (resolution.failure) {
12206
+ unresolved.push({ label: packEntryLabel(entry), message: `[${resolution.failure.code}] ${resolution.failure.message}` });
12207
+ }
12208
+ }
12209
+ const installed = listInstalledPacks();
12210
+ const globalsOn = globalPacksEnabled(config);
12211
+ const globalsApplied = [];
12212
+ if (globalsOn) {
12213
+ for (const ref of discoverPacks(globalPacksDir())) {
12214
+ const match = installed.find((p) => path12.resolve(p.path) === path12.resolve(ref));
12215
+ if (match) globalsApplied.push({ name: match.name, version: match.version });
12216
+ }
12217
+ }
12218
+ const applying = /* @__PURE__ */ new Set([...selectedNames, ...globalsApplied.map((p) => p.name)]);
12219
+ const notApplied = installed.filter((p) => !applying.has(p.name)).map((p) => ({ name: p.name, version: p.version, origin: p.origin }));
12220
+ return { globalsUndeclared, notApplied, unresolved, globalsApplied };
12221
+ } catch {
12222
+ return empty;
12223
+ }
12224
+ }
12225
+ function pinInstalledPacksAsSelections() {
12226
+ const diagnosis = diagnoseProjectPacks();
12227
+ if (!diagnosis.globalsUndeclared || diagnosis.notApplied.length === 0) return [];
12228
+ const added = [];
12229
+ const selections = [];
12230
+ for (const pack of diagnosis.notApplied) {
12231
+ selections.push({
12232
+ name: pack.name,
12233
+ version: pack.version,
12234
+ // Carry the origin so the selection can be obtained elsewhere; a local
12235
+ // path is not fetchable, so it is deliberately not recorded as a source.
12236
+ ...pack.origin && /^[a-z][a-z0-9+.-]*:\/\//i.test(pack.origin) ? { source: pack.origin } : {}
12237
+ });
12238
+ added.push(`${pack.name}@${pack.version}`);
12239
+ }
12240
+ projectConfigRepository.pinGlobalPacksAsSelections(selections);
12241
+ return added;
12242
+ }
12243
+ function packEntryLabel(entry) {
12244
+ if (typeof entry === "string") return entry;
12245
+ return entry.version ? `${entry.name}@${entry.version}` : entry.name;
12246
+ }
12247
+ function packEntryRef(entry, projectRoot) {
12248
+ if (typeof entry === "string") return entry;
12249
+ return resolveSelection(entry, projectRoot).ref ?? null;
12250
+ }
12128
12251
  function resolveSelection(selection, projectRoot) {
12129
12252
  const wanted = selection.version ? `${selection.name}@${selection.version}` : selection.name;
12130
12253
  const fail = (code, message) => ({ failure: { code, severity: "error", name: selection.name, message } });
@@ -12166,7 +12289,7 @@ function verifyIntegrity(selection, packDir, where) {
12166
12289
  };
12167
12290
  }
12168
12291
  function detectBundleStoreDrift(selection, bundleDir) {
12169
- const bundledVersion = path10.basename(bundleDir);
12292
+ const bundledVersion = path12.basename(bundleDir);
12170
12293
  const installed = resolveInstalledPack(selection.name, bundledVersion);
12171
12294
  if (!installed) return void 0;
12172
12295
  const bundleDigest = computePackDigest(bundleDir);
@@ -12180,22 +12303,22 @@ function detectBundleStoreDrift(selection, bundleDir) {
12180
12303
  };
12181
12304
  }
12182
12305
  function findBundledPack(projectRoot, selection) {
12183
- const base = path10.join(projectRoot, ".wai", "packs", selection.name);
12306
+ const base = path12.join(projectRoot, ".wai", "packs", selection.name);
12184
12307
  if (selection.version) {
12185
- const pinned = path10.join(base, selection.version);
12308
+ const pinned = path12.join(base, selection.version);
12186
12309
  return packDirEntry(pinned) ? pinned : null;
12187
12310
  }
12188
12311
  if (packDirEntry(base)) return base;
12189
12312
  let versions;
12190
12313
  try {
12191
- versions = fs8.readdirSync(base, { withFileTypes: true });
12314
+ versions = fs9.readdirSync(base, { withFileTypes: true });
12192
12315
  } catch {
12193
12316
  return null;
12194
12317
  }
12195
12318
  let best = null;
12196
12319
  for (const v of versions) {
12197
12320
  if (!v.isDirectory()) continue;
12198
- const dir = path10.join(base, v.name);
12321
+ const dir = path12.join(base, v.name);
12199
12322
  if (!packDirEntry(dir)) continue;
12200
12323
  if (!best || isNewerVersion(best.version, v.name)) best = { version: v.name, dir };
12201
12324
  }
@@ -12238,21 +12361,21 @@ function buildCodeIndex(model) {
12238
12361
  const declarations = /* @__PURE__ */ new Map();
12239
12362
  const anchors = /* @__PURE__ */ new Map();
12240
12363
  const findingAnchors = /* @__PURE__ */ new Map();
12241
- const namesAt = (cache, path28, make) => {
12242
- const cached = cache.get(path28);
12364
+ const namesAt = (cache, path29, make) => {
12365
+ const cached = cache.get(path29);
12243
12366
  if (cached) return cached;
12244
- const f = facts.get(path28);
12367
+ const f = facts.get(path29);
12245
12368
  if (!f) return NO_NAMES;
12246
12369
  const built = make(f);
12247
- cache.set(path28, built);
12370
+ cache.set(path29, built);
12248
12371
  return built;
12249
12372
  };
12250
12373
  const republished = /* @__PURE__ */ new Map();
12251
- const republishedFrom = (path28) => {
12252
- const cached = republished.get(path28);
12374
+ const republishedFrom = (path29) => {
12375
+ const cached = republished.get(path29);
12253
12376
  if (cached) return cached;
12254
- const out = /* @__PURE__ */ new Set([path28]);
12255
- const queue = [path28];
12377
+ const out = /* @__PURE__ */ new Set([path29]);
12378
+ const queue = [path29];
12256
12379
  while (queue.length) {
12257
12380
  const from = queue.pop();
12258
12381
  const f = facts.get(from);
@@ -12265,7 +12388,7 @@ function buildCodeIndex(model) {
12265
12388
  }
12266
12389
  }
12267
12390
  }
12268
- republished.set(path28, out);
12391
+ republished.set(path29, out);
12269
12392
  return out;
12270
12393
  };
12271
12394
  const NO_ORIGIN = /* @__PURE__ */ new Set();
@@ -12274,9 +12397,9 @@ function buildCodeIndex(model) {
12274
12397
  return to ? republishedFrom(to) : NO_ORIGIN;
12275
12398
  };
12276
12399
  const scopeOf = (site, from) => {
12277
- const path28 = pathKey(site.from ?? from);
12278
- const f = facts.get(path28);
12279
- return f?.status === "analyzed" && f.analysisGrade === "exact" ? { path: path28, facts: f } : void 0;
12400
+ const path29 = pathKey(site.from ?? from);
12401
+ const f = facts.get(path29);
12402
+ return f?.status === "analyzed" && f.analysisGrade === "exact" ? { path: path29, facts: f } : void 0;
12280
12403
  };
12281
12404
  const originOf2 = (site, from) => {
12282
12405
  const resolved = scopeOf(site, from);
@@ -12315,14 +12438,14 @@ function buildCodeIndex(model) {
12315
12438
  if (site.via) for (const typeName of localTypesOf(f, site.via)) widenThroughType(typeName);
12316
12439
  return out;
12317
12440
  };
12318
- const declarationsAt = (path28) => namesAt(declarations, pathKey(path28), (f) => /* @__PURE__ */ new Set([...f.declaredNames, ...f.exportedNames]));
12441
+ const declarationsAt = (path29) => namesAt(declarations, pathKey(path29), (f) => /* @__PURE__ */ new Set([...f.declaredNames, ...f.exportedNames]));
12319
12442
  return {
12320
12443
  paths,
12321
12444
  exactPaths,
12322
- factsAt: (path28) => facts.get(pathKey(path28)),
12445
+ factsAt: (path29) => facts.get(pathKey(path29)),
12323
12446
  declarationsAt,
12324
- anchorsAt: (path28) => namesAt(anchors, pathKey(path28), (f) => /* @__PURE__ */ new Set([...f.declaredNames, ...f.exportedNames, ...f.anchoredNames])),
12325
- findingAnchorsAt: (path28) => namesAt(findingAnchors, pathKey(path28), (f) => new Set(f.anchoredNames)),
12447
+ anchorsAt: (path29) => namesAt(anchors, pathKey(path29), (f) => /* @__PURE__ */ new Set([...f.declaredNames, ...f.exportedNames, ...f.anchoredNames])),
12448
+ findingAnchorsAt: (path29) => namesAt(findingAnchors, pathKey(path29), (f) => new Set(f.anchoredNames)),
12326
12449
  originOf: originOf2,
12327
12450
  possibleOriginsOf
12328
12451
  };
@@ -12360,10 +12483,10 @@ function buildRealizationIndex(ctx) {
12360
12483
  return {
12361
12484
  paths,
12362
12485
  implementationsOf: (compId) => implsByComponent.get(compId) ?? NONE_IMPL,
12363
- implementationsAt: (path28) => implsByPath.get(pathKey(path28)) ?? NONE_IMPL,
12486
+ implementationsAt: (path29) => implsByPath.get(pathKey(path29)) ?? NONE_IMPL,
12364
12487
  filesOf: (compId) => filesByComponent.get(compId) ?? NONE_PATH,
12365
12488
  filesIn: (subsystemId) => filesBySubsystem.get(subsystemId) ?? NONE_PATH,
12366
- componentsAt: (path28) => componentsByPath.get(pathKey(path28)) ?? NONE_COMP
12489
+ componentsAt: (path29) => componentsByPath.get(pathKey(path29)) ?? NONE_COMP
12367
12490
  };
12368
12491
  }
12369
12492
  function buildImportGraph(index, universe) {
@@ -12375,22 +12498,22 @@ function buildImportGraph(index, universe) {
12375
12498
  if (to && to !== from) into.add(to);
12376
12499
  }
12377
12500
  };
12378
- const importsOf = (path28) => {
12379
- const cached = imports.get(path28);
12501
+ const importsOf = (path29) => {
12502
+ const cached = imports.get(path29);
12380
12503
  if (cached) return cached;
12381
- const facts = index.factsAt(path28);
12504
+ const facts = index.factsAt(path29);
12382
12505
  const out = /* @__PURE__ */ new Set();
12383
- if (facts?.status === "analyzed") resolveAll(path28, facts.imports, out);
12384
- imports.set(path28, out);
12506
+ if (facts?.status === "analyzed") resolveAll(path29, facts.imports, out);
12507
+ imports.set(path29, out);
12385
12508
  return out;
12386
12509
  };
12387
- const tracesOf = (path28) => {
12388
- const cached = traces.get(path28);
12510
+ const tracesOf = (path29) => {
12511
+ const cached = traces.get(path29);
12389
12512
  if (cached) return cached;
12390
- const facts = index.factsAt(path28);
12391
- const out = new Set(importsOf(path28));
12392
- if (facts?.status === "analyzed") resolveAll(path28, facts.reexports, out);
12393
- traces.set(path28, out);
12513
+ const facts = index.factsAt(path29);
12514
+ const out = new Set(importsOf(path29));
12515
+ if (facts?.status === "analyzed") resolveAll(path29, facts.reexports, out);
12516
+ traces.set(path29, out);
12394
12517
  return out;
12395
12518
  };
12396
12519
  return {
@@ -13727,11 +13850,11 @@ var unconditionalCallCyclesRule = {
13727
13850
  const memberEdges = keys.flatMap((k) => (adjacency.get(k) ?? []).filter((e) => inScc.has(e.toKey)));
13728
13851
  if (memberEdges.length === 0) continue;
13729
13852
  const anchor = [...memberEdges].sort((a, b) => byCodeUnit(a.fromKey, b.fromKey) || byCodeUnit(a.impl.id, b.impl.id) || a.stepNumber - b.stepNumber)[0];
13730
- const path28 = [...keys].sort(byCodeUnit).join(" \u2192 ");
13853
+ const path29 = [...keys].sort(byCodeUnit).join(" \u2192 ");
13731
13854
  ctx.addIssue(
13732
13855
  "warning",
13733
13856
  "UNCONDITIONAL_CALL_CYCLE",
13734
- `Call cycle with no guard: ${path28} \u2014 every call edge in this cycle is unavoidable on all paths of its narrative (e.g. step ${anchor.stepNumber} of "${anchor.methodName}" in "${anchor.impl.id}" always calls ${anchor.toLabel}). This recurses without a base case, by construction. Guard at least one edge with a branch/return before the call, or lint.allow with the termination argument.`,
13857
+ `Call cycle with no guard: ${path29} \u2014 every call edge in this cycle is unavoidable on all paths of its narrative (e.g. step ${anchor.stepNumber} of "${anchor.methodName}" in "${anchor.impl.id}" always calls ${anchor.toLabel}). This recurses without a base case, by construction. Guard at least one edge with a branch/return before the call, or lint.allow with the termination argument.`,
13735
13858
  anchor.impl.id,
13736
13859
  memberEdges.some((e) => ctx.isImplementationDraft(e.impl))
13737
13860
  );
@@ -15398,8 +15521,8 @@ var lifecycleRule = {
15398
15521
  };
15399
15522
 
15400
15523
  // src/core/rules/wiring/portal-mounts.ts
15401
- function liesUnder(path28, prefix) {
15402
- return path28 === prefix || path28.startsWith(prefix + "/");
15524
+ function liesUnder(path29, prefix) {
15525
+ return path29 === prefix || path29.startsWith(prefix + "/");
15403
15526
  }
15404
15527
  var portalMountsRule = {
15405
15528
  name: "portal-mounts",
@@ -16567,11 +16690,11 @@ var hiddenStateRule = {
16567
16690
  byPath.set(key, list);
16568
16691
  }
16569
16692
  }
16570
- for (const path28 of code.exactPaths) {
16571
- const facts = code.factsAt(path28);
16693
+ for (const path29 of code.exactPaths) {
16694
+ const facts = code.factsAt(path29);
16572
16695
  const bindings = facts.topLevelMutableBindings ?? [];
16573
16696
  if (bindings.length === 0) continue;
16574
- const mapped = byPath.get(path28) ?? [];
16697
+ const mapped = byPath.get(path29) ?? [];
16575
16698
  if (mapped.length === 0) continue;
16576
16699
  if (!mapped.every((m) => isStatelessLogic(m.component))) continue;
16577
16700
  const anchor = [...mapped].sort((a, b) => a.impl.id.localeCompare(b.impl.id))[0];
@@ -16637,7 +16760,7 @@ var dependencyConformanceRule = {
16637
16760
  }
16638
16761
  return false;
16639
16762
  };
16640
- const draftAt = (path28) => realization.implementationsAt(path28).some((impl) => ctx.isImplementationDraft(impl));
16763
+ const draftAt = (path29) => realization.implementationsAt(path29).some((impl) => ctx.isImplementationDraft(impl));
16641
16764
  for (const fromPath of mappedPaths) {
16642
16765
  const fromComponents = realization.componentsAt(fromPath);
16643
16766
  for (const toPath of graph.importsOf(fromPath)) {
@@ -16693,6 +16816,60 @@ var dependencyConformanceRule = {
16693
16816
  }
16694
16817
  };
16695
16818
 
16819
+ // src/core/rules/conformance/portal-imports.ts
16820
+ var portalImportsRule = {
16821
+ name: "portal-imports",
16822
+ description: "A runtime import that crosses a subsystem boundary must land on a file that realizes one of the target subsystem's PUBLISHED components \u2014 its portal file. dependency-conformance asks whether the hop is declared; this asks where it lands. An import that reaches past the portal into a concrete module can use anything that module exports, published or not, so the portal stops being the boundary and names no contract ever promised leak across it \u2014 which is how a surface grows that nobody designed. In-process it is cosmetic at runtime; it is not cosmetic for the contract. Only exact-grade component-mapped files participate; type-only imports are exempt; chained subprojects validate standalone.",
16823
+ codes: [
16824
+ {
16825
+ code: "IMPORT_BYPASSES_PORTAL",
16826
+ defaultSeverity: "warning",
16827
+ summary: "A runtime import crosses into another subsystem through a file that realizes none of its published components",
16828
+ carryable: true
16829
+ }
16830
+ ],
16831
+ check(ctx) {
16832
+ const code = ctx.codeIndex();
16833
+ const realization = ctx.realizationIndex();
16834
+ const mappedPaths = new Set(realization.paths.filter((p) => code.exactPaths.has(p)));
16835
+ const graph = ctx.importGraph(mappedPaths);
16836
+ const portalFiles = /* @__PURE__ */ new Map();
16837
+ const portalFilesOf = (subsystemId) => {
16838
+ let files = portalFiles.get(subsystemId);
16839
+ if (!files) {
16840
+ files = /* @__PURE__ */ new Set();
16841
+ for (const compId of ctx.publicSet.get(subsystemId) ?? []) {
16842
+ for (const f of realization.filesOf(compId)) if (mappedPaths.has(f)) files.add(f);
16843
+ }
16844
+ portalFiles.set(subsystemId, files);
16845
+ }
16846
+ return files;
16847
+ };
16848
+ const draftAt = (path29) => realization.implementationsAt(path29).some((impl) => ctx.isImplementationDraft(impl));
16849
+ for (const fromPath of mappedPaths) {
16850
+ const fromSubsystems = new Set(realization.componentsAt(fromPath).map((c) => c.subsystem));
16851
+ for (const toPath of graph.importsOf(fromPath)) {
16852
+ const crossed = [...new Set(realization.componentsAt(toPath).map((c) => c.subsystem))].filter((s) => !fromSubsystems.has(s));
16853
+ const bypassed = crossed.filter((s) => !portalFilesOf(s).has(toPath));
16854
+ if (bypassed.length === 0) continue;
16855
+ for (const subsystemId of bypassed) {
16856
+ const portals = [...portalFilesOf(subsystemId)];
16857
+ ctx.addIssue(
16858
+ "warning",
16859
+ "IMPORT_BYPASSES_PORTAL",
16860
+ `"${fromPath}" imports "${toPath}", crossing into subsystem "${subsystemId}" somewhere other than its portal file (${portals.length > 0 ? portals.join(", ") : "none realized at exact grade"}). Import the name from the portal file instead; when no portal of "${subsystemId}" publishes it, it is a surface the provider never promised \u2014 publish it on the contract of the portal whose capability it is, or stop depending on it.`,
16861
+ realization.implementationsAt(fromPath)[0]?.id,
16862
+ draftAt(fromPath) || draftAt(toPath),
16863
+ void 0,
16864
+ // One import edge, one indivisible fact: the EDGE is the site.
16865
+ { at: `${fromPath} -> ${toPath}` }
16866
+ );
16867
+ }
16868
+ }
16869
+ }
16870
+ }
16871
+ };
16872
+
16696
16873
  // src/core/rules/conformance/integration-sim-declaration.ts
16697
16874
  var integrationSimDeclarationRule = {
16698
16875
  name: "integration-sim-declaration",
@@ -17204,8 +17381,8 @@ var paramConformanceRule = {
17204
17381
  };
17205
17382
 
17206
17383
  // src/core/rules/conformance/route-coverage.ts
17207
- function liesUnder2(path28, prefix) {
17208
- return path28 === prefix || path28.startsWith(prefix + "/");
17384
+ function liesUnder2(path29, prefix) {
17385
+ return path29 === prefix || path29.startsWith(prefix + "/");
17209
17386
  }
17210
17387
  function normalizeSegment(segment) {
17211
17388
  return /^\{.+\}$/.test(segment) || segment.startsWith(":") ? "*" : segment;
@@ -18827,6 +19004,8 @@ var SDD_RULES = [
18827
19004
  // The fields-vs-Store criterion: mutable module state in logic-only files.
18828
19005
  hiddenStateRule,
18829
19006
  dependencyConformanceRule,
19007
+ // Where a declared crossing LANDS: on the target subsystem's portal file.
19008
+ portalImportsRule,
18830
19009
  // Integration wiring proof rides after the code↔spec family: it consumes
18831
19010
  // the same code model and speaks about the same sourcePath modules. Four
18832
19011
  // questions about one harness, in the order a reader meets them: is one
@@ -18903,8 +19082,8 @@ function knownIssueCodes() {
18903
19082
  }
18904
19083
 
18905
19084
  // src/core/source-analysis.ts
18906
- var fs9 = __toESM(require("fs"));
18907
- var path11 = __toESM(require("path"));
19085
+ var fs10 = __toESM(require("fs"));
19086
+ var path13 = __toESM(require("path"));
18908
19087
  var import_module2 = require("module");
18909
19088
  function emptyCodeModel() {
18910
19089
  return { files: [], projectRoot: "", rootFiles: [] };
@@ -19129,7 +19308,7 @@ function resolveTypeScript(projectRoot) {
19129
19308
  return cached.ts;
19130
19309
  }
19131
19310
  let ts = null;
19132
- const bases = [path11.join(projectRoot, "package.json"), __filename];
19311
+ const bases = [path13.join(projectRoot, "package.json"), __filename];
19133
19312
  for (const base of bases) {
19134
19313
  try {
19135
19314
  const req = (0, import_module2.createRequire)(base);
@@ -19525,7 +19704,7 @@ function walkExact(ts, sourceText, fileName) {
19525
19704
  }
19526
19705
  function resolveRelativeModule(fromFile, specifier) {
19527
19706
  if (!specifier.startsWith(".")) return null;
19528
- const base = path11.resolve(path11.dirname(fromFile), specifier);
19707
+ const base = path13.resolve(path13.dirname(fromFile), specifier);
19529
19708
  const candidates = [
19530
19709
  base,
19531
19710
  base.replace(/\.js$/, ".ts"),
@@ -19533,12 +19712,12 @@ function resolveRelativeModule(fromFile, specifier) {
19533
19712
  `${base}.ts`,
19534
19713
  `${base}.tsx`,
19535
19714
  `${base}.js`,
19536
- path11.join(base, "index.ts"),
19537
- path11.join(base, "index.js")
19715
+ path13.join(base, "index.ts"),
19716
+ path13.join(base, "index.js")
19538
19717
  ];
19539
19718
  for (const c of candidates) {
19540
19719
  try {
19541
- if (fs9.statSync(c).isFile()) return c;
19720
+ if (fs10.statSync(c).isFile()) return c;
19542
19721
  } catch {
19543
19722
  }
19544
19723
  }
@@ -19546,11 +19725,11 @@ function resolveRelativeModule(fromFile, specifier) {
19546
19725
  }
19547
19726
  function reexportTarget(ts, filePath, specifier, projectRoot, visited, exactCache) {
19548
19727
  const target = resolveRelativeModule(filePath, specifier);
19549
- if (!target || path11.relative(projectRoot, target).startsWith("..")) return null;
19728
+ if (!target || path13.relative(projectRoot, target).startsWith("..")) return null;
19550
19729
  let targetFacts = exactCache.get(target);
19551
19730
  if (targetFacts === void 0) {
19552
19731
  try {
19553
- targetFacts = walkExact(ts, fs9.readFileSync(target, "utf8"), target);
19732
+ targetFacts = walkExact(ts, fs10.readFileSync(target, "utf8"), target);
19554
19733
  } catch {
19555
19734
  targetFacts = null;
19556
19735
  }
@@ -19568,7 +19747,7 @@ function carryBody(facts, target, targetPath, local, exported, projectRoot) {
19568
19747
  if (score !== void 0) facts.complexity.set(exported, Math.max(facts.complexity.get(exported) ?? 0, score));
19569
19748
  const targetCalls = target.calls.get(local);
19570
19749
  if (!targetCalls) return;
19571
- const carriedFrom = pathKey(path11.relative(projectRoot, targetPath));
19750
+ const carriedFrom = pathKey(path13.relative(projectRoot, targetPath));
19572
19751
  const sites = facts.calls.get(exported) ?? /* @__PURE__ */ new Map();
19573
19752
  for (const [key, site] of targetCalls) sites.set(carriedFrom + "|" + key, { ...site, from: site.from ?? carriedFrom });
19574
19753
  facts.calls.set(exported, sites);
@@ -19598,24 +19777,24 @@ function walkDeclaredRoots(roots, exclude, projectRoot) {
19598
19777
  const excluded = exclude.map(pathKey);
19599
19778
  const isExcluded = (key) => excluded.some((e) => key === e || key.startsWith(`${e}/`));
19600
19779
  const record = (absolute) => {
19601
- const key = pathKey(path11.relative(projectRoot, absolute));
19780
+ const key = pathKey(path13.relative(projectRoot, absolute));
19602
19781
  if (seen.has(key) || isExcluded(key)) return;
19603
- if (!EXTENSION_LANGUAGE[path11.extname(key).toLowerCase()]) return;
19782
+ if (!EXTENSION_LANGUAGE[path13.extname(key).toLowerCase()]) return;
19604
19783
  seen.add(key);
19605
19784
  found.push(key);
19606
19785
  };
19607
19786
  const descend = (dir) => {
19608
19787
  let entries;
19609
19788
  try {
19610
- entries = fs9.readdirSync(dir, { withFileTypes: true });
19789
+ entries = fs10.readdirSync(dir, { withFileTypes: true });
19611
19790
  } catch {
19612
19791
  return;
19613
19792
  }
19614
19793
  for (const entry of entries.slice().sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0)) {
19615
- const child = path11.join(dir, entry.name);
19794
+ const child = path13.join(dir, entry.name);
19616
19795
  if (entry.isDirectory()) {
19617
19796
  if (entry.name === "node_modules" || entry.name.startsWith(".")) continue;
19618
- if (isExcluded(pathKey(path11.relative(projectRoot, child)))) continue;
19797
+ if (isExcluded(pathKey(path13.relative(projectRoot, child)))) continue;
19619
19798
  descend(child);
19620
19799
  } else if (entry.isFile()) {
19621
19800
  record(child);
@@ -19624,13 +19803,13 @@ function walkDeclaredRoots(roots, exclude, projectRoot) {
19624
19803
  };
19625
19804
  for (const root of roots) {
19626
19805
  const key = pathKey(root);
19627
- if (path11.isAbsolute(key) || path11.normalize(key).split(path11.sep)[0] === "..") continue;
19628
- const absolute = path11.resolve(projectRoot, key);
19629
- if (path11.relative(projectRoot, absolute).startsWith("..")) continue;
19806
+ if (path13.isAbsolute(key) || path13.normalize(key).split(path13.sep)[0] === "..") continue;
19807
+ const absolute = path13.resolve(projectRoot, key);
19808
+ if (path13.relative(projectRoot, absolute).startsWith("..")) continue;
19630
19809
  if (isExcluded(key)) continue;
19631
19810
  let stat;
19632
19811
  try {
19633
- stat = fs9.statSync(absolute);
19812
+ stat = fs10.statSync(absolute);
19634
19813
  } catch {
19635
19814
  continue;
19636
19815
  }
@@ -19656,23 +19835,23 @@ function buildCodeModel(implementations, types, projectRoot, sourceRoots = [], e
19656
19835
  if (seen.has(sourcePath)) continue;
19657
19836
  seen.add(sourcePath);
19658
19837
  const empty = { declaredNames: [], anchoredNames: [], exportedNames: [], imports: [], reexports: [] };
19659
- if (path11.isAbsolute(sourcePath) || path11.normalize(sourcePath).split(path11.sep)[0] === "..") {
19838
+ if (path13.isAbsolute(sourcePath) || path13.normalize(sourcePath).split(path13.sep)[0] === "..") {
19660
19839
  files.push({ path: sourcePath, status: "escaped", ...empty });
19661
19840
  continue;
19662
19841
  }
19663
- const absolute = path11.resolve(projectRoot, sourcePath);
19664
- if (path11.relative(projectRoot, absolute).startsWith("..")) {
19842
+ const absolute = path13.resolve(projectRoot, sourcePath);
19843
+ if (path13.relative(projectRoot, absolute).startsWith("..")) {
19665
19844
  files.push({ path: sourcePath, status: "escaped", ...empty });
19666
19845
  continue;
19667
19846
  }
19668
19847
  let buffer;
19669
19848
  try {
19670
- const stat = fs9.statSync(absolute);
19849
+ const stat = fs10.statSync(absolute);
19671
19850
  if (!stat.isFile()) {
19672
19851
  files.push({ path: sourcePath, status: "missing", ...empty });
19673
19852
  continue;
19674
19853
  }
19675
- buffer = fs9.readFileSync(absolute);
19854
+ buffer = fs10.readFileSync(absolute);
19676
19855
  } catch {
19677
19856
  files.push({ path: sourcePath, status: "missing", ...empty });
19678
19857
  continue;
@@ -19682,7 +19861,7 @@ function buildCodeModel(implementations, types, projectRoot, sourceRoots = [], e
19682
19861
  continue;
19683
19862
  }
19684
19863
  const text = buffer.toString("utf8");
19685
- const language = EXTENSION_LANGUAGE[path11.extname(sourcePath).toLowerCase()];
19864
+ const language = EXTENSION_LANGUAGE[path13.extname(sourcePath).toLowerCase()];
19686
19865
  let analyzed;
19687
19866
  if (language === "typescript" || language === "javascript") {
19688
19867
  const ts = resolveTypeScript(projectRoot);
@@ -19753,6 +19932,7 @@ var DEPTH_GATED_CODES = {
19753
19932
  CONFORMANCE_DEGRADED: "implementations",
19754
19933
  UNDECLARED_DEPENDENCY: "implementations",
19755
19934
  UNREALIZED_DEPENDENCY: "implementations",
19935
+ IMPORT_BYPASSES_PORTAL: "implementations",
19756
19936
  MISSING_INTEGRATION_SIM: "implementations",
19757
19937
  // L5 expectations: narratives and everything whose fuel is narrative edges
19758
19938
  // (the reachability walk and the hydration round-trip would drown a
@@ -19787,6 +19967,7 @@ var COMPLETENESS_RULES = /* @__PURE__ */ new Set([
19787
19967
  "CONFORMANCE_ANALYSIS_SKIPPED",
19788
19968
  "UNDECLARED_DEPENDENCY",
19789
19969
  "UNREALIZED_DEPENDENCY",
19970
+ "IMPORT_BYPASSES_PORTAL",
19790
19971
  // Detail sufficiency reads the realized code like the conformance family
19791
19972
  // does — a draft tree is allowed to disagree with its code.
19792
19973
  "UNNARRATED_COMPLEXITY",
@@ -20218,206 +20399,11 @@ function buildRuleContext(opts) {
20218
20399
  return ctx;
20219
20400
  }
20220
20401
 
20221
- // src/core/variants.ts
20222
- var fs10 = __toESM(require("fs"));
20223
- var os3 = __toESM(require("os"));
20224
- var path12 = __toESM(require("path"));
20225
- var import_zod10 = require("zod");
20226
- var VariantDefSchema = import_zod10.z.object({
20227
- /** Variant id referenced by a component's `variant` (e.g. "publisher", "org/external-config-adapter"). */
20228
- id: import_zod10.z.string().min(1),
20229
- /** The core stereotype this variant specializes — authoritative for generic semantics (Adapter, Orchestrator, …). */
20230
- base: import_zod10.z.string().min(1),
20231
- /** How to implement a component of this variant — the recipe the implementer follows and reuses across same-variant components. */
20232
- guidance: import_zod10.z.string().min(1),
20233
- /** Optional: this variant only applies for the given target language (else it applies everywhere). */
20234
- target: import_zod10.z.string().optional(),
20235
- /** Optional: this variant only applies under the given architectural profile. */
20236
- profile: import_zod10.z.string().optional()
20237
- });
20238
- function globalVariantsDir() {
20239
- return process.env.WAIRON_VARIANTS_DIR ?? path12.join(os3.homedir(), ".wairon", "variants");
20240
- }
20241
- function builtinVariantsDir() {
20242
- const candidates = [
20243
- path12.resolve(__dirname, "..", "templates", "variants"),
20244
- // src/core & dist/cli
20245
- path12.resolve(__dirname, "templates", "variants")
20246
- // dist (library entry)
20247
- ];
20248
- return candidates.find((dir) => fs10.existsSync(dir)) ?? candidates[0];
20249
- }
20250
- function projectVariantsDir() {
20251
- return path12.join(getProjectRoot(), ".wai", "variants");
20252
- }
20253
- function variantFiles(dir) {
20254
- let entries;
20255
- try {
20256
- entries = fs10.readdirSync(dir, { withFileTypes: true });
20257
- } catch {
20258
- return [];
20259
- }
20260
- return entries.filter((e) => e.isFile() && /\.ya?ml$/i.test(e.name)).sort((a, b) => a.name.localeCompare(b.name)).map((e) => path12.join(dir, e.name));
20261
- }
20262
- function parseVariants(raw) {
20263
- if (raw == null) return [];
20264
- return (Array.isArray(raw) ? raw : [raw]).map((item) => VariantDefSchema.parse(item));
20265
- }
20266
- function reportSkippedFile(file, err) {
20267
- console.error(`[variants] skipped "${file}": ${err instanceof Error ? err.message : String(err)}`);
20268
- }
20269
- function readVariantsDir(dir) {
20270
- const out = [];
20271
- for (const file of variantFiles(dir)) {
20272
- try {
20273
- out.push(...parseVariants(readYamlFile(file)));
20274
- } catch (err) {
20275
- reportSkippedFile(file, err);
20276
- }
20277
- }
20278
- return out;
20279
- }
20280
- function mergeById(...layers) {
20281
- const byId = /* @__PURE__ */ new Map();
20282
- for (const layer of layers) {
20283
- for (const v of layer) byId.set(v.id, v);
20284
- }
20285
- return [...byId.values()];
20286
- }
20287
- function resolveVariantGuidance(component, allComponents, variantsById) {
20288
- if (!component.variant) return null;
20289
- const def = variantsById.get(component.variant);
20290
- if (!def) return null;
20291
- return {
20292
- variant: component.variant,
20293
- base: def.base,
20294
- guidance: def.guidance,
20295
- siblings: allComponents.filter((o) => o.variant === component.variant && o.id !== component.id).map((o) => o.id),
20296
- ...def.target ? { target: def.target } : {},
20297
- ...def.profile ? { profile: def.profile } : {}
20298
- };
20299
- }
20300
- function composeVariantGuidance(comps, allComponents, variantsById) {
20301
- const resolved = comps.map((c) => ({ id: c.id, guidance: resolveVariantGuidance(c, allComponents, variantsById) })).filter((r) => r.guidance !== null);
20302
- if (resolved.length === 0) return "";
20303
- const lines = [
20304
- "## Component variants \u2014 reuse the shared approach",
20305
- "",
20306
- "One or more of your components declare a variant \u2014 a base-anchored kind with implementation guidance. Implement every component of the same variant alike, reusing one shared approach instead of reinventing it per instance:",
20307
- ""
20308
- ];
20309
- for (const { id, guidance } of resolved) {
20310
- let line = `- **${id}** \u2014 variant \`${guidance.variant}\` (a kind of ${guidance.base}): ${guidance.guidance}`;
20311
- if (guidance.siblings.length > 0) {
20312
- line += ` Same-variant components elsewhere: ${guidance.siblings.join(", ")} \u2014 implement them consistently, reusing the same logic/concept.`;
20313
- }
20314
- lines.push(line);
20315
- }
20316
- return lines.join("\n");
20317
- }
20318
- function loadProjectVariants() {
20319
- try {
20320
- return mergeById(
20321
- readVariantsDir(builtinVariantsDir()),
20322
- readVariantsDir(globalVariantsDir()),
20323
- readVariantsDir(projectVariantsDir())
20324
- );
20325
- } catch {
20326
- return [];
20327
- }
20328
- }
20329
- function listProjectVariants() {
20330
- return mergeById(readVariantsDir(projectVariantsDir()));
20331
- }
20332
- function rebaseProjectVariants(fromBase, toBase) {
20333
- const rebased = [];
20334
- for (const file of variantFiles(projectVariantsDir())) {
20335
- const content = readFileOrNull(file);
20336
- if (content === null) continue;
20337
- let raw;
20338
- let variants;
20339
- try {
20340
- raw = parseYaml(content, file);
20341
- variants = parseVariants(raw);
20342
- } catch (err) {
20343
- reportSkippedFile(file, err);
20344
- continue;
20345
- }
20346
- const matching = variants.filter((v) => v.base === fromBase);
20347
- if (matching.length === 0) continue;
20348
- writeFile(file, rebasedText(content, fromBase, toBase, withRebasedEntries(raw, fromBase, toBase)));
20349
- for (const v of matching) {
20350
- if (!rebased.includes(v.id)) rebased.push(v.id);
20351
- }
20352
- }
20353
- return rebased;
20354
- }
20355
- function withRebasedEntries(raw, fromBase, toBase) {
20356
- const rebase = (entry) => entry.base === fromBase ? { ...entry, base: toBase } : entry;
20357
- return Array.isArray(raw) ? raw.map(rebase) : rebase(raw);
20358
- }
20359
- function rebasedText(content, fromBase, toBase, rebasedContent) {
20360
- const escaped = fromBase.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
20361
- const baseLine = new RegExp(`^([ \\t]*(?:-[ \\t]+)?base:[ \\t]*)(["']?)${escaped}\\2(?=[ \\t]*(?:#.*)?$)`, "gm");
20362
- const edited = content.replace(baseLine, (_line, key, quote) => `${key}${quote}${toBase}${quote}`);
20363
- try {
20364
- if (JSON.stringify(parseYaml(edited)) === JSON.stringify(rebasedContent)) return edited;
20365
- } catch {
20366
- }
20367
- return serializeYaml(rebasedContent);
20368
- }
20369
-
20370
- // src/core/surfaces.ts
20371
- var fs11 = __toESM(require("fs"));
20372
- var path13 = __toESM(require("path"));
20373
-
20374
- // src/core/openapi.ts
20375
- var yaml2 = __toESM(require("js-yaml"));
20376
-
20377
- // src/core/surfaces.ts
20378
- var SURFACES_DIRNAME = "surfaces";
20379
- function surfacesDir(rootDir) {
20380
- return path13.join(rootDir, ".wai", SURFACES_DIRNAME);
20381
- }
20382
- function listSnapshots(rootDir = getProjectRoot()) {
20383
- const dir = surfacesDir(rootDir);
20384
- if (!fs11.existsSync(dir)) return [];
20385
- const out = [];
20386
- for (const file of fs11.readdirSync(dir)) {
20387
- if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue;
20388
- try {
20389
- out.push(SurfaceSnapshotSchema.parse(readYamlFile(path13.join(dir, file))));
20390
- } catch {
20391
- }
20392
- }
20393
- return out;
20394
- }
20395
- function loadSurfaceSnapshots() {
20396
- return listSnapshots();
20397
- }
20398
- function listMountSnapshots(mounts) {
20399
- const bound2 = path13.resolve(getProjectRoot());
20400
- const out = [];
20401
- for (const namespace of mounts) {
20402
- const dir = resolveSubprojectForNamespace(namespace);
20403
- if (!dir || path13.resolve(dir) === bound2) continue;
20404
- const snapshots = listSnapshots(dir);
20405
- if (snapshots.length > 0) out.push({ namespace, snapshots });
20406
- }
20407
- return out;
20408
- }
20409
- function loadMountSurfaceSnapshots(mounts) {
20410
- return listMountSnapshots(mounts);
20411
- }
20412
-
20413
20402
  // src/core/validation.ts
20414
20403
  var path14 = __toESM(require("path"));
20415
- function loadProjectConfig2() {
20416
- return loadProjectConfig();
20417
- }
20418
20404
  function projectPackSelections() {
20419
20405
  try {
20420
- return (loadProjectConfig2()?.extensions?.packs ?? []).filter((e) => typeof e !== "string");
20406
+ return (loadProjectConfig()?.extensions?.packs ?? []).filter((e) => typeof e !== "string");
20421
20407
  } catch {
20422
20408
  return [];
20423
20409
  }
@@ -20487,7 +20473,7 @@ function validateSddTree(rulesOrOptions, projectType = "backend") {
20487
20473
  const interfaces = loadInterfaceSpecs();
20488
20474
  const implementations = loadImplementationSpecs();
20489
20475
  const types = loadTypeSpecs();
20490
- const surfaceSnapshots = loadSurfaceSnapshots();
20476
+ const surfaceSnapshots = listSnapshots();
20491
20477
  const conformance = rules?.conformance;
20492
20478
  const codeModel = buildCodeModel(
20493
20479
  implementations,
@@ -20534,7 +20520,7 @@ function validateSddTree(rulesOrOptions, projectType = "backend") {
20534
20520
  for (const err of extensions.errors) {
20535
20521
  issues.push(issue("error", "EXTENSION_LOAD_ERROR", err));
20536
20522
  }
20537
- const mountSurfaceSnapshots = loadMountSurfaceSnapshots(
20523
+ const mountSurfaceSnapshots = listMountSnapshots(
20538
20524
  subsystems.filter((s) => s.projectPath).map((s) => s.id)
20539
20525
  );
20540
20526
  const roundTripIssues = dryRunSerializeSpecs(isSpecInScope);
@@ -20622,10 +20608,9 @@ function resolveThroughParent(boundRoot, treatAllAsComplete, childRules) {
20622
20608
  if (chain.length === 0) return null;
20623
20609
  const scope = chain.join("::");
20624
20610
  const inner = runWithProjectRoot(top, () => {
20625
- invalidateSpecCache();
20626
20611
  let governing = { rules: stricterSeverities(void 0, childRules) };
20627
20612
  try {
20628
- const config = loadProjectConfig2();
20613
+ const config = loadProjectConfig();
20629
20614
  if (config) governing = { rules: stricterSeverities(config.rules, childRules), projectType: config.projectType };
20630
20615
  } catch {
20631
20616
  }
@@ -21325,7 +21310,7 @@ function canonicalPath(target) {
21325
21310
  const rest = [];
21326
21311
  for (; ; ) {
21327
21312
  try {
21328
- fs12.lstatSync(existing);
21313
+ fs11.lstatSync(existing);
21329
21314
  break;
21330
21315
  } catch {
21331
21316
  const up = path15.dirname(existing);
@@ -21335,7 +21320,7 @@ function canonicalPath(target) {
21335
21320
  }
21336
21321
  }
21337
21322
  try {
21338
- return path15.join(fs12.realpathSync.native(existing), ...rest);
21323
+ return path15.join(fs11.realpathSync.native(existing), ...rest);
21339
21324
  } catch {
21340
21325
  return null;
21341
21326
  }
@@ -21427,7 +21412,7 @@ function inspectChainedRoots(rootDir = getProjectRoot()) {
21427
21412
  let reason;
21428
21413
  if (projectPathEscapesRoot(projectDir, projectPath, childDir)) reason = "escapes";
21429
21414
  else if (ancestors.has(chainDirKey(childDir))) reason = "cyclic";
21430
- else if (!fs12.existsSync(childDir)) reason = "missing";
21415
+ else if (!fs11.existsSync(childDir)) reason = "missing";
21431
21416
  else if (depth >= 32) reason = "too-deep";
21432
21417
  if (reason) {
21433
21418
  const mount = prefix ? qualifyDeclaredId(localId, prefix, true) : localId;
@@ -21568,9 +21553,9 @@ function findOwner(id, components) {
21568
21553
  }
21569
21554
  function moveComponentFolder(fromDir, toDir) {
21570
21555
  if (path15.normalize(fromDir) === path15.normalize(toDir)) return false;
21571
- if (!fs12.existsSync(fromDir) || fs12.existsSync(toDir)) return false;
21556
+ if (!fs11.existsSync(fromDir) || fs11.existsSync(toDir)) return false;
21572
21557
  ensureDir(path15.dirname(toDir));
21573
- fs12.renameSync(fromDir, toDir);
21558
+ fs11.renameSync(fromDir, toDir);
21574
21559
  return true;
21575
21560
  }
21576
21561
  function formatZodIssues(error) {
@@ -21587,13 +21572,13 @@ var SIGNATURE_TTL_MS = 2e3;
21587
21572
  function computeSpecTreeSignature(dirs) {
21588
21573
  const parts = [];
21589
21574
  for (const dir of dirs) {
21590
- if (!fs12.existsSync(dir)) {
21575
+ if (!fs11.existsSync(dir)) {
21591
21576
  parts.push(`${dir}:missing`);
21592
21577
  continue;
21593
21578
  }
21594
21579
  for (const f of listSpecFiles(dir)) {
21595
21580
  try {
21596
- const st = fs12.statSync(f);
21581
+ const st = fs11.statSync(f);
21597
21582
  parts.push(`${f}:${st.mtimeMs}:${st.size}`);
21598
21583
  } catch {
21599
21584
  parts.push(`${f}:gone`);
@@ -21865,13 +21850,13 @@ function ineffectiveDeltaPaths(delta, merged, stored) {
21865
21850
  const isPlain = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
21866
21851
  const same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
21867
21852
  const at = (prefix, key) => prefix ? `${prefix}.${key}` : key;
21868
- const say = (path28, why) => {
21869
- out.push(`${path28} \u2014 ${why}`);
21853
+ const say = (path29, why) => {
21854
+ out.push(`${path29} \u2014 ${why}`);
21870
21855
  };
21871
- const walkValue = (d, m, s, path28, field) => {
21856
+ const walkValue = (d, m, s, path29, field) => {
21872
21857
  if (Array.isArray(d)) {
21873
21858
  if (!Array.isArray(m)) {
21874
- say(path28, "the level does not have this field, so the write dropped it");
21859
+ say(path29, "the level does not have this field, so the write dropped it");
21875
21860
  return;
21876
21861
  }
21877
21862
  if (field === "narrative" && d.some(carriesEditMarker)) return;
@@ -21879,32 +21864,32 @@ function ineffectiveDeltaPaths(delta, merged, stored) {
21879
21864
  if (carriesEditMarker(element)) continue;
21880
21865
  const key = reportIdentityOf(field, element);
21881
21866
  if (key === null) {
21882
- if (!same(m, d)) say(path28, "the level does not keep this value, so the write dropped it");
21883
- else if (same(s, d)) say(path28, "the stored spec already held this value");
21867
+ if (!same(m, d)) say(path29, "the level does not keep this value, so the write dropped it");
21868
+ else if (same(s, d)) say(path29, "the stored spec already held this value");
21884
21869
  return;
21885
21870
  }
21886
21871
  const mMatch = m.find((i) => reportIdentityOf(field, i) === key);
21887
21872
  const sMatch = Array.isArray(s) ? s.find((i) => reportIdentityOf(field, i) === key) : void 0;
21888
21873
  if (mMatch === void 0) {
21889
- say(at(path28, key), "the write did not store this element");
21874
+ say(at(path29, key), "the write did not store this element");
21890
21875
  continue;
21891
21876
  }
21892
- walk2(element, mMatch, sMatch, at(path28, key), field);
21877
+ walk2(element, mMatch, sMatch, at(path29, key), field);
21893
21878
  }
21894
21879
  return;
21895
21880
  }
21896
21881
  if (isPlain(d)) {
21897
21882
  if (!isPlain(m)) {
21898
- say(path28, "the level does not have this field, so the write dropped it");
21883
+ say(path29, "the level does not have this field, so the write dropped it");
21899
21884
  return;
21900
21885
  }
21901
- walk2(d, m, s, path28, field);
21886
+ walk2(d, m, s, path29, field);
21902
21887
  return;
21903
21888
  }
21904
- if (!same(m, d)) say(path28, "the write did not store it \u2014 the level's schema does not keep this value");
21905
- else if (same(s, d)) say(path28, "the stored spec already held this value");
21889
+ if (!same(m, d)) say(path29, "the write did not store it \u2014 the level's schema does not keep this value");
21890
+ else if (same(s, d)) say(path29, "the stored spec already held this value");
21906
21891
  };
21907
- function walk2(d, m, s, path28, container) {
21892
+ function walk2(d, m, s, path29, container) {
21908
21893
  for (const [key, value] of Object.entries(d)) {
21909
21894
  if (DELTA_VERBS.has(key) || JUMP_LABEL_TWINS.has(key)) continue;
21910
21895
  if (key === "label" && LABEL_TWIN_CONTAINERS.has(container)) continue;
@@ -21914,13 +21899,13 @@ function ineffectiveDeltaPaths(delta, merged, stored) {
21914
21899
  if (typeof name !== "string") continue;
21915
21900
  const had = isPlain(s) && s[name] !== void 0;
21916
21901
  const still = isPlain(m) && m[name] !== void 0;
21917
- if (!had) say(at(path28, name), "unset named a field the stored spec did not have");
21918
- else if (still) say(at(path28, name), "unset did not remove it");
21902
+ if (!had) say(at(path29, name), "unset named a field the stored spec did not have");
21903
+ else if (still) say(at(path29, name), "unset did not remove it");
21919
21904
  }
21920
21905
  continue;
21921
21906
  }
21922
21907
  if (value === void 0 || value === null) continue;
21923
- const here = at(path28, key);
21908
+ const here = at(path29, key);
21924
21909
  const mValue = isPlain(m) ? m[key] : void 0;
21925
21910
  const sValue = isPlain(s) ? s[key] : void 0;
21926
21911
  if (mValue === void 0) {
@@ -21946,6 +21931,15 @@ var SpecWorkspace = class {
21946
21931
  this.rootDir = path15.resolve(rootDir);
21947
21932
  this.paths = aiPathsAt(this.rootDir);
21948
21933
  }
21934
+ /**
21935
+ * The next scan re-verifies the tree's file signature whatever the TTL says.
21936
+ * Called when the bound project root switches to this workspace: a caller that
21937
+ * just bound a root reads it as it is NOW, even if another process changed it
21938
+ * a moment after this workspace last looked.
21939
+ */
21940
+ expireFreshness() {
21941
+ this.lastSignatureCheckMs = 0;
21942
+ }
21949
21943
  invalidate() {
21950
21944
  this.cachedIndex = null;
21951
21945
  this.cachedRecursive = null;
@@ -22199,7 +22193,7 @@ var SpecWorkspace = class {
22199
22193
  });
22200
22194
  continue;
22201
22195
  }
22202
- if (!fs12.existsSync(childDir)) {
22196
+ if (!fs11.existsSync(childDir)) {
22203
22197
  this.loaderIssues.push({
22204
22198
  severity: "error",
22205
22199
  code: "SUBPROJECT_NOT_FOUND",
@@ -23203,8 +23197,8 @@ var SpecWorkspace = class {
23203
23197
  }
23204
23198
  }
23205
23199
  for (const file of files) {
23206
- if (fs12.existsSync(file)) {
23207
- snapshot.set(file, fs12.readFileSync(file, "utf8"));
23200
+ if (fs11.existsSync(file)) {
23201
+ snapshot.set(file, fs11.readFileSync(file, "utf8"));
23208
23202
  }
23209
23203
  }
23210
23204
  return snapshot;
@@ -24273,8 +24267,15 @@ function workspaceFor(rootDir) {
24273
24267
  }
24274
24268
  return ws;
24275
24269
  }
24270
+ var lastServedBinding = null;
24276
24271
  function current() {
24277
- return workspaceFor(getProjectRoot());
24272
+ const ws = workspaceFor(getProjectRoot());
24273
+ const binding = currentRootBinding() ?? ws.rootDir;
24274
+ if (binding !== lastServedBinding) {
24275
+ lastServedBinding = binding;
24276
+ ws.expireFreshness();
24277
+ }
24278
+ return ws;
24278
24279
  }
24279
24280
  function invalidateSpecCache() {
24280
24281
  for (const ws of workspaces.values()) ws.invalidate();
@@ -24371,7 +24372,7 @@ function consumedSurfaceInputsAt(rootDir) {
24371
24372
  const dir = path15.join(rootDir, ".wai", "surfaces");
24372
24373
  if (!pathExists(dir)) return [];
24373
24374
  const keys = [];
24374
- for (const file of fs12.readdirSync(dir)) {
24375
+ for (const file of fs11.readdirSync(dir)) {
24375
24376
  if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue;
24376
24377
  try {
24377
24378
  keys.push(snapshotInputKey(SurfaceSnapshotSchema.parse(readYamlFile(path15.join(dir, file)))));
@@ -24433,6 +24434,9 @@ function specPathsInScope(scopeSubsystem) {
24433
24434
  function snapshotSpecFiles() {
24434
24435
  return current().snapshotSpecFiles();
24435
24436
  }
24437
+ function findLegacySpecFiles() {
24438
+ return current().findLegacySpecFiles();
24439
+ }
24436
24440
  function loadSpec(kind, id) {
24437
24441
  const workspace = current();
24438
24442
  return workspace.load(kind, id);
@@ -24539,7 +24543,7 @@ function unregisterDomain(id) {
24539
24543
  }
24540
24544
 
24541
24545
  // src/core/provision.ts
24542
- var fs13 = __toESM(require("fs"));
24546
+ var fs12 = __toESM(require("fs"));
24543
24547
  var path17 = __toESM(require("path"));
24544
24548
  function defaultProjectConfig(name, now) {
24545
24549
  return {
@@ -24588,7 +24592,7 @@ function provisionProject(name) {
24588
24592
  function ensureProjectInitialized(fallbackName) {
24589
24593
  const now = (/* @__PURE__ */ new Date()).toISOString();
24590
24594
  const paths = aiPathsAt(getProjectRoot());
24591
- const hasSystem = fs13.existsSync(paths.specsSystem());
24595
+ const hasSystem = fs12.existsSync(paths.specsSystem());
24592
24596
  let name = fallbackName;
24593
24597
  if (hasSystem) {
24594
24598
  const existing = loadSystemSpec();
@@ -24607,10 +24611,41 @@ function ensureProjectInitialized(fallbackName) {
24607
24611
  if (wroteConfig || wroteSystem) invalidateSpecCache();
24608
24612
  return { wroteConfig, wroteSystem };
24609
24613
  }
24614
+ function walkChainedSubprojects(projectRoot, onChild) {
24615
+ const visited = /* @__PURE__ */ new Set();
24616
+ const walk2 = (dir) => {
24617
+ const resolved = path17.resolve(dir);
24618
+ if (visited.has(resolved)) return;
24619
+ visited.add(resolved);
24620
+ const specsDir = aiPathsAt(dir).specsDir();
24621
+ if (!fs12.existsSync(specsDir)) return;
24622
+ for (const file of listFilesRecursive(specsDir, ".yaml")) {
24623
+ let raw;
24624
+ try {
24625
+ raw = readYamlFile(file);
24626
+ } catch {
24627
+ continue;
24628
+ }
24629
+ if (!(raw && typeof raw === "object" && "parentSystem" in raw)) continue;
24630
+ const pp = raw.projectPath;
24631
+ if (typeof pp !== "string" || pp.trim() === "") continue;
24632
+ let childDir;
24633
+ try {
24634
+ childDir = assertContainedProjectPath(dir, pp);
24635
+ } catch {
24636
+ continue;
24637
+ }
24638
+ const id = raw.id;
24639
+ onChild(childDir, typeof id === "string" ? id : path17.basename(childDir));
24640
+ walk2(childDir);
24641
+ }
24642
+ };
24643
+ walk2(projectRoot);
24644
+ }
24610
24645
  function listDirectChainedSubprojects(projectRoot) {
24611
24646
  const out = [];
24612
24647
  const specsDir = aiPathsAt(projectRoot).specsDir();
24613
- if (!fs13.existsSync(specsDir)) return out;
24648
+ if (!fs12.existsSync(specsDir)) return out;
24614
24649
  for (const file of listFilesRecursive(specsDir, ".yaml")) {
24615
24650
  let raw;
24616
24651
  try {
@@ -24632,6 +24667,28 @@ function listDirectChainedSubprojects(projectRoot) {
24632
24667
  }
24633
24668
  return out;
24634
24669
  }
24670
+ function childHasSpecsButNoConfig(childDir) {
24671
+ return fs12.existsSync(aiPathsAt(childDir).specsDir()) && !projectConfigRepositoryAt(childDir).exists();
24672
+ }
24673
+ function findChainingSubprojectsMissingConfig(projectRoot) {
24674
+ const missing = [];
24675
+ walkChainedSubprojects(projectRoot, (childDir) => {
24676
+ if (childHasSpecsButNoConfig(childDir)) missing.push(childDir);
24677
+ });
24678
+ return missing;
24679
+ }
24680
+ function backfillChainedSubprojectConfigs(projectRoot) {
24681
+ const backfilled = [];
24682
+ walkChainedSubprojects(projectRoot, (childDir, subsystemId) => {
24683
+ if (childHasSpecsButNoConfig(childDir)) {
24684
+ runWithProjectRoot(childDir, () => {
24685
+ ensureProjectInitialized(subsystemId);
24686
+ });
24687
+ backfilled.push(childDir);
24688
+ }
24689
+ });
24690
+ return backfilled;
24691
+ }
24635
24692
  function createChainedSubsystem(subsystem, projectName) {
24636
24693
  if (!subsystem.projectPath || subsystem.projectPath.trim() === "") {
24637
24694
  throw new WaironError("projectPath is required to create a chained subsystem.");
@@ -24660,14 +24717,14 @@ function moveSubsystemProject(subsystemId, newProjectPath) {
24660
24717
  const oldDir = assertContainedProjectPath(root, sub.projectPath);
24661
24718
  const newDir = assertContainedProjectPath(root, nextPath);
24662
24719
  if (oldDir !== newDir) {
24663
- if (!fs13.existsSync(oldDir)) {
24720
+ if (!fs12.existsSync(oldDir)) {
24664
24721
  throw new WaironError(`Subproject directory not found at its current path: ${oldDir}`);
24665
24722
  }
24666
- if (fs13.existsSync(newDir)) {
24723
+ if (fs12.existsSync(newDir)) {
24667
24724
  throw new WaironError(`Target directory already exists: ${newDir}`);
24668
24725
  }
24669
24726
  ensureDir(path17.dirname(newDir));
24670
- fs13.renameSync(oldDir, newDir);
24727
+ fs12.renameSync(oldDir, newDir);
24671
24728
  }
24672
24729
  saveSubsystemSpec({ ...sub, projectPath: nextPath, updatedAt: (/* @__PURE__ */ new Date()).toISOString() });
24673
24730
  invalidateSpecCache();
@@ -24691,13 +24748,13 @@ function externalizeSubsystem(subsystemId, projectPath) {
24691
24748
  const parentRoot = getProjectRoot();
24692
24749
  const parentSpecsDir = aiPathsAt(parentRoot).specsDir();
24693
24750
  const fooDir = path17.join(parentSpecsDir, subsystemId);
24694
- if (!fs13.existsSync(fooDir)) {
24751
+ if (!fs12.existsSync(fooDir)) {
24695
24752
  throw new WaironError(`subsystem specs directory not found: ${fooDir}`);
24696
24753
  }
24697
24754
  const relPath = toPosixPath(projectPath);
24698
24755
  const childDir = assertContainedProjectPath(parentRoot, relPath);
24699
24756
  const childFooDir = path17.join(childDir, ".wai", "specs", subsystemId);
24700
- if (fs13.existsSync(childFooDir)) {
24757
+ if (fs12.existsSync(childFooDir)) {
24701
24758
  throw new WaironError(`target already contains a "${subsystemId}" subsystem: ${childFooDir}`);
24702
24759
  }
24703
24760
  const renameMap = buildRenameMap(
@@ -24713,7 +24770,7 @@ function externalizeSubsystem(subsystemId, projectPath) {
24713
24770
  saveSystemSpec(bootstrapSystemSpec(childSystemName, now));
24714
24771
  });
24715
24772
  ensureDir(path17.dirname(childFooDir));
24716
- fs13.renameSync(fooDir, childFooDir);
24773
+ fs12.renameSync(fooDir, childFooDir);
24717
24774
  rebaseImplementationPaths(childFooDir, parentRoot, childDir);
24718
24775
  patchSubsystemIndex(path17.join(childFooDir, ".index.yaml"), (s) => {
24719
24776
  s.parentSystem = childSystemName;
@@ -24749,7 +24806,7 @@ function internalizeSubsystem(subsystemId) {
24749
24806
  const childDir = assertContainedProjectPath(parentRoot, foo.projectPath);
24750
24807
  const childWai = path17.join(childDir, ".wai");
24751
24808
  const childFooDir = path17.join(childDir, ".wai", "specs", subsystemId);
24752
- if (!fs13.existsSync(childFooDir)) {
24809
+ if (!fs12.existsSync(childFooDir)) {
24753
24810
  throw new WaironError(`external subproject missing subsystem "${subsystemId}": ${childFooDir}`);
24754
24811
  }
24755
24812
  const childOwnSubs = runWithProjectRoot(childDir, () => loadSubsystemSpecs()).filter((s) => !s.id.includes("::"));
@@ -24763,15 +24820,15 @@ function internalizeSubsystem(subsystemId) {
24763
24820
  );
24764
24821
  const parentSystemName = loadSystemSpec()?.name ?? foo.parentSystem;
24765
24822
  const fooDir = path17.join(parentSpecsDir, subsystemId);
24766
- fs13.rmSync(fooDir, { recursive: true, force: true });
24823
+ fs12.rmSync(fooDir, { recursive: true, force: true });
24767
24824
  ensureDir(path17.dirname(fooDir));
24768
- fs13.renameSync(childFooDir, fooDir);
24825
+ fs12.renameSync(childFooDir, fooDir);
24769
24826
  rebaseImplementationPaths(fooDir, childDir, parentRoot);
24770
24827
  patchSubsystemIndex(path17.join(fooDir, ".index.yaml"), (s) => {
24771
24828
  s.parentSystem = parentSystemName;
24772
24829
  delete s.projectPath;
24773
24830
  });
24774
- fs13.rmSync(childWai, { recursive: true, force: true });
24831
+ fs12.rmSync(childWai, { recursive: true, force: true });
24775
24832
  rewriteRefsInDir(parentSpecsDir, renameMap, fooDir);
24776
24833
  rebaseMovedRefs(fooDir, subsystemId, "outOf");
24777
24834
  invalidateSpecCache();
@@ -24866,7 +24923,7 @@ function rebaseImplementationPaths(specsDir, fromRoot, toRoot) {
24866
24923
  }
24867
24924
  }
24868
24925
  function patchSubsystemIndex(indexPath, mutate) {
24869
- if (!fs13.existsSync(indexPath)) return;
24926
+ if (!fs12.existsSync(indexPath)) return;
24870
24927
  const raw = readYamlFile(indexPath);
24871
24928
  mutate(raw);
24872
24929
  raw.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -24928,7 +24985,7 @@ function moveRenamedSpecs(componentId, newId, component, movingInterface, moving
24928
24985
  if (movedImplementation) {
24929
24986
  const oldFile = getImplementationPath(movedImplementation.id);
24930
24987
  if (path17.resolve(getImplementationPath(implementationId, movedImplementation.contract)) === path17.resolve(oldFile)) {
24931
- fs13.unlinkSync(oldFile);
24988
+ fs12.unlinkSync(oldFile);
24932
24989
  }
24933
24990
  saveImplementationSpec({ ...movedImplementation, id: implementationId });
24934
24991
  }
@@ -24938,17 +24995,17 @@ function moveRenamedSpecs(componentId, newId, component, movingInterface, moving
24938
24995
  invalidateSpecCache();
24939
24996
  }
24940
24997
  function removeSpecFile2(file, id) {
24941
- if (!fs13.existsSync(file)) return;
24998
+ if (!fs12.existsSync(file)) return;
24942
24999
  try {
24943
25000
  if (readYamlFile(file)?.id !== id) return;
24944
25001
  } catch {
24945
25002
  return;
24946
25003
  }
24947
- fs13.unlinkSync(file);
25004
+ fs12.unlinkSync(file);
24948
25005
  const specsRoot = path17.resolve(aiPathsAt(getProjectRoot()).specsDir());
24949
25006
  for (let dir = path17.dirname(path17.resolve(file)); dir !== specsRoot && isWithinDir(specsRoot, dir); dir = path17.dirname(dir)) {
24950
- if (fs13.readdirSync(dir).length > 0) break;
24951
- fs13.rmdirSync(dir);
25007
+ if (fs12.readdirSync(dir).length > 0) break;
25008
+ fs12.rmdirSync(dir);
24952
25009
  }
24953
25010
  }
24954
25011
  var METHOD_NAME = /^[a-z][a-zA-Z0-9]*$/;
@@ -25059,7 +25116,7 @@ function identifierPattern(methodName) {
25059
25116
  }
25060
25117
 
25061
25118
  // src/core/detection.ts
25062
- var fs14 = __toESM(require("fs"));
25119
+ var fs13 = __toESM(require("fs"));
25063
25120
  var path18 = __toESM(require("path"));
25064
25121
  var PACKAGE_MARKERS = [
25065
25122
  "package.json",
@@ -25111,7 +25168,7 @@ function deduplicateIds(candidates, existingIds = /* @__PURE__ */ new Set()) {
25111
25168
  });
25112
25169
  }
25113
25170
  function parseGitmodules(filePath) {
25114
- const content = fs14.readFileSync(filePath, "utf-8");
25171
+ const content = fs13.readFileSync(filePath, "utf-8");
25115
25172
  const entries = [];
25116
25173
  let current2 = {};
25117
25174
  for (const line of content.split("\n")) {
@@ -25134,7 +25191,7 @@ function parseGitmodules(filePath) {
25134
25191
  }
25135
25192
  function detectGitSubmodules(projectRoot) {
25136
25193
  const gitmodulesPath = path18.join(projectRoot, ".gitmodules");
25137
- if (!fs14.existsSync(gitmodulesPath)) return [];
25194
+ if (!fs13.existsSync(gitmodulesPath)) return [];
25138
25195
  return parseGitmodules(gitmodulesPath).map((entry) => ({
25139
25196
  suggestedId: pathToId(entry.path),
25140
25197
  suggestedName: pathToName(entry.path),
@@ -25152,7 +25209,7 @@ function walkForGit(projectRoot, currentDir, depth, results) {
25152
25209
  if (depth > MAX_SCAN_DEPTH) return;
25153
25210
  let entries;
25154
25211
  try {
25155
- entries = fs14.readdirSync(currentDir, { withFileTypes: true });
25212
+ entries = fs13.readdirSync(currentDir, { withFileTypes: true });
25156
25213
  } catch {
25157
25214
  return;
25158
25215
  }
@@ -25163,7 +25220,7 @@ function walkForGit(projectRoot, currentDir, depth, results) {
25163
25220
  const relPath = normalizePath(path18.relative(projectRoot, fullPath));
25164
25221
  if (relPath === "" || relPath === ".") continue;
25165
25222
  const gitPath = path18.join(fullPath, ".git");
25166
- if (fs14.existsSync(gitPath)) {
25223
+ if (fs13.existsSync(gitPath)) {
25167
25224
  results.push({
25168
25225
  suggestedId: pathToId(relPath),
25169
25226
  suggestedName: pathToName(relPath),
@@ -25185,7 +25242,7 @@ function walkForPackages(projectRoot, currentDir, depth, results) {
25185
25242
  if (depth > MAX_SCAN_DEPTH) return;
25186
25243
  let entries;
25187
25244
  try {
25188
- entries = fs14.readdirSync(currentDir, { withFileTypes: true });
25245
+ entries = fs13.readdirSync(currentDir, { withFileTypes: true });
25189
25246
  } catch {
25190
25247
  return;
25191
25248
  }
@@ -25195,7 +25252,7 @@ function walkForPackages(projectRoot, currentDir, depth, results) {
25195
25252
  const fullPath = path18.join(currentDir, entry.name);
25196
25253
  const relPath = normalizePath(path18.relative(projectRoot, fullPath));
25197
25254
  if (relPath === "" || relPath === ".") continue;
25198
- const hasMarker = PACKAGE_MARKERS.some((m) => fs14.existsSync(path18.join(fullPath, m)));
25255
+ const hasMarker = PACKAGE_MARKERS.some((m) => fs13.existsSync(path18.join(fullPath, m)));
25199
25256
  if (hasMarker) {
25200
25257
  results.push({
25201
25258
  suggestedId: pathToId(relPath),
@@ -25220,19 +25277,168 @@ function normalizePath(p) {
25220
25277
  return p.replace(/\\/g, "/");
25221
25278
  }
25222
25279
 
25280
+ // src/core/variants.ts
25281
+ var fs14 = __toESM(require("fs"));
25282
+ var os3 = __toESM(require("os"));
25283
+ var path19 = __toESM(require("path"));
25284
+ var import_zod10 = require("zod");
25285
+ var VariantDefSchema = import_zod10.z.object({
25286
+ /** Variant id referenced by a component's `variant` (e.g. "publisher", "org/external-config-adapter"). */
25287
+ id: import_zod10.z.string().min(1),
25288
+ /** The core stereotype this variant specializes — authoritative for generic semantics (Adapter, Orchestrator, …). */
25289
+ base: import_zod10.z.string().min(1),
25290
+ /** How to implement a component of this variant — the recipe the implementer follows and reuses across same-variant components. */
25291
+ guidance: import_zod10.z.string().min(1),
25292
+ /** Optional: this variant only applies for the given target language (else it applies everywhere). */
25293
+ target: import_zod10.z.string().optional(),
25294
+ /** Optional: this variant only applies under the given architectural profile. */
25295
+ profile: import_zod10.z.string().optional()
25296
+ });
25297
+ function globalVariantsDir() {
25298
+ return process.env.WAIRON_VARIANTS_DIR ?? path19.join(os3.homedir(), ".wairon", "variants");
25299
+ }
25300
+ function builtinVariantsDir() {
25301
+ const candidates = [
25302
+ path19.resolve(__dirname, "..", "templates", "variants"),
25303
+ // src/core & dist/cli
25304
+ path19.resolve(__dirname, "templates", "variants")
25305
+ // dist (library entry)
25306
+ ];
25307
+ return candidates.find((dir) => fs14.existsSync(dir)) ?? candidates[0];
25308
+ }
25309
+ function projectVariantsDir() {
25310
+ return path19.join(getProjectRoot(), ".wai", "variants");
25311
+ }
25312
+ function variantFiles(dir) {
25313
+ let entries;
25314
+ try {
25315
+ entries = fs14.readdirSync(dir, { withFileTypes: true });
25316
+ } catch {
25317
+ return [];
25318
+ }
25319
+ return entries.filter((e) => e.isFile() && /\.ya?ml$/i.test(e.name)).sort((a, b) => a.name.localeCompare(b.name)).map((e) => path19.join(dir, e.name));
25320
+ }
25321
+ function parseVariants(raw) {
25322
+ if (raw == null) return [];
25323
+ return (Array.isArray(raw) ? raw : [raw]).map((item) => VariantDefSchema.parse(item));
25324
+ }
25325
+ function reportSkippedFile(file, err) {
25326
+ console.error(`[variants] skipped "${file}": ${err instanceof Error ? err.message : String(err)}`);
25327
+ }
25328
+ function readVariantsDir(dir) {
25329
+ const out = [];
25330
+ for (const file of variantFiles(dir)) {
25331
+ try {
25332
+ out.push(...parseVariants(readYamlFile(file)));
25333
+ } catch (err) {
25334
+ reportSkippedFile(file, err);
25335
+ }
25336
+ }
25337
+ return out;
25338
+ }
25339
+ function mergeById(...layers) {
25340
+ const byId = /* @__PURE__ */ new Map();
25341
+ for (const layer of layers) {
25342
+ for (const v of layer) byId.set(v.id, v);
25343
+ }
25344
+ return [...byId.values()];
25345
+ }
25346
+ function resolveVariantGuidance(component, allComponents, variantsById) {
25347
+ if (!component.variant) return null;
25348
+ const def = variantsById.get(component.variant);
25349
+ if (!def) return null;
25350
+ return {
25351
+ variant: component.variant,
25352
+ base: def.base,
25353
+ guidance: def.guidance,
25354
+ siblings: allComponents.filter((o) => o.variant === component.variant && o.id !== component.id).map((o) => o.id),
25355
+ ...def.target ? { target: def.target } : {},
25356
+ ...def.profile ? { profile: def.profile } : {}
25357
+ };
25358
+ }
25359
+ function composeVariantGuidance(comps, allComponents, variantsById) {
25360
+ const resolved = comps.map((c) => ({ id: c.id, guidance: resolveVariantGuidance(c, allComponents, variantsById) })).filter((r) => r.guidance !== null);
25361
+ if (resolved.length === 0) return "";
25362
+ const lines = [
25363
+ "## Component variants \u2014 reuse the shared approach",
25364
+ "",
25365
+ "One or more of your components declare a variant \u2014 a base-anchored kind with implementation guidance. Implement every component of the same variant alike, reusing one shared approach instead of reinventing it per instance:",
25366
+ ""
25367
+ ];
25368
+ for (const { id, guidance } of resolved) {
25369
+ let line = `- **${id}** \u2014 variant \`${guidance.variant}\` (a kind of ${guidance.base}): ${guidance.guidance}`;
25370
+ if (guidance.siblings.length > 0) {
25371
+ line += ` Same-variant components elsewhere: ${guidance.siblings.join(", ")} \u2014 implement them consistently, reusing the same logic/concept.`;
25372
+ }
25373
+ lines.push(line);
25374
+ }
25375
+ return lines.join("\n");
25376
+ }
25377
+ function loadProjectVariants() {
25378
+ try {
25379
+ return mergeById(
25380
+ readVariantsDir(builtinVariantsDir()),
25381
+ readVariantsDir(globalVariantsDir()),
25382
+ readVariantsDir(projectVariantsDir())
25383
+ );
25384
+ } catch {
25385
+ return [];
25386
+ }
25387
+ }
25388
+ function listProjectVariants() {
25389
+ return mergeById(readVariantsDir(projectVariantsDir()));
25390
+ }
25391
+ function rebaseProjectVariants(fromBase, toBase) {
25392
+ const rebased = [];
25393
+ for (const file of variantFiles(projectVariantsDir())) {
25394
+ const content = readFileOrNull(file);
25395
+ if (content === null) continue;
25396
+ let raw;
25397
+ let variants;
25398
+ try {
25399
+ raw = parseYaml(content, file);
25400
+ variants = parseVariants(raw);
25401
+ } catch (err) {
25402
+ reportSkippedFile(file, err);
25403
+ continue;
25404
+ }
25405
+ const matching = variants.filter((v) => v.base === fromBase);
25406
+ if (matching.length === 0) continue;
25407
+ writeFile(file, rebasedText(content, fromBase, toBase, withRebasedEntries(raw, fromBase, toBase)));
25408
+ for (const v of matching) {
25409
+ if (!rebased.includes(v.id)) rebased.push(v.id);
25410
+ }
25411
+ }
25412
+ return rebased;
25413
+ }
25414
+ function withRebasedEntries(raw, fromBase, toBase) {
25415
+ const rebase = (entry) => entry.base === fromBase ? { ...entry, base: toBase } : entry;
25416
+ return Array.isArray(raw) ? raw.map(rebase) : rebase(raw);
25417
+ }
25418
+ function rebasedText(content, fromBase, toBase, rebasedContent) {
25419
+ const escaped = fromBase.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
25420
+ const baseLine = new RegExp(`^([ \\t]*(?:-[ \\t]+)?base:[ \\t]*)(["']?)${escaped}\\2(?=[ \\t]*(?:#.*)?$)`, "gm");
25421
+ const edited = content.replace(baseLine, (_line, key, quote) => `${key}${quote}${toBase}${quote}`);
25422
+ try {
25423
+ if (JSON.stringify(parseYaml(edited)) === JSON.stringify(rebasedContent)) return edited;
25424
+ } catch {
25425
+ }
25426
+ return serializeYaml(rebasedContent);
25427
+ }
25428
+
25223
25429
  // src/core/agent_resolver.ts
25224
- var path20 = __toESM(require("path"));
25430
+ var path21 = __toESM(require("path"));
25225
25431
  var fs15 = __toESM(require("fs"));
25226
25432
 
25227
25433
  // src/core/templates.ts
25228
- var path19 = __toESM(require("path"));
25434
+ var path20 = __toESM(require("path"));
25229
25435
  function builtinTemplatesDir() {
25230
- return path19.resolve(__dirname, "..", "templates");
25436
+ return path20.resolve(__dirname, "..", "templates");
25231
25437
  }
25232
25438
  function loadTemplate(id, globalOverride) {
25233
25439
  const dirs = templateSearchDirs(globalOverride);
25234
25440
  for (const dir of dirs) {
25235
- const filePath = path19.join(dir, `${id}.yaml`);
25441
+ const filePath = path20.join(dir, `${id}.yaml`);
25236
25442
  if (pathExists(filePath)) {
25237
25443
  const raw = readYamlFile(filePath);
25238
25444
  return { ...TemplateSchema.parse(raw), templateName: id };
@@ -25241,7 +25447,7 @@ function loadTemplate(id, globalOverride) {
25241
25447
  throw new TemplateNotFoundError(id);
25242
25448
  }
25243
25449
  function loadAgentOverride(agentId) {
25244
- const filePath = path19.join(AI_PATHS.root(), "agents", `${agentId}.md`);
25450
+ const filePath = path20.join(AI_PATHS.root(), "agents", `${agentId}.md`);
25245
25451
  return readFileOrNull(filePath);
25246
25452
  }
25247
25453
  function templateSearchDirs(globalOverride) {
@@ -25393,7 +25599,7 @@ function resolveBudget(profile, config, agentId) {
25393
25599
  var projectFilesCache = /* @__PURE__ */ new Map();
25394
25600
  function listFilesRecursiveSafe(dirPath, ext) {
25395
25601
  if (!fs15.existsSync(dirPath)) return [];
25396
- const nameLower = path20.basename(dirPath).toLowerCase();
25602
+ const nameLower = path21.basename(dirPath).toLowerCase();
25397
25603
  const IGNORED_DIRS = /* @__PURE__ */ new Set([
25398
25604
  "node_modules",
25399
25605
  "target",
@@ -25411,7 +25617,7 @@ function listFilesRecursiveSafe(dirPath, ext) {
25411
25617
  const entries = fs15.readdirSync(dirPath, { withFileTypes: true });
25412
25618
  const files = [];
25413
25619
  for (const entry of entries) {
25414
- const fullPath = path20.join(dirPath, entry.name);
25620
+ const fullPath = path21.join(dirPath, entry.name);
25415
25621
  if (entry.isDirectory()) {
25416
25622
  files.push(...listFilesRecursiveSafe(fullPath, ext));
25417
25623
  } else if (entry.isFile() && entry.name.endsWith(ext)) {
@@ -25424,8 +25630,8 @@ function getProjectFiles(projectDir) {
25424
25630
  let files = projectFilesCache.get(projectDir);
25425
25631
  if (!files) {
25426
25632
  files = [];
25427
- const srcDir = path20.join(projectDir, "src");
25428
- const legacySrcDir = path20.join(projectDir, "legacy-src");
25633
+ const srcDir = path21.join(projectDir, "src");
25634
+ const legacySrcDir = path21.join(projectDir, "legacy-src");
25429
25635
  let searchDir = projectDir;
25430
25636
  if (pathExists(srcDir)) {
25431
25637
  searchDir = srcDir;
@@ -25440,7 +25646,7 @@ function getProjectFiles(projectDir) {
25440
25646
  files.push(...listFilesRecursiveSafe(searchDir, ext));
25441
25647
  }
25442
25648
  const rootDir = getProjectRoot();
25443
- files = files.map((f) => path20.relative(rootDir, f).replace(/\\/g, "/"));
25649
+ files = files.map((f) => path21.relative(rootDir, f).replace(/\\/g, "/"));
25444
25650
  projectFilesCache.set(projectDir, files);
25445
25651
  }
25446
25652
  return files;
@@ -25465,8 +25671,8 @@ function inferSourcePathForComponent(comp, subsystems) {
25465
25671
  let bestFile = null;
25466
25672
  let bestScore = -1;
25467
25673
  for (const f of files) {
25468
- const ext = path20.extname(f);
25469
- const base = path20.basename(f, ext).toLowerCase();
25674
+ const ext = path21.extname(f);
25675
+ const base = path21.basename(f, ext).toLowerCase();
25470
25676
  if (candidates.has(base)) {
25471
25677
  let score = 0;
25472
25678
  const normalizedPath = f.toLowerCase();
@@ -25563,7 +25769,7 @@ function resolveAgentTopology() {
25563
25769
  });
25564
25770
  for (const sub of subsystems) {
25565
25771
  if (sub.projectPath) {
25566
- const mountSpecPath = path20.relative(getProjectRoot(), getSubsystemPath(sub.id)).replace(/\\/g, "/");
25772
+ const mountSpecPath = path21.relative(getProjectRoot(), getSubsystemPath(sub.id)).replace(/\\/g, "/");
25567
25773
  agents.push({
25568
25774
  id: `${sub.id}-owner`,
25569
25775
  name: `${sub.name} (chained subproject)`,
@@ -25585,9 +25791,9 @@ function resolveAgentTopology() {
25585
25791
  }
25586
25792
  const subComponents = components.filter((c) => c.subsystem === sub.id);
25587
25793
  const ownedPaths = [];
25588
- ownedPaths.push(path20.relative(getProjectRoot(), getSubsystemPath(sub.id)).replace(/\\/g, "/"));
25794
+ ownedPaths.push(path21.relative(getProjectRoot(), getSubsystemPath(sub.id)).replace(/\\/g, "/"));
25589
25795
  for (const c of subComponents) {
25590
- ownedPaths.push(path20.relative(getProjectRoot(), getComponentPath(c.id, sub.id)).replace(/\\/g, "/"));
25796
+ ownedPaths.push(path21.relative(getProjectRoot(), getComponentPath(c.id, sub.id)).replace(/\\/g, "/"));
25591
25797
  }
25592
25798
  if (!config.rules.generateComponentImplementers) {
25593
25799
  for (const comp of subComponents) {
@@ -25663,10 +25869,10 @@ function resolveAgentTopology() {
25663
25869
  }
25664
25870
  const dependencies = comp.dependsOn.map((depId) => `${depId}-implementer`);
25665
25871
  const readPaths = [
25666
- path20.relative(getProjectRoot(), AI_PATHS.specsSystem()).replace(/\\/g, "/"),
25667
- path20.relative(getProjectRoot(), getComponentPath(comp.id, comp.subsystem)).replace(/\\/g, "/"),
25668
- ...compInterfaces.map((i) => path20.relative(getProjectRoot(), getInterfacePath(i.id, comp.id)).replace(/\\/g, "/")),
25669
- ...compImpls.map((impl) => path20.relative(getProjectRoot(), getImplementationPath(impl.id, impl.contract)).replace(/\\/g, "/"))
25872
+ path21.relative(getProjectRoot(), AI_PATHS.specsSystem()).replace(/\\/g, "/"),
25873
+ path21.relative(getProjectRoot(), getComponentPath(comp.id, comp.subsystem)).replace(/\\/g, "/"),
25874
+ ...compInterfaces.map((i) => path21.relative(getProjectRoot(), getInterfacePath(i.id, comp.id)).replace(/\\/g, "/")),
25875
+ ...compImpls.map((impl) => path21.relative(getProjectRoot(), getImplementationPath(impl.id, impl.contract)).replace(/\\/g, "/"))
25670
25876
  ];
25671
25877
  agents.push({
25672
25878
  id: `${comp.id}-implementer`,
@@ -25772,10 +25978,10 @@ function loadRegistry() {
25772
25978
  }
25773
25979
 
25774
25980
  // src/exporters/generate.ts
25775
- var path24 = __toESM(require("path"));
25981
+ var path25 = __toESM(require("path"));
25776
25982
 
25777
25983
  // src/exporters/claude.ts
25778
- var path21 = __toESM(require("path"));
25984
+ var path22 = __toESM(require("path"));
25779
25985
  var MODEL_BY_TIER = {
25780
25986
  small: "haiku",
25781
25987
  standard: "sonnet",
@@ -25814,7 +26020,7 @@ var ClaudeExporter = class {
25814
26020
  outputPath(ctx) {
25815
26021
  const { agent, target, projectRoot } = ctx;
25816
26022
  const outputDir = "outputDir" in target ? target.outputDir : ".claude/agents";
25817
- return path21.resolve(projectRoot, outputDir, `${agent.id.replace(/::/g, "--")}.md`);
26023
+ return path22.resolve(projectRoot, outputDir, `${agent.id.replace(/::/g, "--")}.md`);
25818
26024
  }
25819
26025
  export(ctx) {
25820
26026
  const { agent, renderedInstructions, budget } = ctx;
@@ -25839,7 +26045,7 @@ var ClaudeExporter = class {
25839
26045
  };
25840
26046
 
25841
26047
  // src/exporters/custom.ts
25842
- var path22 = __toESM(require("path"));
26048
+ var path23 = __toESM(require("path"));
25843
26049
  var CustomExporter = class {
25844
26050
  constructor() {
25845
26051
  this.targetType = "custom";
@@ -25849,7 +26055,7 @@ var CustomExporter = class {
25849
26055
  if (!("outputDir" in target)) {
25850
26056
  throw new Error("CustomExporter requires target.outputDir");
25851
26057
  }
25852
- return path22.resolve(projectRoot, target.outputDir, `${agent.id.replace(/::/g, "--")}.md`);
26058
+ return path23.resolve(projectRoot, target.outputDir, `${agent.id.replace(/::/g, "--")}.md`);
25853
26059
  }
25854
26060
  export(ctx) {
25855
26061
  const { agent, target, renderedInstructions } = ctx;
@@ -25872,7 +26078,7 @@ var CustomExporter = class {
25872
26078
  };
25873
26079
 
25874
26080
  // src/exporters/gemini.ts
25875
- var path23 = __toESM(require("path"));
26081
+ var path24 = __toESM(require("path"));
25876
26082
  var GeminiExporter = class {
25877
26083
  constructor() {
25878
26084
  this.targetType = "gemini";
@@ -25880,7 +26086,7 @@ var GeminiExporter = class {
25880
26086
  outputPath(ctx) {
25881
26087
  const { agent, target, projectRoot } = ctx;
25882
26088
  const outputDir = "outputDir" in target ? target.outputDir : ".gemini/agents";
25883
- return path23.resolve(projectRoot, outputDir, `${agent.id.replace(/::/g, "--")}.yaml`);
26089
+ return path24.resolve(projectRoot, outputDir, `${agent.id.replace(/::/g, "--")}.yaml`);
25884
26090
  }
25885
26091
  export(ctx) {
25886
26092
  const { agent, renderedInstructions } = ctx;
@@ -25977,7 +26183,7 @@ function resolveExpectedOutputPaths(agents, projectConfig, projectRoot = getProj
25977
26183
  const targetConfig = resolveTargetConfig(agentTarget, projectConfig);
25978
26184
  if (!targetConfig) continue;
25979
26185
  const ctx = { agent, projectRoot, target: targetConfig };
25980
- expected.add(path24.resolve(getExporter(targetConfig).outputPath(ctx)));
26186
+ expected.add(path25.resolve(getExporter(targetConfig).outputPath(ctx)));
25981
26187
  }
25982
26188
  }
25983
26189
  return expected;
@@ -25992,7 +26198,7 @@ function resolveTargetConfig(agentTarget, projectConfig) {
25992
26198
 
25993
26199
  // src/core/treetransfer.ts
25994
26200
  var fs16 = __toESM(require("fs"));
25995
- var path25 = __toESM(require("path"));
26201
+ var path26 = __toESM(require("path"));
25996
26202
  var sdkPortal = __toESM(require_dist());
25997
26203
  var STAGING_PREFIX = ".wai-staging-";
25998
26204
  var BACKUP_DIR = ".wai-backups";
@@ -26018,39 +26224,39 @@ function hasAuthoredSpecs(root) {
26018
26224
  if (!pathExists(specsDir)) {
26019
26225
  return false;
26020
26226
  }
26021
- const systemIndex = path25.resolve(paths.specsSystem());
26227
+ const systemIndex = path26.resolve(paths.specsSystem());
26022
26228
  for (const file of listFilesRecursive(specsDir, ".yaml")) {
26023
- if (path25.resolve(file) !== systemIndex) {
26229
+ if (path26.resolve(file) !== systemIndex) {
26024
26230
  return true;
26025
26231
  }
26026
26232
  }
26027
26233
  return false;
26028
26234
  }
26029
26235
  function createStagingDir(destDir) {
26030
- const root = path25.resolve(destDir);
26236
+ const root = path26.resolve(destDir);
26031
26237
  fs16.mkdirSync(root, { recursive: true });
26032
- const stagingDir = fs16.mkdtempSync(path25.join(root, STAGING_PREFIX));
26238
+ const stagingDir = fs16.mkdtempSync(path26.join(root, STAGING_PREFIX));
26033
26239
  return stagingDir;
26034
26240
  }
26035
26241
  function commitStagedTree(stagingDir, destDir, roots, backupExisting) {
26036
- const root = path25.resolve(destDir);
26037
- const backupDir = path25.join(root, BACKUP_DIR, timestampSlug());
26242
+ const root = path26.resolve(destDir);
26243
+ const backupDir = path26.join(root, BACKUP_DIR, timestampSlug());
26038
26244
  let backedUp = false;
26039
26245
  for (const rootRel of roots) {
26040
26246
  const relative9 = rootRel === "." ? "" : rootRel;
26041
- const stagedSpecDir = path25.join(stagingDir, relative9, ".wai");
26247
+ const stagedSpecDir = path26.join(stagingDir, relative9, ".wai");
26042
26248
  if (!fs16.existsSync(stagedSpecDir)) continue;
26043
- const liveSpecDir = liveSpecDirFor(path25.join(root, relative9));
26249
+ const liveSpecDir = liveSpecDirFor(path26.join(root, relative9));
26044
26250
  if (backupExisting && liveSpecDir && fs16.existsSync(liveSpecDir)) {
26045
- const backupTarget = path25.join(backupDir, relative9, path25.basename(liveSpecDir));
26046
- fs16.mkdirSync(path25.dirname(backupTarget), { recursive: true });
26251
+ const backupTarget = path26.join(backupDir, relative9, path26.basename(liveSpecDir));
26252
+ fs16.mkdirSync(path26.dirname(backupTarget), { recursive: true });
26047
26253
  fs16.renameSync(liveSpecDir, backupTarget);
26048
26254
  backedUp = true;
26049
26255
  } else if (liveSpecDir && fs16.existsSync(liveSpecDir)) {
26050
26256
  fs16.rmSync(liveSpecDir, { recursive: true, force: true });
26051
26257
  }
26052
- const target = path25.join(root, relative9, ".wai");
26053
- fs16.mkdirSync(path25.dirname(target), { recursive: true });
26258
+ const target = path26.join(root, relative9, ".wai");
26259
+ fs16.mkdirSync(path26.dirname(target), { recursive: true });
26054
26260
  if (fs16.existsSync(target)) fs16.rmSync(target, { recursive: true, force: true });
26055
26261
  fs16.renameSync(stagedSpecDir, target);
26056
26262
  }
@@ -26075,7 +26281,7 @@ function exportSpecTree(includeDerived, allowPartial) {
26075
26281
  const skipped = [...inspection.skipped];
26076
26282
  const roots = [{ relativePath: ".", waiDir: aiPathsAt(root).root() }];
26077
26283
  for (const rel2 of inspection.roots) {
26078
- const waiDir = aiPathsAt(path25.resolve(root, rel2)).root();
26284
+ const waiDir = aiPathsAt(path26.resolve(root, rel2)).root();
26079
26285
  if (pathExists(waiDir)) {
26080
26286
  roots.push({ relativePath: rel2, waiDir });
26081
26287
  } else {
@@ -26106,7 +26312,7 @@ function importSpecTree(archive, options) {
26106
26312
  if (!info.compatible) {
26107
26313
  throw new Error("incompatible .waitree archive (format or minimum wairon version)");
26108
26314
  }
26109
- const destDir = path25.resolve(options.destDir ?? getProjectRoot());
26315
+ const destDir = path26.resolve(options.destDir ?? getProjectRoot());
26110
26316
  const occupied = hasSpecTree(destDir);
26111
26317
  const authored = hasAuthoredSpecs(destDir);
26112
26318
  if (authored && options.replaceExisting !== true) {
@@ -26137,9 +26343,9 @@ function importSpecTree(archive, options) {
26137
26343
  return result;
26138
26344
  }
26139
26345
  function liveSpecDirFor(rootDir) {
26140
- const modern = path25.join(rootDir, ".wai");
26346
+ const modern = path26.join(rootDir, ".wai");
26141
26347
  if (fs16.existsSync(modern)) return modern;
26142
- const legacy = path25.join(rootDir, ".wairon");
26348
+ const legacy = path26.join(rootDir, ".wairon");
26143
26349
  if (fs16.existsSync(legacy)) return legacy;
26144
26350
  return null;
26145
26351
  }
@@ -26281,7 +26487,7 @@ function repairForeignStepFields(apply) {
26281
26487
 
26282
26488
  // src/core/approval.ts
26283
26489
  var crypto3 = __toESM(require("crypto"));
26284
- var path26 = __toESM(require("path"));
26490
+ var path27 = __toESM(require("path"));
26285
26491
 
26286
26492
  // src/models/lock.ts
26287
26493
  function describeApprover(who) {
@@ -26298,12 +26504,12 @@ function digest(content) {
26298
26504
  return crypto3.createHash("sha256").update(normalized, "utf8").digest("hex");
26299
26505
  }
26300
26506
  function currentSpecDigests(root = getProjectRoot()) {
26301
- const mountDirs = loadSubsystemSpecs().filter((s) => s.projectPath && !s.id.includes("::")).map((s) => `${path26.resolve(root, s.projectPath).split(path26.sep).join("/")}/`);
26507
+ const mountDirs = loadSubsystemSpecs().filter((s) => s.projectPath && !s.id.includes("::")).map((s) => `${path27.resolve(root, s.projectPath).split(path27.sep).join("/")}/`);
26302
26508
  const out = {};
26303
26509
  for (const [abs, content] of snapshotSpecFiles()) {
26304
- const normalized = path26.resolve(abs).split(path26.sep).join("/");
26510
+ const normalized = path27.resolve(abs).split(path27.sep).join("/");
26305
26511
  if (mountDirs.some((dir) => normalized.startsWith(dir))) continue;
26306
- out[path26.relative(root, abs).split(path26.sep).join("/")] = digest(content);
26512
+ out[path27.relative(root, abs).split(path27.sep).join("/")] = digest(content);
26307
26513
  }
26308
26514
  return out;
26309
26515
  }
@@ -26361,7 +26567,7 @@ function currentChildPins(mounts, root = getProjectRoot()) {
26361
26567
  const pins = {};
26362
26568
  for (const mount of mounts) {
26363
26569
  if (!mount.projectPath || mount.id.includes("::")) continue;
26364
- const child = readLockRecordAt(path26.resolve(root, mount.projectPath));
26570
+ const child = readLockRecordAt(path27.resolve(root, mount.projectPath));
26365
26571
  if (child) pins[mount.id] = pinOf(child.stateId);
26366
26572
  }
26367
26573
  return pins;
@@ -26463,7 +26669,7 @@ function localApprover() {
26463
26669
  // src/utils/ai-guide.ts
26464
26670
  var fs17 = __toESM(require("fs"));
26465
26671
  var os5 = __toESM(require("os"));
26466
- var path27 = __toESM(require("path"));
26672
+ var path28 = __toESM(require("path"));
26467
26673
 
26468
26674
  // src/core/stamp.ts
26469
26675
  function versionStamp() {
@@ -26523,13 +26729,13 @@ This project uses **wairon**. System specs live under \`.wai/specs/\` (L0 System
26523
26729
  * **Variants**: \`gateway\`, a Portal that authenticates, authorizes, validates or rate-limits before it dispatches. Logic is an Orchestrator, and \`dependencyClass: pure | read\` bounds what it may depend on (unset = a workflow). Specialist and Gateway are retired stereotypes.
26524
26730
  * Use \`owns\` for private member containment (exactly one hop) and \`dependsOn\` for collaborators. Never use generic suffixes like "Manager", "Helper", or "Utils".`;
26525
26731
  function globalGuideFilePath(targetType) {
26526
- if (targetType === "claude") return path27.join(process.env["CLAUDE_CONFIG_DIR"] || path27.join(os5.homedir(), ".claude"), "CLAUDE.md");
26527
- if (targetType === "gemini") return path27.join(process.env["GEMINI_CONFIG_DIR"] || path27.join(os5.homedir(), ".gemini"), "GEMINI.md");
26732
+ if (targetType === "claude") return path28.join(process.env["CLAUDE_CONFIG_DIR"] || path28.join(os5.homedir(), ".claude"), "CLAUDE.md");
26733
+ if (targetType === "gemini") return path28.join(process.env["GEMINI_CONFIG_DIR"] || path28.join(os5.homedir(), ".gemini"), "GEMINI.md");
26528
26734
  return null;
26529
26735
  }
26530
26736
  function localGuideFilePath(projectRoot, targetType) {
26531
- if (targetType === "claude") return path27.join(projectRoot, ".claude", "CLAUDE.md");
26532
- if (targetType === "gemini" || targetType === "agy") return path27.join(projectRoot, ".gemini", "GEMINI.md");
26737
+ if (targetType === "claude") return path28.join(projectRoot, ".claude", "CLAUDE.md");
26738
+ if (targetType === "gemini" || targetType === "agy") return path28.join(projectRoot, ".gemini", "GEMINI.md");
26533
26739
  return null;
26534
26740
  }
26535
26741
  function injectGuide(filePath, scope) {
@@ -26544,7 +26750,7 @@ ${GUIDE_MARKER_END}
26544
26750
  const existing = fs17.existsSync(filePath) ? fs17.readFileSync(filePath, "utf-8") : "";
26545
26751
  const stripped = stripGuideSection(existing);
26546
26752
  const newContent = stripped.trimEnd() + section;
26547
- fs17.mkdirSync(path27.dirname(filePath), { recursive: true });
26753
+ fs17.mkdirSync(path28.dirname(filePath), { recursive: true });
26548
26754
  fs17.writeFileSync(filePath, newContent, "utf-8");
26549
26755
  }
26550
26756
  function stripGuideSection(content) {
@@ -26555,7 +26761,7 @@ function stripGuideSection(content) {
26555
26761
  }
26556
26762
  function writeRootGuideDelegator(projectRoot, targetType) {
26557
26763
  if (targetType === "claude") {
26558
- const filePath = path27.join(projectRoot, "CLAUDE.md");
26764
+ const filePath = path28.join(projectRoot, "CLAUDE.md");
26559
26765
  const content = `@.claude/CLAUDE.md
26560
26766
 
26561
26767
  # Wairon SDD Project
@@ -26570,7 +26776,7 @@ the \`wairon\` CLI is the human developer's tool, not yours.
26570
26776
  `;
26571
26777
  fs17.writeFileSync(filePath, content, "utf-8");
26572
26778
  } else if (targetType === "gemini" || targetType === "agy") {
26573
- const filePath = path27.join(projectRoot, "GEMINI.md");
26779
+ const filePath = path28.join(projectRoot, "GEMINI.md");
26574
26780
  const content = `# Wairon SDD Project
26575
26781
  ${GUIDE_MARKER_START}
26576
26782
  ${versionStamp()}
@@ -26579,7 +26785,7 @@ ${GUIDE_MARKER_END}
26579
26785
  `;
26580
26786
  fs17.writeFileSync(filePath, content, "utf-8");
26581
26787
  } else if (targetType === "cursor") {
26582
- const filePath = path27.join(projectRoot, ".cursorrules");
26788
+ const filePath = path28.join(projectRoot, ".cursorrules");
26583
26789
  const content = `# Wairon SDD Project
26584
26790
 
26585
26791
  This project uses the Wairon Spec-Driven Development (SDD) framework.
@@ -26588,8 +26794,8 @@ Refer to the rules in [.cursor/rules/](.cursor/rules/) for full instructions.
26588
26794
  `;
26589
26795
  fs17.writeFileSync(filePath, content, "utf-8");
26590
26796
  } else if (targetType === "copilot") {
26591
- const filePath = path27.join(projectRoot, ".github", "copilot-instructions.md");
26592
- fs17.mkdirSync(path27.dirname(filePath), { recursive: true });
26797
+ const filePath = path28.join(projectRoot, ".github", "copilot-instructions.md");
26798
+ fs17.mkdirSync(path28.dirname(filePath), { recursive: true });
26593
26799
  const content = `# Wairon SDD Project
26594
26800
 
26595
26801
  This project uses the Wairon Spec-Driven Development (SDD) framework.
@@ -26598,7 +26804,7 @@ Refer to the prompts in [.github/prompts/](.github/prompts/) for instructions.
26598
26804
  `;
26599
26805
  fs17.writeFileSync(filePath, content, "utf-8");
26600
26806
  } else if (targetType === "codex") {
26601
- const filePath = path27.join(projectRoot, ".codexrules");
26807
+ const filePath = path28.join(projectRoot, ".codexrules");
26602
26808
  const content = `# Wairon SDD Project
26603
26809
 
26604
26810
  Refer to [.codex/agents/](.codex/agents/) for full instructions.
@@ -26974,18 +27180,15 @@ var logger = {
26974
27180
 
26975
27181
  // src/core/skills.ts
26976
27182
  var SKILL_NAMES = ["sdd-architect", "sdd-narrative", "sdd-auditor", "sdd-implement", "sdd-delegate"];
26977
- function loadProjectConfig3() {
26978
- return loadProjectConfig();
26979
- }
26980
27183
  function activeTargetTypes2() {
26981
- const config = loadProjectConfig3();
27184
+ const config = loadProjectConfig();
26982
27185
  if (!config) return [];
26983
27186
  return activeTargetTypes(config);
26984
27187
  }
26985
27188
  var RESOURCE_SKILL_IDS = [...SKILL_NAMES].sort();
26986
27189
 
26987
27190
  // src/index.ts
26988
- function loadProjectConfig4() {
27191
+ function loadProjectConfig2() {
26989
27192
  const config = loadProjectConfig();
26990
27193
  if (!config) throw new ProjectNotInitializedError();
26991
27194
  return config;
@@ -27118,13 +27321,17 @@ function loadProjectConfig4() {
27118
27321
  ambiguityMessage,
27119
27322
  approvalRecord,
27120
27323
  approvalVerdict,
27324
+ assertContainedProjectPath,
27121
27325
  assertProjectInitialized,
27122
27326
  backendCommand,
27327
+ backfillChainedSubprojectConfigs,
27123
27328
  buildCanvasDataModel,
27124
27329
  buildProjectGraph,
27125
27330
  buildRuleContext,
27126
27331
  callSitesOf,
27127
27332
  captureApprovedSpecs,
27333
+ checkDeclarativePack,
27334
+ clearLoaderIssues,
27128
27335
  cognitiveScore,
27129
27336
  complexityLevel,
27130
27337
  composeAgentBrief,
@@ -27139,6 +27346,7 @@ function loadProjectConfig4() {
27139
27346
  createEmptyTopologyConfig,
27140
27347
  createProjectConfig,
27141
27348
  currentChildPins,
27349
+ currentRootBinding,
27142
27350
  declaredPackNames,
27143
27351
  declaredProfileIds,
27144
27352
  declaresGlobalPacks,
@@ -27151,6 +27359,7 @@ function loadProjectConfig4() {
27151
27359
  deriveExecutionProfile,
27152
27360
  derivedDocPaths,
27153
27361
  detectDomainCandidates,
27362
+ diagnoseProjectPacks,
27154
27363
  diagramSetIndex,
27155
27364
  diffAgainstApproval,
27156
27365
  diffSize,
@@ -27166,6 +27375,9 @@ function loadProjectConfig4() {
27166
27375
  factsFor,
27167
27376
  fieldTypeRefs,
27168
27377
  fieldTypesOf,
27378
+ findChainingParent,
27379
+ findChainingSubprojectsMissingConfig,
27380
+ findLegacySpecFiles,
27169
27381
  findProjectRoot,
27170
27382
  findSystemRoot,
27171
27383
  fromProjectRoot,
@@ -27175,6 +27387,7 @@ function loadProjectConfig4() {
27175
27387
  generateDiagramSet,
27176
27388
  generateSequenceDiagram,
27177
27389
  getExporter,
27390
+ getLoaderIssues,
27178
27391
  getProjectRoot,
27179
27392
  getProjectRootOverride,
27180
27393
  getRequestParentReach,
@@ -27182,6 +27395,7 @@ function loadProjectConfig4() {
27182
27395
  getStatusReport,
27183
27396
  globalGuideFilePath,
27184
27397
  globalPacksDir,
27398
+ globalPacksEnabled,
27185
27399
  globalTemplatesDir,
27186
27400
  hasContext,
27187
27401
  hasFunctionBody,
@@ -27214,6 +27428,7 @@ function loadProjectConfig4() {
27214
27428
  loadInterfaceSpecs,
27215
27429
  loadProjectConfig,
27216
27430
  loadProjectExtensions,
27431
+ loadProjectVariants,
27217
27432
  loadRegistry,
27218
27433
  loadSpec,
27219
27434
  loadSpecGraph,
@@ -27237,12 +27452,16 @@ function loadProjectConfig4() {
27237
27452
  moveSubsystemProject,
27238
27453
  movedChildren,
27239
27454
  narrativeStepForeignFields,
27455
+ packDirEntry,
27456
+ packEntryLabel,
27457
+ packEntryRef,
27240
27458
  packStoreDir,
27241
27459
  parseDeclaredCall,
27242
27460
  parseYaml,
27243
27461
  passesIntentFloor,
27244
27462
  pathExists,
27245
27463
  pathKey,
27464
+ pinInstalledPacksAsSelections,
27246
27465
  projectConfigExists,
27247
27466
  provisionProject,
27248
27467
  qualifiedTypeId,
@@ -27270,12 +27489,14 @@ function loadProjectConfig4() {
27270
27489
  resolveImport,
27271
27490
  resolveInstalledPack,
27272
27491
  resolveSubprojectForNamespace,
27492
+ resolveVariantGuidance,
27273
27493
  retireSpecialists,
27274
27494
  runWithProjectBinding,
27275
27495
  runWithProjectRoot,
27276
27496
  sameContract,
27277
27497
  saveSpec,
27278
27498
  saveTopologyConfig,
27499
+ scanAllSpecs,
27279
27500
  serializeYaml,
27280
27501
  setExecutionTier,
27281
27502
  setLogLevel,