@wairon/cli 5.1.1-dev.71 → 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/cli/index.js +5540 -5675
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +805 -568
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
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
|
|
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 =
|
|
3103
|
-
fs18.mkdirSync(
|
|
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,
|
|
3116
|
+
walkPackDir(root, path30.join(current2, entry.name), out);
|
|
3117
3117
|
} else if (entry.isFile()) {
|
|
3118
|
-
const absolute =
|
|
3119
|
-
const relative22 =
|
|
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) =>
|
|
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 =
|
|
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 =
|
|
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(
|
|
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,
|
|
@@ -3539,16 +3544,12 @@ __export(src_exports, {
|
|
|
3539
3544
|
defaultNarrativeDetail: () => defaultNarrativeDetail,
|
|
3540
3545
|
defaultPackSelections: () => defaultPackSelections,
|
|
3541
3546
|
defaultTargetConfig: () => defaultTargetConfig,
|
|
3542
|
-
deleteComponentSpec: () => deleteComponentSpec,
|
|
3543
|
-
deleteImplementationSpec: () => deleteImplementationSpec,
|
|
3544
|
-
deleteInterfaceSpec: () => deleteInterfaceSpec,
|
|
3545
3547
|
deleteSpec: () => deleteSpec,
|
|
3546
|
-
deleteSubsystemSpec: () => deleteSubsystemSpec,
|
|
3547
|
-
deleteTypeSpec: () => deleteTypeSpec,
|
|
3548
3548
|
deregisterPackRef: () => deregisterPackRef,
|
|
3549
3549
|
deriveExecutionProfile: () => deriveExecutionProfile,
|
|
3550
3550
|
derivedDocPaths: () => derivedDocPaths,
|
|
3551
3551
|
detectDomainCandidates: () => detectDomainCandidates,
|
|
3552
|
+
diagnoseProjectPacks: () => diagnoseProjectPacks,
|
|
3552
3553
|
diagramSetIndex: () => diagramSetIndex,
|
|
3553
3554
|
diffAgainstApproval: () => diffAgainstApproval,
|
|
3554
3555
|
diffSize: () => diffSize,
|
|
@@ -3564,6 +3565,9 @@ __export(src_exports, {
|
|
|
3564
3565
|
factsFor: () => factsFor,
|
|
3565
3566
|
fieldTypeRefs: () => fieldTypeRefs,
|
|
3566
3567
|
fieldTypesOf: () => fieldTypesOf,
|
|
3568
|
+
findChainingParent: () => findChainingParent,
|
|
3569
|
+
findChainingSubprojectsMissingConfig: () => findChainingSubprojectsMissingConfig,
|
|
3570
|
+
findLegacySpecFiles: () => findLegacySpecFiles,
|
|
3567
3571
|
findProjectRoot: () => findProjectRoot,
|
|
3568
3572
|
findSystemRoot: () => findSystemRoot,
|
|
3569
3573
|
fromProjectRoot: () => fromProjectRoot,
|
|
@@ -3573,6 +3577,7 @@ __export(src_exports, {
|
|
|
3573
3577
|
generateDiagramSet: () => generateDiagramSet,
|
|
3574
3578
|
generateSequenceDiagram: () => generateSequenceDiagram,
|
|
3575
3579
|
getExporter: () => getExporter,
|
|
3580
|
+
getLoaderIssues: () => getLoaderIssues,
|
|
3576
3581
|
getProjectRoot: () => getProjectRoot,
|
|
3577
3582
|
getProjectRootOverride: () => getProjectRootOverride,
|
|
3578
3583
|
getRequestParentReach: () => getRequestParentReach,
|
|
@@ -3580,6 +3585,7 @@ __export(src_exports, {
|
|
|
3580
3585
|
getStatusReport: () => getStatusReport,
|
|
3581
3586
|
globalGuideFilePath: () => globalGuideFilePath,
|
|
3582
3587
|
globalPacksDir: () => globalPacksDir,
|
|
3588
|
+
globalPacksEnabled: () => globalPacksEnabled,
|
|
3583
3589
|
globalTemplatesDir: () => globalTemplatesDir,
|
|
3584
3590
|
hasContext: () => hasContext,
|
|
3585
3591
|
hasFunctionBody: () => hasFunctionBody,
|
|
@@ -3610,8 +3616,9 @@ __export(src_exports, {
|
|
|
3610
3616
|
loadImplementationSpecs: () => loadImplementationSpecs,
|
|
3611
3617
|
loadInterfaceSpec: () => loadInterfaceSpec,
|
|
3612
3618
|
loadInterfaceSpecs: () => loadInterfaceSpecs,
|
|
3613
|
-
loadProjectConfig: () =>
|
|
3619
|
+
loadProjectConfig: () => loadProjectConfig2,
|
|
3614
3620
|
loadProjectExtensions: () => loadProjectExtensions,
|
|
3621
|
+
loadProjectVariants: () => loadProjectVariants,
|
|
3615
3622
|
loadRegistry: () => loadRegistry,
|
|
3616
3623
|
loadSpec: () => loadSpec,
|
|
3617
3624
|
loadSpecGraph: () => loadSpecGraph,
|
|
@@ -3635,12 +3642,16 @@ __export(src_exports, {
|
|
|
3635
3642
|
moveSubsystemProject: () => moveSubsystemProject,
|
|
3636
3643
|
movedChildren: () => movedChildren,
|
|
3637
3644
|
narrativeStepForeignFields: () => narrativeStepForeignFields,
|
|
3645
|
+
packDirEntry: () => packDirEntry,
|
|
3646
|
+
packEntryLabel: () => packEntryLabel,
|
|
3647
|
+
packEntryRef: () => packEntryRef,
|
|
3638
3648
|
packStoreDir: () => packStoreDir,
|
|
3639
3649
|
parseDeclaredCall: () => parseDeclaredCall,
|
|
3640
3650
|
parseYaml: () => parseYaml,
|
|
3641
3651
|
passesIntentFloor: () => passesIntentFloor,
|
|
3642
3652
|
pathExists: () => pathExists,
|
|
3643
3653
|
pathKey: () => pathKey,
|
|
3654
|
+
pinInstalledPacksAsSelections: () => pinInstalledPacksAsSelections,
|
|
3644
3655
|
projectConfigExists: () => projectConfigExists,
|
|
3645
3656
|
provisionProject: () => provisionProject,
|
|
3646
3657
|
qualifiedTypeId: () => qualifiedTypeId,
|
|
@@ -3668,18 +3679,14 @@ __export(src_exports, {
|
|
|
3668
3679
|
resolveImport: () => resolveImport,
|
|
3669
3680
|
resolveInstalledPack: () => resolveInstalledPack,
|
|
3670
3681
|
resolveSubprojectForNamespace: () => resolveSubprojectForNamespace,
|
|
3682
|
+
resolveVariantGuidance: () => resolveVariantGuidance,
|
|
3671
3683
|
retireSpecialists: () => retireSpecialists,
|
|
3672
3684
|
runWithProjectBinding: () => runWithProjectBinding,
|
|
3673
3685
|
runWithProjectRoot: () => runWithProjectRoot,
|
|
3674
3686
|
sameContract: () => sameContract,
|
|
3675
|
-
saveComponentSpec: () => saveComponentSpec,
|
|
3676
|
-
saveImplementationSpec: () => saveImplementationSpec,
|
|
3677
|
-
saveInterfaceSpec: () => saveInterfaceSpec,
|
|
3678
3687
|
saveSpec: () => saveSpec,
|
|
3679
|
-
saveSubsystemSpec: () => saveSubsystemSpec,
|
|
3680
|
-
saveSystemSpec: () => saveSystemSpec,
|
|
3681
3688
|
saveTopologyConfig: () => saveTopologyConfig,
|
|
3682
|
-
|
|
3689
|
+
scanAllSpecs: () => scanAllSpecs,
|
|
3683
3690
|
serializeYaml: () => serializeYaml,
|
|
3684
3691
|
setExecutionTier: () => setExecutionTier,
|
|
3685
3692
|
setLogLevel: () => setLogLevel,
|
|
@@ -3712,7 +3719,7 @@ module.exports = __toCommonJS(src_exports);
|
|
|
3712
3719
|
|
|
3713
3720
|
// src/config/project-config.ts
|
|
3714
3721
|
var fs2 = __toESM(require("fs"));
|
|
3715
|
-
var
|
|
3722
|
+
var path3 = __toESM(require("path"));
|
|
3716
3723
|
var import_zod4 = require("zod");
|
|
3717
3724
|
|
|
3718
3725
|
// src/utils/fs.ts
|
|
@@ -3765,6 +3772,9 @@ function listFilesRecursive(dirPath, ext) {
|
|
|
3765
3772
|
}
|
|
3766
3773
|
var projectRootOverride = null;
|
|
3767
3774
|
var requestRootStore = new import_node_async_hooks.AsyncLocalStorage();
|
|
3775
|
+
function currentRootBinding() {
|
|
3776
|
+
return requestRootStore.getStore();
|
|
3777
|
+
}
|
|
3768
3778
|
function runWithProjectRoot(dir, fn) {
|
|
3769
3779
|
return requestRootStore.run({ ...requestRootStore.getStore(), root: path.resolve(dir) }, fn);
|
|
3770
3780
|
}
|
|
@@ -3909,6 +3919,7 @@ var BundleNotFoundError = class extends WaironError {
|
|
|
3909
3919
|
};
|
|
3910
3920
|
|
|
3911
3921
|
// src/models/project.ts
|
|
3922
|
+
var path2 = __toESM(require("path"));
|
|
3912
3923
|
var import_zod3 = require("zod");
|
|
3913
3924
|
|
|
3914
3925
|
// src/models/agent.ts
|
|
@@ -4496,16 +4507,28 @@ function activeTargetTypes(config) {
|
|
|
4496
4507
|
const targets = config.targets;
|
|
4497
4508
|
return targets.filter((t) => typeof t === "string" || t.enabled !== false).map((t) => typeof t === "string" ? t : t.type);
|
|
4498
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
|
+
}
|
|
4499
4522
|
|
|
4500
4523
|
// src/config/project-config.ts
|
|
4501
4524
|
function waiDirAt(root) {
|
|
4502
|
-
const wai =
|
|
4503
|
-
const legacy =
|
|
4525
|
+
const wai = path3.join(root, ".wai");
|
|
4526
|
+
const legacy = path3.join(root, ".wairon");
|
|
4504
4527
|
return !fs2.existsSync(wai) && fs2.existsSync(legacy) ? legacy : wai;
|
|
4505
4528
|
}
|
|
4506
4529
|
function projectConfigFsAdapterAt(rootDir) {
|
|
4507
|
-
const root =
|
|
4508
|
-
const file = () =>
|
|
4530
|
+
const root = path3.resolve(rootDir);
|
|
4531
|
+
const file = () => path3.join(waiDirAt(root), "project.yaml");
|
|
4509
4532
|
return {
|
|
4510
4533
|
readDocument() {
|
|
4511
4534
|
return readYamlFile(file());
|
|
@@ -4714,15 +4737,15 @@ function indexOver(store, root) {
|
|
|
4714
4737
|
specsDir() {
|
|
4715
4738
|
try {
|
|
4716
4739
|
const declared = store.readField("paths.specsDir");
|
|
4717
|
-
if (declared) return
|
|
4740
|
+
if (declared) return path3.resolve(root, declared);
|
|
4718
4741
|
} catch {
|
|
4719
4742
|
}
|
|
4720
|
-
return
|
|
4743
|
+
return path3.join(waiDirAt(root), "specs");
|
|
4721
4744
|
}
|
|
4722
4745
|
};
|
|
4723
4746
|
}
|
|
4724
4747
|
function projectConfigRepositoryOver(adapter, rootDir) {
|
|
4725
|
-
const root =
|
|
4748
|
+
const root = path3.resolve(rootDir);
|
|
4726
4749
|
const store = storeOver(adapter, root);
|
|
4727
4750
|
const index = indexOver(store, root);
|
|
4728
4751
|
const registry = registryOver(store, root);
|
|
@@ -4819,36 +4842,24 @@ var projectConfigRepository = {
|
|
|
4819
4842
|
bound().pinGlobalPacksAsSelections(selections);
|
|
4820
4843
|
}
|
|
4821
4844
|
};
|
|
4822
|
-
var PACK_EXT_RE = /\.(ya?ml|cjs|js)$/i;
|
|
4823
|
-
function declaredPackNames(config) {
|
|
4824
|
-
const selection = config.profileSelection;
|
|
4825
|
-
return [.../* @__PURE__ */ new Set([
|
|
4826
|
-
...(config.extensions?.packs ?? []).map((entry) => typeof entry === "string" ? path2.basename(entry).replace(PACK_EXT_RE, "") : entry.name),
|
|
4827
|
-
...selection?.requiredPackNames ?? [],
|
|
4828
|
-
...selection?.defaultPackNames ?? []
|
|
4829
|
-
])];
|
|
4830
|
-
}
|
|
4831
|
-
function declaredProfileIds(config) {
|
|
4832
|
-
return [...new Set(config.profileSelection?.profileIds ?? [])];
|
|
4833
|
-
}
|
|
4834
4845
|
|
|
4835
4846
|
// src/core/domain_projector.ts
|
|
4836
4847
|
var path16 = __toESM(require("path"));
|
|
4837
4848
|
|
|
4838
4849
|
// src/core/specs.ts
|
|
4839
|
-
var
|
|
4850
|
+
var fs11 = __toESM(require("fs"));
|
|
4840
4851
|
var path15 = __toESM(require("path"));
|
|
4841
4852
|
|
|
4842
4853
|
// src/config/paths.ts
|
|
4843
4854
|
var fs3 = __toESM(require("fs"));
|
|
4844
|
-
var
|
|
4855
|
+
var path4 = __toESM(require("path"));
|
|
4845
4856
|
function aiPathsAt(rootDir) {
|
|
4846
|
-
const resolvedRoot =
|
|
4857
|
+
const resolvedRoot = path4.resolve(rootDir);
|
|
4847
4858
|
const aiDirAt2 = (...segments) => {
|
|
4848
|
-
const waiPath =
|
|
4849
|
-
const waironPath =
|
|
4859
|
+
const waiPath = path4.join(resolvedRoot, ".wai");
|
|
4860
|
+
const waironPath = path4.join(resolvedRoot, ".wairon");
|
|
4850
4861
|
const base = !fs3.existsSync(waiPath) && fs3.existsSync(waironPath) ? waironPath : waiPath;
|
|
4851
|
-
return
|
|
4862
|
+
return path4.join(base, ...segments);
|
|
4852
4863
|
};
|
|
4853
4864
|
const specsDir = () => projectConfigRepositoryAt(resolvedRoot).specsDir();
|
|
4854
4865
|
return {
|
|
@@ -4865,12 +4876,12 @@ function aiPathsAt(rootDir) {
|
|
|
4865
4876
|
contextDomainsMd: () => aiDirAt2("context", "domains.md"),
|
|
4866
4877
|
contextWaironGuideMd: () => aiDirAt2("context", "wairon-guide.md"),
|
|
4867
4878
|
specsDir,
|
|
4868
|
-
specsSystem: () =>
|
|
4869
|
-
specsSubsystemsDir: () =>
|
|
4870
|
-
specsComponentsDir: () =>
|
|
4871
|
-
specsInterfacesDir: () =>
|
|
4872
|
-
specsImplementationsDir: () =>
|
|
4873
|
-
specsTypesDir: () =>
|
|
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")
|
|
4874
4885
|
};
|
|
4875
4886
|
}
|
|
4876
4887
|
var AI_PATHS = {
|
|
@@ -4951,7 +4962,7 @@ function stateIdEquals(a, b) {
|
|
|
4951
4962
|
|
|
4952
4963
|
// src/core/lockfile.ts
|
|
4953
4964
|
var fs4 = __toESM(require("fs"));
|
|
4954
|
-
var
|
|
4965
|
+
var path5 = __toESM(require("path"));
|
|
4955
4966
|
function lockPath() {
|
|
4956
4967
|
return aiDir("lock.json");
|
|
4957
4968
|
}
|
|
@@ -4983,7 +4994,7 @@ function normalizeRecord(raw) {
|
|
|
4983
4994
|
}
|
|
4984
4995
|
function writeLockRecord(record) {
|
|
4985
4996
|
const p = lockPath();
|
|
4986
|
-
fs4.mkdirSync(
|
|
4997
|
+
fs4.mkdirSync(path5.dirname(p), { recursive: true });
|
|
4987
4998
|
const tmp = `${p}.tmp`;
|
|
4988
4999
|
fs4.writeFileSync(tmp, JSON.stringify(withSortedMaps(record), null, 2) + "\n");
|
|
4989
5000
|
fs4.renameSync(tmp, p);
|
|
@@ -5006,7 +5017,7 @@ function withSortedMaps(record) {
|
|
|
5006
5017
|
|
|
5007
5018
|
// src/core/spec-files.ts
|
|
5008
5019
|
var fs5 = __toESM(require("fs"));
|
|
5009
|
-
var
|
|
5020
|
+
var path6 = __toESM(require("path"));
|
|
5010
5021
|
var SPEC_FILE_EXTENSION = ".yaml";
|
|
5011
5022
|
function readSpecFile(filePath) {
|
|
5012
5023
|
return readYamlFile(filePath);
|
|
@@ -5020,7 +5031,7 @@ function listSpecFiles(specsDir) {
|
|
|
5020
5031
|
function removeSpecFile(filePath, specsRoot) {
|
|
5021
5032
|
if (!fs5.existsSync(filePath)) return false;
|
|
5022
5033
|
fs5.unlinkSync(filePath);
|
|
5023
|
-
pruneEmptyDirs(
|
|
5034
|
+
pruneEmptyDirs(path6.dirname(filePath), path6.resolve(specsRoot));
|
|
5024
5035
|
return true;
|
|
5025
5036
|
}
|
|
5026
5037
|
function pruneEmptyDirs(dir, specsRoot) {
|
|
@@ -5028,7 +5039,7 @@ function pruneEmptyDirs(dir, specsRoot) {
|
|
|
5028
5039
|
while (at !== specsRoot && at.startsWith(specsRoot)) {
|
|
5029
5040
|
if (!fs5.existsSync(at) || fs5.readdirSync(at).length > 0) return;
|
|
5030
5041
|
fs5.rmdirSync(at);
|
|
5031
|
-
at =
|
|
5042
|
+
at = path6.dirname(at);
|
|
5032
5043
|
}
|
|
5033
5044
|
}
|
|
5034
5045
|
|
|
@@ -5206,7 +5217,13 @@ var PublicInterfaceSchema = import_zod8.z.object({
|
|
|
5206
5217
|
/** The L2 component that realizes this public interface (the subsystem's published surface). */
|
|
5207
5218
|
component: SpecIdSchema.optional(),
|
|
5208
5219
|
/** Optional L3 interface on that component backing this entry. */
|
|
5209
|
-
interface: SpecIdSchema.optional()
|
|
5220
|
+
interface: SpecIdSchema.optional(),
|
|
5221
|
+
/**
|
|
5222
|
+
* The subsystems this surface is published to. Absent, anyone may depend on
|
|
5223
|
+
* it; present, only these subsystems may — when every entry publishing the
|
|
5224
|
+
* component names consumers, the union of those lists is the whole set.
|
|
5225
|
+
*/
|
|
5226
|
+
consumers: import_zod8.z.array(SpecIdSchema).optional()
|
|
5210
5227
|
});
|
|
5211
5228
|
var TrustedLinkSchema = import_zod8.z.object({
|
|
5212
5229
|
/** The peer subsystem id this link sanctions tight coupling with. */
|
|
@@ -6580,7 +6597,7 @@ function jumpFieldsOf(s) {
|
|
|
6580
6597
|
}
|
|
6581
6598
|
|
|
6582
6599
|
// src/models/code-model.ts
|
|
6583
|
-
var
|
|
6600
|
+
var path7 = __toESM(require("path"));
|
|
6584
6601
|
function pathKey(sourcePath) {
|
|
6585
6602
|
return sourcePath.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
6586
6603
|
}
|
|
@@ -6615,7 +6632,7 @@ function hasFunctionBody(facts, symbol) {
|
|
|
6615
6632
|
}
|
|
6616
6633
|
function resolveImport(fromFile, specifier, knownPaths) {
|
|
6617
6634
|
if (!specifier.startsWith(".")) return void 0;
|
|
6618
|
-
const joined = pathKey(
|
|
6635
|
+
const joined = pathKey(path7.posix.normalize(path7.posix.join(path7.posix.dirname(fromFile), specifier)));
|
|
6619
6636
|
const candidates = [
|
|
6620
6637
|
joined,
|
|
6621
6638
|
joined.replace(/\.js$/, ".ts"),
|
|
@@ -6711,7 +6728,7 @@ function resolveNarrativeLabels(methodName, steps) {
|
|
|
6711
6728
|
|
|
6712
6729
|
// src/core/canvas.ts
|
|
6713
6730
|
var fs6 = __toESM(require("fs"));
|
|
6714
|
-
var
|
|
6731
|
+
var path8 = __toESM(require("path"));
|
|
6715
6732
|
|
|
6716
6733
|
// src/core/canvas-layout.ts
|
|
6717
6734
|
function computeLayout(model, collapsed) {
|
|
@@ -7370,9 +7387,9 @@ function embedJson(value) {
|
|
|
7370
7387
|
}
|
|
7371
7388
|
function loadCytoscapeLib() {
|
|
7372
7389
|
const candidates = [
|
|
7373
|
-
|
|
7390
|
+
path8.resolve(__dirname, "..", "templates", "canvas", "cytoscape.min.js"),
|
|
7374
7391
|
// src/core & dist/cli
|
|
7375
|
-
|
|
7392
|
+
path8.resolve(__dirname, "templates", "canvas", "cytoscape.min.js")
|
|
7376
7393
|
// dist (library entry)
|
|
7377
7394
|
];
|
|
7378
7395
|
for (const p of candidates) {
|
|
@@ -11544,10 +11561,47 @@ var MODEL = __MODEL_JSON__;
|
|
|
11544
11561
|
</html>
|
|
11545
11562
|
`;
|
|
11546
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
|
+
|
|
11547
11601
|
// src/core/extensions.ts
|
|
11548
|
-
var
|
|
11602
|
+
var fs9 = __toESM(require("fs"));
|
|
11549
11603
|
var os2 = __toESM(require("os"));
|
|
11550
|
-
var
|
|
11604
|
+
var path12 = __toESM(require("path"));
|
|
11551
11605
|
var import_module = require("module");
|
|
11552
11606
|
var import_zod9 = require("zod");
|
|
11553
11607
|
|
|
@@ -11575,12 +11629,12 @@ function isNewerVersion(current2, candidate) {
|
|
|
11575
11629
|
|
|
11576
11630
|
// src/core/packstore.ts
|
|
11577
11631
|
var crypto2 = __toESM(require("crypto"));
|
|
11578
|
-
var
|
|
11579
|
-
var
|
|
11632
|
+
var fs8 = __toESM(require("fs"));
|
|
11633
|
+
var path11 = __toESM(require("path"));
|
|
11580
11634
|
|
|
11581
11635
|
// src/config/defaults.ts
|
|
11582
11636
|
var os = __toESM(require("os"));
|
|
11583
|
-
var
|
|
11637
|
+
var path10 = __toESM(require("path"));
|
|
11584
11638
|
var DEFAULT_TARGET_DIRS = {
|
|
11585
11639
|
claude: ".claude/agents",
|
|
11586
11640
|
gemini: ".gemini/agents",
|
|
@@ -11596,7 +11650,7 @@ function defaultTargetConfig(type) {
|
|
|
11596
11650
|
enabled: true
|
|
11597
11651
|
};
|
|
11598
11652
|
}
|
|
11599
|
-
var WAIRON_VERSION = "5.1.1-dev.
|
|
11653
|
+
var WAIRON_VERSION = "5.1.1-dev.73";
|
|
11600
11654
|
var GITHUB_REPO = "SYW-Apps/Waffle-AIron";
|
|
11601
11655
|
var ARCHITECT_AGENT_ID = "agent-architect";
|
|
11602
11656
|
var ARCHITECT_TEMPLATE_ID = "architect";
|
|
@@ -11607,7 +11661,7 @@ function globalTemplatesDir(projectOverride) {
|
|
|
11607
11661
|
if (projectOverride) {
|
|
11608
11662
|
return projectOverride;
|
|
11609
11663
|
}
|
|
11610
|
-
return
|
|
11664
|
+
return path10.join(os.homedir(), ".wairon", "templates");
|
|
11611
11665
|
}
|
|
11612
11666
|
var BACKEND_COMMANDS = {
|
|
11613
11667
|
claude: "claude",
|
|
@@ -11643,7 +11697,7 @@ function packStoreDir() {
|
|
|
11643
11697
|
function packFiles(dir, prefix = "") {
|
|
11644
11698
|
let entries;
|
|
11645
11699
|
try {
|
|
11646
|
-
entries =
|
|
11700
|
+
entries = fs8.readdirSync(dir, { withFileTypes: true });
|
|
11647
11701
|
} catch {
|
|
11648
11702
|
return [];
|
|
11649
11703
|
}
|
|
@@ -11651,25 +11705,25 @@ function packFiles(dir, prefix = "") {
|
|
|
11651
11705
|
for (const e of entries) {
|
|
11652
11706
|
if (DIGEST_EXCLUDED.has(e.name)) continue;
|
|
11653
11707
|
const rel2 = prefix ? `${prefix}/${e.name}` : e.name;
|
|
11654
|
-
if (e.isDirectory()) out.push(...packFiles(
|
|
11708
|
+
if (e.isDirectory()) out.push(...packFiles(path11.join(dir, e.name), rel2));
|
|
11655
11709
|
else if (e.isFile()) out.push(rel2);
|
|
11656
11710
|
}
|
|
11657
11711
|
return out.sort();
|
|
11658
11712
|
}
|
|
11659
11713
|
function computePackDigest(packDir) {
|
|
11660
11714
|
const hash = crypto2.createHash("sha256");
|
|
11661
|
-
const abs =
|
|
11715
|
+
const abs = path11.resolve(packDir);
|
|
11662
11716
|
let isFile = false;
|
|
11663
11717
|
try {
|
|
11664
|
-
isFile =
|
|
11718
|
+
isFile = fs8.statSync(abs).isFile();
|
|
11665
11719
|
} catch {
|
|
11666
11720
|
}
|
|
11667
|
-
const entries = isFile ? [[
|
|
11721
|
+
const entries = isFile ? [[path11.basename(abs), abs]] : packFiles(abs).map((rel2) => [rel2, path11.join(abs, rel2)]);
|
|
11668
11722
|
for (const [rel2, full] of entries) {
|
|
11669
11723
|
hash.update(rel2);
|
|
11670
11724
|
hash.update("\0");
|
|
11671
11725
|
try {
|
|
11672
|
-
hash.update(
|
|
11726
|
+
hash.update(fs8.readFileSync(full));
|
|
11673
11727
|
} catch {
|
|
11674
11728
|
}
|
|
11675
11729
|
hash.update("\0");
|
|
@@ -11678,7 +11732,7 @@ function computePackDigest(packDir) {
|
|
|
11678
11732
|
}
|
|
11679
11733
|
function readInstallRecord(packPath) {
|
|
11680
11734
|
try {
|
|
11681
|
-
const raw = readYamlFile(
|
|
11735
|
+
const raw = readYamlFile(path11.join(packPath, INSTALL_RECORD));
|
|
11682
11736
|
return raw && typeof raw === "object" ? raw : {};
|
|
11683
11737
|
} catch {
|
|
11684
11738
|
return {};
|
|
@@ -11709,14 +11763,14 @@ function installedFrom(location, name, version) {
|
|
|
11709
11763
|
function versionedEntries(nameDir, fallbackName) {
|
|
11710
11764
|
let versions;
|
|
11711
11765
|
try {
|
|
11712
|
-
versions =
|
|
11766
|
+
versions = fs8.readdirSync(nameDir, { withFileTypes: true });
|
|
11713
11767
|
} catch {
|
|
11714
11768
|
return [];
|
|
11715
11769
|
}
|
|
11716
11770
|
const out = [];
|
|
11717
11771
|
for (const v of versions) {
|
|
11718
11772
|
if (!v.isDirectory()) continue;
|
|
11719
|
-
const versionDir =
|
|
11773
|
+
const versionDir = path11.join(nameDir, v.name);
|
|
11720
11774
|
const entryFile = packDirEntry(versionDir);
|
|
11721
11775
|
if (!entryFile) continue;
|
|
11722
11776
|
out.push(installedFrom(versionDir, declaredName(entryFile) ?? fallbackName, v.name));
|
|
@@ -11724,7 +11778,7 @@ function versionedEntries(nameDir, fallbackName) {
|
|
|
11724
11778
|
return out;
|
|
11725
11779
|
}
|
|
11726
11780
|
function storeEntryPacks(store, entry) {
|
|
11727
|
-
const full =
|
|
11781
|
+
const full = path11.join(store, entry.name);
|
|
11728
11782
|
if (entry.isFile()) {
|
|
11729
11783
|
if (!PACK_FILE_RE.test(entry.name)) return [];
|
|
11730
11784
|
const name = declaredName(full) ?? entry.name.replace(PACK_FILE_RE, "");
|
|
@@ -11739,7 +11793,7 @@ function listInstalledPacks() {
|
|
|
11739
11793
|
const store = packStoreDir();
|
|
11740
11794
|
let entries;
|
|
11741
11795
|
try {
|
|
11742
|
-
entries =
|
|
11796
|
+
entries = fs8.readdirSync(store, { withFileTypes: true });
|
|
11743
11797
|
} catch {
|
|
11744
11798
|
return [];
|
|
11745
11799
|
}
|
|
@@ -11756,17 +11810,17 @@ function resolveInstalledPack(name, version) {
|
|
|
11756
11810
|
return candidates[0];
|
|
11757
11811
|
}
|
|
11758
11812
|
function installPackFromDirectory(sourceDir, origin) {
|
|
11759
|
-
const abs =
|
|
11813
|
+
const abs = path11.resolve(sourceDir);
|
|
11760
11814
|
const entryFile = packDirEntry(abs);
|
|
11761
11815
|
if (!entryFile) {
|
|
11762
11816
|
throw new Error(`"${sourceDir}" is not a pack directory (no pack.yaml | pack.cjs | index.cjs | \u2026).`);
|
|
11763
11817
|
}
|
|
11764
|
-
const manifest = readManifest(entryFile,
|
|
11818
|
+
const manifest = readManifest(entryFile, path11.dirname(entryFile));
|
|
11765
11819
|
const version = manifest.version && manifest.version.length > 0 ? manifest.version : UNVERSIONED;
|
|
11766
|
-
const dest =
|
|
11767
|
-
|
|
11768
|
-
|
|
11769
|
-
|
|
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 });
|
|
11770
11824
|
const digest2 = computePackDigest(dest);
|
|
11771
11825
|
const record = {
|
|
11772
11826
|
origin,
|
|
@@ -11774,7 +11828,7 @@ function installPackFromDirectory(sourceDir, origin) {
|
|
|
11774
11828
|
waironVersion: WAIRON_VERSION,
|
|
11775
11829
|
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
11776
11830
|
};
|
|
11777
|
-
writeYamlFile(
|
|
11831
|
+
writeYamlFile(path11.join(dest, INSTALL_RECORD), record);
|
|
11778
11832
|
return {
|
|
11779
11833
|
name: manifest.name,
|
|
11780
11834
|
version,
|
|
@@ -11789,11 +11843,11 @@ function uninstallPack(name, version) {
|
|
|
11789
11843
|
const targets = listInstalledPacks().filter((p) => p.name === name && (!version || p.version === version));
|
|
11790
11844
|
if (targets.length === 0) return false;
|
|
11791
11845
|
for (const target of targets) {
|
|
11792
|
-
|
|
11793
|
-
const parent =
|
|
11794
|
-
if (
|
|
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;
|
|
11795
11849
|
try {
|
|
11796
|
-
if (
|
|
11850
|
+
if (fs8.readdirSync(parent).length === 0) fs8.rmdirSync(parent);
|
|
11797
11851
|
} catch {
|
|
11798
11852
|
}
|
|
11799
11853
|
}
|
|
@@ -11944,6 +11998,10 @@ function skillExtendErrors(skills) {
|
|
|
11944
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(", ")}).`);
|
|
11945
11999
|
}
|
|
11946
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
|
+
}
|
|
11947
12005
|
function globalPacksEnabled(config) {
|
|
11948
12006
|
return config.extensions?.useGlobalPacks ?? GLOBAL_PACKS_DEFAULT;
|
|
11949
12007
|
}
|
|
@@ -11951,27 +12009,27 @@ function emptyExtensions() {
|
|
|
11951
12009
|
return { packNames: [], packs: [], rules: [], profiles: {}, languages: {}, skills: [], patterns: [], guarantees: [], assertions: [], instructions: [], errors: [], selectionFailures: [] };
|
|
11952
12010
|
}
|
|
11953
12011
|
function globalPacksDir() {
|
|
11954
|
-
return process.env.WAIRON_PACKS_DIR ??
|
|
12012
|
+
return process.env.WAIRON_PACKS_DIR ?? path12.join(os2.homedir(), ".wairon", "packs");
|
|
11955
12013
|
}
|
|
11956
12014
|
var PACK_DIR_ENTRIES = ["pack.yaml", "pack.yml", "pack.cjs", "pack.js", "index.cjs", "index.js"];
|
|
11957
12015
|
function packDirEntry(dir) {
|
|
11958
12016
|
for (const name of PACK_DIR_ENTRIES) {
|
|
11959
|
-
const p =
|
|
11960
|
-
if (
|
|
12017
|
+
const p = path12.join(dir, name);
|
|
12018
|
+
if (fs9.existsSync(p)) return p;
|
|
11961
12019
|
}
|
|
11962
12020
|
return null;
|
|
11963
12021
|
}
|
|
11964
12022
|
function latestVersionDir(nameDir) {
|
|
11965
12023
|
let versions;
|
|
11966
12024
|
try {
|
|
11967
|
-
versions =
|
|
12025
|
+
versions = fs9.readdirSync(nameDir, { withFileTypes: true });
|
|
11968
12026
|
} catch {
|
|
11969
12027
|
return null;
|
|
11970
12028
|
}
|
|
11971
12029
|
let best = null;
|
|
11972
12030
|
for (const v of versions) {
|
|
11973
12031
|
if (!v.isDirectory()) continue;
|
|
11974
|
-
const dir =
|
|
12032
|
+
const dir = path12.join(nameDir, v.name);
|
|
11975
12033
|
if (!packDirEntry(dir)) continue;
|
|
11976
12034
|
if (!best || isNewerVersion(best.version, v.name)) best = { version: v.name, dir };
|
|
11977
12035
|
}
|
|
@@ -11980,13 +12038,13 @@ function latestVersionDir(nameDir) {
|
|
|
11980
12038
|
function discoverPacks(dir) {
|
|
11981
12039
|
let entries;
|
|
11982
12040
|
try {
|
|
11983
|
-
entries =
|
|
12041
|
+
entries = fs9.readdirSync(dir, { withFileTypes: true });
|
|
11984
12042
|
} catch {
|
|
11985
12043
|
return [];
|
|
11986
12044
|
}
|
|
11987
12045
|
const refs = [];
|
|
11988
12046
|
for (const e of entries.sort((a, b) => compareOrdinal(a.name, b.name))) {
|
|
11989
|
-
const full =
|
|
12047
|
+
const full = path12.join(dir, e.name);
|
|
11990
12048
|
if (e.isDirectory()) {
|
|
11991
12049
|
if (packDirEntry(full)) refs.push(full);
|
|
11992
12050
|
else {
|
|
@@ -12016,7 +12074,7 @@ function mergePack(out, pack, ref, scope, packDir) {
|
|
|
12016
12074
|
foreignBuiltins: [.../* @__PURE__ */ new Set([...existing.foreignBuiltins, ...def.foreignBuiltins])]
|
|
12017
12075
|
} : def;
|
|
12018
12076
|
}
|
|
12019
|
-
for (const s of pack.skills) out.skills.push({ ...s, pack: pack.name, packVersion: pack.version, sourcePath:
|
|
12077
|
+
for (const s of pack.skills) out.skills.push({ ...s, pack: pack.name, packVersion: pack.version, sourcePath: path12.resolve(packDir, s.source) });
|
|
12020
12078
|
for (const p of pack.patterns) out.patterns.push({ ...p, pack: pack.name });
|
|
12021
12079
|
out.guarantees = [.../* @__PURE__ */ new Set([...out.guarantees, ...pack.guarantees])];
|
|
12022
12080
|
for (const a of pack.assertions) out.assertions.push({ ...a, pack: pack.name, fullCode: assertionFullCode(pack.name, a.code) });
|
|
@@ -12024,10 +12082,10 @@ function mergePack(out, pack, ref, scope, packDir) {
|
|
|
12024
12082
|
}
|
|
12025
12083
|
var isYamlPath = (p) => /\.ya?ml$/i.test(p);
|
|
12026
12084
|
function resolvePackRef(ref, projectRoot) {
|
|
12027
|
-
const pathLike = ref.startsWith(".") ||
|
|
12085
|
+
const pathLike = ref.startsWith(".") || path12.isAbsolute(ref) || isYamlPath(ref);
|
|
12028
12086
|
if (!pathLike) return ref;
|
|
12029
|
-
const resolved =
|
|
12030
|
-
if (
|
|
12087
|
+
const resolved = path12.resolve(projectRoot, ref);
|
|
12088
|
+
if (fs9.existsSync(resolved) && fs9.statSync(resolved).isDirectory()) {
|
|
12031
12089
|
const entry = packDirEntry(resolved);
|
|
12032
12090
|
if (!entry) throw new Error(`directory pack has no entry file (${PACK_DIR_ENTRIES.join(" | ")})`);
|
|
12033
12091
|
return entry;
|
|
@@ -12040,7 +12098,7 @@ function readManifest(target, projectRoot) {
|
|
|
12040
12098
|
if (raw == null) throw new Error("file not found or empty");
|
|
12041
12099
|
return { ...DeclarativePackSchema.parse(raw), rules: [] };
|
|
12042
12100
|
}
|
|
12043
|
-
const req = (0, import_module.createRequire)(
|
|
12101
|
+
const req = (0, import_module.createRequire)(path12.join(projectRoot, "package.json"));
|
|
12044
12102
|
const modRaw = req(target);
|
|
12045
12103
|
const mod = modRaw?.default ?? modRaw;
|
|
12046
12104
|
const parsed = DeclarativePackSchema.parse({
|
|
@@ -12068,7 +12126,7 @@ function loadExtensionPacks(refs, projectRoot) {
|
|
|
12068
12126
|
try {
|
|
12069
12127
|
const target = resolvePackRef(ref, projectRoot);
|
|
12070
12128
|
const manifest = readManifest(target, projectRoot);
|
|
12071
|
-
mergePack(out, manifest, ref, scope,
|
|
12129
|
+
mergePack(out, manifest, ref, scope, path12.dirname(target));
|
|
12072
12130
|
for (const r of manifest.rules) out.rules.push(r);
|
|
12073
12131
|
} catch (e) {
|
|
12074
12132
|
out.errors.push(`Extension pack "${ref}" failed to load: ${e instanceof Error ? e.message : String(e)}`);
|
|
@@ -12114,7 +12172,7 @@ function defaultPackSelections() {
|
|
|
12114
12172
|
const entry = packDirEntry(pack.path) ?? pack.path;
|
|
12115
12173
|
let manifest;
|
|
12116
12174
|
try {
|
|
12117
|
-
manifest = readManifest(entry,
|
|
12175
|
+
manifest = readManifest(entry, path12.dirname(entry));
|
|
12118
12176
|
} catch {
|
|
12119
12177
|
continue;
|
|
12120
12178
|
}
|
|
@@ -12130,6 +12188,66 @@ function defaultPackSelections() {
|
|
|
12130
12188
|
return [];
|
|
12131
12189
|
}
|
|
12132
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
|
+
}
|
|
12133
12251
|
function resolveSelection(selection, projectRoot) {
|
|
12134
12252
|
const wanted = selection.version ? `${selection.name}@${selection.version}` : selection.name;
|
|
12135
12253
|
const fail = (code, message) => ({ failure: { code, severity: "error", name: selection.name, message } });
|
|
@@ -12171,7 +12289,7 @@ function verifyIntegrity(selection, packDir, where) {
|
|
|
12171
12289
|
};
|
|
12172
12290
|
}
|
|
12173
12291
|
function detectBundleStoreDrift(selection, bundleDir) {
|
|
12174
|
-
const bundledVersion =
|
|
12292
|
+
const bundledVersion = path12.basename(bundleDir);
|
|
12175
12293
|
const installed = resolveInstalledPack(selection.name, bundledVersion);
|
|
12176
12294
|
if (!installed) return void 0;
|
|
12177
12295
|
const bundleDigest = computePackDigest(bundleDir);
|
|
@@ -12185,22 +12303,22 @@ function detectBundleStoreDrift(selection, bundleDir) {
|
|
|
12185
12303
|
};
|
|
12186
12304
|
}
|
|
12187
12305
|
function findBundledPack(projectRoot, selection) {
|
|
12188
|
-
const base =
|
|
12306
|
+
const base = path12.join(projectRoot, ".wai", "packs", selection.name);
|
|
12189
12307
|
if (selection.version) {
|
|
12190
|
-
const pinned =
|
|
12308
|
+
const pinned = path12.join(base, selection.version);
|
|
12191
12309
|
return packDirEntry(pinned) ? pinned : null;
|
|
12192
12310
|
}
|
|
12193
12311
|
if (packDirEntry(base)) return base;
|
|
12194
12312
|
let versions;
|
|
12195
12313
|
try {
|
|
12196
|
-
versions =
|
|
12314
|
+
versions = fs9.readdirSync(base, { withFileTypes: true });
|
|
12197
12315
|
} catch {
|
|
12198
12316
|
return null;
|
|
12199
12317
|
}
|
|
12200
12318
|
let best = null;
|
|
12201
12319
|
for (const v of versions) {
|
|
12202
12320
|
if (!v.isDirectory()) continue;
|
|
12203
|
-
const dir =
|
|
12321
|
+
const dir = path12.join(base, v.name);
|
|
12204
12322
|
if (!packDirEntry(dir)) continue;
|
|
12205
12323
|
if (!best || isNewerVersion(best.version, v.name)) best = { version: v.name, dir };
|
|
12206
12324
|
}
|
|
@@ -12243,21 +12361,21 @@ function buildCodeIndex(model) {
|
|
|
12243
12361
|
const declarations = /* @__PURE__ */ new Map();
|
|
12244
12362
|
const anchors = /* @__PURE__ */ new Map();
|
|
12245
12363
|
const findingAnchors = /* @__PURE__ */ new Map();
|
|
12246
|
-
const namesAt = (cache,
|
|
12247
|
-
const cached = cache.get(
|
|
12364
|
+
const namesAt = (cache, path29, make) => {
|
|
12365
|
+
const cached = cache.get(path29);
|
|
12248
12366
|
if (cached) return cached;
|
|
12249
|
-
const f = facts.get(
|
|
12367
|
+
const f = facts.get(path29);
|
|
12250
12368
|
if (!f) return NO_NAMES;
|
|
12251
12369
|
const built = make(f);
|
|
12252
|
-
cache.set(
|
|
12370
|
+
cache.set(path29, built);
|
|
12253
12371
|
return built;
|
|
12254
12372
|
};
|
|
12255
12373
|
const republished = /* @__PURE__ */ new Map();
|
|
12256
|
-
const republishedFrom = (
|
|
12257
|
-
const cached = republished.get(
|
|
12374
|
+
const republishedFrom = (path29) => {
|
|
12375
|
+
const cached = republished.get(path29);
|
|
12258
12376
|
if (cached) return cached;
|
|
12259
|
-
const out = /* @__PURE__ */ new Set([
|
|
12260
|
-
const queue = [
|
|
12377
|
+
const out = /* @__PURE__ */ new Set([path29]);
|
|
12378
|
+
const queue = [path29];
|
|
12261
12379
|
while (queue.length) {
|
|
12262
12380
|
const from = queue.pop();
|
|
12263
12381
|
const f = facts.get(from);
|
|
@@ -12270,7 +12388,7 @@ function buildCodeIndex(model) {
|
|
|
12270
12388
|
}
|
|
12271
12389
|
}
|
|
12272
12390
|
}
|
|
12273
|
-
republished.set(
|
|
12391
|
+
republished.set(path29, out);
|
|
12274
12392
|
return out;
|
|
12275
12393
|
};
|
|
12276
12394
|
const NO_ORIGIN = /* @__PURE__ */ new Set();
|
|
@@ -12279,9 +12397,9 @@ function buildCodeIndex(model) {
|
|
|
12279
12397
|
return to ? republishedFrom(to) : NO_ORIGIN;
|
|
12280
12398
|
};
|
|
12281
12399
|
const scopeOf = (site, from) => {
|
|
12282
|
-
const
|
|
12283
|
-
const f = facts.get(
|
|
12284
|
-
return f?.status === "analyzed" && f.analysisGrade === "exact" ? { path:
|
|
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;
|
|
12285
12403
|
};
|
|
12286
12404
|
const originOf2 = (site, from) => {
|
|
12287
12405
|
const resolved = scopeOf(site, from);
|
|
@@ -12320,14 +12438,14 @@ function buildCodeIndex(model) {
|
|
|
12320
12438
|
if (site.via) for (const typeName of localTypesOf(f, site.via)) widenThroughType(typeName);
|
|
12321
12439
|
return out;
|
|
12322
12440
|
};
|
|
12323
|
-
const declarationsAt = (
|
|
12441
|
+
const declarationsAt = (path29) => namesAt(declarations, pathKey(path29), (f) => /* @__PURE__ */ new Set([...f.declaredNames, ...f.exportedNames]));
|
|
12324
12442
|
return {
|
|
12325
12443
|
paths,
|
|
12326
12444
|
exactPaths,
|
|
12327
|
-
factsAt: (
|
|
12445
|
+
factsAt: (path29) => facts.get(pathKey(path29)),
|
|
12328
12446
|
declarationsAt,
|
|
12329
|
-
anchorsAt: (
|
|
12330
|
-
findingAnchorsAt: (
|
|
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)),
|
|
12331
12449
|
originOf: originOf2,
|
|
12332
12450
|
possibleOriginsOf
|
|
12333
12451
|
};
|
|
@@ -12365,10 +12483,10 @@ function buildRealizationIndex(ctx) {
|
|
|
12365
12483
|
return {
|
|
12366
12484
|
paths,
|
|
12367
12485
|
implementationsOf: (compId) => implsByComponent.get(compId) ?? NONE_IMPL,
|
|
12368
|
-
implementationsAt: (
|
|
12486
|
+
implementationsAt: (path29) => implsByPath.get(pathKey(path29)) ?? NONE_IMPL,
|
|
12369
12487
|
filesOf: (compId) => filesByComponent.get(compId) ?? NONE_PATH,
|
|
12370
12488
|
filesIn: (subsystemId) => filesBySubsystem.get(subsystemId) ?? NONE_PATH,
|
|
12371
|
-
componentsAt: (
|
|
12489
|
+
componentsAt: (path29) => componentsByPath.get(pathKey(path29)) ?? NONE_COMP
|
|
12372
12490
|
};
|
|
12373
12491
|
}
|
|
12374
12492
|
function buildImportGraph(index, universe) {
|
|
@@ -12380,22 +12498,22 @@ function buildImportGraph(index, universe) {
|
|
|
12380
12498
|
if (to && to !== from) into.add(to);
|
|
12381
12499
|
}
|
|
12382
12500
|
};
|
|
12383
|
-
const importsOf = (
|
|
12384
|
-
const cached = imports.get(
|
|
12501
|
+
const importsOf = (path29) => {
|
|
12502
|
+
const cached = imports.get(path29);
|
|
12385
12503
|
if (cached) return cached;
|
|
12386
|
-
const facts = index.factsAt(
|
|
12504
|
+
const facts = index.factsAt(path29);
|
|
12387
12505
|
const out = /* @__PURE__ */ new Set();
|
|
12388
|
-
if (facts?.status === "analyzed") resolveAll(
|
|
12389
|
-
imports.set(
|
|
12506
|
+
if (facts?.status === "analyzed") resolveAll(path29, facts.imports, out);
|
|
12507
|
+
imports.set(path29, out);
|
|
12390
12508
|
return out;
|
|
12391
12509
|
};
|
|
12392
|
-
const tracesOf = (
|
|
12393
|
-
const cached = traces.get(
|
|
12510
|
+
const tracesOf = (path29) => {
|
|
12511
|
+
const cached = traces.get(path29);
|
|
12394
12512
|
if (cached) return cached;
|
|
12395
|
-
const facts = index.factsAt(
|
|
12396
|
-
const out = new Set(importsOf(
|
|
12397
|
-
if (facts?.status === "analyzed") resolveAll(
|
|
12398
|
-
traces.set(
|
|
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);
|
|
12399
12517
|
return out;
|
|
12400
12518
|
};
|
|
12401
12519
|
return {
|
|
@@ -12779,6 +12897,32 @@ var publicSurfaceBindingRule = {
|
|
|
12779
12897
|
}
|
|
12780
12898
|
};
|
|
12781
12899
|
|
|
12900
|
+
// src/core/rules/integrity/public-surface-consumers.ts
|
|
12901
|
+
var publicSurfaceConsumersRule = {
|
|
12902
|
+
name: "public-surface-consumers",
|
|
12903
|
+
description: "Every subsystem a published surface names as its consumer must exist in the tree. A consumers list restricts who may depend on the surface, so an id that names nothing locks the surface against a caller nobody can be \u2014 and a typo there silently locks out the caller that was meant, which the boundary rule would then report against the wrong party.",
|
|
12904
|
+
codes: [
|
|
12905
|
+
{ code: "PUBLIC_INTERFACE_UNKNOWN_CONSUMER", defaultSeverity: "error", summary: "A published surface names as its consumer a subsystem the tree does not have" }
|
|
12906
|
+
],
|
|
12907
|
+
check(ctx) {
|
|
12908
|
+
const known = new Set(ctx.subsystems.map((s) => s.id));
|
|
12909
|
+
for (const sub of ctx.subsystems) {
|
|
12910
|
+
for (const pi of sub.publicInterfaces) {
|
|
12911
|
+
for (const consumer of pi.consumers ?? []) {
|
|
12912
|
+
if (known.has(consumer)) continue;
|
|
12913
|
+
ctx.addIssue(
|
|
12914
|
+
"error",
|
|
12915
|
+
"PUBLIC_INTERFACE_UNKNOWN_CONSUMER",
|
|
12916
|
+
`Subsystem "${sub.id}" publishes "${pi.component ?? `${pi.type} ${pi.details}`}" to consumer "${consumer}", which names no subsystem of this tree. Name an existing subsystem, or drop the id \u2014 a consumers list admits only the subsystems it names.`,
|
|
12917
|
+
sub.id,
|
|
12918
|
+
isDraftSubsystem(sub)
|
|
12919
|
+
);
|
|
12920
|
+
}
|
|
12921
|
+
}
|
|
12922
|
+
}
|
|
12923
|
+
}
|
|
12924
|
+
};
|
|
12925
|
+
|
|
12782
12926
|
// src/core/rules/integrity/public-surface-declared-type.ts
|
|
12783
12927
|
var pubTypeMatches = (piType, ct, portalType) => {
|
|
12784
12928
|
switch (piType) {
|
|
@@ -13706,11 +13850,11 @@ var unconditionalCallCyclesRule = {
|
|
|
13706
13850
|
const memberEdges = keys.flatMap((k) => (adjacency.get(k) ?? []).filter((e) => inScc.has(e.toKey)));
|
|
13707
13851
|
if (memberEdges.length === 0) continue;
|
|
13708
13852
|
const anchor = [...memberEdges].sort((a, b) => byCodeUnit(a.fromKey, b.fromKey) || byCodeUnit(a.impl.id, b.impl.id) || a.stepNumber - b.stepNumber)[0];
|
|
13709
|
-
const
|
|
13853
|
+
const path29 = [...keys].sort(byCodeUnit).join(" \u2192 ");
|
|
13710
13854
|
ctx.addIssue(
|
|
13711
13855
|
"warning",
|
|
13712
13856
|
"UNCONDITIONAL_CALL_CYCLE",
|
|
13713
|
-
`Call cycle with no guard: ${
|
|
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.`,
|
|
13714
13858
|
anchor.impl.id,
|
|
13715
13859
|
memberEdges.some((e) => ctx.isImplementationDraft(e.impl))
|
|
13716
13860
|
);
|
|
@@ -14148,14 +14292,15 @@ var authSourceWiringRule = {
|
|
|
14148
14292
|
// src/core/rules/doctrine/subsystem-boundary-dependencies.ts
|
|
14149
14293
|
var subsystemBoundaryDepsRule = {
|
|
14150
14294
|
name: "subsystem-boundary-dependencies",
|
|
14151
|
-
description: "Judges every dependsOn edge that leaves its own subsystem, and every one that resolves nowhere. Across subsystems the shape is client Adapter \u2192 published remote Portal, OR a direct in-process edge licensed by a trustedLink declared on the SOURCE subsystem (the published-Portal target requirement applies either way). A reference that names nothing in this tree is resolved against the stored surface snapshots: a hit is a DECLARED remote portal and the same Adapter requirement applies to it, snapshots of several providers that disagree make the reference ambiguous, and a reference authored to leave this root that no snapshot covers warns instead of erroring. Boundary rules are never relaxed by a pack profile.",
|
|
14295
|
+
description: "Judges every dependsOn edge that leaves its own subsystem, and every one that resolves nowhere. Across subsystems the shape is client Adapter \u2192 published remote Portal, OR a direct in-process edge licensed by a trustedLink declared on the SOURCE subsystem (the published-Portal target requirement applies either way). A published surface may also name the subsystems it serves (a publicInterfaces entry's consumers): a component every one of whose entries names consumers may be depended on only from those subsystems, which is how a provider keeps a surface \u2014 the raw spec writes \u2014 away from a door that must not reach it. A reference that names nothing in this tree is resolved against the stored surface snapshots: a hit is a DECLARED remote portal and the same Adapter requirement applies to it, snapshots of several providers that disagree make the reference ambiguous, and a reference authored to leave this root that no snapshot covers warns instead of erroring. Boundary rules are never relaxed by a pack profile.",
|
|
14152
14296
|
codes: [
|
|
14153
14297
|
{ code: "INVALID_DEPENDENCY_REFERENCE", defaultSeverity: "error", summary: "dependsOn names a non-existent component" },
|
|
14154
14298
|
{ code: "CROSS_TREE_REF_UNRESOLVED", defaultSeverity: "warning", summary: "Cross-tree dependsOn (super::/:: form) with no surface snapshot covering it" },
|
|
14155
14299
|
{ code: "SURFACE_REF_AMBIGUOUS", defaultSeverity: "error", summary: "Cross-tree dependsOn matched by surface snapshots of several providers with different contracts" },
|
|
14156
14300
|
{ code: "CROSS_SUBSYSTEM_NON_ADAPTER", defaultSeverity: "error", summary: "Non-Adapter component crossing a subsystem boundary" },
|
|
14157
14301
|
{ code: "CROSS_SUBSYSTEM_PRIVATE_ACCESS", defaultSeverity: "error", summary: "Cross-subsystem dependency on an unpublished component" },
|
|
14158
|
-
{ code: "CROSS_SUBSYSTEM_TARGET_NON_PORTAL", defaultSeverity: "error", summary: "Cross-subsystem hop entering through a non-Portal" }
|
|
14302
|
+
{ code: "CROSS_SUBSYSTEM_TARGET_NON_PORTAL", defaultSeverity: "error", summary: "Cross-subsystem hop entering through a non-Portal" },
|
|
14303
|
+
{ code: "CROSS_SUBSYSTEM_UNLISTED_CONSUMER", defaultSeverity: "error", summary: "Cross-subsystem dependency on a surface published only to other subsystems" }
|
|
14159
14304
|
],
|
|
14160
14305
|
check(ctx) {
|
|
14161
14306
|
for (const edge of ctx.dependencyEdges().all) {
|
|
@@ -14238,9 +14383,24 @@ var subsystemBoundaryDepsRule = {
|
|
|
14238
14383
|
edge.draftContext
|
|
14239
14384
|
);
|
|
14240
14385
|
}
|
|
14386
|
+
const publishedTo = restrictedConsumers(ctx, depComp.subsystem, depComp.id);
|
|
14387
|
+
if (publishedTo && !publishedTo.includes(comp.subsystem)) {
|
|
14388
|
+
ctx.addIssue(
|
|
14389
|
+
"error",
|
|
14390
|
+
"CROSS_SUBSYSTEM_UNLISTED_CONSUMER",
|
|
14391
|
+
`Boundary violation: "${comp.id}" (subsystem "${comp.subsystem}") depends on "${depComp.id}", which subsystem "${depComp.subsystem}" publishes only to ${publishedTo.map((s) => `"${s}"`).join(", ")}. Depend on a surface published to "${comp.subsystem}" instead, or \u2014 when "${comp.subsystem}" really is a caller the provider meant to serve \u2014 add it to the entry's consumers.`,
|
|
14392
|
+
comp.id,
|
|
14393
|
+
edge.draftContext
|
|
14394
|
+
);
|
|
14395
|
+
}
|
|
14241
14396
|
}
|
|
14242
14397
|
}
|
|
14243
14398
|
};
|
|
14399
|
+
function restrictedConsumers(ctx, subsystemId, componentId) {
|
|
14400
|
+
const entries = (ctx.subsystems.find((s) => s.id === subsystemId)?.publicInterfaces ?? []).filter((pi) => pi.component === componentId);
|
|
14401
|
+
if (entries.length === 0 || entries.some((pi) => pi.consumers === void 0)) return null;
|
|
14402
|
+
return [...new Set(entries.flatMap((pi) => pi.consumers ?? []))];
|
|
14403
|
+
}
|
|
14244
14404
|
|
|
14245
14405
|
// src/core/rules/doctrine/stereotype-terms.ts
|
|
14246
14406
|
var NEVER_INLINE_STATE = " Never resolve this by merging the store's state into the consuming component \u2014 state hidden inside a logic block is invisible to the spec and unrecoverable.";
|
|
@@ -15361,8 +15521,8 @@ var lifecycleRule = {
|
|
|
15361
15521
|
};
|
|
15362
15522
|
|
|
15363
15523
|
// src/core/rules/wiring/portal-mounts.ts
|
|
15364
|
-
function liesUnder(
|
|
15365
|
-
return
|
|
15524
|
+
function liesUnder(path29, prefix) {
|
|
15525
|
+
return path29 === prefix || path29.startsWith(prefix + "/");
|
|
15366
15526
|
}
|
|
15367
15527
|
var portalMountsRule = {
|
|
15368
15528
|
name: "portal-mounts",
|
|
@@ -16530,11 +16690,11 @@ var hiddenStateRule = {
|
|
|
16530
16690
|
byPath.set(key, list);
|
|
16531
16691
|
}
|
|
16532
16692
|
}
|
|
16533
|
-
for (const
|
|
16534
|
-
const facts = code.factsAt(
|
|
16693
|
+
for (const path29 of code.exactPaths) {
|
|
16694
|
+
const facts = code.factsAt(path29);
|
|
16535
16695
|
const bindings = facts.topLevelMutableBindings ?? [];
|
|
16536
16696
|
if (bindings.length === 0) continue;
|
|
16537
|
-
const mapped = byPath.get(
|
|
16697
|
+
const mapped = byPath.get(path29) ?? [];
|
|
16538
16698
|
if (mapped.length === 0) continue;
|
|
16539
16699
|
if (!mapped.every((m) => isStatelessLogic(m.component))) continue;
|
|
16540
16700
|
const anchor = [...mapped].sort((a, b) => a.impl.id.localeCompare(b.impl.id))[0];
|
|
@@ -16600,7 +16760,7 @@ var dependencyConformanceRule = {
|
|
|
16600
16760
|
}
|
|
16601
16761
|
return false;
|
|
16602
16762
|
};
|
|
16603
|
-
const draftAt = (
|
|
16763
|
+
const draftAt = (path29) => realization.implementationsAt(path29).some((impl) => ctx.isImplementationDraft(impl));
|
|
16604
16764
|
for (const fromPath of mappedPaths) {
|
|
16605
16765
|
const fromComponents = realization.componentsAt(fromPath);
|
|
16606
16766
|
for (const toPath of graph.importsOf(fromPath)) {
|
|
@@ -16656,6 +16816,60 @@ var dependencyConformanceRule = {
|
|
|
16656
16816
|
}
|
|
16657
16817
|
};
|
|
16658
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
|
+
|
|
16659
16873
|
// src/core/rules/conformance/integration-sim-declaration.ts
|
|
16660
16874
|
var integrationSimDeclarationRule = {
|
|
16661
16875
|
name: "integration-sim-declaration",
|
|
@@ -17167,8 +17381,8 @@ var paramConformanceRule = {
|
|
|
17167
17381
|
};
|
|
17168
17382
|
|
|
17169
17383
|
// src/core/rules/conformance/route-coverage.ts
|
|
17170
|
-
function liesUnder2(
|
|
17171
|
-
return
|
|
17384
|
+
function liesUnder2(path29, prefix) {
|
|
17385
|
+
return path29 === prefix || path29.startsWith(prefix + "/");
|
|
17172
17386
|
}
|
|
17173
17387
|
function normalizeSegment(segment) {
|
|
17174
17388
|
return /^\{.+\}$/.test(segment) || segment.startsWith(":") ? "*" : segment;
|
|
@@ -18733,10 +18947,11 @@ var SDD_RULES = [
|
|
|
18733
18947
|
assertionForbiddenEdgesRule,
|
|
18734
18948
|
assertionRequiredFieldsRule,
|
|
18735
18949
|
assertionEndpointShapesRule,
|
|
18736
|
-
// The published surface in
|
|
18737
|
-
// that component's stereotype can realize the type it
|
|
18738
|
-
// the contract it binds is that component's own.
|
|
18950
|
+
// The published surface in four questions: what backs the entry, who it is
|
|
18951
|
+
// published to, whether that component's stereotype can realize the type it
|
|
18952
|
+
// declares, and whether the contract it binds is that component's own.
|
|
18739
18953
|
publicSurfaceBindingRule,
|
|
18954
|
+
publicSurfaceConsumersRule,
|
|
18740
18955
|
publicSurfaceDeclaredTypeRule,
|
|
18741
18956
|
publicSurfaceBoundContractRule,
|
|
18742
18957
|
cyclesRule,
|
|
@@ -18789,6 +19004,8 @@ var SDD_RULES = [
|
|
|
18789
19004
|
// The fields-vs-Store criterion: mutable module state in logic-only files.
|
|
18790
19005
|
hiddenStateRule,
|
|
18791
19006
|
dependencyConformanceRule,
|
|
19007
|
+
// Where a declared crossing LANDS: on the target subsystem's portal file.
|
|
19008
|
+
portalImportsRule,
|
|
18792
19009
|
// Integration wiring proof rides after the code↔spec family: it consumes
|
|
18793
19010
|
// the same code model and speaks about the same sourcePath modules. Four
|
|
18794
19011
|
// questions about one harness, in the order a reader meets them: is one
|
|
@@ -18865,8 +19082,8 @@ function knownIssueCodes() {
|
|
|
18865
19082
|
}
|
|
18866
19083
|
|
|
18867
19084
|
// src/core/source-analysis.ts
|
|
18868
|
-
var
|
|
18869
|
-
var
|
|
19085
|
+
var fs10 = __toESM(require("fs"));
|
|
19086
|
+
var path13 = __toESM(require("path"));
|
|
18870
19087
|
var import_module2 = require("module");
|
|
18871
19088
|
function emptyCodeModel() {
|
|
18872
19089
|
return { files: [], projectRoot: "", rootFiles: [] };
|
|
@@ -19091,7 +19308,7 @@ function resolveTypeScript(projectRoot) {
|
|
|
19091
19308
|
return cached.ts;
|
|
19092
19309
|
}
|
|
19093
19310
|
let ts = null;
|
|
19094
|
-
const bases = [
|
|
19311
|
+
const bases = [path13.join(projectRoot, "package.json"), __filename];
|
|
19095
19312
|
for (const base of bases) {
|
|
19096
19313
|
try {
|
|
19097
19314
|
const req = (0, import_module2.createRequire)(base);
|
|
@@ -19487,7 +19704,7 @@ function walkExact(ts, sourceText, fileName) {
|
|
|
19487
19704
|
}
|
|
19488
19705
|
function resolveRelativeModule(fromFile, specifier) {
|
|
19489
19706
|
if (!specifier.startsWith(".")) return null;
|
|
19490
|
-
const base =
|
|
19707
|
+
const base = path13.resolve(path13.dirname(fromFile), specifier);
|
|
19491
19708
|
const candidates = [
|
|
19492
19709
|
base,
|
|
19493
19710
|
base.replace(/\.js$/, ".ts"),
|
|
@@ -19495,12 +19712,12 @@ function resolveRelativeModule(fromFile, specifier) {
|
|
|
19495
19712
|
`${base}.ts`,
|
|
19496
19713
|
`${base}.tsx`,
|
|
19497
19714
|
`${base}.js`,
|
|
19498
|
-
|
|
19499
|
-
|
|
19715
|
+
path13.join(base, "index.ts"),
|
|
19716
|
+
path13.join(base, "index.js")
|
|
19500
19717
|
];
|
|
19501
19718
|
for (const c of candidates) {
|
|
19502
19719
|
try {
|
|
19503
|
-
if (
|
|
19720
|
+
if (fs10.statSync(c).isFile()) return c;
|
|
19504
19721
|
} catch {
|
|
19505
19722
|
}
|
|
19506
19723
|
}
|
|
@@ -19508,11 +19725,11 @@ function resolveRelativeModule(fromFile, specifier) {
|
|
|
19508
19725
|
}
|
|
19509
19726
|
function reexportTarget(ts, filePath, specifier, projectRoot, visited, exactCache) {
|
|
19510
19727
|
const target = resolveRelativeModule(filePath, specifier);
|
|
19511
|
-
if (!target ||
|
|
19728
|
+
if (!target || path13.relative(projectRoot, target).startsWith("..")) return null;
|
|
19512
19729
|
let targetFacts = exactCache.get(target);
|
|
19513
19730
|
if (targetFacts === void 0) {
|
|
19514
19731
|
try {
|
|
19515
|
-
targetFacts = walkExact(ts,
|
|
19732
|
+
targetFacts = walkExact(ts, fs10.readFileSync(target, "utf8"), target);
|
|
19516
19733
|
} catch {
|
|
19517
19734
|
targetFacts = null;
|
|
19518
19735
|
}
|
|
@@ -19530,7 +19747,7 @@ function carryBody(facts, target, targetPath, local, exported, projectRoot) {
|
|
|
19530
19747
|
if (score !== void 0) facts.complexity.set(exported, Math.max(facts.complexity.get(exported) ?? 0, score));
|
|
19531
19748
|
const targetCalls = target.calls.get(local);
|
|
19532
19749
|
if (!targetCalls) return;
|
|
19533
|
-
const carriedFrom = pathKey(
|
|
19750
|
+
const carriedFrom = pathKey(path13.relative(projectRoot, targetPath));
|
|
19534
19751
|
const sites = facts.calls.get(exported) ?? /* @__PURE__ */ new Map();
|
|
19535
19752
|
for (const [key, site] of targetCalls) sites.set(carriedFrom + "|" + key, { ...site, from: site.from ?? carriedFrom });
|
|
19536
19753
|
facts.calls.set(exported, sites);
|
|
@@ -19560,24 +19777,24 @@ function walkDeclaredRoots(roots, exclude, projectRoot) {
|
|
|
19560
19777
|
const excluded = exclude.map(pathKey);
|
|
19561
19778
|
const isExcluded = (key) => excluded.some((e) => key === e || key.startsWith(`${e}/`));
|
|
19562
19779
|
const record = (absolute) => {
|
|
19563
|
-
const key = pathKey(
|
|
19780
|
+
const key = pathKey(path13.relative(projectRoot, absolute));
|
|
19564
19781
|
if (seen.has(key) || isExcluded(key)) return;
|
|
19565
|
-
if (!EXTENSION_LANGUAGE[
|
|
19782
|
+
if (!EXTENSION_LANGUAGE[path13.extname(key).toLowerCase()]) return;
|
|
19566
19783
|
seen.add(key);
|
|
19567
19784
|
found.push(key);
|
|
19568
19785
|
};
|
|
19569
19786
|
const descend = (dir) => {
|
|
19570
19787
|
let entries;
|
|
19571
19788
|
try {
|
|
19572
|
-
entries =
|
|
19789
|
+
entries = fs10.readdirSync(dir, { withFileTypes: true });
|
|
19573
19790
|
} catch {
|
|
19574
19791
|
return;
|
|
19575
19792
|
}
|
|
19576
19793
|
for (const entry of entries.slice().sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0)) {
|
|
19577
|
-
const child =
|
|
19794
|
+
const child = path13.join(dir, entry.name);
|
|
19578
19795
|
if (entry.isDirectory()) {
|
|
19579
19796
|
if (entry.name === "node_modules" || entry.name.startsWith(".")) continue;
|
|
19580
|
-
if (isExcluded(pathKey(
|
|
19797
|
+
if (isExcluded(pathKey(path13.relative(projectRoot, child)))) continue;
|
|
19581
19798
|
descend(child);
|
|
19582
19799
|
} else if (entry.isFile()) {
|
|
19583
19800
|
record(child);
|
|
@@ -19586,13 +19803,13 @@ function walkDeclaredRoots(roots, exclude, projectRoot) {
|
|
|
19586
19803
|
};
|
|
19587
19804
|
for (const root of roots) {
|
|
19588
19805
|
const key = pathKey(root);
|
|
19589
|
-
if (
|
|
19590
|
-
const absolute =
|
|
19591
|
-
if (
|
|
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;
|
|
19592
19809
|
if (isExcluded(key)) continue;
|
|
19593
19810
|
let stat;
|
|
19594
19811
|
try {
|
|
19595
|
-
stat =
|
|
19812
|
+
stat = fs10.statSync(absolute);
|
|
19596
19813
|
} catch {
|
|
19597
19814
|
continue;
|
|
19598
19815
|
}
|
|
@@ -19618,23 +19835,23 @@ function buildCodeModel(implementations, types, projectRoot, sourceRoots = [], e
|
|
|
19618
19835
|
if (seen.has(sourcePath)) continue;
|
|
19619
19836
|
seen.add(sourcePath);
|
|
19620
19837
|
const empty = { declaredNames: [], anchoredNames: [], exportedNames: [], imports: [], reexports: [] };
|
|
19621
|
-
if (
|
|
19838
|
+
if (path13.isAbsolute(sourcePath) || path13.normalize(sourcePath).split(path13.sep)[0] === "..") {
|
|
19622
19839
|
files.push({ path: sourcePath, status: "escaped", ...empty });
|
|
19623
19840
|
continue;
|
|
19624
19841
|
}
|
|
19625
|
-
const absolute =
|
|
19626
|
-
if (
|
|
19842
|
+
const absolute = path13.resolve(projectRoot, sourcePath);
|
|
19843
|
+
if (path13.relative(projectRoot, absolute).startsWith("..")) {
|
|
19627
19844
|
files.push({ path: sourcePath, status: "escaped", ...empty });
|
|
19628
19845
|
continue;
|
|
19629
19846
|
}
|
|
19630
19847
|
let buffer;
|
|
19631
19848
|
try {
|
|
19632
|
-
const stat =
|
|
19849
|
+
const stat = fs10.statSync(absolute);
|
|
19633
19850
|
if (!stat.isFile()) {
|
|
19634
19851
|
files.push({ path: sourcePath, status: "missing", ...empty });
|
|
19635
19852
|
continue;
|
|
19636
19853
|
}
|
|
19637
|
-
buffer =
|
|
19854
|
+
buffer = fs10.readFileSync(absolute);
|
|
19638
19855
|
} catch {
|
|
19639
19856
|
files.push({ path: sourcePath, status: "missing", ...empty });
|
|
19640
19857
|
continue;
|
|
@@ -19644,7 +19861,7 @@ function buildCodeModel(implementations, types, projectRoot, sourceRoots = [], e
|
|
|
19644
19861
|
continue;
|
|
19645
19862
|
}
|
|
19646
19863
|
const text = buffer.toString("utf8");
|
|
19647
|
-
const language = EXTENSION_LANGUAGE[
|
|
19864
|
+
const language = EXTENSION_LANGUAGE[path13.extname(sourcePath).toLowerCase()];
|
|
19648
19865
|
let analyzed;
|
|
19649
19866
|
if (language === "typescript" || language === "javascript") {
|
|
19650
19867
|
const ts = resolveTypeScript(projectRoot);
|
|
@@ -19715,6 +19932,7 @@ var DEPTH_GATED_CODES = {
|
|
|
19715
19932
|
CONFORMANCE_DEGRADED: "implementations",
|
|
19716
19933
|
UNDECLARED_DEPENDENCY: "implementations",
|
|
19717
19934
|
UNREALIZED_DEPENDENCY: "implementations",
|
|
19935
|
+
IMPORT_BYPASSES_PORTAL: "implementations",
|
|
19718
19936
|
MISSING_INTEGRATION_SIM: "implementations",
|
|
19719
19937
|
// L5 expectations: narratives and everything whose fuel is narrative edges
|
|
19720
19938
|
// (the reachability walk and the hydration round-trip would drown a
|
|
@@ -19749,6 +19967,7 @@ var COMPLETENESS_RULES = /* @__PURE__ */ new Set([
|
|
|
19749
19967
|
"CONFORMANCE_ANALYSIS_SKIPPED",
|
|
19750
19968
|
"UNDECLARED_DEPENDENCY",
|
|
19751
19969
|
"UNREALIZED_DEPENDENCY",
|
|
19970
|
+
"IMPORT_BYPASSES_PORTAL",
|
|
19752
19971
|
// Detail sufficiency reads the realized code like the conformance family
|
|
19753
19972
|
// does — a draft tree is allowed to disagree with its code.
|
|
19754
19973
|
"UNNARRATED_COMPLEXITY",
|
|
@@ -20180,244 +20399,49 @@ function buildRuleContext(opts) {
|
|
|
20180
20399
|
return ctx;
|
|
20181
20400
|
}
|
|
20182
20401
|
|
|
20183
|
-
// src/core/
|
|
20184
|
-
var
|
|
20185
|
-
|
|
20186
|
-
var path12 = __toESM(require("path"));
|
|
20187
|
-
var import_zod10 = require("zod");
|
|
20188
|
-
var VariantDefSchema = import_zod10.z.object({
|
|
20189
|
-
/** Variant id referenced by a component's `variant` (e.g. "publisher", "org/external-config-adapter"). */
|
|
20190
|
-
id: import_zod10.z.string().min(1),
|
|
20191
|
-
/** The core stereotype this variant specializes — authoritative for generic semantics (Adapter, Orchestrator, …). */
|
|
20192
|
-
base: import_zod10.z.string().min(1),
|
|
20193
|
-
/** How to implement a component of this variant — the recipe the implementer follows and reuses across same-variant components. */
|
|
20194
|
-
guidance: import_zod10.z.string().min(1),
|
|
20195
|
-
/** Optional: this variant only applies for the given target language (else it applies everywhere). */
|
|
20196
|
-
target: import_zod10.z.string().optional(),
|
|
20197
|
-
/** Optional: this variant only applies under the given architectural profile. */
|
|
20198
|
-
profile: import_zod10.z.string().optional()
|
|
20199
|
-
});
|
|
20200
|
-
function globalVariantsDir() {
|
|
20201
|
-
return process.env.WAIRON_VARIANTS_DIR ?? path12.join(os3.homedir(), ".wairon", "variants");
|
|
20202
|
-
}
|
|
20203
|
-
function builtinVariantsDir() {
|
|
20204
|
-
const candidates = [
|
|
20205
|
-
path12.resolve(__dirname, "..", "templates", "variants"),
|
|
20206
|
-
// src/core & dist/cli
|
|
20207
|
-
path12.resolve(__dirname, "templates", "variants")
|
|
20208
|
-
// dist (library entry)
|
|
20209
|
-
];
|
|
20210
|
-
return candidates.find((dir) => fs10.existsSync(dir)) ?? candidates[0];
|
|
20211
|
-
}
|
|
20212
|
-
function projectVariantsDir() {
|
|
20213
|
-
return path12.join(getProjectRoot(), ".wai", "variants");
|
|
20214
|
-
}
|
|
20215
|
-
function variantFiles(dir) {
|
|
20216
|
-
let entries;
|
|
20402
|
+
// src/core/validation.ts
|
|
20403
|
+
var path14 = __toESM(require("path"));
|
|
20404
|
+
function projectPackSelections() {
|
|
20217
20405
|
try {
|
|
20218
|
-
|
|
20406
|
+
return (loadProjectConfig()?.extensions?.packs ?? []).filter((e) => typeof e !== "string");
|
|
20219
20407
|
} catch {
|
|
20220
20408
|
return [];
|
|
20221
20409
|
}
|
|
20222
|
-
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));
|
|
20223
|
-
}
|
|
20224
|
-
function parseVariants(raw) {
|
|
20225
|
-
if (raw == null) return [];
|
|
20226
|
-
return (Array.isArray(raw) ? raw : [raw]).map((item) => VariantDefSchema.parse(item));
|
|
20227
20410
|
}
|
|
20228
|
-
|
|
20229
|
-
|
|
20411
|
+
var RESOLUTION_FAILURE_CODES = /* @__PURE__ */ new Set([
|
|
20412
|
+
"UNDEFINED_TYPE_REFERENCE",
|
|
20413
|
+
"INVALID_DEPENDENCY_REFERENCE",
|
|
20414
|
+
"INVALID_TARGET_COMPONENT_REFERENCE",
|
|
20415
|
+
"INVALID_SUBSYSTEM_REFERENCE",
|
|
20416
|
+
"INVALID_TRUSTED_LINK",
|
|
20417
|
+
"CROSS_TREE_REF_UNRESOLVED"
|
|
20418
|
+
]);
|
|
20419
|
+
var SEVERITY_RANK = { off: 0, warning: 1, error: 2 };
|
|
20420
|
+
function issueKey(issue2) {
|
|
20421
|
+
return `${issue2.code}|${issue2.specId ?? ""}`;
|
|
20230
20422
|
}
|
|
20231
|
-
function
|
|
20232
|
-
const
|
|
20233
|
-
for (const
|
|
20234
|
-
|
|
20235
|
-
|
|
20236
|
-
|
|
20237
|
-
reportSkippedFile(file, err);
|
|
20238
|
-
}
|
|
20423
|
+
function worstByKey(issues) {
|
|
20424
|
+
const worst = /* @__PURE__ */ new Map();
|
|
20425
|
+
for (const issue2 of issues) {
|
|
20426
|
+
const key = issueKey(issue2);
|
|
20427
|
+
const seen = worst.get(key);
|
|
20428
|
+
if (!seen || SEVERITY_RANK[issue2.severity] > SEVERITY_RANK[seen]) worst.set(key, issue2.severity);
|
|
20239
20429
|
}
|
|
20240
|
-
return
|
|
20430
|
+
return worst;
|
|
20241
20431
|
}
|
|
20242
|
-
function
|
|
20243
|
-
const
|
|
20244
|
-
|
|
20245
|
-
|
|
20432
|
+
function stricterSeverities(parent, child) {
|
|
20433
|
+
const fromParent = parent?.sddRuleSeverity ?? {};
|
|
20434
|
+
const fromChild = child?.sddRuleSeverity ?? {};
|
|
20435
|
+
const codes = /* @__PURE__ */ new Set([...Object.keys(fromParent), ...Object.keys(fromChild)]);
|
|
20436
|
+
if (codes.size === 0) return parent ?? child;
|
|
20437
|
+
const defaults = new Map(knownIssueCodes().map((rc) => [rc.code, rc.defaultSeverity]));
|
|
20438
|
+
const merged = {};
|
|
20439
|
+
for (const code of codes) {
|
|
20440
|
+
const p = fromParent[code] ?? defaults.get(code);
|
|
20441
|
+
const c = fromChild[code] ?? defaults.get(code);
|
|
20442
|
+
merged[code] = p === void 0 || c === void 0 ? p ?? c : SEVERITY_RANK[p] >= SEVERITY_RANK[c] ? p : c;
|
|
20246
20443
|
}
|
|
20247
|
-
return
|
|
20248
|
-
}
|
|
20249
|
-
function resolveVariantGuidance(component, allComponents, variantsById) {
|
|
20250
|
-
if (!component.variant) return null;
|
|
20251
|
-
const def = variantsById.get(component.variant);
|
|
20252
|
-
if (!def) return null;
|
|
20253
|
-
return {
|
|
20254
|
-
variant: component.variant,
|
|
20255
|
-
base: def.base,
|
|
20256
|
-
guidance: def.guidance,
|
|
20257
|
-
siblings: allComponents.filter((o) => o.variant === component.variant && o.id !== component.id).map((o) => o.id),
|
|
20258
|
-
...def.target ? { target: def.target } : {},
|
|
20259
|
-
...def.profile ? { profile: def.profile } : {}
|
|
20260
|
-
};
|
|
20261
|
-
}
|
|
20262
|
-
function composeVariantGuidance(comps, allComponents, variantsById) {
|
|
20263
|
-
const resolved = comps.map((c) => ({ id: c.id, guidance: resolveVariantGuidance(c, allComponents, variantsById) })).filter((r) => r.guidance !== null);
|
|
20264
|
-
if (resolved.length === 0) return "";
|
|
20265
|
-
const lines = [
|
|
20266
|
-
"## Component variants \u2014 reuse the shared approach",
|
|
20267
|
-
"",
|
|
20268
|
-
"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:",
|
|
20269
|
-
""
|
|
20270
|
-
];
|
|
20271
|
-
for (const { id, guidance } of resolved) {
|
|
20272
|
-
let line = `- **${id}** \u2014 variant \`${guidance.variant}\` (a kind of ${guidance.base}): ${guidance.guidance}`;
|
|
20273
|
-
if (guidance.siblings.length > 0) {
|
|
20274
|
-
line += ` Same-variant components elsewhere: ${guidance.siblings.join(", ")} \u2014 implement them consistently, reusing the same logic/concept.`;
|
|
20275
|
-
}
|
|
20276
|
-
lines.push(line);
|
|
20277
|
-
}
|
|
20278
|
-
return lines.join("\n");
|
|
20279
|
-
}
|
|
20280
|
-
function loadProjectVariants() {
|
|
20281
|
-
try {
|
|
20282
|
-
return mergeById(
|
|
20283
|
-
readVariantsDir(builtinVariantsDir()),
|
|
20284
|
-
readVariantsDir(globalVariantsDir()),
|
|
20285
|
-
readVariantsDir(projectVariantsDir())
|
|
20286
|
-
);
|
|
20287
|
-
} catch {
|
|
20288
|
-
return [];
|
|
20289
|
-
}
|
|
20290
|
-
}
|
|
20291
|
-
function listProjectVariants() {
|
|
20292
|
-
return mergeById(readVariantsDir(projectVariantsDir()));
|
|
20293
|
-
}
|
|
20294
|
-
function rebaseProjectVariants(fromBase, toBase) {
|
|
20295
|
-
const rebased = [];
|
|
20296
|
-
for (const file of variantFiles(projectVariantsDir())) {
|
|
20297
|
-
const content = readFileOrNull(file);
|
|
20298
|
-
if (content === null) continue;
|
|
20299
|
-
let raw;
|
|
20300
|
-
let variants;
|
|
20301
|
-
try {
|
|
20302
|
-
raw = parseYaml(content, file);
|
|
20303
|
-
variants = parseVariants(raw);
|
|
20304
|
-
} catch (err) {
|
|
20305
|
-
reportSkippedFile(file, err);
|
|
20306
|
-
continue;
|
|
20307
|
-
}
|
|
20308
|
-
const matching = variants.filter((v) => v.base === fromBase);
|
|
20309
|
-
if (matching.length === 0) continue;
|
|
20310
|
-
writeFile(file, rebasedText(content, fromBase, toBase, withRebasedEntries(raw, fromBase, toBase)));
|
|
20311
|
-
for (const v of matching) {
|
|
20312
|
-
if (!rebased.includes(v.id)) rebased.push(v.id);
|
|
20313
|
-
}
|
|
20314
|
-
}
|
|
20315
|
-
return rebased;
|
|
20316
|
-
}
|
|
20317
|
-
function withRebasedEntries(raw, fromBase, toBase) {
|
|
20318
|
-
const rebase = (entry) => entry.base === fromBase ? { ...entry, base: toBase } : entry;
|
|
20319
|
-
return Array.isArray(raw) ? raw.map(rebase) : rebase(raw);
|
|
20320
|
-
}
|
|
20321
|
-
function rebasedText(content, fromBase, toBase, rebasedContent) {
|
|
20322
|
-
const escaped = fromBase.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
20323
|
-
const baseLine = new RegExp(`^([ \\t]*(?:-[ \\t]+)?base:[ \\t]*)(["']?)${escaped}\\2(?=[ \\t]*(?:#.*)?$)`, "gm");
|
|
20324
|
-
const edited = content.replace(baseLine, (_line, key, quote) => `${key}${quote}${toBase}${quote}`);
|
|
20325
|
-
try {
|
|
20326
|
-
if (JSON.stringify(parseYaml(edited)) === JSON.stringify(rebasedContent)) return edited;
|
|
20327
|
-
} catch {
|
|
20328
|
-
}
|
|
20329
|
-
return serializeYaml(rebasedContent);
|
|
20330
|
-
}
|
|
20331
|
-
|
|
20332
|
-
// src/core/surfaces.ts
|
|
20333
|
-
var fs11 = __toESM(require("fs"));
|
|
20334
|
-
var path13 = __toESM(require("path"));
|
|
20335
|
-
|
|
20336
|
-
// src/core/openapi.ts
|
|
20337
|
-
var yaml2 = __toESM(require("js-yaml"));
|
|
20338
|
-
|
|
20339
|
-
// src/core/surfaces.ts
|
|
20340
|
-
var SURFACES_DIRNAME = "surfaces";
|
|
20341
|
-
function surfacesDir(rootDir) {
|
|
20342
|
-
return path13.join(rootDir, ".wai", SURFACES_DIRNAME);
|
|
20343
|
-
}
|
|
20344
|
-
function listSnapshots(rootDir = getProjectRoot()) {
|
|
20345
|
-
const dir = surfacesDir(rootDir);
|
|
20346
|
-
if (!fs11.existsSync(dir)) return [];
|
|
20347
|
-
const out = [];
|
|
20348
|
-
for (const file of fs11.readdirSync(dir)) {
|
|
20349
|
-
if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue;
|
|
20350
|
-
try {
|
|
20351
|
-
out.push(SurfaceSnapshotSchema.parse(readYamlFile(path13.join(dir, file))));
|
|
20352
|
-
} catch {
|
|
20353
|
-
}
|
|
20354
|
-
}
|
|
20355
|
-
return out;
|
|
20356
|
-
}
|
|
20357
|
-
function loadSurfaceSnapshots() {
|
|
20358
|
-
return listSnapshots();
|
|
20359
|
-
}
|
|
20360
|
-
function listMountSnapshots(mounts) {
|
|
20361
|
-
const bound2 = path13.resolve(getProjectRoot());
|
|
20362
|
-
const out = [];
|
|
20363
|
-
for (const namespace of mounts) {
|
|
20364
|
-
const dir = resolveSubprojectForNamespace(namespace);
|
|
20365
|
-
if (!dir || path13.resolve(dir) === bound2) continue;
|
|
20366
|
-
const snapshots = listSnapshots(dir);
|
|
20367
|
-
if (snapshots.length > 0) out.push({ namespace, snapshots });
|
|
20368
|
-
}
|
|
20369
|
-
return out;
|
|
20370
|
-
}
|
|
20371
|
-
function loadMountSurfaceSnapshots(mounts) {
|
|
20372
|
-
return listMountSnapshots(mounts);
|
|
20373
|
-
}
|
|
20374
|
-
|
|
20375
|
-
// src/core/validation.ts
|
|
20376
|
-
var path14 = __toESM(require("path"));
|
|
20377
|
-
function loadProjectConfig2() {
|
|
20378
|
-
return loadProjectConfig();
|
|
20379
|
-
}
|
|
20380
|
-
function projectPackSelections() {
|
|
20381
|
-
try {
|
|
20382
|
-
return (loadProjectConfig2()?.extensions?.packs ?? []).filter((e) => typeof e !== "string");
|
|
20383
|
-
} catch {
|
|
20384
|
-
return [];
|
|
20385
|
-
}
|
|
20386
|
-
}
|
|
20387
|
-
var RESOLUTION_FAILURE_CODES = /* @__PURE__ */ new Set([
|
|
20388
|
-
"UNDEFINED_TYPE_REFERENCE",
|
|
20389
|
-
"INVALID_DEPENDENCY_REFERENCE",
|
|
20390
|
-
"INVALID_TARGET_COMPONENT_REFERENCE",
|
|
20391
|
-
"INVALID_SUBSYSTEM_REFERENCE",
|
|
20392
|
-
"INVALID_TRUSTED_LINK",
|
|
20393
|
-
"CROSS_TREE_REF_UNRESOLVED"
|
|
20394
|
-
]);
|
|
20395
|
-
var SEVERITY_RANK = { off: 0, warning: 1, error: 2 };
|
|
20396
|
-
function issueKey(issue2) {
|
|
20397
|
-
return `${issue2.code}|${issue2.specId ?? ""}`;
|
|
20398
|
-
}
|
|
20399
|
-
function worstByKey(issues) {
|
|
20400
|
-
const worst = /* @__PURE__ */ new Map();
|
|
20401
|
-
for (const issue2 of issues) {
|
|
20402
|
-
const key = issueKey(issue2);
|
|
20403
|
-
const seen = worst.get(key);
|
|
20404
|
-
if (!seen || SEVERITY_RANK[issue2.severity] > SEVERITY_RANK[seen]) worst.set(key, issue2.severity);
|
|
20405
|
-
}
|
|
20406
|
-
return worst;
|
|
20407
|
-
}
|
|
20408
|
-
function stricterSeverities(parent, child) {
|
|
20409
|
-
const fromParent = parent?.sddRuleSeverity ?? {};
|
|
20410
|
-
const fromChild = child?.sddRuleSeverity ?? {};
|
|
20411
|
-
const codes = /* @__PURE__ */ new Set([...Object.keys(fromParent), ...Object.keys(fromChild)]);
|
|
20412
|
-
if (codes.size === 0) return parent ?? child;
|
|
20413
|
-
const defaults = new Map(knownIssueCodes().map((rc) => [rc.code, rc.defaultSeverity]));
|
|
20414
|
-
const merged = {};
|
|
20415
|
-
for (const code of codes) {
|
|
20416
|
-
const p = fromParent[code] ?? defaults.get(code);
|
|
20417
|
-
const c = fromChild[code] ?? defaults.get(code);
|
|
20418
|
-
merged[code] = p === void 0 || c === void 0 ? p ?? c : SEVERITY_RANK[p] >= SEVERITY_RANK[c] ? p : c;
|
|
20419
|
-
}
|
|
20420
|
-
return { ...parent ?? child, sddRuleSeverity: merged };
|
|
20444
|
+
return { ...parent ?? child, sddRuleSeverity: merged };
|
|
20421
20445
|
}
|
|
20422
20446
|
function issue(severity, code, message, agentId, specId) {
|
|
20423
20447
|
return { severity, code, message, agentId, specId };
|
|
@@ -20449,7 +20473,7 @@ function validateSddTree(rulesOrOptions, projectType = "backend") {
|
|
|
20449
20473
|
const interfaces = loadInterfaceSpecs();
|
|
20450
20474
|
const implementations = loadImplementationSpecs();
|
|
20451
20475
|
const types = loadTypeSpecs();
|
|
20452
|
-
const surfaceSnapshots =
|
|
20476
|
+
const surfaceSnapshots = listSnapshots();
|
|
20453
20477
|
const conformance = rules?.conformance;
|
|
20454
20478
|
const codeModel = buildCodeModel(
|
|
20455
20479
|
implementations,
|
|
@@ -20496,7 +20520,7 @@ function validateSddTree(rulesOrOptions, projectType = "backend") {
|
|
|
20496
20520
|
for (const err of extensions.errors) {
|
|
20497
20521
|
issues.push(issue("error", "EXTENSION_LOAD_ERROR", err));
|
|
20498
20522
|
}
|
|
20499
|
-
const mountSurfaceSnapshots =
|
|
20523
|
+
const mountSurfaceSnapshots = listMountSnapshots(
|
|
20500
20524
|
subsystems.filter((s) => s.projectPath).map((s) => s.id)
|
|
20501
20525
|
);
|
|
20502
20526
|
const roundTripIssues = dryRunSerializeSpecs(isSpecInScope);
|
|
@@ -20584,10 +20608,9 @@ function resolveThroughParent(boundRoot, treatAllAsComplete, childRules) {
|
|
|
20584
20608
|
if (chain.length === 0) return null;
|
|
20585
20609
|
const scope = chain.join("::");
|
|
20586
20610
|
const inner = runWithProjectRoot(top, () => {
|
|
20587
|
-
invalidateSpecCache();
|
|
20588
20611
|
let governing = { rules: stricterSeverities(void 0, childRules) };
|
|
20589
20612
|
try {
|
|
20590
|
-
const config =
|
|
20613
|
+
const config = loadProjectConfig();
|
|
20591
20614
|
if (config) governing = { rules: stricterSeverities(config.rules, childRules), projectType: config.projectType };
|
|
20592
20615
|
} catch {
|
|
20593
20616
|
}
|
|
@@ -21287,7 +21310,7 @@ function canonicalPath(target) {
|
|
|
21287
21310
|
const rest = [];
|
|
21288
21311
|
for (; ; ) {
|
|
21289
21312
|
try {
|
|
21290
|
-
|
|
21313
|
+
fs11.lstatSync(existing);
|
|
21291
21314
|
break;
|
|
21292
21315
|
} catch {
|
|
21293
21316
|
const up = path15.dirname(existing);
|
|
@@ -21297,7 +21320,7 @@ function canonicalPath(target) {
|
|
|
21297
21320
|
}
|
|
21298
21321
|
}
|
|
21299
21322
|
try {
|
|
21300
|
-
return path15.join(
|
|
21323
|
+
return path15.join(fs11.realpathSync.native(existing), ...rest);
|
|
21301
21324
|
} catch {
|
|
21302
21325
|
return null;
|
|
21303
21326
|
}
|
|
@@ -21389,7 +21412,7 @@ function inspectChainedRoots(rootDir = getProjectRoot()) {
|
|
|
21389
21412
|
let reason;
|
|
21390
21413
|
if (projectPathEscapesRoot(projectDir, projectPath, childDir)) reason = "escapes";
|
|
21391
21414
|
else if (ancestors.has(chainDirKey(childDir))) reason = "cyclic";
|
|
21392
|
-
else if (!
|
|
21415
|
+
else if (!fs11.existsSync(childDir)) reason = "missing";
|
|
21393
21416
|
else if (depth >= 32) reason = "too-deep";
|
|
21394
21417
|
if (reason) {
|
|
21395
21418
|
const mount = prefix ? qualifyDeclaredId(localId, prefix, true) : localId;
|
|
@@ -21441,7 +21464,10 @@ function stripNamespaceFromSubsystem(spec, prefix) {
|
|
|
21441
21464
|
publicInterfaces: spec.publicInterfaces.map((pi) => ({
|
|
21442
21465
|
...pi,
|
|
21443
21466
|
component: pi.component ? relMember(pi.component) : void 0,
|
|
21444
|
-
interface: pi.interface ? relMember(pi.interface) : void 0
|
|
21467
|
+
interface: pi.interface ? relMember(pi.interface) : void 0,
|
|
21468
|
+
// consumers name SUBSYSTEMS — peers of this one, so they are relative to
|
|
21469
|
+
// the namespace the subsystem itself is declared in, never its members'.
|
|
21470
|
+
...pi.consumers ? { consumers: pi.consumers.map((c) => c.includes("::") ? relativizeId(c, prefix) : c) } : {}
|
|
21445
21471
|
})),
|
|
21446
21472
|
lifecycle: spec.lifecycle?.map((le) => ({
|
|
21447
21473
|
...le,
|
|
@@ -21527,9 +21553,9 @@ function findOwner(id, components) {
|
|
|
21527
21553
|
}
|
|
21528
21554
|
function moveComponentFolder(fromDir, toDir) {
|
|
21529
21555
|
if (path15.normalize(fromDir) === path15.normalize(toDir)) return false;
|
|
21530
|
-
if (!
|
|
21556
|
+
if (!fs11.existsSync(fromDir) || fs11.existsSync(toDir)) return false;
|
|
21531
21557
|
ensureDir(path15.dirname(toDir));
|
|
21532
|
-
|
|
21558
|
+
fs11.renameSync(fromDir, toDir);
|
|
21533
21559
|
return true;
|
|
21534
21560
|
}
|
|
21535
21561
|
function formatZodIssues(error) {
|
|
@@ -21546,13 +21572,13 @@ var SIGNATURE_TTL_MS = 2e3;
|
|
|
21546
21572
|
function computeSpecTreeSignature(dirs) {
|
|
21547
21573
|
const parts = [];
|
|
21548
21574
|
for (const dir of dirs) {
|
|
21549
|
-
if (!
|
|
21575
|
+
if (!fs11.existsSync(dir)) {
|
|
21550
21576
|
parts.push(`${dir}:missing`);
|
|
21551
21577
|
continue;
|
|
21552
21578
|
}
|
|
21553
21579
|
for (const f of listSpecFiles(dir)) {
|
|
21554
21580
|
try {
|
|
21555
|
-
const st =
|
|
21581
|
+
const st = fs11.statSync(f);
|
|
21556
21582
|
parts.push(`${f}:${st.mtimeMs}:${st.size}`);
|
|
21557
21583
|
} catch {
|
|
21558
21584
|
parts.push(`${f}:gone`);
|
|
@@ -21824,13 +21850,13 @@ function ineffectiveDeltaPaths(delta, merged, stored) {
|
|
|
21824
21850
|
const isPlain = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
21825
21851
|
const same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
21826
21852
|
const at = (prefix, key) => prefix ? `${prefix}.${key}` : key;
|
|
21827
|
-
const say = (
|
|
21828
|
-
out.push(`${
|
|
21853
|
+
const say = (path29, why) => {
|
|
21854
|
+
out.push(`${path29} \u2014 ${why}`);
|
|
21829
21855
|
};
|
|
21830
|
-
const walkValue = (d, m, s,
|
|
21856
|
+
const walkValue = (d, m, s, path29, field) => {
|
|
21831
21857
|
if (Array.isArray(d)) {
|
|
21832
21858
|
if (!Array.isArray(m)) {
|
|
21833
|
-
say(
|
|
21859
|
+
say(path29, "the level does not have this field, so the write dropped it");
|
|
21834
21860
|
return;
|
|
21835
21861
|
}
|
|
21836
21862
|
if (field === "narrative" && d.some(carriesEditMarker)) return;
|
|
@@ -21838,32 +21864,32 @@ function ineffectiveDeltaPaths(delta, merged, stored) {
|
|
|
21838
21864
|
if (carriesEditMarker(element)) continue;
|
|
21839
21865
|
const key = reportIdentityOf(field, element);
|
|
21840
21866
|
if (key === null) {
|
|
21841
|
-
if (!same(m, d)) say(
|
|
21842
|
-
else if (same(s, d)) say(
|
|
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");
|
|
21843
21869
|
return;
|
|
21844
21870
|
}
|
|
21845
21871
|
const mMatch = m.find((i) => reportIdentityOf(field, i) === key);
|
|
21846
21872
|
const sMatch = Array.isArray(s) ? s.find((i) => reportIdentityOf(field, i) === key) : void 0;
|
|
21847
21873
|
if (mMatch === void 0) {
|
|
21848
|
-
say(at(
|
|
21874
|
+
say(at(path29, key), "the write did not store this element");
|
|
21849
21875
|
continue;
|
|
21850
21876
|
}
|
|
21851
|
-
walk2(element, mMatch, sMatch, at(
|
|
21877
|
+
walk2(element, mMatch, sMatch, at(path29, key), field);
|
|
21852
21878
|
}
|
|
21853
21879
|
return;
|
|
21854
21880
|
}
|
|
21855
21881
|
if (isPlain(d)) {
|
|
21856
21882
|
if (!isPlain(m)) {
|
|
21857
|
-
say(
|
|
21883
|
+
say(path29, "the level does not have this field, so the write dropped it");
|
|
21858
21884
|
return;
|
|
21859
21885
|
}
|
|
21860
|
-
walk2(d, m, s,
|
|
21886
|
+
walk2(d, m, s, path29, field);
|
|
21861
21887
|
return;
|
|
21862
21888
|
}
|
|
21863
|
-
if (!same(m, d)) say(
|
|
21864
|
-
else if (same(s, d)) say(
|
|
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");
|
|
21865
21891
|
};
|
|
21866
|
-
function walk2(d, m, s,
|
|
21892
|
+
function walk2(d, m, s, path29, container) {
|
|
21867
21893
|
for (const [key, value] of Object.entries(d)) {
|
|
21868
21894
|
if (DELTA_VERBS.has(key) || JUMP_LABEL_TWINS.has(key)) continue;
|
|
21869
21895
|
if (key === "label" && LABEL_TWIN_CONTAINERS.has(container)) continue;
|
|
@@ -21873,13 +21899,13 @@ function ineffectiveDeltaPaths(delta, merged, stored) {
|
|
|
21873
21899
|
if (typeof name !== "string") continue;
|
|
21874
21900
|
const had = isPlain(s) && s[name] !== void 0;
|
|
21875
21901
|
const still = isPlain(m) && m[name] !== void 0;
|
|
21876
|
-
if (!had) say(at(
|
|
21877
|
-
else if (still) say(at(
|
|
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");
|
|
21878
21904
|
}
|
|
21879
21905
|
continue;
|
|
21880
21906
|
}
|
|
21881
21907
|
if (value === void 0 || value === null) continue;
|
|
21882
|
-
const here = at(
|
|
21908
|
+
const here = at(path29, key);
|
|
21883
21909
|
const mValue = isPlain(m) ? m[key] : void 0;
|
|
21884
21910
|
const sValue = isPlain(s) ? s[key] : void 0;
|
|
21885
21911
|
if (mValue === void 0) {
|
|
@@ -21905,6 +21931,15 @@ var SpecWorkspace = class {
|
|
|
21905
21931
|
this.rootDir = path15.resolve(rootDir);
|
|
21906
21932
|
this.paths = aiPathsAt(this.rootDir);
|
|
21907
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
|
+
}
|
|
21908
21943
|
invalidate() {
|
|
21909
21944
|
this.cachedIndex = null;
|
|
21910
21945
|
this.cachedRecursive = null;
|
|
@@ -22049,7 +22084,10 @@ var SpecWorkspace = class {
|
|
|
22049
22084
|
publicInterfaces: sub.publicInterfaces.map((p) => ({
|
|
22050
22085
|
...p,
|
|
22051
22086
|
component: p.component ? qualifyId(p.component, componentPrefix, this.rootSubsystems) : void 0,
|
|
22052
|
-
interface: p.interface ? qualifyId(p.interface, componentPrefix, this.rootSubsystems) : void 0
|
|
22087
|
+
interface: p.interface ? qualifyId(p.interface, componentPrefix, this.rootSubsystems) : void 0,
|
|
22088
|
+
// Each consumer is a subsystem reference: qualified into the namespace
|
|
22089
|
+
// this subsystem is declared in, like a component's `subsystem` field.
|
|
22090
|
+
...p.consumers ? { consumers: p.consumers.map((c) => qualifySubsystemRef(c, namespacePrefix, this.rootSubsystems)) } : {}
|
|
22053
22091
|
})),
|
|
22054
22092
|
lifecycle: sub.lifecycle?.map((le) => ({
|
|
22055
22093
|
...le,
|
|
@@ -22155,7 +22193,7 @@ var SpecWorkspace = class {
|
|
|
22155
22193
|
});
|
|
22156
22194
|
continue;
|
|
22157
22195
|
}
|
|
22158
|
-
if (!
|
|
22196
|
+
if (!fs11.existsSync(childDir)) {
|
|
22159
22197
|
this.loaderIssues.push({
|
|
22160
22198
|
severity: "error",
|
|
22161
22199
|
code: "SUBPROJECT_NOT_FOUND",
|
|
@@ -23159,8 +23197,8 @@ var SpecWorkspace = class {
|
|
|
23159
23197
|
}
|
|
23160
23198
|
}
|
|
23161
23199
|
for (const file of files) {
|
|
23162
|
-
if (
|
|
23163
|
-
snapshot.set(file,
|
|
23200
|
+
if (fs11.existsSync(file)) {
|
|
23201
|
+
snapshot.set(file, fs11.readFileSync(file, "utf8"));
|
|
23164
23202
|
}
|
|
23165
23203
|
}
|
|
23166
23204
|
return snapshot;
|
|
@@ -23663,7 +23701,8 @@ var SpecWorkspace = class {
|
|
|
23663
23701
|
out.publicInterfaces = out.publicInterfaces.map((pi) => ({
|
|
23664
23702
|
...pi,
|
|
23665
23703
|
...typeof pi?.component === "string" ? { component: qm(pi.component) } : {},
|
|
23666
|
-
...typeof pi?.interface === "string" ? { interface: qm(pi.interface) } : {}
|
|
23704
|
+
...typeof pi?.interface === "string" ? { interface: qm(pi.interface) } : {},
|
|
23705
|
+
...Array.isArray(pi?.consumers) ? { consumers: pi.consumers.map((c) => typeof c === "string" ? qualifySubsystemRef(c, prefix, this.rootSubsystems) : c) } : {}
|
|
23667
23706
|
}));
|
|
23668
23707
|
}
|
|
23669
23708
|
if (Array.isArray(out.lifecycle)) {
|
|
@@ -24228,8 +24267,15 @@ function workspaceFor(rootDir) {
|
|
|
24228
24267
|
}
|
|
24229
24268
|
return ws;
|
|
24230
24269
|
}
|
|
24270
|
+
var lastServedBinding = null;
|
|
24231
24271
|
function current() {
|
|
24232
|
-
|
|
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;
|
|
24233
24279
|
}
|
|
24234
24280
|
function invalidateSpecCache() {
|
|
24235
24281
|
for (const ws of workspaces.values()) ws.invalidate();
|
|
@@ -24274,9 +24320,6 @@ function loadSubsystemSpec(id) {
|
|
|
24274
24320
|
function saveSubsystemSpec(spec) {
|
|
24275
24321
|
current().saveSubsystemSpec(spec);
|
|
24276
24322
|
}
|
|
24277
|
-
function deleteSubsystemSpec(id) {
|
|
24278
|
-
return current().deleteSubsystemSpec(id);
|
|
24279
|
-
}
|
|
24280
24323
|
function loadComponentSpecs() {
|
|
24281
24324
|
return current().loadComponentSpecs();
|
|
24282
24325
|
}
|
|
@@ -24286,9 +24329,6 @@ function loadComponentSpec(id) {
|
|
|
24286
24329
|
function saveComponentSpec(spec, opts) {
|
|
24287
24330
|
return current().saveComponentSpec(spec, opts);
|
|
24288
24331
|
}
|
|
24289
|
-
function deleteComponentSpec(id) {
|
|
24290
|
-
return current().deleteComponentSpec(id);
|
|
24291
|
-
}
|
|
24292
24332
|
function loadInterfaceSpecs() {
|
|
24293
24333
|
return current().loadInterfaceSpecs();
|
|
24294
24334
|
}
|
|
@@ -24298,9 +24338,6 @@ function loadInterfaceSpec(id) {
|
|
|
24298
24338
|
function saveInterfaceSpec(spec, opts) {
|
|
24299
24339
|
return current().saveInterfaceSpec(spec, opts);
|
|
24300
24340
|
}
|
|
24301
|
-
function deleteInterfaceSpec(id) {
|
|
24302
|
-
return current().deleteInterfaceSpec(id);
|
|
24303
|
-
}
|
|
24304
24341
|
function loadImplementationSpecs() {
|
|
24305
24342
|
return current().loadImplementationSpecs();
|
|
24306
24343
|
}
|
|
@@ -24310,18 +24347,12 @@ function loadImplementationSpec(id) {
|
|
|
24310
24347
|
function saveImplementationSpec(spec, opts) {
|
|
24311
24348
|
return current().saveImplementationSpec(spec, opts);
|
|
24312
24349
|
}
|
|
24313
|
-
function deleteImplementationSpec(id) {
|
|
24314
|
-
return current().deleteImplementationSpec(id);
|
|
24315
|
-
}
|
|
24316
24350
|
function loadTypeSpecs() {
|
|
24317
24351
|
return current().loadTypeSpecs();
|
|
24318
24352
|
}
|
|
24319
24353
|
function loadTypeSpec(id) {
|
|
24320
24354
|
return current().loadTypeSpec(id);
|
|
24321
24355
|
}
|
|
24322
|
-
function saveTypeSpec(spec) {
|
|
24323
|
-
return current().saveTypeSpec(spec);
|
|
24324
|
-
}
|
|
24325
24356
|
function dryRunSerializeSpecs(include) {
|
|
24326
24357
|
return current().dryRunSerializeSpecs(include);
|
|
24327
24358
|
}
|
|
@@ -24341,7 +24372,7 @@ function consumedSurfaceInputsAt(rootDir) {
|
|
|
24341
24372
|
const dir = path15.join(rootDir, ".wai", "surfaces");
|
|
24342
24373
|
if (!pathExists(dir)) return [];
|
|
24343
24374
|
const keys = [];
|
|
24344
|
-
for (const file of
|
|
24375
|
+
for (const file of fs11.readdirSync(dir)) {
|
|
24345
24376
|
if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue;
|
|
24346
24377
|
try {
|
|
24347
24378
|
keys.push(snapshotInputKey(SurfaceSnapshotSchema.parse(readYamlFile(path15.join(dir, file)))));
|
|
@@ -24397,15 +24428,15 @@ function computeStateIdAt(root) {
|
|
|
24397
24428
|
return `${s.algorithm}:${s.digest}`;
|
|
24398
24429
|
});
|
|
24399
24430
|
}
|
|
24400
|
-
function deleteTypeSpec(id) {
|
|
24401
|
-
return current().deleteTypeSpec(id);
|
|
24402
|
-
}
|
|
24403
24431
|
function specPathsInScope(scopeSubsystem) {
|
|
24404
24432
|
return current().specPathsInScope(scopeSubsystem);
|
|
24405
24433
|
}
|
|
24406
24434
|
function snapshotSpecFiles() {
|
|
24407
24435
|
return current().snapshotSpecFiles();
|
|
24408
24436
|
}
|
|
24437
|
+
function findLegacySpecFiles() {
|
|
24438
|
+
return current().findLegacySpecFiles();
|
|
24439
|
+
}
|
|
24409
24440
|
function loadSpec(kind, id) {
|
|
24410
24441
|
const workspace = current();
|
|
24411
24442
|
return workspace.load(kind, id);
|
|
@@ -24512,7 +24543,7 @@ function unregisterDomain(id) {
|
|
|
24512
24543
|
}
|
|
24513
24544
|
|
|
24514
24545
|
// src/core/provision.ts
|
|
24515
|
-
var
|
|
24546
|
+
var fs12 = __toESM(require("fs"));
|
|
24516
24547
|
var path17 = __toESM(require("path"));
|
|
24517
24548
|
function defaultProjectConfig(name, now) {
|
|
24518
24549
|
return {
|
|
@@ -24561,7 +24592,7 @@ function provisionProject(name) {
|
|
|
24561
24592
|
function ensureProjectInitialized(fallbackName) {
|
|
24562
24593
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
24563
24594
|
const paths = aiPathsAt(getProjectRoot());
|
|
24564
|
-
const hasSystem =
|
|
24595
|
+
const hasSystem = fs12.existsSync(paths.specsSystem());
|
|
24565
24596
|
let name = fallbackName;
|
|
24566
24597
|
if (hasSystem) {
|
|
24567
24598
|
const existing = loadSystemSpec();
|
|
@@ -24580,10 +24611,41 @@ function ensureProjectInitialized(fallbackName) {
|
|
|
24580
24611
|
if (wroteConfig || wroteSystem) invalidateSpecCache();
|
|
24581
24612
|
return { wroteConfig, wroteSystem };
|
|
24582
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
|
+
}
|
|
24583
24645
|
function listDirectChainedSubprojects(projectRoot) {
|
|
24584
24646
|
const out = [];
|
|
24585
24647
|
const specsDir = aiPathsAt(projectRoot).specsDir();
|
|
24586
|
-
if (!
|
|
24648
|
+
if (!fs12.existsSync(specsDir)) return out;
|
|
24587
24649
|
for (const file of listFilesRecursive(specsDir, ".yaml")) {
|
|
24588
24650
|
let raw;
|
|
24589
24651
|
try {
|
|
@@ -24605,6 +24667,28 @@ function listDirectChainedSubprojects(projectRoot) {
|
|
|
24605
24667
|
}
|
|
24606
24668
|
return out;
|
|
24607
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
|
+
}
|
|
24608
24692
|
function createChainedSubsystem(subsystem, projectName) {
|
|
24609
24693
|
if (!subsystem.projectPath || subsystem.projectPath.trim() === "") {
|
|
24610
24694
|
throw new WaironError("projectPath is required to create a chained subsystem.");
|
|
@@ -24633,14 +24717,14 @@ function moveSubsystemProject(subsystemId, newProjectPath) {
|
|
|
24633
24717
|
const oldDir = assertContainedProjectPath(root, sub.projectPath);
|
|
24634
24718
|
const newDir = assertContainedProjectPath(root, nextPath);
|
|
24635
24719
|
if (oldDir !== newDir) {
|
|
24636
|
-
if (!
|
|
24720
|
+
if (!fs12.existsSync(oldDir)) {
|
|
24637
24721
|
throw new WaironError(`Subproject directory not found at its current path: ${oldDir}`);
|
|
24638
24722
|
}
|
|
24639
|
-
if (
|
|
24723
|
+
if (fs12.existsSync(newDir)) {
|
|
24640
24724
|
throw new WaironError(`Target directory already exists: ${newDir}`);
|
|
24641
24725
|
}
|
|
24642
24726
|
ensureDir(path17.dirname(newDir));
|
|
24643
|
-
|
|
24727
|
+
fs12.renameSync(oldDir, newDir);
|
|
24644
24728
|
}
|
|
24645
24729
|
saveSubsystemSpec({ ...sub, projectPath: nextPath, updatedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
24646
24730
|
invalidateSpecCache();
|
|
@@ -24664,13 +24748,13 @@ function externalizeSubsystem(subsystemId, projectPath) {
|
|
|
24664
24748
|
const parentRoot = getProjectRoot();
|
|
24665
24749
|
const parentSpecsDir = aiPathsAt(parentRoot).specsDir();
|
|
24666
24750
|
const fooDir = path17.join(parentSpecsDir, subsystemId);
|
|
24667
|
-
if (!
|
|
24751
|
+
if (!fs12.existsSync(fooDir)) {
|
|
24668
24752
|
throw new WaironError(`subsystem specs directory not found: ${fooDir}`);
|
|
24669
24753
|
}
|
|
24670
24754
|
const relPath = toPosixPath(projectPath);
|
|
24671
24755
|
const childDir = assertContainedProjectPath(parentRoot, relPath);
|
|
24672
24756
|
const childFooDir = path17.join(childDir, ".wai", "specs", subsystemId);
|
|
24673
|
-
if (
|
|
24757
|
+
if (fs12.existsSync(childFooDir)) {
|
|
24674
24758
|
throw new WaironError(`target already contains a "${subsystemId}" subsystem: ${childFooDir}`);
|
|
24675
24759
|
}
|
|
24676
24760
|
const renameMap = buildRenameMap(
|
|
@@ -24686,7 +24770,7 @@ function externalizeSubsystem(subsystemId, projectPath) {
|
|
|
24686
24770
|
saveSystemSpec(bootstrapSystemSpec(childSystemName, now));
|
|
24687
24771
|
});
|
|
24688
24772
|
ensureDir(path17.dirname(childFooDir));
|
|
24689
|
-
|
|
24773
|
+
fs12.renameSync(fooDir, childFooDir);
|
|
24690
24774
|
rebaseImplementationPaths(childFooDir, parentRoot, childDir);
|
|
24691
24775
|
patchSubsystemIndex(path17.join(childFooDir, ".index.yaml"), (s) => {
|
|
24692
24776
|
s.parentSystem = childSystemName;
|
|
@@ -24722,7 +24806,7 @@ function internalizeSubsystem(subsystemId) {
|
|
|
24722
24806
|
const childDir = assertContainedProjectPath(parentRoot, foo.projectPath);
|
|
24723
24807
|
const childWai = path17.join(childDir, ".wai");
|
|
24724
24808
|
const childFooDir = path17.join(childDir, ".wai", "specs", subsystemId);
|
|
24725
|
-
if (!
|
|
24809
|
+
if (!fs12.existsSync(childFooDir)) {
|
|
24726
24810
|
throw new WaironError(`external subproject missing subsystem "${subsystemId}": ${childFooDir}`);
|
|
24727
24811
|
}
|
|
24728
24812
|
const childOwnSubs = runWithProjectRoot(childDir, () => loadSubsystemSpecs()).filter((s) => !s.id.includes("::"));
|
|
@@ -24736,15 +24820,15 @@ function internalizeSubsystem(subsystemId) {
|
|
|
24736
24820
|
);
|
|
24737
24821
|
const parentSystemName = loadSystemSpec()?.name ?? foo.parentSystem;
|
|
24738
24822
|
const fooDir = path17.join(parentSpecsDir, subsystemId);
|
|
24739
|
-
|
|
24823
|
+
fs12.rmSync(fooDir, { recursive: true, force: true });
|
|
24740
24824
|
ensureDir(path17.dirname(fooDir));
|
|
24741
|
-
|
|
24825
|
+
fs12.renameSync(childFooDir, fooDir);
|
|
24742
24826
|
rebaseImplementationPaths(fooDir, childDir, parentRoot);
|
|
24743
24827
|
patchSubsystemIndex(path17.join(fooDir, ".index.yaml"), (s) => {
|
|
24744
24828
|
s.parentSystem = parentSystemName;
|
|
24745
24829
|
delete s.projectPath;
|
|
24746
24830
|
});
|
|
24747
|
-
|
|
24831
|
+
fs12.rmSync(childWai, { recursive: true, force: true });
|
|
24748
24832
|
rewriteRefsInDir(parentSpecsDir, renameMap, fooDir);
|
|
24749
24833
|
rebaseMovedRefs(fooDir, subsystemId, "outOf");
|
|
24750
24834
|
invalidateSpecCache();
|
|
@@ -24839,7 +24923,7 @@ function rebaseImplementationPaths(specsDir, fromRoot, toRoot) {
|
|
|
24839
24923
|
}
|
|
24840
24924
|
}
|
|
24841
24925
|
function patchSubsystemIndex(indexPath, mutate) {
|
|
24842
|
-
if (!
|
|
24926
|
+
if (!fs12.existsSync(indexPath)) return;
|
|
24843
24927
|
const raw = readYamlFile(indexPath);
|
|
24844
24928
|
mutate(raw);
|
|
24845
24929
|
raw.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -24901,7 +24985,7 @@ function moveRenamedSpecs(componentId, newId, component, movingInterface, moving
|
|
|
24901
24985
|
if (movedImplementation) {
|
|
24902
24986
|
const oldFile = getImplementationPath(movedImplementation.id);
|
|
24903
24987
|
if (path17.resolve(getImplementationPath(implementationId, movedImplementation.contract)) === path17.resolve(oldFile)) {
|
|
24904
|
-
|
|
24988
|
+
fs12.unlinkSync(oldFile);
|
|
24905
24989
|
}
|
|
24906
24990
|
saveImplementationSpec({ ...movedImplementation, id: implementationId });
|
|
24907
24991
|
}
|
|
@@ -24911,17 +24995,17 @@ function moveRenamedSpecs(componentId, newId, component, movingInterface, moving
|
|
|
24911
24995
|
invalidateSpecCache();
|
|
24912
24996
|
}
|
|
24913
24997
|
function removeSpecFile2(file, id) {
|
|
24914
|
-
if (!
|
|
24998
|
+
if (!fs12.existsSync(file)) return;
|
|
24915
24999
|
try {
|
|
24916
25000
|
if (readYamlFile(file)?.id !== id) return;
|
|
24917
25001
|
} catch {
|
|
24918
25002
|
return;
|
|
24919
25003
|
}
|
|
24920
|
-
|
|
25004
|
+
fs12.unlinkSync(file);
|
|
24921
25005
|
const specsRoot = path17.resolve(aiPathsAt(getProjectRoot()).specsDir());
|
|
24922
25006
|
for (let dir = path17.dirname(path17.resolve(file)); dir !== specsRoot && isWithinDir(specsRoot, dir); dir = path17.dirname(dir)) {
|
|
24923
|
-
if (
|
|
24924
|
-
|
|
25007
|
+
if (fs12.readdirSync(dir).length > 0) break;
|
|
25008
|
+
fs12.rmdirSync(dir);
|
|
24925
25009
|
}
|
|
24926
25010
|
}
|
|
24927
25011
|
var METHOD_NAME = /^[a-z][a-zA-Z0-9]*$/;
|
|
@@ -25032,7 +25116,7 @@ function identifierPattern(methodName) {
|
|
|
25032
25116
|
}
|
|
25033
25117
|
|
|
25034
25118
|
// src/core/detection.ts
|
|
25035
|
-
var
|
|
25119
|
+
var fs13 = __toESM(require("fs"));
|
|
25036
25120
|
var path18 = __toESM(require("path"));
|
|
25037
25121
|
var PACKAGE_MARKERS = [
|
|
25038
25122
|
"package.json",
|
|
@@ -25084,7 +25168,7 @@ function deduplicateIds(candidates, existingIds = /* @__PURE__ */ new Set()) {
|
|
|
25084
25168
|
});
|
|
25085
25169
|
}
|
|
25086
25170
|
function parseGitmodules(filePath) {
|
|
25087
|
-
const content =
|
|
25171
|
+
const content = fs13.readFileSync(filePath, "utf-8");
|
|
25088
25172
|
const entries = [];
|
|
25089
25173
|
let current2 = {};
|
|
25090
25174
|
for (const line of content.split("\n")) {
|
|
@@ -25107,7 +25191,7 @@ function parseGitmodules(filePath) {
|
|
|
25107
25191
|
}
|
|
25108
25192
|
function detectGitSubmodules(projectRoot) {
|
|
25109
25193
|
const gitmodulesPath = path18.join(projectRoot, ".gitmodules");
|
|
25110
|
-
if (!
|
|
25194
|
+
if (!fs13.existsSync(gitmodulesPath)) return [];
|
|
25111
25195
|
return parseGitmodules(gitmodulesPath).map((entry) => ({
|
|
25112
25196
|
suggestedId: pathToId(entry.path),
|
|
25113
25197
|
suggestedName: pathToName(entry.path),
|
|
@@ -25125,7 +25209,7 @@ function walkForGit(projectRoot, currentDir, depth, results) {
|
|
|
25125
25209
|
if (depth > MAX_SCAN_DEPTH) return;
|
|
25126
25210
|
let entries;
|
|
25127
25211
|
try {
|
|
25128
|
-
entries =
|
|
25212
|
+
entries = fs13.readdirSync(currentDir, { withFileTypes: true });
|
|
25129
25213
|
} catch {
|
|
25130
25214
|
return;
|
|
25131
25215
|
}
|
|
@@ -25136,7 +25220,7 @@ function walkForGit(projectRoot, currentDir, depth, results) {
|
|
|
25136
25220
|
const relPath = normalizePath(path18.relative(projectRoot, fullPath));
|
|
25137
25221
|
if (relPath === "" || relPath === ".") continue;
|
|
25138
25222
|
const gitPath = path18.join(fullPath, ".git");
|
|
25139
|
-
if (
|
|
25223
|
+
if (fs13.existsSync(gitPath)) {
|
|
25140
25224
|
results.push({
|
|
25141
25225
|
suggestedId: pathToId(relPath),
|
|
25142
25226
|
suggestedName: pathToName(relPath),
|
|
@@ -25158,7 +25242,7 @@ function walkForPackages(projectRoot, currentDir, depth, results) {
|
|
|
25158
25242
|
if (depth > MAX_SCAN_DEPTH) return;
|
|
25159
25243
|
let entries;
|
|
25160
25244
|
try {
|
|
25161
|
-
entries =
|
|
25245
|
+
entries = fs13.readdirSync(currentDir, { withFileTypes: true });
|
|
25162
25246
|
} catch {
|
|
25163
25247
|
return;
|
|
25164
25248
|
}
|
|
@@ -25168,7 +25252,7 @@ function walkForPackages(projectRoot, currentDir, depth, results) {
|
|
|
25168
25252
|
const fullPath = path18.join(currentDir, entry.name);
|
|
25169
25253
|
const relPath = normalizePath(path18.relative(projectRoot, fullPath));
|
|
25170
25254
|
if (relPath === "" || relPath === ".") continue;
|
|
25171
|
-
const hasMarker = PACKAGE_MARKERS.some((m) =>
|
|
25255
|
+
const hasMarker = PACKAGE_MARKERS.some((m) => fs13.existsSync(path18.join(fullPath, m)));
|
|
25172
25256
|
if (hasMarker) {
|
|
25173
25257
|
results.push({
|
|
25174
25258
|
suggestedId: pathToId(relPath),
|
|
@@ -25193,19 +25277,168 @@ function normalizePath(p) {
|
|
|
25193
25277
|
return p.replace(/\\/g, "/");
|
|
25194
25278
|
}
|
|
25195
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
|
+
|
|
25196
25429
|
// src/core/agent_resolver.ts
|
|
25197
|
-
var
|
|
25430
|
+
var path21 = __toESM(require("path"));
|
|
25198
25431
|
var fs15 = __toESM(require("fs"));
|
|
25199
25432
|
|
|
25200
25433
|
// src/core/templates.ts
|
|
25201
|
-
var
|
|
25434
|
+
var path20 = __toESM(require("path"));
|
|
25202
25435
|
function builtinTemplatesDir() {
|
|
25203
|
-
return
|
|
25436
|
+
return path20.resolve(__dirname, "..", "templates");
|
|
25204
25437
|
}
|
|
25205
25438
|
function loadTemplate(id, globalOverride) {
|
|
25206
25439
|
const dirs = templateSearchDirs(globalOverride);
|
|
25207
25440
|
for (const dir of dirs) {
|
|
25208
|
-
const filePath =
|
|
25441
|
+
const filePath = path20.join(dir, `${id}.yaml`);
|
|
25209
25442
|
if (pathExists(filePath)) {
|
|
25210
25443
|
const raw = readYamlFile(filePath);
|
|
25211
25444
|
return { ...TemplateSchema.parse(raw), templateName: id };
|
|
@@ -25214,7 +25447,7 @@ function loadTemplate(id, globalOverride) {
|
|
|
25214
25447
|
throw new TemplateNotFoundError(id);
|
|
25215
25448
|
}
|
|
25216
25449
|
function loadAgentOverride(agentId) {
|
|
25217
|
-
const filePath =
|
|
25450
|
+
const filePath = path20.join(AI_PATHS.root(), "agents", `${agentId}.md`);
|
|
25218
25451
|
return readFileOrNull(filePath);
|
|
25219
25452
|
}
|
|
25220
25453
|
function templateSearchDirs(globalOverride) {
|
|
@@ -25366,7 +25599,7 @@ function resolveBudget(profile, config, agentId) {
|
|
|
25366
25599
|
var projectFilesCache = /* @__PURE__ */ new Map();
|
|
25367
25600
|
function listFilesRecursiveSafe(dirPath, ext) {
|
|
25368
25601
|
if (!fs15.existsSync(dirPath)) return [];
|
|
25369
|
-
const nameLower =
|
|
25602
|
+
const nameLower = path21.basename(dirPath).toLowerCase();
|
|
25370
25603
|
const IGNORED_DIRS = /* @__PURE__ */ new Set([
|
|
25371
25604
|
"node_modules",
|
|
25372
25605
|
"target",
|
|
@@ -25384,7 +25617,7 @@ function listFilesRecursiveSafe(dirPath, ext) {
|
|
|
25384
25617
|
const entries = fs15.readdirSync(dirPath, { withFileTypes: true });
|
|
25385
25618
|
const files = [];
|
|
25386
25619
|
for (const entry of entries) {
|
|
25387
|
-
const fullPath =
|
|
25620
|
+
const fullPath = path21.join(dirPath, entry.name);
|
|
25388
25621
|
if (entry.isDirectory()) {
|
|
25389
25622
|
files.push(...listFilesRecursiveSafe(fullPath, ext));
|
|
25390
25623
|
} else if (entry.isFile() && entry.name.endsWith(ext)) {
|
|
@@ -25397,8 +25630,8 @@ function getProjectFiles(projectDir) {
|
|
|
25397
25630
|
let files = projectFilesCache.get(projectDir);
|
|
25398
25631
|
if (!files) {
|
|
25399
25632
|
files = [];
|
|
25400
|
-
const srcDir =
|
|
25401
|
-
const legacySrcDir =
|
|
25633
|
+
const srcDir = path21.join(projectDir, "src");
|
|
25634
|
+
const legacySrcDir = path21.join(projectDir, "legacy-src");
|
|
25402
25635
|
let searchDir = projectDir;
|
|
25403
25636
|
if (pathExists(srcDir)) {
|
|
25404
25637
|
searchDir = srcDir;
|
|
@@ -25413,7 +25646,7 @@ function getProjectFiles(projectDir) {
|
|
|
25413
25646
|
files.push(...listFilesRecursiveSafe(searchDir, ext));
|
|
25414
25647
|
}
|
|
25415
25648
|
const rootDir = getProjectRoot();
|
|
25416
|
-
files = files.map((f) =>
|
|
25649
|
+
files = files.map((f) => path21.relative(rootDir, f).replace(/\\/g, "/"));
|
|
25417
25650
|
projectFilesCache.set(projectDir, files);
|
|
25418
25651
|
}
|
|
25419
25652
|
return files;
|
|
@@ -25438,8 +25671,8 @@ function inferSourcePathForComponent(comp, subsystems) {
|
|
|
25438
25671
|
let bestFile = null;
|
|
25439
25672
|
let bestScore = -1;
|
|
25440
25673
|
for (const f of files) {
|
|
25441
|
-
const ext =
|
|
25442
|
-
const base =
|
|
25674
|
+
const ext = path21.extname(f);
|
|
25675
|
+
const base = path21.basename(f, ext).toLowerCase();
|
|
25443
25676
|
if (candidates.has(base)) {
|
|
25444
25677
|
let score = 0;
|
|
25445
25678
|
const normalizedPath = f.toLowerCase();
|
|
@@ -25536,7 +25769,7 @@ function resolveAgentTopology() {
|
|
|
25536
25769
|
});
|
|
25537
25770
|
for (const sub of subsystems) {
|
|
25538
25771
|
if (sub.projectPath) {
|
|
25539
|
-
const mountSpecPath =
|
|
25772
|
+
const mountSpecPath = path21.relative(getProjectRoot(), getSubsystemPath(sub.id)).replace(/\\/g, "/");
|
|
25540
25773
|
agents.push({
|
|
25541
25774
|
id: `${sub.id}-owner`,
|
|
25542
25775
|
name: `${sub.name} (chained subproject)`,
|
|
@@ -25558,9 +25791,9 @@ function resolveAgentTopology() {
|
|
|
25558
25791
|
}
|
|
25559
25792
|
const subComponents = components.filter((c) => c.subsystem === sub.id);
|
|
25560
25793
|
const ownedPaths = [];
|
|
25561
|
-
ownedPaths.push(
|
|
25794
|
+
ownedPaths.push(path21.relative(getProjectRoot(), getSubsystemPath(sub.id)).replace(/\\/g, "/"));
|
|
25562
25795
|
for (const c of subComponents) {
|
|
25563
|
-
ownedPaths.push(
|
|
25796
|
+
ownedPaths.push(path21.relative(getProjectRoot(), getComponentPath(c.id, sub.id)).replace(/\\/g, "/"));
|
|
25564
25797
|
}
|
|
25565
25798
|
if (!config.rules.generateComponentImplementers) {
|
|
25566
25799
|
for (const comp of subComponents) {
|
|
@@ -25636,10 +25869,10 @@ function resolveAgentTopology() {
|
|
|
25636
25869
|
}
|
|
25637
25870
|
const dependencies = comp.dependsOn.map((depId) => `${depId}-implementer`);
|
|
25638
25871
|
const readPaths = [
|
|
25639
|
-
|
|
25640
|
-
|
|
25641
|
-
...compInterfaces.map((i) =>
|
|
25642
|
-
...compImpls.map((impl) =>
|
|
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, "/"))
|
|
25643
25876
|
];
|
|
25644
25877
|
agents.push({
|
|
25645
25878
|
id: `${comp.id}-implementer`,
|
|
@@ -25745,10 +25978,10 @@ function loadRegistry() {
|
|
|
25745
25978
|
}
|
|
25746
25979
|
|
|
25747
25980
|
// src/exporters/generate.ts
|
|
25748
|
-
var
|
|
25981
|
+
var path25 = __toESM(require("path"));
|
|
25749
25982
|
|
|
25750
25983
|
// src/exporters/claude.ts
|
|
25751
|
-
var
|
|
25984
|
+
var path22 = __toESM(require("path"));
|
|
25752
25985
|
var MODEL_BY_TIER = {
|
|
25753
25986
|
small: "haiku",
|
|
25754
25987
|
standard: "sonnet",
|
|
@@ -25787,7 +26020,7 @@ var ClaudeExporter = class {
|
|
|
25787
26020
|
outputPath(ctx) {
|
|
25788
26021
|
const { agent, target, projectRoot } = ctx;
|
|
25789
26022
|
const outputDir = "outputDir" in target ? target.outputDir : ".claude/agents";
|
|
25790
|
-
return
|
|
26023
|
+
return path22.resolve(projectRoot, outputDir, `${agent.id.replace(/::/g, "--")}.md`);
|
|
25791
26024
|
}
|
|
25792
26025
|
export(ctx) {
|
|
25793
26026
|
const { agent, renderedInstructions, budget } = ctx;
|
|
@@ -25812,7 +26045,7 @@ var ClaudeExporter = class {
|
|
|
25812
26045
|
};
|
|
25813
26046
|
|
|
25814
26047
|
// src/exporters/custom.ts
|
|
25815
|
-
var
|
|
26048
|
+
var path23 = __toESM(require("path"));
|
|
25816
26049
|
var CustomExporter = class {
|
|
25817
26050
|
constructor() {
|
|
25818
26051
|
this.targetType = "custom";
|
|
@@ -25822,7 +26055,7 @@ var CustomExporter = class {
|
|
|
25822
26055
|
if (!("outputDir" in target)) {
|
|
25823
26056
|
throw new Error("CustomExporter requires target.outputDir");
|
|
25824
26057
|
}
|
|
25825
|
-
return
|
|
26058
|
+
return path23.resolve(projectRoot, target.outputDir, `${agent.id.replace(/::/g, "--")}.md`);
|
|
25826
26059
|
}
|
|
25827
26060
|
export(ctx) {
|
|
25828
26061
|
const { agent, target, renderedInstructions } = ctx;
|
|
@@ -25845,7 +26078,7 @@ var CustomExporter = class {
|
|
|
25845
26078
|
};
|
|
25846
26079
|
|
|
25847
26080
|
// src/exporters/gemini.ts
|
|
25848
|
-
var
|
|
26081
|
+
var path24 = __toESM(require("path"));
|
|
25849
26082
|
var GeminiExporter = class {
|
|
25850
26083
|
constructor() {
|
|
25851
26084
|
this.targetType = "gemini";
|
|
@@ -25853,7 +26086,7 @@ var GeminiExporter = class {
|
|
|
25853
26086
|
outputPath(ctx) {
|
|
25854
26087
|
const { agent, target, projectRoot } = ctx;
|
|
25855
26088
|
const outputDir = "outputDir" in target ? target.outputDir : ".gemini/agents";
|
|
25856
|
-
return
|
|
26089
|
+
return path24.resolve(projectRoot, outputDir, `${agent.id.replace(/::/g, "--")}.yaml`);
|
|
25857
26090
|
}
|
|
25858
26091
|
export(ctx) {
|
|
25859
26092
|
const { agent, renderedInstructions } = ctx;
|
|
@@ -25950,7 +26183,7 @@ function resolveExpectedOutputPaths(agents, projectConfig, projectRoot = getProj
|
|
|
25950
26183
|
const targetConfig = resolveTargetConfig(agentTarget, projectConfig);
|
|
25951
26184
|
if (!targetConfig) continue;
|
|
25952
26185
|
const ctx = { agent, projectRoot, target: targetConfig };
|
|
25953
|
-
expected.add(
|
|
26186
|
+
expected.add(path25.resolve(getExporter(targetConfig).outputPath(ctx)));
|
|
25954
26187
|
}
|
|
25955
26188
|
}
|
|
25956
26189
|
return expected;
|
|
@@ -25965,7 +26198,7 @@ function resolveTargetConfig(agentTarget, projectConfig) {
|
|
|
25965
26198
|
|
|
25966
26199
|
// src/core/treetransfer.ts
|
|
25967
26200
|
var fs16 = __toESM(require("fs"));
|
|
25968
|
-
var
|
|
26201
|
+
var path26 = __toESM(require("path"));
|
|
25969
26202
|
var sdkPortal = __toESM(require_dist());
|
|
25970
26203
|
var STAGING_PREFIX = ".wai-staging-";
|
|
25971
26204
|
var BACKUP_DIR = ".wai-backups";
|
|
@@ -25991,39 +26224,39 @@ function hasAuthoredSpecs(root) {
|
|
|
25991
26224
|
if (!pathExists(specsDir)) {
|
|
25992
26225
|
return false;
|
|
25993
26226
|
}
|
|
25994
|
-
const systemIndex =
|
|
26227
|
+
const systemIndex = path26.resolve(paths.specsSystem());
|
|
25995
26228
|
for (const file of listFilesRecursive(specsDir, ".yaml")) {
|
|
25996
|
-
if (
|
|
26229
|
+
if (path26.resolve(file) !== systemIndex) {
|
|
25997
26230
|
return true;
|
|
25998
26231
|
}
|
|
25999
26232
|
}
|
|
26000
26233
|
return false;
|
|
26001
26234
|
}
|
|
26002
26235
|
function createStagingDir(destDir) {
|
|
26003
|
-
const root =
|
|
26236
|
+
const root = path26.resolve(destDir);
|
|
26004
26237
|
fs16.mkdirSync(root, { recursive: true });
|
|
26005
|
-
const stagingDir = fs16.mkdtempSync(
|
|
26238
|
+
const stagingDir = fs16.mkdtempSync(path26.join(root, STAGING_PREFIX));
|
|
26006
26239
|
return stagingDir;
|
|
26007
26240
|
}
|
|
26008
26241
|
function commitStagedTree(stagingDir, destDir, roots, backupExisting) {
|
|
26009
|
-
const root =
|
|
26010
|
-
const backupDir =
|
|
26242
|
+
const root = path26.resolve(destDir);
|
|
26243
|
+
const backupDir = path26.join(root, BACKUP_DIR, timestampSlug());
|
|
26011
26244
|
let backedUp = false;
|
|
26012
26245
|
for (const rootRel of roots) {
|
|
26013
26246
|
const relative9 = rootRel === "." ? "" : rootRel;
|
|
26014
|
-
const stagedSpecDir =
|
|
26247
|
+
const stagedSpecDir = path26.join(stagingDir, relative9, ".wai");
|
|
26015
26248
|
if (!fs16.existsSync(stagedSpecDir)) continue;
|
|
26016
|
-
const liveSpecDir = liveSpecDirFor(
|
|
26249
|
+
const liveSpecDir = liveSpecDirFor(path26.join(root, relative9));
|
|
26017
26250
|
if (backupExisting && liveSpecDir && fs16.existsSync(liveSpecDir)) {
|
|
26018
|
-
const backupTarget =
|
|
26019
|
-
fs16.mkdirSync(
|
|
26251
|
+
const backupTarget = path26.join(backupDir, relative9, path26.basename(liveSpecDir));
|
|
26252
|
+
fs16.mkdirSync(path26.dirname(backupTarget), { recursive: true });
|
|
26020
26253
|
fs16.renameSync(liveSpecDir, backupTarget);
|
|
26021
26254
|
backedUp = true;
|
|
26022
26255
|
} else if (liveSpecDir && fs16.existsSync(liveSpecDir)) {
|
|
26023
26256
|
fs16.rmSync(liveSpecDir, { recursive: true, force: true });
|
|
26024
26257
|
}
|
|
26025
|
-
const target =
|
|
26026
|
-
fs16.mkdirSync(
|
|
26258
|
+
const target = path26.join(root, relative9, ".wai");
|
|
26259
|
+
fs16.mkdirSync(path26.dirname(target), { recursive: true });
|
|
26027
26260
|
if (fs16.existsSync(target)) fs16.rmSync(target, { recursive: true, force: true });
|
|
26028
26261
|
fs16.renameSync(stagedSpecDir, target);
|
|
26029
26262
|
}
|
|
@@ -26048,7 +26281,7 @@ function exportSpecTree(includeDerived, allowPartial) {
|
|
|
26048
26281
|
const skipped = [...inspection.skipped];
|
|
26049
26282
|
const roots = [{ relativePath: ".", waiDir: aiPathsAt(root).root() }];
|
|
26050
26283
|
for (const rel2 of inspection.roots) {
|
|
26051
|
-
const waiDir = aiPathsAt(
|
|
26284
|
+
const waiDir = aiPathsAt(path26.resolve(root, rel2)).root();
|
|
26052
26285
|
if (pathExists(waiDir)) {
|
|
26053
26286
|
roots.push({ relativePath: rel2, waiDir });
|
|
26054
26287
|
} else {
|
|
@@ -26079,7 +26312,7 @@ function importSpecTree(archive, options) {
|
|
|
26079
26312
|
if (!info.compatible) {
|
|
26080
26313
|
throw new Error("incompatible .waitree archive (format or minimum wairon version)");
|
|
26081
26314
|
}
|
|
26082
|
-
const destDir =
|
|
26315
|
+
const destDir = path26.resolve(options.destDir ?? getProjectRoot());
|
|
26083
26316
|
const occupied = hasSpecTree(destDir);
|
|
26084
26317
|
const authored = hasAuthoredSpecs(destDir);
|
|
26085
26318
|
if (authored && options.replaceExisting !== true) {
|
|
@@ -26110,9 +26343,9 @@ function importSpecTree(archive, options) {
|
|
|
26110
26343
|
return result;
|
|
26111
26344
|
}
|
|
26112
26345
|
function liveSpecDirFor(rootDir) {
|
|
26113
|
-
const modern =
|
|
26346
|
+
const modern = path26.join(rootDir, ".wai");
|
|
26114
26347
|
if (fs16.existsSync(modern)) return modern;
|
|
26115
|
-
const legacy =
|
|
26348
|
+
const legacy = path26.join(rootDir, ".wairon");
|
|
26116
26349
|
if (fs16.existsSync(legacy)) return legacy;
|
|
26117
26350
|
return null;
|
|
26118
26351
|
}
|
|
@@ -26254,7 +26487,7 @@ function repairForeignStepFields(apply) {
|
|
|
26254
26487
|
|
|
26255
26488
|
// src/core/approval.ts
|
|
26256
26489
|
var crypto3 = __toESM(require("crypto"));
|
|
26257
|
-
var
|
|
26490
|
+
var path27 = __toESM(require("path"));
|
|
26258
26491
|
|
|
26259
26492
|
// src/models/lock.ts
|
|
26260
26493
|
function describeApprover(who) {
|
|
@@ -26271,12 +26504,12 @@ function digest(content) {
|
|
|
26271
26504
|
return crypto3.createHash("sha256").update(normalized, "utf8").digest("hex");
|
|
26272
26505
|
}
|
|
26273
26506
|
function currentSpecDigests(root = getProjectRoot()) {
|
|
26274
|
-
const mountDirs = loadSubsystemSpecs().filter((s) => s.projectPath && !s.id.includes("::")).map((s) => `${
|
|
26507
|
+
const mountDirs = loadSubsystemSpecs().filter((s) => s.projectPath && !s.id.includes("::")).map((s) => `${path27.resolve(root, s.projectPath).split(path27.sep).join("/")}/`);
|
|
26275
26508
|
const out = {};
|
|
26276
26509
|
for (const [abs, content] of snapshotSpecFiles()) {
|
|
26277
|
-
const normalized =
|
|
26510
|
+
const normalized = path27.resolve(abs).split(path27.sep).join("/");
|
|
26278
26511
|
if (mountDirs.some((dir) => normalized.startsWith(dir))) continue;
|
|
26279
|
-
out[
|
|
26512
|
+
out[path27.relative(root, abs).split(path27.sep).join("/")] = digest(content);
|
|
26280
26513
|
}
|
|
26281
26514
|
return out;
|
|
26282
26515
|
}
|
|
@@ -26334,7 +26567,7 @@ function currentChildPins(mounts, root = getProjectRoot()) {
|
|
|
26334
26567
|
const pins = {};
|
|
26335
26568
|
for (const mount of mounts) {
|
|
26336
26569
|
if (!mount.projectPath || mount.id.includes("::")) continue;
|
|
26337
|
-
const child = readLockRecordAt(
|
|
26570
|
+
const child = readLockRecordAt(path27.resolve(root, mount.projectPath));
|
|
26338
26571
|
if (child) pins[mount.id] = pinOf(child.stateId);
|
|
26339
26572
|
}
|
|
26340
26573
|
return pins;
|
|
@@ -26436,7 +26669,7 @@ function localApprover() {
|
|
|
26436
26669
|
// src/utils/ai-guide.ts
|
|
26437
26670
|
var fs17 = __toESM(require("fs"));
|
|
26438
26671
|
var os5 = __toESM(require("os"));
|
|
26439
|
-
var
|
|
26672
|
+
var path28 = __toESM(require("path"));
|
|
26440
26673
|
|
|
26441
26674
|
// src/core/stamp.ts
|
|
26442
26675
|
function versionStamp() {
|
|
@@ -26496,13 +26729,13 @@ This project uses **wairon**. System specs live under \`.wai/specs/\` (L0 System
|
|
|
26496
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.
|
|
26497
26730
|
* Use \`owns\` for private member containment (exactly one hop) and \`dependsOn\` for collaborators. Never use generic suffixes like "Manager", "Helper", or "Utils".`;
|
|
26498
26731
|
function globalGuideFilePath(targetType) {
|
|
26499
|
-
if (targetType === "claude") return
|
|
26500
|
-
if (targetType === "gemini") return
|
|
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");
|
|
26501
26734
|
return null;
|
|
26502
26735
|
}
|
|
26503
26736
|
function localGuideFilePath(projectRoot, targetType) {
|
|
26504
|
-
if (targetType === "claude") return
|
|
26505
|
-
if (targetType === "gemini" || targetType === "agy") return
|
|
26737
|
+
if (targetType === "claude") return path28.join(projectRoot, ".claude", "CLAUDE.md");
|
|
26738
|
+
if (targetType === "gemini" || targetType === "agy") return path28.join(projectRoot, ".gemini", "GEMINI.md");
|
|
26506
26739
|
return null;
|
|
26507
26740
|
}
|
|
26508
26741
|
function injectGuide(filePath, scope) {
|
|
@@ -26517,7 +26750,7 @@ ${GUIDE_MARKER_END}
|
|
|
26517
26750
|
const existing = fs17.existsSync(filePath) ? fs17.readFileSync(filePath, "utf-8") : "";
|
|
26518
26751
|
const stripped = stripGuideSection(existing);
|
|
26519
26752
|
const newContent = stripped.trimEnd() + section;
|
|
26520
|
-
fs17.mkdirSync(
|
|
26753
|
+
fs17.mkdirSync(path28.dirname(filePath), { recursive: true });
|
|
26521
26754
|
fs17.writeFileSync(filePath, newContent, "utf-8");
|
|
26522
26755
|
}
|
|
26523
26756
|
function stripGuideSection(content) {
|
|
@@ -26528,7 +26761,7 @@ function stripGuideSection(content) {
|
|
|
26528
26761
|
}
|
|
26529
26762
|
function writeRootGuideDelegator(projectRoot, targetType) {
|
|
26530
26763
|
if (targetType === "claude") {
|
|
26531
|
-
const filePath =
|
|
26764
|
+
const filePath = path28.join(projectRoot, "CLAUDE.md");
|
|
26532
26765
|
const content = `@.claude/CLAUDE.md
|
|
26533
26766
|
|
|
26534
26767
|
# Wairon SDD Project
|
|
@@ -26543,7 +26776,7 @@ the \`wairon\` CLI is the human developer's tool, not yours.
|
|
|
26543
26776
|
`;
|
|
26544
26777
|
fs17.writeFileSync(filePath, content, "utf-8");
|
|
26545
26778
|
} else if (targetType === "gemini" || targetType === "agy") {
|
|
26546
|
-
const filePath =
|
|
26779
|
+
const filePath = path28.join(projectRoot, "GEMINI.md");
|
|
26547
26780
|
const content = `# Wairon SDD Project
|
|
26548
26781
|
${GUIDE_MARKER_START}
|
|
26549
26782
|
${versionStamp()}
|
|
@@ -26552,7 +26785,7 @@ ${GUIDE_MARKER_END}
|
|
|
26552
26785
|
`;
|
|
26553
26786
|
fs17.writeFileSync(filePath, content, "utf-8");
|
|
26554
26787
|
} else if (targetType === "cursor") {
|
|
26555
|
-
const filePath =
|
|
26788
|
+
const filePath = path28.join(projectRoot, ".cursorrules");
|
|
26556
26789
|
const content = `# Wairon SDD Project
|
|
26557
26790
|
|
|
26558
26791
|
This project uses the Wairon Spec-Driven Development (SDD) framework.
|
|
@@ -26561,8 +26794,8 @@ Refer to the rules in [.cursor/rules/](.cursor/rules/) for full instructions.
|
|
|
26561
26794
|
`;
|
|
26562
26795
|
fs17.writeFileSync(filePath, content, "utf-8");
|
|
26563
26796
|
} else if (targetType === "copilot") {
|
|
26564
|
-
const filePath =
|
|
26565
|
-
fs17.mkdirSync(
|
|
26797
|
+
const filePath = path28.join(projectRoot, ".github", "copilot-instructions.md");
|
|
26798
|
+
fs17.mkdirSync(path28.dirname(filePath), { recursive: true });
|
|
26566
26799
|
const content = `# Wairon SDD Project
|
|
26567
26800
|
|
|
26568
26801
|
This project uses the Wairon Spec-Driven Development (SDD) framework.
|
|
@@ -26571,7 +26804,7 @@ Refer to the prompts in [.github/prompts/](.github/prompts/) for instructions.
|
|
|
26571
26804
|
`;
|
|
26572
26805
|
fs17.writeFileSync(filePath, content, "utf-8");
|
|
26573
26806
|
} else if (targetType === "codex") {
|
|
26574
|
-
const filePath =
|
|
26807
|
+
const filePath = path28.join(projectRoot, ".codexrules");
|
|
26575
26808
|
const content = `# Wairon SDD Project
|
|
26576
26809
|
|
|
26577
26810
|
Refer to [.codex/agents/](.codex/agents/) for full instructions.
|
|
@@ -26947,18 +27180,15 @@ var logger = {
|
|
|
26947
27180
|
|
|
26948
27181
|
// src/core/skills.ts
|
|
26949
27182
|
var SKILL_NAMES = ["sdd-architect", "sdd-narrative", "sdd-auditor", "sdd-implement", "sdd-delegate"];
|
|
26950
|
-
function loadProjectConfig3() {
|
|
26951
|
-
return loadProjectConfig();
|
|
26952
|
-
}
|
|
26953
27183
|
function activeTargetTypes2() {
|
|
26954
|
-
const config =
|
|
27184
|
+
const config = loadProjectConfig();
|
|
26955
27185
|
if (!config) return [];
|
|
26956
27186
|
return activeTargetTypes(config);
|
|
26957
27187
|
}
|
|
26958
27188
|
var RESOURCE_SKILL_IDS = [...SKILL_NAMES].sort();
|
|
26959
27189
|
|
|
26960
27190
|
// src/index.ts
|
|
26961
|
-
function
|
|
27191
|
+
function loadProjectConfig2() {
|
|
26962
27192
|
const config = loadProjectConfig();
|
|
26963
27193
|
if (!config) throw new ProjectNotInitializedError();
|
|
26964
27194
|
return config;
|
|
@@ -27091,13 +27321,17 @@ function loadProjectConfig4() {
|
|
|
27091
27321
|
ambiguityMessage,
|
|
27092
27322
|
approvalRecord,
|
|
27093
27323
|
approvalVerdict,
|
|
27324
|
+
assertContainedProjectPath,
|
|
27094
27325
|
assertProjectInitialized,
|
|
27095
27326
|
backendCommand,
|
|
27327
|
+
backfillChainedSubprojectConfigs,
|
|
27096
27328
|
buildCanvasDataModel,
|
|
27097
27329
|
buildProjectGraph,
|
|
27098
27330
|
buildRuleContext,
|
|
27099
27331
|
callSitesOf,
|
|
27100
27332
|
captureApprovedSpecs,
|
|
27333
|
+
checkDeclarativePack,
|
|
27334
|
+
clearLoaderIssues,
|
|
27101
27335
|
cognitiveScore,
|
|
27102
27336
|
complexityLevel,
|
|
27103
27337
|
composeAgentBrief,
|
|
@@ -27112,6 +27346,7 @@ function loadProjectConfig4() {
|
|
|
27112
27346
|
createEmptyTopologyConfig,
|
|
27113
27347
|
createProjectConfig,
|
|
27114
27348
|
currentChildPins,
|
|
27349
|
+
currentRootBinding,
|
|
27115
27350
|
declaredPackNames,
|
|
27116
27351
|
declaredProfileIds,
|
|
27117
27352
|
declaresGlobalPacks,
|
|
@@ -27119,16 +27354,12 @@ function loadProjectConfig4() {
|
|
|
27119
27354
|
defaultNarrativeDetail,
|
|
27120
27355
|
defaultPackSelections,
|
|
27121
27356
|
defaultTargetConfig,
|
|
27122
|
-
deleteComponentSpec,
|
|
27123
|
-
deleteImplementationSpec,
|
|
27124
|
-
deleteInterfaceSpec,
|
|
27125
27357
|
deleteSpec,
|
|
27126
|
-
deleteSubsystemSpec,
|
|
27127
|
-
deleteTypeSpec,
|
|
27128
27358
|
deregisterPackRef,
|
|
27129
27359
|
deriveExecutionProfile,
|
|
27130
27360
|
derivedDocPaths,
|
|
27131
27361
|
detectDomainCandidates,
|
|
27362
|
+
diagnoseProjectPacks,
|
|
27132
27363
|
diagramSetIndex,
|
|
27133
27364
|
diffAgainstApproval,
|
|
27134
27365
|
diffSize,
|
|
@@ -27144,6 +27375,9 @@ function loadProjectConfig4() {
|
|
|
27144
27375
|
factsFor,
|
|
27145
27376
|
fieldTypeRefs,
|
|
27146
27377
|
fieldTypesOf,
|
|
27378
|
+
findChainingParent,
|
|
27379
|
+
findChainingSubprojectsMissingConfig,
|
|
27380
|
+
findLegacySpecFiles,
|
|
27147
27381
|
findProjectRoot,
|
|
27148
27382
|
findSystemRoot,
|
|
27149
27383
|
fromProjectRoot,
|
|
@@ -27153,6 +27387,7 @@ function loadProjectConfig4() {
|
|
|
27153
27387
|
generateDiagramSet,
|
|
27154
27388
|
generateSequenceDiagram,
|
|
27155
27389
|
getExporter,
|
|
27390
|
+
getLoaderIssues,
|
|
27156
27391
|
getProjectRoot,
|
|
27157
27392
|
getProjectRootOverride,
|
|
27158
27393
|
getRequestParentReach,
|
|
@@ -27160,6 +27395,7 @@ function loadProjectConfig4() {
|
|
|
27160
27395
|
getStatusReport,
|
|
27161
27396
|
globalGuideFilePath,
|
|
27162
27397
|
globalPacksDir,
|
|
27398
|
+
globalPacksEnabled,
|
|
27163
27399
|
globalTemplatesDir,
|
|
27164
27400
|
hasContext,
|
|
27165
27401
|
hasFunctionBody,
|
|
@@ -27192,6 +27428,7 @@ function loadProjectConfig4() {
|
|
|
27192
27428
|
loadInterfaceSpecs,
|
|
27193
27429
|
loadProjectConfig,
|
|
27194
27430
|
loadProjectExtensions,
|
|
27431
|
+
loadProjectVariants,
|
|
27195
27432
|
loadRegistry,
|
|
27196
27433
|
loadSpec,
|
|
27197
27434
|
loadSpecGraph,
|
|
@@ -27215,12 +27452,16 @@ function loadProjectConfig4() {
|
|
|
27215
27452
|
moveSubsystemProject,
|
|
27216
27453
|
movedChildren,
|
|
27217
27454
|
narrativeStepForeignFields,
|
|
27455
|
+
packDirEntry,
|
|
27456
|
+
packEntryLabel,
|
|
27457
|
+
packEntryRef,
|
|
27218
27458
|
packStoreDir,
|
|
27219
27459
|
parseDeclaredCall,
|
|
27220
27460
|
parseYaml,
|
|
27221
27461
|
passesIntentFloor,
|
|
27222
27462
|
pathExists,
|
|
27223
27463
|
pathKey,
|
|
27464
|
+
pinInstalledPacksAsSelections,
|
|
27224
27465
|
projectConfigExists,
|
|
27225
27466
|
provisionProject,
|
|
27226
27467
|
qualifiedTypeId,
|
|
@@ -27248,18 +27489,14 @@ function loadProjectConfig4() {
|
|
|
27248
27489
|
resolveImport,
|
|
27249
27490
|
resolveInstalledPack,
|
|
27250
27491
|
resolveSubprojectForNamespace,
|
|
27492
|
+
resolveVariantGuidance,
|
|
27251
27493
|
retireSpecialists,
|
|
27252
27494
|
runWithProjectBinding,
|
|
27253
27495
|
runWithProjectRoot,
|
|
27254
27496
|
sameContract,
|
|
27255
|
-
saveComponentSpec,
|
|
27256
|
-
saveImplementationSpec,
|
|
27257
|
-
saveInterfaceSpec,
|
|
27258
27497
|
saveSpec,
|
|
27259
|
-
saveSubsystemSpec,
|
|
27260
|
-
saveSystemSpec,
|
|
27261
27498
|
saveTopologyConfig,
|
|
27262
|
-
|
|
27499
|
+
scanAllSpecs,
|
|
27263
27500
|
serializeYaml,
|
|
27264
27501
|
setExecutionTier,
|
|
27265
27502
|
setLogLevel,
|