@wairon/cli 5.1.1-dev.60 → 5.1.1-dev.62
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 +1487 -1473
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +1142 -2611
- 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 path28 = __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");
|
|
@@ -3060,8 +3060,8 @@ var require_dist = __commonJS({
|
|
|
3060
3060
|
function slug(name) {
|
|
3061
3061
|
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
3062
3062
|
}
|
|
3063
|
-
var
|
|
3064
|
-
var
|
|
3063
|
+
var fs18 = __toESM2(require("fs"));
|
|
3064
|
+
var path29 = __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,9 +3099,9 @@ var require_dist = __commonJS({
|
|
|
3099
3099
|
}
|
|
3100
3100
|
function writeTree(destDir, files) {
|
|
3101
3101
|
for (const file of files) {
|
|
3102
|
-
const absolute =
|
|
3103
|
-
|
|
3104
|
-
|
|
3102
|
+
const absolute = path29.join(destDir, file.path);
|
|
3103
|
+
fs18.mkdirSync(path29.dirname(absolute), { recursive: true });
|
|
3104
|
+
fs18.writeFileSync(absolute, file.contents);
|
|
3105
3105
|
}
|
|
3106
3106
|
}
|
|
3107
3107
|
function classifyKind(name, symlinks) {
|
|
@@ -3110,14 +3110,14 @@ var require_dist = __commonJS({
|
|
|
3110
3110
|
return "file";
|
|
3111
3111
|
}
|
|
3112
3112
|
function walkPackDir(root, current2, out) {
|
|
3113
|
-
for (const entry of
|
|
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, path29.join(current2, entry.name), out);
|
|
3117
3117
|
} else if (entry.isFile()) {
|
|
3118
|
-
const absolute =
|
|
3119
|
-
const relative22 =
|
|
3120
|
-
out.push({ path: relative22, contents:
|
|
3118
|
+
const absolute = path29.join(current2, entry.name);
|
|
3119
|
+
const relative22 = path29.relative(root, absolute).split(path29.sep).join("/");
|
|
3120
|
+
out.push({ path: relative22, contents: fs18.readFileSync(absolute) });
|
|
3121
3121
|
}
|
|
3122
3122
|
}
|
|
3123
3123
|
}
|
|
@@ -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) => path28.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 = path28.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 = path28.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(path28.sep).join("/").replace(/^\.\//, "").replace(/\/+$/, "");
|
|
3321
3321
|
return posix2 === "" || posix2 === "." ? "." : posix2;
|
|
3322
3322
|
}
|
|
3323
3323
|
function slugify(projectName) {
|
|
@@ -3392,7 +3392,6 @@ __export(src_exports, {
|
|
|
3392
3392
|
AgentRecordSchema: () => AgentRecordSchema,
|
|
3393
3393
|
AgentStatusSchema: () => AgentStatusSchema,
|
|
3394
3394
|
AgentTemplateSchema: () => AgentTemplateSchema,
|
|
3395
|
-
AssertionSelectorSchema: () => AssertionSelectorSchema,
|
|
3396
3395
|
BACKEND_COMMANDS: () => BACKEND_COMMANDS,
|
|
3397
3396
|
BUILTIN_PROFILES: () => BUILTIN_PROFILES,
|
|
3398
3397
|
BUILTIN_TYPES: () => BUILTIN_TYPES,
|
|
@@ -3400,8 +3399,6 @@ __export(src_exports, {
|
|
|
3400
3399
|
BuiltinTargetConfigSchema: () => BuiltinTargetConfigSchema,
|
|
3401
3400
|
BuiltinTargetSchema: () => BuiltinTargetSchema,
|
|
3402
3401
|
BundleNotFoundError: () => BundleNotFoundError,
|
|
3403
|
-
COMPONENT_AUTH_SOURCE: () => COMPONENT_AUTH_SOURCE,
|
|
3404
|
-
CONTEXT_PATHS: () => CONTEXT_PATHS,
|
|
3405
3402
|
CarriedDebtKindSchema: () => CarriedDebtKindSchema,
|
|
3406
3403
|
CarriedDebtSchema: () => CarriedDebtSchema,
|
|
3407
3404
|
CarriedFindingSchema: () => CarriedFindingSchema,
|
|
@@ -3418,7 +3415,6 @@ __export(src_exports, {
|
|
|
3418
3415
|
CustomTargetSchema: () => CustomTargetSchema,
|
|
3419
3416
|
DEFAULT_TARGET_DIRS: () => DEFAULT_TARGET_DIRS,
|
|
3420
3417
|
DatabaseSpecSchema: () => DatabaseSpecSchema,
|
|
3421
|
-
DeclarativePackSchema: () => DeclarativePackSchema,
|
|
3422
3418
|
DependencyClassSchema: () => DependencyClassSchema,
|
|
3423
3419
|
DesignDepthSchema: () => DesignDepthSchema,
|
|
3424
3420
|
DiagramConfigSchema: () => DiagramConfigSchema,
|
|
@@ -3434,7 +3430,6 @@ __export(src_exports, {
|
|
|
3434
3430
|
ExternalLinkTypeSchema: () => ExternalLinkTypeSchema,
|
|
3435
3431
|
FindingDeclarationSchema: () => FindingDeclarationSchema,
|
|
3436
3432
|
GITHUB_REPO: () => GITHUB_REPO,
|
|
3437
|
-
GLOBAL_PACKS_DEFAULT: () => GLOBAL_PACKS_DEFAULT,
|
|
3438
3433
|
GeminiExporter: () => GeminiExporter,
|
|
3439
3434
|
GroupSpecSchema: () => GroupSpecSchema,
|
|
3440
3435
|
GuaranteeSchema: () => GuaranteeSchema,
|
|
@@ -3442,7 +3437,6 @@ __export(src_exports, {
|
|
|
3442
3437
|
ImplementationSpecSchema: () => ImplementationSpecSchema,
|
|
3443
3438
|
InterfaceSpecSchema: () => InterfaceSpecSchema,
|
|
3444
3439
|
InvariantSchema: () => InvariantSchema,
|
|
3445
|
-
LanguagePackDefSchema: () => LanguagePackDefSchema,
|
|
3446
3440
|
LifecycleEntrypointSchema: () => LifecycleEntrypointSchema,
|
|
3447
3441
|
LintAllowSchema: () => LintAllowSchema,
|
|
3448
3442
|
LintConfigSchema: () => LintConfigSchema,
|
|
@@ -3456,21 +3450,15 @@ __export(src_exports, {
|
|
|
3456
3450
|
NarrativeStepSchema: () => NarrativeStepSchema,
|
|
3457
3451
|
NarrativeStepTypeSchema: () => NarrativeStepTypeSchema,
|
|
3458
3452
|
OutputTargetSchema: () => OutputTargetSchema,
|
|
3459
|
-
PACK_DIR_ENTRIES: () => PACK_DIR_ENTRIES,
|
|
3460
3453
|
PATTERN_TYPES: () => PATTERN_TYPES,
|
|
3461
3454
|
PROJECT_KINDS: () => PROJECT_KINDS,
|
|
3462
|
-
PackAssertionSchema: () => PackAssertionSchema,
|
|
3463
|
-
PackInstructionBlockSchema: () => PackInstructionBlockSchema,
|
|
3464
3455
|
PackSelectionSchema: () => PackSelectionSchema,
|
|
3465
|
-
PackSkillSchema: () => PackSkillSchema,
|
|
3466
3456
|
ParallelBranchSchema: () => ParallelBranchSchema,
|
|
3467
3457
|
PathsConfigSchema: () => PathsConfigSchema,
|
|
3468
|
-
PatternDefSchema: () => PatternDefSchema,
|
|
3469
3458
|
PatternRefSchema: () => PatternRefSchema,
|
|
3470
3459
|
PortalAuthSchema: () => PortalAuthSchema,
|
|
3471
3460
|
PortalAuthSchemeSchema: () => PortalAuthSchemeSchema,
|
|
3472
3461
|
PortalTypeSchema: () => PortalTypeSchema,
|
|
3473
|
-
ProfileDefSchema: () => ProfileDefSchema,
|
|
3474
3462
|
ProfileSelectionSubjectSchema: () => ProfileSelectionSubjectSchema,
|
|
3475
3463
|
ProjectConfigSchema: () => ProjectConfigSchema,
|
|
3476
3464
|
ProjectNotInitializedError: () => ProjectNotInitializedError,
|
|
@@ -3489,10 +3477,8 @@ __export(src_exports, {
|
|
|
3489
3477
|
STEP_TYPE_FIELDS: () => STEP_TYPE_FIELDS,
|
|
3490
3478
|
SUPPORTED_ALIASES: () => SUPPORTED_ALIASES,
|
|
3491
3479
|
SURFACE_AUDIENCES: () => SURFACE_AUDIENCES,
|
|
3492
|
-
SkillResourceNotFoundError: () => SkillResourceNotFoundError,
|
|
3493
3480
|
SpecIdSchema: () => SpecIdSchema,
|
|
3494
3481
|
SpecStatusSchema: () => SpecStatusSchema,
|
|
3495
|
-
SpecWorkspace: () => SpecWorkspace,
|
|
3496
3482
|
SubsystemSpecSchema: () => SubsystemSpecSchema,
|
|
3497
3483
|
SurfaceAudienceSchema: () => SurfaceAudienceSchema,
|
|
3498
3484
|
SurfaceContractEntrySchema: () => SurfaceContractEntrySchema,
|
|
@@ -3512,9 +3498,6 @@ __export(src_exports, {
|
|
|
3512
3498
|
TypeKindSchema: () => TypeKindSchema,
|
|
3513
3499
|
TypeMethodSchema: () => TypeMethodSchema,
|
|
3514
3500
|
TypeSpecSchema: () => TypeSpecSchema,
|
|
3515
|
-
UNVERSIONED: () => UNVERSIONED,
|
|
3516
|
-
UnknownAgentError: () => UnknownAgentError,
|
|
3517
|
-
VariantDefSchema: () => VariantDefSchema,
|
|
3518
3501
|
WAIRON_MANAGED_BANNER: () => WAIRON_MANAGED_BANNER,
|
|
3519
3502
|
WAIRON_MANAGED_MARKER: () => WAIRON_MANAGED_MARKER,
|
|
3520
3503
|
WAIRON_VERSION: () => WAIRON_VERSION,
|
|
@@ -3525,44 +3508,28 @@ __export(src_exports, {
|
|
|
3525
3508
|
aiDirAt: () => aiDirAt,
|
|
3526
3509
|
aiPathsAt: () => aiPathsAt,
|
|
3527
3510
|
ambiguityMessage: () => ambiguityMessage,
|
|
3528
|
-
applySpecStatus: () => applySpecStatus,
|
|
3529
3511
|
approvalRecord: () => approvalRecord,
|
|
3530
|
-
|
|
3512
|
+
approvalVerdict: () => approvalVerdict,
|
|
3531
3513
|
assertProjectInitialized: () => assertProjectInitialized,
|
|
3532
|
-
assertionFullCode: () => assertionFullCode,
|
|
3533
|
-
audienceRank: () => audienceRank,
|
|
3534
3514
|
backendCommand: () => backendCommand,
|
|
3535
|
-
backfillChainedSubprojectConfigs: () => backfillChainedSubprojectConfigs,
|
|
3536
3515
|
buildCanvasDataModel: () => buildCanvasDataModel,
|
|
3537
|
-
buildGraphModel: () => buildGraphModel,
|
|
3538
3516
|
buildProjectGraph: () => buildProjectGraph,
|
|
3539
3517
|
buildRuleContext: () => buildRuleContext,
|
|
3540
|
-
buildServerInstructions: () => buildServerInstructions2,
|
|
3541
|
-
buildTreeArchive: () => buildTreeArchive2,
|
|
3542
3518
|
callSitesOf: () => callSitesOf,
|
|
3543
3519
|
captureApprovedSpecs: () => captureApprovedSpecs,
|
|
3544
|
-
checkSkillFreshness: () => checkSkillFreshness,
|
|
3545
|
-
clearLoaderIssues: () => clearLoaderIssues,
|
|
3546
3520
|
cognitiveScore: () => cognitiveScore,
|
|
3547
|
-
collectPromotableSpecs: () => collectPromotableSpecs,
|
|
3548
|
-
commitStagedTree: () => commitStagedTree,
|
|
3549
3521
|
complexityLevel: () => complexityLevel,
|
|
3550
3522
|
composeAgentBrief: () => composeAgentBrief,
|
|
3551
3523
|
composeRuleSequence: () => composeRuleSequence,
|
|
3552
|
-
composeVariantGuidance: () => composeVariantGuidance,
|
|
3553
|
-
computeGateStateId: () => computeGateStateId,
|
|
3554
|
-
computePackDigest: () => computePackDigest,
|
|
3555
3524
|
computeStateId: () => computeStateId,
|
|
3556
3525
|
computeStateIdAt: () => computeStateIdAt,
|
|
3557
3526
|
conceptNoun: () => conceptNoun,
|
|
3558
3527
|
consumedContractInputs: () => consumedContractInputs,
|
|
3559
|
-
contextDir: () => contextDir,
|
|
3560
3528
|
createAgentRecord: () => createAgentRecord,
|
|
3561
3529
|
createChainedSubsystem: () => createChainedSubsystem,
|
|
3562
3530
|
createEmptyRegistry: () => createEmptyRegistry,
|
|
3563
3531
|
createEmptyTopologyConfig: () => createEmptyTopologyConfig,
|
|
3564
3532
|
createProjectConfig: () => createProjectConfig,
|
|
3565
|
-
createStagingDir: () => createStagingDir,
|
|
3566
3533
|
currentChildPins: () => currentChildPins,
|
|
3567
3534
|
declaredPackNames: () => declaredPackNames,
|
|
3568
3535
|
declaredProfileIds: () => declaredProfileIds,
|
|
@@ -3572,129 +3539,82 @@ __export(src_exports, {
|
|
|
3572
3539
|
defaultPackSelections: () => defaultPackSelections,
|
|
3573
3540
|
defaultTargetConfig: () => defaultTargetConfig,
|
|
3574
3541
|
deleteComponentSpec: () => deleteComponentSpec,
|
|
3575
|
-
deleteGroupSpec: () => deleteGroupSpec,
|
|
3576
3542
|
deleteImplementationSpec: () => deleteImplementationSpec,
|
|
3577
3543
|
deleteInterfaceSpec: () => deleteInterfaceSpec,
|
|
3578
3544
|
deleteSubsystemSpec: () => deleteSubsystemSpec,
|
|
3579
3545
|
deleteTypeSpec: () => deleteTypeSpec,
|
|
3580
3546
|
deregisterPackRef: () => deregisterPackRef,
|
|
3581
3547
|
deriveExecutionProfile: () => deriveExecutionProfile,
|
|
3582
|
-
|
|
3548
|
+
derivedDocPaths: () => derivedDocPaths,
|
|
3583
3549
|
detectDomainCandidates: () => detectDomainCandidates,
|
|
3584
|
-
diagnoseProjectPacks: () => diagnoseProjectPacks,
|
|
3585
3550
|
diagramSetIndex: () => diagramSetIndex,
|
|
3586
3551
|
diffAgainstApproval: () => diffAgainstApproval,
|
|
3587
3552
|
diffSize: () => diffSize,
|
|
3588
|
-
discardStagingDir: () => discardStagingDir,
|
|
3589
3553
|
discoverPacks: () => discoverPacks,
|
|
3590
3554
|
dryRunSerializeSpecs: () => dryRunSerializeSpecs,
|
|
3591
3555
|
effectiveDetail: () => effectiveDetail,
|
|
3592
3556
|
emptyExtensions: () => emptyExtensions,
|
|
3593
3557
|
ensureDir: () => ensureDir,
|
|
3594
3558
|
ensureProjectInitialized: () => ensureProjectInitialized,
|
|
3595
|
-
exportSddSkills: () => exportSddSkills,
|
|
3596
3559
|
exportSpecTree: () => exportSpecTree,
|
|
3597
|
-
exportSurface: () => exportSurface,
|
|
3598
3560
|
externalizeSubsystem: () => externalizeSubsystem,
|
|
3599
|
-
extractTreeArchive: () => extractTreeArchive2,
|
|
3600
3561
|
extractTypeIdentifiers: () => extractTypeIdentifiers,
|
|
3601
3562
|
factsFor: () => factsFor,
|
|
3602
3563
|
fieldTypeRefs: () => fieldTypeRefs,
|
|
3603
3564
|
fieldTypesOf: () => fieldTypesOf,
|
|
3604
|
-
findChainingParent: () => findChainingParent,
|
|
3605
|
-
findChainingSubprojectsMissingConfig: () => findChainingSubprojectsMissingConfig,
|
|
3606
|
-
findLegacySpecFiles: () => findLegacySpecFiles,
|
|
3607
3565
|
findProjectRoot: () => findProjectRoot,
|
|
3608
3566
|
findSystemRoot: () => findSystemRoot,
|
|
3609
|
-
findTestsReferencing: () => findTestsReferencing2,
|
|
3610
|
-
fromOpenApi: () => fromOpenApi,
|
|
3611
3567
|
fromProjectRoot: () => fromProjectRoot,
|
|
3612
3568
|
generateAgent: () => generateAgent,
|
|
3613
3569
|
generateAll: () => generateAll,
|
|
3614
3570
|
generateComponentDiagram: () => generateComponentDiagram,
|
|
3615
3571
|
generateDiagramSet: () => generateDiagramSet,
|
|
3616
3572
|
generateSequenceDiagram: () => generateSequenceDiagram,
|
|
3617
|
-
getComponentPath: () => getComponentPath,
|
|
3618
3573
|
getExporter: () => getExporter,
|
|
3619
|
-
getGroupPath: () => getGroupPath,
|
|
3620
|
-
getImplementationPath: () => getImplementationPath,
|
|
3621
|
-
getInterfacePath: () => getInterfacePath,
|
|
3622
|
-
getLoaderIssues: () => getLoaderIssues,
|
|
3623
3574
|
getProjectRoot: () => getProjectRoot,
|
|
3624
3575
|
getProjectRootOverride: () => getProjectRootOverride,
|
|
3625
3576
|
getRequestParentReach: () => getRequestParentReach,
|
|
3626
3577
|
getRequestProjectRoot: () => getRequestProjectRoot,
|
|
3627
|
-
|
|
3628
|
-
getSubprojectPrefix: () => getSubprojectPrefix,
|
|
3629
|
-
getSubsystemPath: () => getSubsystemPath,
|
|
3630
|
-
getTypePath: () => getTypePath,
|
|
3578
|
+
getStatusReport: () => getStatusReport,
|
|
3631
3579
|
globalGuideFilePath: () => globalGuideFilePath,
|
|
3632
3580
|
globalPacksDir: () => globalPacksDir,
|
|
3633
|
-
globalPacksEnabled: () => globalPacksEnabled,
|
|
3634
3581
|
globalTemplatesDir: () => globalTemplatesDir,
|
|
3635
|
-
globalVariantsDir: () => globalVariantsDir,
|
|
3636
|
-
hasArchitectureContext: () => hasArchitectureContext,
|
|
3637
|
-
hasAuthoredSpecs: () => hasAuthoredSpecs,
|
|
3638
3582
|
hasContext: () => hasContext,
|
|
3639
3583
|
hasFunctionBody: () => hasFunctionBody,
|
|
3640
|
-
hasSpecTree: () => hasSpecTree,
|
|
3641
3584
|
headNoun: () => headNoun,
|
|
3642
3585
|
holdsState: () => holdsState,
|
|
3643
3586
|
implementationSourceFiles: () => implementationSourceFiles,
|
|
3644
3587
|
importBindingOf: () => importBindingOf,
|
|
3645
3588
|
importSpecTree: () => importSpecTree,
|
|
3646
|
-
importSurface: () => importSurface,
|
|
3647
|
-
ineffectiveDeltaPaths: () => ineffectiveDeltaPaths,
|
|
3648
3589
|
injectGuide: () => injectGuide,
|
|
3649
|
-
inspectChainedRoots: () => inspectChainedRoots,
|
|
3650
|
-
inspectTreeArchive: () => inspectTreeArchive2,
|
|
3651
3590
|
installPackFromDirectory: () => installPackFromDirectory,
|
|
3652
3591
|
interfaceGenericParameters: () => interfaceGenericParameters,
|
|
3653
3592
|
internalizeSubsystem: () => internalizeSubsystem,
|
|
3654
|
-
invalidateSpecCache: () => invalidateSpecCache,
|
|
3655
3593
|
isDraftSubsystem: () => isDraftSubsystem,
|
|
3656
3594
|
isLogic: () => isLogic,
|
|
3657
|
-
isOpenApiDocument: () => isOpenApiDocument,
|
|
3658
3595
|
isPattern: () => isPattern,
|
|
3659
3596
|
isProjectInitialized: () => isProjectInitialized,
|
|
3660
3597
|
isProvidedBy: () => isProvidedBy,
|
|
3661
3598
|
isRetired: () => isRetired,
|
|
3662
|
-
listChainedRoots: () => listChainedRoots,
|
|
3663
3599
|
listDirectChainedSubprojects: () => listDirectChainedSubprojects,
|
|
3664
|
-
listExternalInterfaces: () => listExternalInterfaces,
|
|
3665
3600
|
listFiles: () => listFiles,
|
|
3666
3601
|
listFilesRecursive: () => listFilesRecursive,
|
|
3667
3602
|
listInstalledPacks: () => listInstalledPacks,
|
|
3668
|
-
listMountSnapshots: () => listMountSnapshots,
|
|
3669
|
-
listProjectVariants: () => listProjectVariants,
|
|
3670
|
-
listResources: () => listResources,
|
|
3671
|
-
listRules: () => listRules2,
|
|
3672
|
-
listSkillNames: () => listSkillNames,
|
|
3673
|
-
listSkillResources: () => listSkillResources,
|
|
3674
|
-
listSnapshots: () => listSnapshots,
|
|
3675
|
-
listTemplateIds: () => listTemplateIds,
|
|
3676
|
-
loadAgentOverride: () => loadAgentOverride,
|
|
3677
3603
|
loadComponentSpec: () => loadComponentSpec,
|
|
3678
3604
|
loadComponentSpecs: () => loadComponentSpecs,
|
|
3679
3605
|
loadExtensionPacks: () => loadExtensionPacks,
|
|
3680
3606
|
loadExtensions: () => loadExtensions,
|
|
3681
|
-
loadGroupSpec: () => loadGroupSpec,
|
|
3682
|
-
loadGroupSpecs: () => loadGroupSpecs,
|
|
3683
3607
|
loadImplementationSpec: () => loadImplementationSpec,
|
|
3684
3608
|
loadImplementationSpecs: () => loadImplementationSpecs,
|
|
3685
3609
|
loadInterfaceSpec: () => loadInterfaceSpec,
|
|
3686
3610
|
loadInterfaceSpecs: () => loadInterfaceSpecs,
|
|
3687
|
-
loadMountSurfaceSnapshots: () => loadMountSurfaceSnapshots,
|
|
3688
3611
|
loadProjectConfig: () => loadProjectConfig4,
|
|
3689
3612
|
loadProjectExtensions: () => loadProjectExtensions,
|
|
3690
|
-
loadProjectVariants: () => loadProjectVariants,
|
|
3691
3613
|
loadRegistry: () => loadRegistry,
|
|
3692
3614
|
loadSpecGraph: () => loadSpecGraph,
|
|
3693
3615
|
loadSubsystemSpec: () => loadSubsystemSpec,
|
|
3694
3616
|
loadSubsystemSpecs: () => loadSubsystemSpecs,
|
|
3695
|
-
loadSurfaceSnapshots: () => loadSurfaceSnapshots,
|
|
3696
3617
|
loadSystemSpec: () => loadSystemSpec,
|
|
3697
|
-
loadTemplate: () => loadTemplate,
|
|
3698
3618
|
loadTopologyConfig: () => loadTopologyConfig,
|
|
3699
3619
|
loadTypeSpec: () => loadTypeSpec,
|
|
3700
3620
|
loadTypeSpecs: () => loadTypeSpecs,
|
|
@@ -3712,53 +3632,30 @@ __export(src_exports, {
|
|
|
3712
3632
|
moveSubsystemProject: () => moveSubsystemProject,
|
|
3713
3633
|
movedChildren: () => movedChildren,
|
|
3714
3634
|
narrativeStepForeignFields: () => narrativeStepForeignFields,
|
|
3715
|
-
normalizeApprover: () => normalizeApprover,
|
|
3716
|
-
normalizeComponentLayout: () => normalizeComponentLayout,
|
|
3717
|
-
packDirEntry: () => packDirEntry,
|
|
3718
|
-
packEntryLabel: () => packEntryLabel,
|
|
3719
|
-
packEntryRef: () => packEntryRef,
|
|
3720
3635
|
packStoreDir: () => packStoreDir,
|
|
3721
3636
|
parseDeclaredCall: () => parseDeclaredCall,
|
|
3722
|
-
parseTemplate: () => parseTemplate,
|
|
3723
3637
|
parseYaml: () => parseYaml,
|
|
3724
3638
|
passesIntentFloor: () => passesIntentFloor,
|
|
3725
3639
|
pathExists: () => pathExists,
|
|
3726
3640
|
pathKey: () => pathKey,
|
|
3727
|
-
pinFamilySurfaces: () => pinFamilySurfaces,
|
|
3728
|
-
pinInstalledPacksAsSelections: () => pinInstalledPacksAsSelections,
|
|
3729
|
-
projectChildSurface: () => projectChildSurface,
|
|
3730
3641
|
projectConfigExists: () => projectConfigExists,
|
|
3731
|
-
projectOwnSurface: () => projectOwnSurface,
|
|
3732
|
-
projectSubsystemSurface: () => projectSubsystemSurface,
|
|
3733
3642
|
provisionProject: () => provisionProject,
|
|
3734
3643
|
qualifiedTypeId: () => qualifiedTypeId,
|
|
3735
|
-
readArchitectureContext: () => readArchitectureContext,
|
|
3736
3644
|
readFileOrNull: () => readFileOrNull,
|
|
3737
3645
|
readJsonFile: () => readJsonFile,
|
|
3738
3646
|
readLockRecord: () => readLockRecord,
|
|
3739
|
-
readLockRecordAt: () => readLockRecordAt,
|
|
3740
3647
|
readLockState: () => readLockState,
|
|
3741
|
-
readManifest: () => readManifest,
|
|
3742
|
-
readProjectContext: () => readProjectContext,
|
|
3743
|
-
readResource: () => readResource,
|
|
3744
|
-
readSkillResource: () => readSkillResource,
|
|
3745
3648
|
readStampVersion: () => readStampVersion,
|
|
3746
3649
|
readYamlFile: () => readYamlFile,
|
|
3747
|
-
rebaseProjectVariants: () => rebaseProjectVariants,
|
|
3748
|
-
rebaseReference: () => rebaseReference,
|
|
3749
3650
|
recordProfileSelection: () => recordProfileSelection,
|
|
3750
3651
|
registerExporter: () => registerExporter,
|
|
3751
3652
|
registerPackRef: () => registerPackRef,
|
|
3752
3653
|
reinjectLocalGuides: () => reinjectLocalGuides,
|
|
3753
3654
|
removeDomain: () => removeDomain,
|
|
3754
3655
|
removePackSelection: () => removePackSelection,
|
|
3755
|
-
removeSnapshot: () => removeSnapshot,
|
|
3756
3656
|
renameComponent: () => renameComponent,
|
|
3757
3657
|
renameMethod: () => renameMethod,
|
|
3758
3658
|
renderDiagram: () => renderDiagram,
|
|
3759
|
-
renderDomainsDoc: () => renderDomainsDoc,
|
|
3760
|
-
renderTemplateInstructions: () => renderTemplateInstructions,
|
|
3761
|
-
renderWaironGuide: () => renderWaironGuide,
|
|
3762
3659
|
repairForeignStepFields: () => repairForeignStepFields,
|
|
3763
3660
|
resolveAgentTopology: () => resolveAgentTopology,
|
|
3764
3661
|
resolveBudget: () => resolveBudget,
|
|
@@ -3767,47 +3664,31 @@ __export(src_exports, {
|
|
|
3767
3664
|
resolveExpectedOutputPaths: () => resolveExpectedOutputPaths,
|
|
3768
3665
|
resolveImport: () => resolveImport,
|
|
3769
3666
|
resolveInstalledPack: () => resolveInstalledPack,
|
|
3770
|
-
resolvePackRef: () => resolvePackRef,
|
|
3771
3667
|
resolveSubprojectForNamespace: () => resolveSubprojectForNamespace,
|
|
3772
|
-
resolveVariantGuidance: () => resolveVariantGuidance,
|
|
3773
|
-
restoreSpecFiles: () => restoreSpecFiles,
|
|
3774
3668
|
retireSpecialists: () => retireSpecialists,
|
|
3775
|
-
rewriteSpecRefs: () => rewriteSpecRefs,
|
|
3776
3669
|
runWithProjectBinding: () => runWithProjectBinding,
|
|
3777
3670
|
runWithProjectRoot: () => runWithProjectRoot,
|
|
3778
3671
|
sameContract: () => sameContract,
|
|
3779
3672
|
saveComponentSpec: () => saveComponentSpec,
|
|
3780
|
-
saveGroupSpec: () => saveGroupSpec,
|
|
3781
3673
|
saveImplementationSpec: () => saveImplementationSpec,
|
|
3782
3674
|
saveInterfaceSpec: () => saveInterfaceSpec,
|
|
3783
|
-
saveSnapshot: () => saveSnapshot,
|
|
3784
3675
|
saveSubsystemSpec: () => saveSubsystemSpec,
|
|
3785
3676
|
saveSystemSpec: () => saveSystemSpec,
|
|
3786
3677
|
saveTopologyConfig: () => saveTopologyConfig,
|
|
3787
3678
|
saveTypeSpec: () => saveTypeSpec,
|
|
3788
|
-
scanAllSpecs: () => scanAllSpecs,
|
|
3789
3679
|
serializeYaml: () => serializeYaml,
|
|
3790
3680
|
setExecutionTier: () => setExecutionTier,
|
|
3791
3681
|
setLogLevel: () => setLogLevel,
|
|
3792
3682
|
setProjectRoot: () => setProjectRoot,
|
|
3793
3683
|
setProjectType: () => setProjectType,
|
|
3794
3684
|
settledSpecPaths: () => settledSpecPaths,
|
|
3795
|
-
skillExtendErrors: () => skillExtendErrors,
|
|
3796
|
-
skillsDirForTarget: () => skillsDirForTarget,
|
|
3797
|
-
snapshotSpecFiles: () => snapshotSpecFiles,
|
|
3798
|
-
specChanges: () => specChanges,
|
|
3799
|
-
specKind: () => specKind,
|
|
3800
3685
|
specPathsInScope: () => specPathsInScope,
|
|
3801
3686
|
splitNamespace: () => splitNamespace,
|
|
3802
|
-
stateIdEquals: () => stateIdEquals,
|
|
3803
|
-
stateIdString: () => stateIdString,
|
|
3804
3687
|
stepConfigVerdict: () => stepConfigVerdict,
|
|
3805
3688
|
stepFieldsFor: () => stepFieldsFor,
|
|
3806
3689
|
stepGraph: () => stepGraph,
|
|
3807
3690
|
syncContextFiles: () => syncContextFiles,
|
|
3808
3691
|
toMarkdown: () => toMarkdown,
|
|
3809
|
-
toOpenApi: () => toOpenApi,
|
|
3810
|
-
toOpenApiSet: () => toOpenApiSet,
|
|
3811
3692
|
typeBindingOf: () => typeBindingOf,
|
|
3812
3693
|
typeGenericParameters: () => typeGenericParameters,
|
|
3813
3694
|
typeMatchesRef: () => typeMatchesRef,
|
|
@@ -3815,18 +3696,11 @@ __export(src_exports, {
|
|
|
3815
3696
|
uninstallPack: () => uninstallPack,
|
|
3816
3697
|
updateSpec: () => updateSpec,
|
|
3817
3698
|
upsertPackSelection: () => upsertPackSelection,
|
|
3818
|
-
validateAsComplete: () => validateAsComplete,
|
|
3819
|
-
validateComponentCandidate: () => validateComponentCandidate,
|
|
3820
|
-
validateProjectConfig: () => validateProjectConfig,
|
|
3821
|
-
validateRegistry: () => validateRegistry,
|
|
3822
3699
|
validateSddTree: () => validateSddTree,
|
|
3823
|
-
workspaceFor: () => workspaceFor,
|
|
3824
|
-
writeArchitectureContext: () => writeArchitectureContext,
|
|
3825
3700
|
writeFile: () => writeFile,
|
|
3826
3701
|
writeFileIfChanged: () => writeFileIfChanged,
|
|
3827
3702
|
writeJsonFile: () => writeJsonFile,
|
|
3828
3703
|
writeLockRecord: () => writeLockRecord,
|
|
3829
|
-
writeProjectContext: () => writeProjectContext,
|
|
3830
3704
|
writeRootGuideDelegator: () => writeRootGuideDelegator,
|
|
3831
3705
|
writeYamlFile: () => writeYamlFile
|
|
3832
3706
|
});
|
|
@@ -4718,17 +4592,17 @@ function overlayKnownFields(schema, typed, onDisk) {
|
|
|
4718
4592
|
}
|
|
4719
4593
|
return typed;
|
|
4720
4594
|
}
|
|
4721
|
-
function overlayLevel(typed, onDisk,
|
|
4595
|
+
function overlayLevel(typed, onDisk, schemaFor) {
|
|
4722
4596
|
const document = isPlainObject(onDisk) ? onDisk : {};
|
|
4723
4597
|
const out = {};
|
|
4724
4598
|
for (const [key, stored] of Object.entries(document)) {
|
|
4725
|
-
const schema =
|
|
4599
|
+
const schema = schemaFor(key);
|
|
4726
4600
|
if (schema === null) out[key] = stored;
|
|
4727
4601
|
else if (typed[key] !== void 0) out[key] = overlayKnownFields(schema, typed[key], stored);
|
|
4728
4602
|
}
|
|
4729
4603
|
for (const [key, value] of Object.entries(typed)) {
|
|
4730
4604
|
if (hasOwn(document, key) || value === void 0) continue;
|
|
4731
|
-
const schema =
|
|
4605
|
+
const schema = schemaFor(key);
|
|
4732
4606
|
if (schema !== null) out[key] = overlayKnownFields(schema, value, void 0);
|
|
4733
4607
|
}
|
|
4734
4608
|
return out;
|
|
@@ -5085,10 +4959,6 @@ function normalizeApprover(value) {
|
|
|
5085
4959
|
}
|
|
5086
4960
|
return { id: typeof value === "string" && value ? value : "unknown", source: "legacy" };
|
|
5087
4961
|
}
|
|
5088
|
-
function describeApprover(who) {
|
|
5089
|
-
const label = who.name ? `${who.name} (${who.id})` : who.id;
|
|
5090
|
-
return who.source === "hosted" ? `${label} [authenticated]` : label;
|
|
5091
|
-
}
|
|
5092
4962
|
function readLockRecord() {
|
|
5093
4963
|
try {
|
|
5094
4964
|
return normalizeRecord(JSON.parse(fs4.readFileSync(lockPath(), "utf8")));
|
|
@@ -6406,10 +6276,10 @@ function stepGraph(method) {
|
|
|
6406
6276
|
const s = byNum.get(n);
|
|
6407
6277
|
if (s.type !== "parallel" || s.endStep === void 0 || !s.branches?.length) continue;
|
|
6408
6278
|
const entries = s.branches.map((b) => b.step).sort((a, b) => a - b);
|
|
6409
|
-
const
|
|
6279
|
+
const join17 = fallNext(s.endStep);
|
|
6410
6280
|
for (let i = 0; i < entries.length; i++) {
|
|
6411
6281
|
const armEnd = i + 1 < entries.length ? prevOf(entries[i + 1]) : s.endStep;
|
|
6412
|
-
if (armEnd !== void 0 && armEnd >= entries[i]) armEndJoin.set(armEnd,
|
|
6282
|
+
if (armEnd !== void 0 && armEnd >= entries[i]) armEndJoin.set(armEnd, join17);
|
|
6413
6283
|
}
|
|
6414
6284
|
}
|
|
6415
6285
|
const successorsOf = (n) => {
|
|
@@ -11662,7 +11532,7 @@ function defaultTargetConfig(type) {
|
|
|
11662
11532
|
enabled: true
|
|
11663
11533
|
};
|
|
11664
11534
|
}
|
|
11665
|
-
var WAIRON_VERSION = "5.1.1-dev.
|
|
11535
|
+
var WAIRON_VERSION = "5.1.1-dev.62";
|
|
11666
11536
|
var GITHUB_REPO = "SYW-Apps/Waffle-AIron";
|
|
11667
11537
|
var ARCHITECT_AGENT_ID = "agent-architect";
|
|
11668
11538
|
var ARCHITECT_TEMPLATE_ID = "architect";
|
|
@@ -12196,66 +12066,6 @@ function defaultPackSelections() {
|
|
|
12196
12066
|
return [];
|
|
12197
12067
|
}
|
|
12198
12068
|
}
|
|
12199
|
-
function diagnoseProjectPacks() {
|
|
12200
|
-
const empty = { globalsUndeclared: false, notApplied: [], unresolved: [], globalsApplied: [] };
|
|
12201
|
-
try {
|
|
12202
|
-
const config = projectConfigRepository.load();
|
|
12203
|
-
if (!config) return empty;
|
|
12204
|
-
const globalsUndeclared = !projectConfigRepository.declaresGlobalPacks();
|
|
12205
|
-
const projectRoot = getProjectRoot();
|
|
12206
|
-
const entries = config.extensions?.packs ?? [];
|
|
12207
|
-
const unresolved = [];
|
|
12208
|
-
const selectedNames = /* @__PURE__ */ new Set();
|
|
12209
|
-
for (const entry of entries) {
|
|
12210
|
-
if (typeof entry === "string") continue;
|
|
12211
|
-
selectedNames.add(entry.name);
|
|
12212
|
-
const resolution = resolveSelection(entry, projectRoot);
|
|
12213
|
-
if (resolution.failure) {
|
|
12214
|
-
unresolved.push({ label: packEntryLabel(entry), message: `[${resolution.failure.code}] ${resolution.failure.message}` });
|
|
12215
|
-
}
|
|
12216
|
-
}
|
|
12217
|
-
const installed = listInstalledPacks();
|
|
12218
|
-
const globalsOn = globalPacksEnabled(config);
|
|
12219
|
-
const globalsApplied = [];
|
|
12220
|
-
if (globalsOn) {
|
|
12221
|
-
for (const ref of discoverPacks(globalPacksDir())) {
|
|
12222
|
-
const match = installed.find((p) => path10.resolve(p.path) === path10.resolve(ref));
|
|
12223
|
-
if (match) globalsApplied.push({ name: match.name, version: match.version });
|
|
12224
|
-
}
|
|
12225
|
-
}
|
|
12226
|
-
const applying = /* @__PURE__ */ new Set([...selectedNames, ...globalsApplied.map((p) => p.name)]);
|
|
12227
|
-
const notApplied = installed.filter((p) => !applying.has(p.name)).map((p) => ({ name: p.name, version: p.version, origin: p.origin }));
|
|
12228
|
-
return { globalsUndeclared, notApplied, unresolved, globalsApplied };
|
|
12229
|
-
} catch {
|
|
12230
|
-
return empty;
|
|
12231
|
-
}
|
|
12232
|
-
}
|
|
12233
|
-
function pinInstalledPacksAsSelections() {
|
|
12234
|
-
const diagnosis = diagnoseProjectPacks();
|
|
12235
|
-
if (!diagnosis.globalsUndeclared || diagnosis.notApplied.length === 0) return [];
|
|
12236
|
-
const added = [];
|
|
12237
|
-
const selections = [];
|
|
12238
|
-
for (const pack of diagnosis.notApplied) {
|
|
12239
|
-
selections.push({
|
|
12240
|
-
name: pack.name,
|
|
12241
|
-
version: pack.version,
|
|
12242
|
-
// Carry the origin so the selection can be obtained elsewhere; a local
|
|
12243
|
-
// path is not fetchable, so it is deliberately not recorded as a source.
|
|
12244
|
-
...pack.origin && /^[a-z][a-z0-9+.-]*:\/\//i.test(pack.origin) ? { source: pack.origin } : {}
|
|
12245
|
-
});
|
|
12246
|
-
added.push(`${pack.name}@${pack.version}`);
|
|
12247
|
-
}
|
|
12248
|
-
projectConfigRepository.pinGlobalPacksAsSelections(selections);
|
|
12249
|
-
return added;
|
|
12250
|
-
}
|
|
12251
|
-
function packEntryLabel(entry) {
|
|
12252
|
-
if (typeof entry === "string") return entry;
|
|
12253
|
-
return entry.version ? `${entry.name}@${entry.version}` : entry.name;
|
|
12254
|
-
}
|
|
12255
|
-
function packEntryRef(entry, projectRoot) {
|
|
12256
|
-
if (typeof entry === "string") return entry;
|
|
12257
|
-
return resolveSelection(entry, projectRoot).ref ?? null;
|
|
12258
|
-
}
|
|
12259
12069
|
function resolveSelection(selection, projectRoot) {
|
|
12260
12070
|
const wanted = selection.version ? `${selection.name}@${selection.version}` : selection.name;
|
|
12261
12071
|
const fail = (code, message) => ({ failure: { code, severity: "error", name: selection.name, message } });
|
|
@@ -12369,21 +12179,21 @@ function buildCodeIndex(model) {
|
|
|
12369
12179
|
const declarations = /* @__PURE__ */ new Map();
|
|
12370
12180
|
const anchors = /* @__PURE__ */ new Map();
|
|
12371
12181
|
const findingAnchors = /* @__PURE__ */ new Map();
|
|
12372
|
-
const namesAt = (cache,
|
|
12373
|
-
const cached = cache.get(
|
|
12182
|
+
const namesAt = (cache, path28, make) => {
|
|
12183
|
+
const cached = cache.get(path28);
|
|
12374
12184
|
if (cached) return cached;
|
|
12375
|
-
const f = facts.get(
|
|
12185
|
+
const f = facts.get(path28);
|
|
12376
12186
|
if (!f) return NO_NAMES;
|
|
12377
12187
|
const built = make(f);
|
|
12378
|
-
cache.set(
|
|
12188
|
+
cache.set(path28, built);
|
|
12379
12189
|
return built;
|
|
12380
12190
|
};
|
|
12381
12191
|
const republished = /* @__PURE__ */ new Map();
|
|
12382
|
-
const republishedFrom = (
|
|
12383
|
-
const cached = republished.get(
|
|
12192
|
+
const republishedFrom = (path28) => {
|
|
12193
|
+
const cached = republished.get(path28);
|
|
12384
12194
|
if (cached) return cached;
|
|
12385
|
-
const out = /* @__PURE__ */ new Set([
|
|
12386
|
-
const queue = [
|
|
12195
|
+
const out = /* @__PURE__ */ new Set([path28]);
|
|
12196
|
+
const queue = [path28];
|
|
12387
12197
|
while (queue.length) {
|
|
12388
12198
|
const from = queue.pop();
|
|
12389
12199
|
const f = facts.get(from);
|
|
@@ -12396,7 +12206,7 @@ function buildCodeIndex(model) {
|
|
|
12396
12206
|
}
|
|
12397
12207
|
}
|
|
12398
12208
|
}
|
|
12399
|
-
republished.set(
|
|
12209
|
+
republished.set(path28, out);
|
|
12400
12210
|
return out;
|
|
12401
12211
|
};
|
|
12402
12212
|
const NO_ORIGIN = /* @__PURE__ */ new Set();
|
|
@@ -12405,9 +12215,9 @@ function buildCodeIndex(model) {
|
|
|
12405
12215
|
return to ? republishedFrom(to) : NO_ORIGIN;
|
|
12406
12216
|
};
|
|
12407
12217
|
const scopeOf = (site, from) => {
|
|
12408
|
-
const
|
|
12409
|
-
const f = facts.get(
|
|
12410
|
-
return f?.status === "analyzed" && f.analysisGrade === "exact" ? { path:
|
|
12218
|
+
const path28 = pathKey(site.from ?? from);
|
|
12219
|
+
const f = facts.get(path28);
|
|
12220
|
+
return f?.status === "analyzed" && f.analysisGrade === "exact" ? { path: path28, facts: f } : void 0;
|
|
12411
12221
|
};
|
|
12412
12222
|
const originOf = (site, from) => {
|
|
12413
12223
|
const resolved = scopeOf(site, from);
|
|
@@ -12446,14 +12256,14 @@ function buildCodeIndex(model) {
|
|
|
12446
12256
|
if (site.via) for (const typeName of localTypesOf(f, site.via)) widenThroughType(typeName);
|
|
12447
12257
|
return out;
|
|
12448
12258
|
};
|
|
12449
|
-
const declarationsAt = (
|
|
12259
|
+
const declarationsAt = (path28) => namesAt(declarations, pathKey(path28), (f) => /* @__PURE__ */ new Set([...f.declaredNames, ...f.exportedNames]));
|
|
12450
12260
|
return {
|
|
12451
12261
|
paths,
|
|
12452
12262
|
exactPaths,
|
|
12453
|
-
factsAt: (
|
|
12263
|
+
factsAt: (path28) => facts.get(pathKey(path28)),
|
|
12454
12264
|
declarationsAt,
|
|
12455
|
-
anchorsAt: (
|
|
12456
|
-
findingAnchorsAt: (
|
|
12265
|
+
anchorsAt: (path28) => namesAt(anchors, pathKey(path28), (f) => /* @__PURE__ */ new Set([...f.declaredNames, ...f.exportedNames, ...f.anchoredNames])),
|
|
12266
|
+
findingAnchorsAt: (path28) => namesAt(findingAnchors, pathKey(path28), (f) => new Set(f.anchoredNames)),
|
|
12457
12267
|
originOf,
|
|
12458
12268
|
possibleOriginsOf
|
|
12459
12269
|
};
|
|
@@ -12491,10 +12301,10 @@ function buildRealizationIndex(ctx) {
|
|
|
12491
12301
|
return {
|
|
12492
12302
|
paths,
|
|
12493
12303
|
implementationsOf: (compId) => implsByComponent.get(compId) ?? NONE_IMPL,
|
|
12494
|
-
implementationsAt: (
|
|
12304
|
+
implementationsAt: (path28) => implsByPath.get(pathKey(path28)) ?? NONE_IMPL,
|
|
12495
12305
|
filesOf: (compId) => filesByComponent.get(compId) ?? NONE_PATH,
|
|
12496
12306
|
filesIn: (subsystemId) => filesBySubsystem.get(subsystemId) ?? NONE_PATH,
|
|
12497
|
-
componentsAt: (
|
|
12307
|
+
componentsAt: (path28) => componentsByPath.get(pathKey(path28)) ?? NONE_COMP
|
|
12498
12308
|
};
|
|
12499
12309
|
}
|
|
12500
12310
|
function buildImportGraph(index, universe) {
|
|
@@ -12506,22 +12316,22 @@ function buildImportGraph(index, universe) {
|
|
|
12506
12316
|
if (to && to !== from) into.add(to);
|
|
12507
12317
|
}
|
|
12508
12318
|
};
|
|
12509
|
-
const importsOf = (
|
|
12510
|
-
const cached = imports.get(
|
|
12319
|
+
const importsOf = (path28) => {
|
|
12320
|
+
const cached = imports.get(path28);
|
|
12511
12321
|
if (cached) return cached;
|
|
12512
|
-
const facts = index.factsAt(
|
|
12322
|
+
const facts = index.factsAt(path28);
|
|
12513
12323
|
const out = /* @__PURE__ */ new Set();
|
|
12514
|
-
if (facts?.status === "analyzed") resolveAll(
|
|
12515
|
-
imports.set(
|
|
12324
|
+
if (facts?.status === "analyzed") resolveAll(path28, facts.imports, out);
|
|
12325
|
+
imports.set(path28, out);
|
|
12516
12326
|
return out;
|
|
12517
12327
|
};
|
|
12518
|
-
const tracesOf = (
|
|
12519
|
-
const cached = traces.get(
|
|
12328
|
+
const tracesOf = (path28) => {
|
|
12329
|
+
const cached = traces.get(path28);
|
|
12520
12330
|
if (cached) return cached;
|
|
12521
|
-
const facts = index.factsAt(
|
|
12522
|
-
const out = new Set(importsOf(
|
|
12523
|
-
if (facts?.status === "analyzed") resolveAll(
|
|
12524
|
-
traces.set(
|
|
12331
|
+
const facts = index.factsAt(path28);
|
|
12332
|
+
const out = new Set(importsOf(path28));
|
|
12333
|
+
if (facts?.status === "analyzed") resolveAll(path28, facts.reexports, out);
|
|
12334
|
+
traces.set(path28, out);
|
|
12525
12335
|
return out;
|
|
12526
12336
|
};
|
|
12527
12337
|
return {
|
|
@@ -13832,11 +13642,11 @@ var unconditionalCallCyclesRule = {
|
|
|
13832
13642
|
const memberEdges = keys.flatMap((k) => (adjacency.get(k) ?? []).filter((e) => inScc.has(e.toKey)));
|
|
13833
13643
|
if (memberEdges.length === 0) continue;
|
|
13834
13644
|
const anchor = [...memberEdges].sort((a, b) => byCodeUnit(a.fromKey, b.fromKey) || byCodeUnit(a.impl.id, b.impl.id) || a.stepNumber - b.stepNumber)[0];
|
|
13835
|
-
const
|
|
13645
|
+
const path28 = [...keys].sort(byCodeUnit).join(" \u2192 ");
|
|
13836
13646
|
ctx.addIssue(
|
|
13837
13647
|
"warning",
|
|
13838
13648
|
"UNCONDITIONAL_CALL_CYCLE",
|
|
13839
|
-
`Call cycle with no guard: ${
|
|
13649
|
+
`Call cycle with no guard: ${path28} \u2014 every call edge in this cycle is unavoidable on all paths of its narrative (e.g. step ${anchor.stepNumber} of "${anchor.methodName}" in "${anchor.impl.id}" always calls ${anchor.toLabel}). This recurses without a base case, by construction. Guard at least one edge with a branch/return before the call, or lint.allow with the termination argument.`,
|
|
13840
13650
|
anchor.impl.id,
|
|
13841
13651
|
memberEdges.some((e) => ctx.isImplementationDraft(e.impl))
|
|
13842
13652
|
);
|
|
@@ -16578,11 +16388,11 @@ var hiddenStateRule = {
|
|
|
16578
16388
|
byPath.set(key, list);
|
|
16579
16389
|
}
|
|
16580
16390
|
}
|
|
16581
|
-
for (const
|
|
16582
|
-
const facts = code.factsAt(
|
|
16391
|
+
for (const path28 of code.exactPaths) {
|
|
16392
|
+
const facts = code.factsAt(path28);
|
|
16583
16393
|
const bindings = facts.topLevelMutableBindings ?? [];
|
|
16584
16394
|
if (bindings.length === 0) continue;
|
|
16585
|
-
const mapped = byPath.get(
|
|
16395
|
+
const mapped = byPath.get(path28) ?? [];
|
|
16586
16396
|
if (mapped.length === 0) continue;
|
|
16587
16397
|
if (!mapped.every((m) => isStatelessLogic(m.component))) continue;
|
|
16588
16398
|
const anchor = [...mapped].sort((a, b) => a.impl.id.localeCompare(b.impl.id))[0];
|
|
@@ -16648,7 +16458,7 @@ var dependencyConformanceRule = {
|
|
|
16648
16458
|
}
|
|
16649
16459
|
return false;
|
|
16650
16460
|
};
|
|
16651
|
-
const draftAt = (
|
|
16461
|
+
const draftAt = (path28) => realization.implementationsAt(path28).some((impl) => ctx.isImplementationDraft(impl));
|
|
16652
16462
|
for (const fromPath of mappedPaths) {
|
|
16653
16463
|
const fromComponents = realization.componentsAt(fromPath);
|
|
16654
16464
|
for (const toPath of graph.importsOf(fromPath)) {
|
|
@@ -18356,9 +18166,6 @@ function ruleSequence() {
|
|
|
18356
18166
|
const audits = [carriedDebtRule, lintAllowsRule].filter((r) => ruleSet.includes(r));
|
|
18357
18167
|
return [...ruleSet.filter((r) => !audits.includes(r)), ...audits];
|
|
18358
18168
|
}
|
|
18359
|
-
function specScopedRules() {
|
|
18360
|
-
return ruleSequence().filter((r) => r.scope === "spec");
|
|
18361
|
-
}
|
|
18362
18169
|
function knownIssueCodes() {
|
|
18363
18170
|
return listRules().flatMap((r) => r.codes);
|
|
18364
18171
|
}
|
|
@@ -19001,48 +18808,6 @@ function buildCodeModel(implementations, types, projectRoot, sourceRoots = [], e
|
|
|
19001
18808
|
}
|
|
19002
18809
|
return { files, projectRoot, rootFiles };
|
|
19003
18810
|
}
|
|
19004
|
-
function readTestFiles(testRoots, projectRoot) {
|
|
19005
|
-
const scanned = [];
|
|
19006
|
-
for (const key of walkDeclaredRoots(testRoots, [], projectRoot)) {
|
|
19007
|
-
let text;
|
|
19008
|
-
try {
|
|
19009
|
-
const buffer = fs9.readFileSync(path11.resolve(projectRoot, key));
|
|
19010
|
-
if (looksBinary(buffer)) continue;
|
|
19011
|
-
text = buffer.toString("utf8");
|
|
19012
|
-
} catch {
|
|
19013
|
-
continue;
|
|
19014
|
-
}
|
|
19015
|
-
const imports = /* @__PURE__ */ new Set();
|
|
19016
|
-
for (const m of text.matchAll(NAMED_IMPORT_BINDINGS_RE)) {
|
|
19017
|
-
for (const name of boundNames(m[1] ?? "", false)) imports.add(name);
|
|
19018
|
-
}
|
|
19019
|
-
const words2 = /* @__PURE__ */ new Set();
|
|
19020
|
-
for (const m of text.matchAll(IDENTIFIER_RE)) words2.add(m[0]);
|
|
19021
|
-
scanned.push({ path: key, imports, words: words2 });
|
|
19022
|
-
}
|
|
19023
|
-
return scanned;
|
|
19024
|
-
}
|
|
19025
|
-
function findTestsReferencing(methods, projectRoot, testRoots = []) {
|
|
19026
|
-
const scanned = readTestFiles(testRoots, projectRoot);
|
|
19027
|
-
if (scanned.length === 0) return [];
|
|
19028
|
-
const indiscriminateAbove = scanned.length / 10;
|
|
19029
|
-
const found = [];
|
|
19030
|
-
for (const method of methods) {
|
|
19031
|
-
const symbol = method.symbol ?? method.name;
|
|
19032
|
-
const imported = scanned.filter((f) => f.imports.has(symbol)).map((f) => f.path);
|
|
19033
|
-
const mentioned = scanned.filter((f) => !f.imports.has(symbol) && f.words.has(symbol)).map((f) => f.path);
|
|
19034
|
-
const indiscriminate = mentioned.length > indiscriminateAbove;
|
|
19035
|
-
if (imported.length === 0 && mentioned.length === 0) continue;
|
|
19036
|
-
found.push({
|
|
19037
|
-
method: method.name,
|
|
19038
|
-
symbol,
|
|
19039
|
-
imported,
|
|
19040
|
-
mentioned: indiscriminate ? [] : mentioned,
|
|
19041
|
-
indiscriminate
|
|
19042
|
-
});
|
|
19043
|
-
}
|
|
19044
|
-
return found;
|
|
19045
|
-
}
|
|
19046
18811
|
|
|
19047
18812
|
// src/core/rules/index.ts
|
|
19048
18813
|
function composeRuleSequence(extraRules = []) {
|
|
@@ -19537,119 +19302,6 @@ function buildRuleContext(opts) {
|
|
|
19537
19302
|
return ctx;
|
|
19538
19303
|
}
|
|
19539
19304
|
|
|
19540
|
-
// src/core/rules/candidate.ts
|
|
19541
|
-
function stubSystem() {
|
|
19542
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
19543
|
-
return {
|
|
19544
|
-
schemaVersion: "1.0.0",
|
|
19545
|
-
name: "candidate",
|
|
19546
|
-
vision: "",
|
|
19547
|
-
boundaries: [],
|
|
19548
|
-
globalRequirements: [],
|
|
19549
|
-
databases: [],
|
|
19550
|
-
createdAt: now,
|
|
19551
|
-
updatedAt: now
|
|
19552
|
-
};
|
|
19553
|
-
}
|
|
19554
|
-
function validateComponentCandidate(candidate, opts = {}) {
|
|
19555
|
-
const issues = [];
|
|
19556
|
-
registerBuiltinRules();
|
|
19557
|
-
if (opts.extensions?.rules?.length) registerPackRules(opts.extensions.rules);
|
|
19558
|
-
const knownCodes = /* @__PURE__ */ new Set([
|
|
19559
|
-
...knownIssueCodes().map((rc) => rc.code),
|
|
19560
|
-
...(opts.extensions?.assertions ?? []).map((a) => a.fullCode)
|
|
19561
|
-
]);
|
|
19562
|
-
const ctx = buildRuleContext({
|
|
19563
|
-
system: stubSystem(),
|
|
19564
|
-
subsystems: [],
|
|
19565
|
-
components: [candidate],
|
|
19566
|
-
interfaces: [],
|
|
19567
|
-
implementations: [],
|
|
19568
|
-
types: [],
|
|
19569
|
-
rules: opts.rules,
|
|
19570
|
-
projectType: opts.projectType ?? "backend",
|
|
19571
|
-
extensions: opts.extensions,
|
|
19572
|
-
// Only a tree-scoped rule reads these (roundtrip-serialization); no
|
|
19573
|
-
// spec-scoped rule does, so a candidate carries none.
|
|
19574
|
-
roundTripIssues: [],
|
|
19575
|
-
knownIssueCodes: knownCodes,
|
|
19576
|
-
issues
|
|
19577
|
-
});
|
|
19578
|
-
for (const rule of specScopedRules()) {
|
|
19579
|
-
rule.check(ctx);
|
|
19580
|
-
}
|
|
19581
|
-
const own = issues.filter((i) => !i.specId || i.specId === candidate.id);
|
|
19582
|
-
return {
|
|
19583
|
-
errors: own.filter((i) => i.severity === "error"),
|
|
19584
|
-
warnings: own.filter((i) => i.severity === "warning")
|
|
19585
|
-
};
|
|
19586
|
-
}
|
|
19587
|
-
|
|
19588
|
-
// src/core/rules/gate-identity.ts
|
|
19589
|
-
var crypto3 = __toESM(require("crypto"));
|
|
19590
|
-
var GATE_ALGORITHM = "sha256+content+doctrine+inputs";
|
|
19591
|
-
function doctrineIdentity(doctrine, builtinRules, gate) {
|
|
19592
|
-
const byKey = (items, key) => [...items].sort((a, b) => compareOrdinal(key(a), key(b)));
|
|
19593
|
-
return {
|
|
19594
|
-
/**
|
|
19595
|
-
* The BUILTIN rule set, by identity rather than by wairon version.
|
|
19596
|
-
*
|
|
19597
|
-
* A binary upgrade changes the gate only when the rules change, so hashing the
|
|
19598
|
-
* version would invalidate every lock on every patch while hashing nothing
|
|
19599
|
-
* would let a minor that ADDS a rule leave locks asserting they passed a gate
|
|
19600
|
-
* that no longer exists. Keying on the registry means a release that touches no
|
|
19601
|
-
* rule keeps every lock valid, and one that adds, removes, or re-grades a code
|
|
19602
|
-
* invalidates exactly the locks it should.
|
|
19603
|
-
*
|
|
19604
|
-
* Residual gap, accepted knowingly: a rule whose IMPLEMENTATION grows stricter
|
|
19605
|
-
* without its name, codes, or default severity changing is not caught. Folding
|
|
19606
|
-
* in the wairon version would catch it at the cost of churning every lock on
|
|
19607
|
-
* every release — the trade this projection deliberately declines.
|
|
19608
|
-
*/
|
|
19609
|
-
builtinRules: byKey(
|
|
19610
|
-
builtinRules.map((r) => ({
|
|
19611
|
-
name: r.name,
|
|
19612
|
-
codes: byKey(r.codes.map((c) => ({ code: c.code, severity: c.defaultSeverity })), (c) => c.code)
|
|
19613
|
-
})),
|
|
19614
|
-
(r) => r.name
|
|
19615
|
-
),
|
|
19616
|
-
/**
|
|
19617
|
-
* Which profile GOVERNS, and the project's own rule tuning. Both decide
|
|
19618
|
-
* verdicts — a projectType switch changes the doctrine family outright, and
|
|
19619
|
-
* `rules` carries severity overrides, complexity caps, and designDepth.
|
|
19620
|
-
*/
|
|
19621
|
-
projectType: gate.projectType ?? null,
|
|
19622
|
-
rulesConfig: gate.rules ?? null,
|
|
19623
|
-
packs: byKey(
|
|
19624
|
-
doctrine.packs.map((p) => ({ name: p.name, version: p.version ?? null, scope: p.scope })),
|
|
19625
|
-
(p) => `${p.name}@${p.version ?? ""}#${p.scope}`
|
|
19626
|
-
),
|
|
19627
|
-
// Merged records already encode pack precedence, so their resolved content is
|
|
19628
|
-
// the identity — a load-order change that flips a collision winner shows up here.
|
|
19629
|
-
profiles: doctrine.profiles,
|
|
19630
|
-
languages: doctrine.languages,
|
|
19631
|
-
patterns: byKey(
|
|
19632
|
-
doctrine.patterns.map((p) => ({ id: p.id, version: p.version, pack: p.pack })),
|
|
19633
|
-
(p) => `${p.pack}/${p.id}@${p.version}`
|
|
19634
|
-
),
|
|
19635
|
-
guarantees: [...doctrine.guarantees].sort(),
|
|
19636
|
-
assertions: byKey(doctrine.assertions.map((a) => ({ ...a })), (a) => a.fullCode),
|
|
19637
|
-
rules: byKey(
|
|
19638
|
-
doctrine.rules.map((r) => ({ name: r.name, codes: r.codes.map((c) => c.code).sort() })),
|
|
19639
|
-
(r) => r.name
|
|
19640
|
-
)
|
|
19641
|
-
};
|
|
19642
|
-
}
|
|
19643
|
-
function computeGateIdentity(content, doctrine, builtinRules, inputs, gate) {
|
|
19644
|
-
const payload = {
|
|
19645
|
-
content: content.digest,
|
|
19646
|
-
doctrine: doctrineIdentity(doctrine, builtinRules, gate),
|
|
19647
|
-
inputs: [...inputs].sort()
|
|
19648
|
-
};
|
|
19649
|
-
const digest2 = crypto3.createHash("sha256").update(canonicalize(payload)).digest("hex");
|
|
19650
|
-
return { algorithm: GATE_ALGORITHM, digest: digest2 };
|
|
19651
|
-
}
|
|
19652
|
-
|
|
19653
19305
|
// src/core/variants.ts
|
|
19654
19306
|
var fs10 = __toESM(require("fs"));
|
|
19655
19307
|
var os3 = __toESM(require("os"));
|
|
@@ -19803,523 +19455,14 @@ function rebasedText(content, fromBase, toBase, rebasedContent) {
|
|
|
19803
19455
|
var fs11 = __toESM(require("fs"));
|
|
19804
19456
|
var path13 = __toESM(require("path"));
|
|
19805
19457
|
|
|
19806
|
-
// src/utils/filenames.ts
|
|
19807
|
-
function safeFilenamePart(value) {
|
|
19808
|
-
return value.replace(/[^a-zA-Z0-9._-]/g, "-");
|
|
19809
|
-
}
|
|
19810
|
-
|
|
19811
19458
|
// src/core/openapi.ts
|
|
19812
19459
|
var yaml2 = __toESM(require("js-yaml"));
|
|
19813
|
-
var PRIMITIVES = {
|
|
19814
|
-
string: { type: "string" },
|
|
19815
|
-
number: { type: "number" },
|
|
19816
|
-
float: { type: "number" },
|
|
19817
|
-
decimal: { type: "number" },
|
|
19818
|
-
int: { type: "integer" },
|
|
19819
|
-
integer: { type: "integer" },
|
|
19820
|
-
boolean: { type: "boolean" },
|
|
19821
|
-
bool: { type: "boolean" },
|
|
19822
|
-
date: { type: "string", format: "date-time" },
|
|
19823
|
-
datetime: { type: "string", format: "date-time" },
|
|
19824
|
-
uuid: { type: "string", format: "uuid" },
|
|
19825
|
-
json: { type: "object" },
|
|
19826
|
-
object: { type: "object" },
|
|
19827
|
-
any: {},
|
|
19828
|
-
unknown: {},
|
|
19829
|
-
void: {}
|
|
19830
|
-
};
|
|
19831
|
-
function schemaFor(typeRef, closureIds) {
|
|
19832
|
-
const trimmed = typeRef.trim().replace(/^promise\s*<(.+)>$/i, "$1").trim();
|
|
19833
|
-
const arrayMatch = /^(.+)\[\]$/.exec(trimmed);
|
|
19834
|
-
if (arrayMatch) {
|
|
19835
|
-
return { type: "array", items: schemaFor(arrayMatch[1], closureIds) };
|
|
19836
|
-
}
|
|
19837
|
-
const lower = trimmed.toLowerCase();
|
|
19838
|
-
if (lower in PRIMITIVES) {
|
|
19839
|
-
const p = PRIMITIVES[lower];
|
|
19840
|
-
return p.type ? { ...p } : {};
|
|
19841
|
-
}
|
|
19842
|
-
const local = trimmed.split(/::|\./).pop().toLowerCase().replace(/[^a-z0-9_-]/g, "");
|
|
19843
|
-
const hit = [...closureIds].find((id) => id.toLowerCase() === local);
|
|
19844
|
-
if (hit) return { $ref: `#/components/schemas/${hit}` };
|
|
19845
|
-
return { type: "object", description: `Unresolved type: ${trimmed}` };
|
|
19846
|
-
}
|
|
19847
|
-
function operationFor(method, closureIds) {
|
|
19848
|
-
const endpoint = method.endpoint;
|
|
19849
|
-
const httpVerb = endpoint && endpoint.transport === "HTTP" ? endpoint.method.toLowerCase() : "post";
|
|
19850
|
-
const bodyVerbs = /* @__PURE__ */ new Set(["post", "put", "patch"]);
|
|
19851
|
-
const params = method.params ?? [];
|
|
19852
|
-
const op = {
|
|
19853
|
-
operationId: method.name,
|
|
19854
|
-
summary: method.description,
|
|
19855
|
-
responses: {
|
|
19856
|
-
"200": {
|
|
19857
|
-
description: method.returns || "Success",
|
|
19858
|
-
...method.returns && method.returns.toLowerCase() !== "void" ? { content: { "application/json": { schema: schemaFor(method.returns, closureIds) } } } : {}
|
|
19859
|
-
}
|
|
19860
|
-
}
|
|
19861
|
-
};
|
|
19862
|
-
if (method.guarantees?.length) op["x-wairon-guarantees"] = method.guarantees;
|
|
19863
|
-
if (method.effect) op["x-wairon-effect"] = method.effect;
|
|
19864
|
-
if (method.ext && Object.keys(method.ext).length) op["x-wairon-ext"] = method.ext;
|
|
19865
|
-
if (params.length) {
|
|
19866
|
-
if (bodyVerbs.has(httpVerb)) {
|
|
19867
|
-
op.requestBody = {
|
|
19868
|
-
required: true,
|
|
19869
|
-
content: {
|
|
19870
|
-
"application/json": {
|
|
19871
|
-
schema: {
|
|
19872
|
-
type: "object",
|
|
19873
|
-
properties: Object.fromEntries(params.map((p) => [p.name, schemaFor(p.type, closureIds)])),
|
|
19874
|
-
required: params.filter((p) => !p.optional).map((p) => p.name)
|
|
19875
|
-
}
|
|
19876
|
-
}
|
|
19877
|
-
}
|
|
19878
|
-
};
|
|
19879
|
-
} else {
|
|
19880
|
-
op.parameters = params.map((p) => ({
|
|
19881
|
-
name: p.name,
|
|
19882
|
-
in: "query",
|
|
19883
|
-
required: !p.optional,
|
|
19884
|
-
...p.description ? { description: p.description } : {},
|
|
19885
|
-
schema: schemaFor(p.type, closureIds)
|
|
19886
|
-
}));
|
|
19887
|
-
}
|
|
19888
|
-
}
|
|
19889
|
-
return op;
|
|
19890
|
-
}
|
|
19891
|
-
function securitySchemeObject(auth) {
|
|
19892
|
-
if (auth.scheme === "none") return null;
|
|
19893
|
-
const desc = auth.description ? { description: auth.description } : {};
|
|
19894
|
-
switch (auth.scheme) {
|
|
19895
|
-
case "apiKey":
|
|
19896
|
-
return { type: "apiKey", in: auth.in ?? "header", name: auth.name ?? "X-API-Key", ...desc };
|
|
19897
|
-
case "bearer":
|
|
19898
|
-
return { type: "http", scheme: "bearer", ...auth.bearerFormat ? { bearerFormat: auth.bearerFormat } : {}, ...desc };
|
|
19899
|
-
case "basic":
|
|
19900
|
-
return { type: "http", scheme: "basic", ...desc };
|
|
19901
|
-
case "oauth2": {
|
|
19902
|
-
const flow = { scopes: Object.fromEntries((auth.scopes ?? []).map((s) => [s.name, s.description])) };
|
|
19903
|
-
if (auth.authorizationUrl) flow.authorizationUrl = auth.authorizationUrl;
|
|
19904
|
-
if (auth.tokenUrl) flow.tokenUrl = auth.tokenUrl;
|
|
19905
|
-
if (auth.refreshUrl) flow.refreshUrl = auth.refreshUrl;
|
|
19906
|
-
return { type: "oauth2", flows: { [auth.flow ?? "authorizationCode"]: flow }, ...desc };
|
|
19907
|
-
}
|
|
19908
|
-
case "openIdConnect":
|
|
19909
|
-
return { type: "openIdConnect", openIdConnectUrl: auth.openIdConnectUrl ?? "", ...desc };
|
|
19910
|
-
case "custom":
|
|
19911
|
-
return { type: "apiKey", in: auth.in ?? "header", name: auth.name ?? "Authorization", description: auth.description ?? auth.example ?? "Custom authentication scheme." };
|
|
19912
|
-
default:
|
|
19913
|
-
return null;
|
|
19914
|
-
}
|
|
19915
|
-
}
|
|
19916
|
-
function schemeBaseName(scheme) {
|
|
19917
|
-
return { apiKey: "ApiKeyAuth", bearer: "BearerAuth", basic: "BasicAuth", oauth2: "OAuth2", openIdConnect: "OpenIdConnect", custom: "CustomAuth" }[scheme] ?? "Auth";
|
|
19918
|
-
}
|
|
19919
|
-
function buildSecurity(entries) {
|
|
19920
|
-
const schemes = {};
|
|
19921
|
-
const nameByContent = /* @__PURE__ */ new Map();
|
|
19922
|
-
const securityByEntry = /* @__PURE__ */ new Map();
|
|
19923
|
-
for (const entry of entries) {
|
|
19924
|
-
if (!entry.auth) continue;
|
|
19925
|
-
const obj = securitySchemeObject(entry.auth);
|
|
19926
|
-
if (!obj) continue;
|
|
19927
|
-
const content = JSON.stringify(obj);
|
|
19928
|
-
let name = nameByContent.get(content);
|
|
19929
|
-
if (!name) {
|
|
19930
|
-
name = schemeBaseName(entry.auth.scheme);
|
|
19931
|
-
for (let n = 2; schemes[name]; n++) name = schemeBaseName(entry.auth.scheme) + n;
|
|
19932
|
-
schemes[name] = obj;
|
|
19933
|
-
nameByContent.set(content, name);
|
|
19934
|
-
}
|
|
19935
|
-
const scopeNames = entry.auth.scheme === "oauth2" ? (entry.auth.scopes ?? []).map((s) => s.name) : [];
|
|
19936
|
-
securityByEntry.set(entry.id, { [name]: scopeNames });
|
|
19937
|
-
}
|
|
19938
|
-
return { schemes, securityByEntry };
|
|
19939
|
-
}
|
|
19940
|
-
function httpEntriesOf(snapshot) {
|
|
19941
|
-
return snapshot.interfaces.filter((e) => e.type === "REST" || e.methods.some((m) => m.endpoint?.transport === "HTTP"));
|
|
19942
|
-
}
|
|
19943
|
-
function renderDoc(snapshot, entries, closureIds, opts = {}) {
|
|
19944
|
-
const { schemes, securityByEntry } = buildSecurity(entries);
|
|
19945
|
-
const paths = {};
|
|
19946
|
-
for (const entry of entries) {
|
|
19947
|
-
const security = securityByEntry.get(entry.id);
|
|
19948
|
-
for (const method of entry.methods) {
|
|
19949
|
-
const endpoint = method.endpoint;
|
|
19950
|
-
if (!endpoint || endpoint.transport !== "HTTP") continue;
|
|
19951
|
-
const p = endpoint.path.startsWith("/") ? endpoint.path : `/${endpoint.path}`;
|
|
19952
|
-
paths[p] = paths[p] ?? {};
|
|
19953
|
-
paths[p][endpoint.method.toLowerCase()] = {
|
|
19954
|
-
tags: [entry.id],
|
|
19955
|
-
...operationFor(method, closureIds),
|
|
19956
|
-
...security ? { security: [security] } : {}
|
|
19957
|
-
};
|
|
19958
|
-
}
|
|
19959
|
-
}
|
|
19960
|
-
const schemas = {};
|
|
19961
|
-
for (const t of snapshot.types) {
|
|
19962
|
-
schemas[t.id] = {
|
|
19963
|
-
type: "object",
|
|
19964
|
-
title: t.name,
|
|
19965
|
-
properties: Object.fromEntries(t.fields.map((f) => [f.name, schemaFor(f.type, closureIds)])),
|
|
19966
|
-
required: t.fields.filter((f) => !f.optional).map((f) => f.name)
|
|
19967
|
-
};
|
|
19968
|
-
}
|
|
19969
|
-
const components = {};
|
|
19970
|
-
if (Object.keys(schemas).length) components.schemas = schemas;
|
|
19971
|
-
if (Object.keys(schemes).length) components.securitySchemes = schemes;
|
|
19972
|
-
const basePaths = [...new Set(entries.map((e) => e.basePath).filter((b) => !!b))];
|
|
19973
|
-
const servers = opts.servers && basePaths.length === 1 ? [{ url: basePaths[0] }] : void 0;
|
|
19974
|
-
return {
|
|
19975
|
-
openapi: "3.1.0",
|
|
19976
|
-
info: {
|
|
19977
|
-
title: opts.title ?? snapshot.projectName,
|
|
19978
|
-
version: snapshot.version ?? "0.0.0",
|
|
19979
|
-
...snapshot.stateId ? { "x-wairon-state-id": snapshot.stateId } : {},
|
|
19980
|
-
"x-wairon-origin": snapshot.origin,
|
|
19981
|
-
"x-wairon-generated-at": snapshot.generatedAt
|
|
19982
|
-
},
|
|
19983
|
-
...servers ? { servers } : {},
|
|
19984
|
-
paths,
|
|
19985
|
-
...Object.keys(components).length ? { components } : {}
|
|
19986
|
-
};
|
|
19987
|
-
}
|
|
19988
|
-
function toOpenApi(snapshot) {
|
|
19989
|
-
const closureIds = new Set(snapshot.types.map((t) => t.id));
|
|
19990
|
-
return JSON.stringify(renderDoc(snapshot, httpEntriesOf(snapshot), closureIds), null, 2);
|
|
19991
|
-
}
|
|
19992
|
-
function toOpenApiSet(snapshot) {
|
|
19993
|
-
const closureIds = new Set(snapshot.types.map((t) => t.id));
|
|
19994
|
-
const byPortal = /* @__PURE__ */ new Map();
|
|
19995
|
-
const order = [];
|
|
19996
|
-
for (const entry of httpEntriesOf(snapshot)) {
|
|
19997
|
-
if (!byPortal.has(entry.component)) {
|
|
19998
|
-
byPortal.set(entry.component, []);
|
|
19999
|
-
order.push(entry.component);
|
|
20000
|
-
}
|
|
20001
|
-
byPortal.get(entry.component).push(entry);
|
|
20002
|
-
}
|
|
20003
|
-
return order.map((portalId) => {
|
|
20004
|
-
const entries = byPortal.get(portalId);
|
|
20005
|
-
const name = entries[0]?.name ?? portalId;
|
|
20006
|
-
return { portalId, name, document: JSON.stringify(renderDoc(snapshot, entries, closureIds, { title: name, servers: true }), null, 2) };
|
|
20007
|
-
});
|
|
20008
|
-
}
|
|
20009
|
-
function isOpenApiDocument(body) {
|
|
20010
|
-
try {
|
|
20011
|
-
const parsed = yaml2.load(body);
|
|
20012
|
-
return !!parsed && typeof parsed === "object" && typeof parsed.openapi === "string";
|
|
20013
|
-
} catch {
|
|
20014
|
-
return false;
|
|
20015
|
-
}
|
|
20016
|
-
}
|
|
20017
|
-
function typeRefFromSchema(schema) {
|
|
20018
|
-
if (!schema) return "json";
|
|
20019
|
-
const ref = schema.$ref;
|
|
20020
|
-
if (typeof ref === "string") return ref.split("/").pop() ?? "json";
|
|
20021
|
-
if (schema.type === "array") {
|
|
20022
|
-
return `${typeRefFromSchema(schema.items)}[]`;
|
|
20023
|
-
}
|
|
20024
|
-
const t = schema.type;
|
|
20025
|
-
if (t === "integer") return "int";
|
|
20026
|
-
if (typeof t === "string" && t !== "object") return t;
|
|
20027
|
-
return "json";
|
|
20028
|
-
}
|
|
20029
|
-
function authFromSecurityScheme(scheme) {
|
|
20030
|
-
const desc = typeof scheme.description === "string" ? { description: scheme.description } : {};
|
|
20031
|
-
if (scheme.type === "apiKey") {
|
|
20032
|
-
return {
|
|
20033
|
-
scheme: "apiKey",
|
|
20034
|
-
...scheme.in === "header" || scheme.in === "query" || scheme.in === "cookie" ? { in: scheme.in } : {},
|
|
20035
|
-
...typeof scheme.name === "string" ? { name: scheme.name } : {},
|
|
20036
|
-
...desc
|
|
20037
|
-
};
|
|
20038
|
-
}
|
|
20039
|
-
if (scheme.type === "http") {
|
|
20040
|
-
if (scheme.scheme === "bearer") return { scheme: "bearer", ...typeof scheme.bearerFormat === "string" ? { bearerFormat: scheme.bearerFormat } : {}, ...desc };
|
|
20041
|
-
if (scheme.scheme === "basic") return { scheme: "basic", ...desc };
|
|
20042
|
-
}
|
|
20043
|
-
if (scheme.type === "oauth2") {
|
|
20044
|
-
const flows = scheme.flows ?? {};
|
|
20045
|
-
const flowKey = Object.keys(flows)[0];
|
|
20046
|
-
const f = flows[flowKey] ?? {};
|
|
20047
|
-
return {
|
|
20048
|
-
scheme: "oauth2",
|
|
20049
|
-
...flowKey === "authorizationCode" || flowKey === "clientCredentials" || flowKey === "implicit" || flowKey === "password" ? { flow: flowKey } : {},
|
|
20050
|
-
...typeof f.authorizationUrl === "string" ? { authorizationUrl: f.authorizationUrl } : {},
|
|
20051
|
-
...typeof f.tokenUrl === "string" ? { tokenUrl: f.tokenUrl } : {},
|
|
20052
|
-
...typeof f.refreshUrl === "string" ? { refreshUrl: f.refreshUrl } : {},
|
|
20053
|
-
scopes: Object.entries(f.scopes ?? {}).map(([name, description]) => ({ name, description })),
|
|
20054
|
-
...desc
|
|
20055
|
-
};
|
|
20056
|
-
}
|
|
20057
|
-
if (scheme.type === "openIdConnect") {
|
|
20058
|
-
return { scheme: "openIdConnect", openIdConnectUrl: typeof scheme.openIdConnectUrl === "string" ? scheme.openIdConnectUrl : "", ...desc };
|
|
20059
|
-
}
|
|
20060
|
-
return void 0;
|
|
20061
|
-
}
|
|
20062
|
-
function fromOpenApi(document, projectName) {
|
|
20063
|
-
let parsed;
|
|
20064
|
-
try {
|
|
20065
|
-
parsed = yaml2.load(document);
|
|
20066
|
-
} catch (e) {
|
|
20067
|
-
throw new Error(`Invalid surface document: not parseable as JSON/YAML (${e instanceof Error ? e.message : String(e)})`);
|
|
20068
|
-
}
|
|
20069
|
-
if (!parsed || typeof parsed !== "object" || typeof parsed.openapi !== "string" || typeof parsed.paths !== "object") {
|
|
20070
|
-
throw new Error('Invalid surface document: missing OpenAPI "openapi"/"paths" structure.');
|
|
20071
|
-
}
|
|
20072
|
-
const info = parsed.info ?? {};
|
|
20073
|
-
const methods = [];
|
|
20074
|
-
for (const [rawPath, ops] of Object.entries(parsed.paths)) {
|
|
20075
|
-
for (const [verb, opRaw] of Object.entries(ops ?? {})) {
|
|
20076
|
-
if (!["get", "post", "put", "delete", "patch", "options", "head"].includes(verb)) continue;
|
|
20077
|
-
const op = opRaw ?? {};
|
|
20078
|
-
const name = typeof op.operationId === "string" && /^[a-zA-Z0-9_]+$/.test(op.operationId) ? op.operationId : `${verb}_${rawPath.replace(/[^a-zA-Z0-9]+/g, "_").replace(/^_+|_+$/g, "")}`;
|
|
20079
|
-
const params = [];
|
|
20080
|
-
for (const p of op.parameters ?? []) {
|
|
20081
|
-
if (typeof p.name !== "string") continue;
|
|
20082
|
-
params.push({
|
|
20083
|
-
name: p.name,
|
|
20084
|
-
type: typeRefFromSchema(p.schema),
|
|
20085
|
-
...p.required === true ? {} : { optional: true },
|
|
20086
|
-
...typeof p.description === "string" ? { description: p.description } : {}
|
|
20087
|
-
});
|
|
20088
|
-
}
|
|
20089
|
-
const bodySchema = op.requestBody?.content?.["application/json"]?.schema;
|
|
20090
|
-
if (bodySchema) {
|
|
20091
|
-
const props = bodySchema.properties ?? {};
|
|
20092
|
-
const required = new Set(bodySchema.required ?? []);
|
|
20093
|
-
if (Object.keys(props).length) {
|
|
20094
|
-
for (const [pname, pschema] of Object.entries(props)) {
|
|
20095
|
-
params.push({ name: pname, type: typeRefFromSchema(pschema), ...required.has(pname) ? {} : { optional: true } });
|
|
20096
|
-
}
|
|
20097
|
-
} else {
|
|
20098
|
-
params.push({ name: "body", type: typeRefFromSchema(bodySchema) });
|
|
20099
|
-
}
|
|
20100
|
-
}
|
|
20101
|
-
const okResponse = op.responses?.["200"] ?? op.responses?.["201"];
|
|
20102
|
-
const responseSchema = okResponse?.content?.["application/json"]?.schema;
|
|
20103
|
-
const returns = responseSchema ? typeRefFromSchema(responseSchema) : "void";
|
|
20104
|
-
const rawGuarantees = op["x-wairon-guarantees"];
|
|
20105
|
-
const guarantees = Array.isArray(rawGuarantees) ? rawGuarantees.filter((g) => typeof g === "string" && g.length > 0) : [];
|
|
20106
|
-
const rawEffect = op["x-wairon-effect"];
|
|
20107
|
-
const effect = rawEffect === "read" || rawEffect === "write" ? rawEffect : void 0;
|
|
20108
|
-
const rawExt = op["x-wairon-ext"];
|
|
20109
|
-
const ext = rawExt && typeof rawExt === "object" && !Array.isArray(rawExt) ? rawExt : void 0;
|
|
20110
|
-
methods.push({
|
|
20111
|
-
name,
|
|
20112
|
-
description: typeof op.summary === "string" ? op.summary : typeof op.description === "string" ? op.description : name,
|
|
20113
|
-
signature: `${name}(${params.map((p) => `${p.name}: ${p.type}`).join(", ")}): ${returns}`,
|
|
20114
|
-
returns,
|
|
20115
|
-
params,
|
|
20116
|
-
endpoint: { transport: "HTTP", method: verb.toUpperCase(), path: rawPath },
|
|
20117
|
-
...guarantees.length ? { guarantees } : {},
|
|
20118
|
-
...effect ? { effect } : {},
|
|
20119
|
-
...ext ? { ext } : {}
|
|
20120
|
-
});
|
|
20121
|
-
}
|
|
20122
|
-
}
|
|
20123
|
-
const types = [];
|
|
20124
|
-
const schemas = parsed.components?.schemas ?? {};
|
|
20125
|
-
for (const [id, schema] of Object.entries(schemas)) {
|
|
20126
|
-
const props = schema.properties ?? {};
|
|
20127
|
-
const required = new Set(schema.required ?? []);
|
|
20128
|
-
types.push({
|
|
20129
|
-
id,
|
|
20130
|
-
name: typeof schema.title === "string" ? schema.title : id,
|
|
20131
|
-
kind: "value-object",
|
|
20132
|
-
fields: Object.entries(props).map(([fname, fschema]) => ({
|
|
20133
|
-
name: fname,
|
|
20134
|
-
type: typeRefFromSchema(fschema),
|
|
20135
|
-
...required.has(fname) ? {} : { optional: true }
|
|
20136
|
-
}))
|
|
20137
|
-
});
|
|
20138
|
-
}
|
|
20139
|
-
const securitySchemes = parsed.components?.securitySchemes ?? {};
|
|
20140
|
-
const firstScheme = Object.values(securitySchemes)[0];
|
|
20141
|
-
const importedAuth = firstScheme ? authFromSecurityScheme(firstScheme) : void 0;
|
|
20142
|
-
const entry = {
|
|
20143
|
-
id: `${projectName}-api`,
|
|
20144
|
-
name: typeof info.title === "string" ? info.title : projectName,
|
|
20145
|
-
audience: "external",
|
|
20146
|
-
type: "REST",
|
|
20147
|
-
component: `${projectName}-api`,
|
|
20148
|
-
methods,
|
|
20149
|
-
details: typeof info.description === "string" ? info.description : `Imported OpenAPI surface of ${projectName}.`,
|
|
20150
|
-
...typeof info.version === "string" ? { version: info.version } : {},
|
|
20151
|
-
...importedAuth ? { auth: importedAuth } : {}
|
|
20152
|
-
};
|
|
20153
|
-
return SurfaceSnapshotSchema.parse({
|
|
20154
|
-
projectName,
|
|
20155
|
-
origin: "authored",
|
|
20156
|
-
...typeof info.version === "string" ? { version: info.version } : {},
|
|
20157
|
-
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
20158
|
-
interfaces: [entry],
|
|
20159
|
-
types
|
|
20160
|
-
});
|
|
20161
|
-
}
|
|
20162
19460
|
|
|
20163
19461
|
// src/core/surfaces.ts
|
|
20164
19462
|
var SURFACES_DIRNAME = "surfaces";
|
|
20165
19463
|
function surfacesDir(rootDir) {
|
|
20166
19464
|
return path13.join(rootDir, ".wai", SURFACES_DIRNAME);
|
|
20167
19465
|
}
|
|
20168
|
-
function audienceRank(audience) {
|
|
20169
|
-
const idx = SURFACE_AUDIENCES.indexOf(audience ?? "instance");
|
|
20170
|
-
return idx === -1 ? SURFACE_AUDIENCES.indexOf("instance") : idx;
|
|
20171
|
-
}
|
|
20172
|
-
function stateIdString() {
|
|
20173
|
-
const s = computeStateId();
|
|
20174
|
-
return `${s.algorithm}:${s.digest}`;
|
|
20175
|
-
}
|
|
20176
|
-
function computeTypeClosure(entries, types) {
|
|
20177
|
-
const included = /* @__PURE__ */ new Map();
|
|
20178
|
-
const queue = [];
|
|
20179
|
-
const enqueueRef = (ref) => {
|
|
20180
|
-
if (BUILTIN_TYPES.has(ref.toLowerCase())) return;
|
|
20181
|
-
for (const spec of types) {
|
|
20182
|
-
const qualifiedId = spec.subsystem && !spec.id.startsWith(`${spec.subsystem}::`) ? `${spec.subsystem}::${spec.id}` : spec.id;
|
|
20183
|
-
if (matchTypeRef(ref, qualifiedId) && !included.has(spec.id)) {
|
|
20184
|
-
included.set(spec.id, spec);
|
|
20185
|
-
queue.push(spec.id);
|
|
20186
|
-
}
|
|
20187
|
-
}
|
|
20188
|
-
};
|
|
20189
|
-
for (const entry of entries) {
|
|
20190
|
-
for (const m of entry.methods) {
|
|
20191
|
-
for (const ref of methodTypeRefs(m)) enqueueRef(ref);
|
|
20192
|
-
}
|
|
20193
|
-
}
|
|
20194
|
-
while (queue.length) {
|
|
20195
|
-
const spec = included.get(queue.shift());
|
|
20196
|
-
for (const field of spec.fields) {
|
|
20197
|
-
for (const ref of extractTypeIdentifiers(field.type)) enqueueRef(ref);
|
|
20198
|
-
}
|
|
20199
|
-
}
|
|
20200
|
-
return [...included.values()].map((t) => ({
|
|
20201
|
-
id: t.id,
|
|
20202
|
-
name: t.name,
|
|
20203
|
-
kind: t.kind,
|
|
20204
|
-
fields: t.fields.map((f) => ({
|
|
20205
|
-
name: f.name,
|
|
20206
|
-
type: f.type,
|
|
20207
|
-
...f.description ? { description: f.description } : {},
|
|
20208
|
-
...f.optional ? { optional: true } : {}
|
|
20209
|
-
}))
|
|
20210
|
-
}));
|
|
20211
|
-
}
|
|
20212
|
-
function projectOwnSurface(maxAudience) {
|
|
20213
|
-
const system = loadSystemSpec();
|
|
20214
|
-
if (!system) {
|
|
20215
|
-
throw new Error("Cannot project a surface: the L0 system spec is missing.");
|
|
20216
|
-
}
|
|
20217
|
-
const subsystems = loadSubsystemSpecs();
|
|
20218
|
-
const components = loadComponentSpecs();
|
|
20219
|
-
const interfaces = loadInterfaceSpecs();
|
|
20220
|
-
const types = loadTypeSpecs();
|
|
20221
|
-
const floor = audienceRank(maxAudience);
|
|
20222
|
-
const rawEntries = system.publicInterfaces ?? [];
|
|
20223
|
-
const entries = [];
|
|
20224
|
-
for (const raw of rawEntries) {
|
|
20225
|
-
const audience = raw.audience ?? "instance";
|
|
20226
|
-
if (audienceRank(audience) < floor) continue;
|
|
20227
|
-
if (!raw.component) continue;
|
|
20228
|
-
const comp = components.find((c) => c.id === raw.component);
|
|
20229
|
-
if (!comp) continue;
|
|
20230
|
-
const compInterfaces = interfaces.filter((i) => i.component === comp.id && (!raw.interface || i.id === raw.interface));
|
|
20231
|
-
const methods = compInterfaces.flatMap((i) => i.methods);
|
|
20232
|
-
const subsystemType = subsystems.find((s) => s.id === comp.subsystem)?.publicInterfaces.find((pi) => pi.component === comp.id)?.type;
|
|
20233
|
-
entries.push({
|
|
20234
|
-
id: raw.id ?? raw.interface ?? comp.id,
|
|
20235
|
-
name: raw.name ?? comp.name,
|
|
20236
|
-
audience,
|
|
20237
|
-
type: raw.type ?? subsystemType ?? "Custom",
|
|
20238
|
-
component: comp.id,
|
|
20239
|
-
methods,
|
|
20240
|
-
...comp.dispatch && comp.dispatch.length ? { dispatch: comp.dispatch } : {},
|
|
20241
|
-
// Project the backing Portal's auth + basePath so the codec can emit
|
|
20242
|
-
// OpenAPI security + per-portal servers self-contained from the snapshot.
|
|
20243
|
-
...comp.auth && comp.auth.scheme !== "none" ? { auth: comp.auth } : {},
|
|
20244
|
-
...comp.basePath ? { basePath: comp.basePath } : {},
|
|
20245
|
-
details: raw.details ?? "",
|
|
20246
|
-
...raw.version ? { version: raw.version } : {},
|
|
20247
|
-
...raw.stability ? { stability: raw.stability } : {}
|
|
20248
|
-
});
|
|
20249
|
-
}
|
|
20250
|
-
return SurfaceSnapshotSchema.parse({
|
|
20251
|
-
projectName: system.name,
|
|
20252
|
-
origin: "generated",
|
|
20253
|
-
stateId: stateIdString(),
|
|
20254
|
-
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
20255
|
-
interfaces: entries,
|
|
20256
|
-
types: computeTypeClosure(entries, types)
|
|
20257
|
-
});
|
|
20258
|
-
}
|
|
20259
|
-
function projectChildSurface() {
|
|
20260
|
-
return projectOwnSurface("project");
|
|
20261
|
-
}
|
|
20262
|
-
function localName(id) {
|
|
20263
|
-
return id.split("::").pop();
|
|
20264
|
-
}
|
|
20265
|
-
var CROSS_BOUNDARY_TARGETS = /* @__PURE__ */ new Set(["Portal", "Observer"]);
|
|
20266
|
-
function projectSubsystemSurface(subsystemId) {
|
|
20267
|
-
const system = loadSystemSpec();
|
|
20268
|
-
if (!system) {
|
|
20269
|
-
throw new Error("Cannot project a subsystem surface: the L0 system spec is missing.");
|
|
20270
|
-
}
|
|
20271
|
-
const subsystems = loadSubsystemSpecs();
|
|
20272
|
-
const target = subsystems.find((s) => s.id === subsystemId);
|
|
20273
|
-
if (!target) {
|
|
20274
|
-
throw new Error(`Cannot project a subsystem surface: subsystem "${subsystemId}" does not exist.`);
|
|
20275
|
-
}
|
|
20276
|
-
const components = loadComponentSpecs();
|
|
20277
|
-
const interfaces = loadInterfaceSpecs();
|
|
20278
|
-
const types = loadTypeSpecs();
|
|
20279
|
-
const entries = [];
|
|
20280
|
-
const unprojectable = [];
|
|
20281
|
-
for (const pub of target.publicInterfaces ?? []) {
|
|
20282
|
-
if (!pub.component) continue;
|
|
20283
|
-
const comp = components.find((c) => c.id === pub.component || c.id === `${subsystemId}::${pub.component}`);
|
|
20284
|
-
if (!comp) continue;
|
|
20285
|
-
if (!CROSS_BOUNDARY_TARGETS.has(comp.componentType)) {
|
|
20286
|
-
unprojectable.push({ component: pub.component, componentType: comp.componentType });
|
|
20287
|
-
continue;
|
|
20288
|
-
}
|
|
20289
|
-
const compInterfaces = interfaces.filter((i) => i.component === comp.id && (!pub.interface || i.id === pub.interface || i.id === `${subsystemId}::${pub.interface}`));
|
|
20290
|
-
const methods = compInterfaces.flatMap((i) => i.methods);
|
|
20291
|
-
entries.push({
|
|
20292
|
-
id: localName(pub.interface ?? comp.id),
|
|
20293
|
-
name: comp.name,
|
|
20294
|
-
// Family ceiling: a sibling surface is consumable by the system family only.
|
|
20295
|
-
audience: "project",
|
|
20296
|
-
type: pub.type ?? "Custom",
|
|
20297
|
-
// The snapshot carries the LOCAL portal name — consumers resolve cross-tree
|
|
20298
|
-
// refs by their final segment.
|
|
20299
|
-
component: localName(comp.id),
|
|
20300
|
-
methods,
|
|
20301
|
-
...comp.dispatch && comp.dispatch.length ? { dispatch: comp.dispatch } : {},
|
|
20302
|
-
// Project the backing component's auth + basePath so the codec can emit
|
|
20303
|
-
// OpenAPI security + per-portal servers self-contained from the snapshot.
|
|
20304
|
-
...comp.auth && comp.auth.scheme !== "none" ? { auth: comp.auth } : {},
|
|
20305
|
-
...comp.basePath ? { basePath: comp.basePath } : {},
|
|
20306
|
-
details: pub.details ?? ""
|
|
20307
|
-
});
|
|
20308
|
-
}
|
|
20309
|
-
for (const skipped of unprojectable) {
|
|
20310
|
-
console.error(
|
|
20311
|
-
`[surfaces] skipped "${subsystemId}::${skipped.component}": a published ${skipped.componentType} can never serve a cross-boundary caller, so it stays out of every chained child's sibling surface \u2014 publish this surface through a Portal, or an Observer (for events).`
|
|
20312
|
-
);
|
|
20313
|
-
}
|
|
20314
|
-
return SurfaceSnapshotSchema.parse({
|
|
20315
|
-
projectName: `${system.name}::${subsystemId}`,
|
|
20316
|
-
origin: "generated",
|
|
20317
|
-
stateId: stateIdString(),
|
|
20318
|
-
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
20319
|
-
interfaces: entries,
|
|
20320
|
-
types: computeTypeClosure(entries, types)
|
|
20321
|
-
});
|
|
20322
|
-
}
|
|
20323
19466
|
function listSnapshots(rootDir = getProjectRoot()) {
|
|
20324
19467
|
const dir = surfacesDir(rootDir);
|
|
20325
19468
|
if (!fs11.existsSync(dir)) return [];
|
|
@@ -20333,54 +19476,6 @@ function listSnapshots(rootDir = getProjectRoot()) {
|
|
|
20333
19476
|
}
|
|
20334
19477
|
return out;
|
|
20335
19478
|
}
|
|
20336
|
-
function getSnapshot(projectName, rootDir = getProjectRoot()) {
|
|
20337
|
-
return listSnapshots(rootDir).find((s) => s.projectName === projectName) ?? null;
|
|
20338
|
-
}
|
|
20339
|
-
function snapshotFilename(projectName) {
|
|
20340
|
-
return `${safeFilenamePart(projectName)}.yaml`;
|
|
20341
|
-
}
|
|
20342
|
-
function writeSnapshotIfChanged(snapshot, rootDir) {
|
|
20343
|
-
const dir = surfacesDir(rootDir);
|
|
20344
|
-
fs11.mkdirSync(dir, { recursive: true });
|
|
20345
|
-
const p = path13.join(dir, snapshotFilename(snapshot.projectName));
|
|
20346
|
-
const next = SurfaceSnapshotSchema.parse(snapshot);
|
|
20347
|
-
if (fs11.existsSync(p)) {
|
|
20348
|
-
try {
|
|
20349
|
-
const existing = SurfaceSnapshotSchema.parse(readYamlFile(p));
|
|
20350
|
-
if (surfaceContentKey(existing) === surfaceContentKey(next)) {
|
|
20351
|
-
return { path: p, changed: false };
|
|
20352
|
-
}
|
|
20353
|
-
} catch {
|
|
20354
|
-
}
|
|
20355
|
-
}
|
|
20356
|
-
writeYamlFile(p, next);
|
|
20357
|
-
return { path: p, changed: true };
|
|
20358
|
-
}
|
|
20359
|
-
function saveSnapshot(snapshot, rootDir = getProjectRoot()) {
|
|
20360
|
-
return writeSnapshotIfChanged(snapshot, rootDir).path;
|
|
20361
|
-
}
|
|
20362
|
-
function removeSnapshot(projectName, rootDir = getProjectRoot()) {
|
|
20363
|
-
const dir = surfacesDir(rootDir);
|
|
20364
|
-
const direct = path13.join(dir, snapshotFilename(projectName));
|
|
20365
|
-
if (fs11.existsSync(direct)) {
|
|
20366
|
-
fs11.unlinkSync(direct);
|
|
20367
|
-
return true;
|
|
20368
|
-
}
|
|
20369
|
-
if (!fs11.existsSync(dir)) return false;
|
|
20370
|
-
for (const file of fs11.readdirSync(dir)) {
|
|
20371
|
-
if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue;
|
|
20372
|
-
const p = path13.join(dir, file);
|
|
20373
|
-
try {
|
|
20374
|
-
const snap = SurfaceSnapshotSchema.parse(readYamlFile(p));
|
|
20375
|
-
if (snap.projectName === projectName) {
|
|
20376
|
-
fs11.unlinkSync(p);
|
|
20377
|
-
return true;
|
|
20378
|
-
}
|
|
20379
|
-
} catch {
|
|
20380
|
-
}
|
|
20381
|
-
}
|
|
20382
|
-
return false;
|
|
20383
|
-
}
|
|
20384
19479
|
function loadSurfaceSnapshots() {
|
|
20385
19480
|
return listSnapshots();
|
|
20386
19481
|
}
|
|
@@ -20398,136 +19493,12 @@ function listMountSnapshots(mounts) {
|
|
|
20398
19493
|
function loadMountSurfaceSnapshots(mounts) {
|
|
20399
19494
|
return listMountSnapshots(mounts);
|
|
20400
19495
|
}
|
|
20401
|
-
function selectPortalSpec(renderedSet, portalId) {
|
|
20402
|
-
const hit = renderedSet.find((spec) => spec.portalId === portalId);
|
|
20403
|
-
if (!hit) {
|
|
20404
|
-
const known = renderedSet.map((s) => s.portalId).join(", ");
|
|
20405
|
-
throw new Error(`Unknown portal "${portalId}" \u2014 this surface renders: ${known || "(no portals)"}.`);
|
|
20406
|
-
}
|
|
20407
|
-
return [hit];
|
|
20408
|
-
}
|
|
20409
|
-
function perPortalPath(resolvedOut, portalId) {
|
|
20410
|
-
const ext = path13.extname(resolvedOut);
|
|
20411
|
-
const stem = ext ? resolvedOut.slice(0, -ext.length) : resolvedOut;
|
|
20412
|
-
return `${stem}.${safeFilenamePart(portalId)}${ext}`;
|
|
20413
|
-
}
|
|
20414
|
-
function writeSurfaceFile(outPath, snapshot, renderedSet) {
|
|
20415
|
-
const resolved = path13.resolve(outPath);
|
|
20416
|
-
fs11.mkdirSync(path13.dirname(resolved), { recursive: true });
|
|
20417
|
-
if (!renderedSet || renderedSet.length === 0) {
|
|
20418
|
-
writeYamlFile(resolved, snapshot);
|
|
20419
|
-
return [resolved];
|
|
20420
|
-
}
|
|
20421
|
-
if (renderedSet.length === 1) {
|
|
20422
|
-
fs11.writeFileSync(resolved, renderedSet[0].document);
|
|
20423
|
-
return [resolved];
|
|
20424
|
-
}
|
|
20425
|
-
return renderedSet.map((spec) => {
|
|
20426
|
-
const target = perPortalPath(resolved, spec.portalId);
|
|
20427
|
-
fs11.writeFileSync(target, spec.document);
|
|
20428
|
-
return target;
|
|
20429
|
-
});
|
|
20430
|
-
}
|
|
20431
|
-
function exportResult(snapshot, renderedSet, writtenPaths) {
|
|
20432
|
-
const rendered = renderedSet?.length === 1 ? renderedSet[0].document : void 0;
|
|
20433
|
-
return {
|
|
20434
|
-
snapshot,
|
|
20435
|
-
...rendered !== void 0 ? { rendered } : {},
|
|
20436
|
-
...renderedSet ? { renderedSet } : {},
|
|
20437
|
-
...writtenPaths.length === 1 ? { writtenTo: writtenPaths[0] } : {},
|
|
20438
|
-
...writtenPaths.length ? { writtenPaths } : {}
|
|
20439
|
-
};
|
|
20440
|
-
}
|
|
20441
|
-
function exportSurface(maxAudience, format, outPath, portalId) {
|
|
20442
|
-
const snapshot = projectOwnSurface(maxAudience);
|
|
20443
|
-
let renderedSet = format === "openapi" ? toOpenApiSet(snapshot) : void 0;
|
|
20444
|
-
if (renderedSet && portalId) renderedSet = selectPortalSpec(renderedSet, portalId);
|
|
20445
|
-
const writtenPaths = outPath ? writeSurfaceFile(outPath, snapshot, renderedSet) : [];
|
|
20446
|
-
return exportResult(snapshot, renderedSet, writtenPaths);
|
|
20447
|
-
}
|
|
20448
|
-
function importSurface(sourcePath, origin) {
|
|
20449
|
-
const resolved = path13.resolve(sourcePath);
|
|
20450
|
-
if (!fs11.existsSync(resolved)) {
|
|
20451
|
-
throw new Error(`Surface document not found: ${resolved}`);
|
|
20452
|
-
}
|
|
20453
|
-
const body = fs11.readFileSync(resolved, "utf8");
|
|
20454
|
-
let snapshot;
|
|
20455
|
-
if (isOpenApiDocument(body)) {
|
|
20456
|
-
const projectName = path13.basename(resolved).replace(/\.(json|ya?ml)$/i, "");
|
|
20457
|
-
snapshot = fromOpenApi(body, projectName);
|
|
20458
|
-
snapshot = { ...snapshot, origin };
|
|
20459
|
-
} else {
|
|
20460
|
-
snapshot = SurfaceSnapshotSchema.parse(readYamlFile(resolved));
|
|
20461
|
-
snapshot = { ...snapshot, origin };
|
|
20462
|
-
}
|
|
20463
|
-
saveSnapshot(snapshot);
|
|
20464
|
-
return snapshot;
|
|
20465
|
-
}
|
|
20466
|
-
function projectFamilySurfaces(parent) {
|
|
20467
|
-
return runWithProjectRoot(parent.parentRoot, () => {
|
|
20468
|
-
invalidateSpecCache();
|
|
20469
|
-
const siblings = loadSubsystemSpecs().filter((s) => !s.id.includes("::") && s.id !== parent.subsystemId);
|
|
20470
|
-
return [projectChildSurface(), ...siblings.map((s) => projectSubsystemSurface(s.id))];
|
|
20471
|
-
});
|
|
20472
|
-
}
|
|
20473
|
-
function pinFamilySurfaces() {
|
|
20474
|
-
const parent = resolveChainingParent();
|
|
20475
|
-
if (!parent) return null;
|
|
20476
|
-
const childRoot = getProjectRoot();
|
|
20477
|
-
const projected = projectFamilySurfaces(parent);
|
|
20478
|
-
const before = new Map(listSnapshots(childRoot).map((s) => [s.projectName, surfaceContentKey(s)]));
|
|
20479
|
-
const changed = [];
|
|
20480
|
-
for (const snapshot of projected) {
|
|
20481
|
-
const stored = saveSnapshot(snapshot, childRoot);
|
|
20482
|
-
if (before.get(snapshot.projectName) !== surfaceContentKey(SurfaceSnapshotSchema.parse(snapshot))) {
|
|
20483
|
-
changed.push(stored);
|
|
20484
|
-
}
|
|
20485
|
-
}
|
|
20486
|
-
return changed;
|
|
20487
|
-
}
|
|
20488
|
-
function projectedFamilyContent(parent) {
|
|
20489
|
-
try {
|
|
20490
|
-
return new Map(projectFamilySurfaces(parent).map((s) => [s.projectName, surfaceContentKey(s)]));
|
|
20491
|
-
} catch {
|
|
20492
|
-
return null;
|
|
20493
|
-
}
|
|
20494
|
-
}
|
|
20495
|
-
function listExternalInterfaces() {
|
|
20496
|
-
const snapshots = listSnapshots();
|
|
20497
|
-
const chainingParent = resolveChainingParent();
|
|
20498
|
-
const projected = chainingParent ? projectedFamilyContent(chainingParent) : null;
|
|
20499
|
-
return snapshots.map((snapshot) => {
|
|
20500
|
-
const generated = snapshot.origin === "generated";
|
|
20501
|
-
const sourceKind = !generated ? "foreign" : snapshot.projectName.includes("::") ? "sibling" : "parent";
|
|
20502
|
-
const freshness = generated && projected ? projected.get(snapshot.projectName) === surfaceContentKey(snapshot) ? "fresh" : "stale" : "unverifiable";
|
|
20503
|
-
return {
|
|
20504
|
-
projectName: snapshot.projectName,
|
|
20505
|
-
origin: snapshot.origin,
|
|
20506
|
-
sourceKind,
|
|
20507
|
-
generatedAt: snapshot.generatedAt,
|
|
20508
|
-
...snapshot.stateId ? { stateId: snapshot.stateId } : {},
|
|
20509
|
-
...snapshot.version ? { version: snapshot.version } : {},
|
|
20510
|
-
freshness,
|
|
20511
|
-
interfaceIds: snapshot.interfaces.map((e) => e.id)
|
|
20512
|
-
};
|
|
20513
|
-
});
|
|
20514
|
-
}
|
|
20515
|
-
function surfaceContentKey(snapshot) {
|
|
20516
|
-
const { stateId, generatedAt, origin, ...content } = snapshot;
|
|
20517
|
-
return JSON.stringify(content);
|
|
20518
|
-
}
|
|
20519
19496
|
|
|
20520
19497
|
// src/core/validation.ts
|
|
20521
19498
|
var path14 = __toESM(require("path"));
|
|
20522
19499
|
function loadProjectConfig2() {
|
|
20523
19500
|
return loadProjectConfig();
|
|
20524
19501
|
}
|
|
20525
|
-
function computeStateId2() {
|
|
20526
|
-
return computeStateId();
|
|
20527
|
-
}
|
|
20528
|
-
function consumedContractInputs2() {
|
|
20529
|
-
return consumedContractInputs();
|
|
20530
|
-
}
|
|
20531
19502
|
function projectPackSelections() {
|
|
20532
19503
|
try {
|
|
20533
19504
|
return (loadProjectConfig2()?.extensions?.packs ?? []).filter((e) => typeof e !== "string");
|
|
@@ -20535,9 +19506,6 @@ function projectPackSelections() {
|
|
|
20535
19506
|
return [];
|
|
20536
19507
|
}
|
|
20537
19508
|
}
|
|
20538
|
-
function findTestsReferencing2(methods, projectRoot, testRoots = []) {
|
|
20539
|
-
return findTestsReferencing(methods, projectRoot, testRoots);
|
|
20540
|
-
}
|
|
20541
19509
|
var RESOLUTION_FAILURE_CODES = /* @__PURE__ */ new Set([
|
|
20542
19510
|
"UNDEFINED_TYPE_REFERENCE",
|
|
20543
19511
|
"INVALID_DEPENDENCY_REFERENCE",
|
|
@@ -20576,90 +19544,6 @@ function stricterSeverities(parent, child) {
|
|
|
20576
19544
|
function issue(severity, code, message, agentId, specId) {
|
|
20577
19545
|
return { severity, code, message, agentId, specId };
|
|
20578
19546
|
}
|
|
20579
|
-
function validateRegistry(registry, rules) {
|
|
20580
|
-
const issues = [];
|
|
20581
|
-
const idCounts = /* @__PURE__ */ new Map();
|
|
20582
|
-
for (const agent of registry.agents) {
|
|
20583
|
-
idCounts.set(agent.id, (idCounts.get(agent.id) ?? 0) + 1);
|
|
20584
|
-
}
|
|
20585
|
-
for (const [id, count] of idCounts) {
|
|
20586
|
-
if (count > 1) {
|
|
20587
|
-
issues.push(issue("error", "DUPLICATE_AGENT_ID", `Duplicate agent id: "${id}"`, id));
|
|
20588
|
-
}
|
|
20589
|
-
}
|
|
20590
|
-
for (const agent of registry.agents) {
|
|
20591
|
-
validateAgent(agent, rules, issues);
|
|
20592
|
-
}
|
|
20593
|
-
if (rules.noOverlappingOwnership) {
|
|
20594
|
-
checkOverlappingOwnership(registry.agents, issues);
|
|
20595
|
-
}
|
|
20596
|
-
return {
|
|
20597
|
-
valid: issues.every((i) => i.severity !== "error"),
|
|
20598
|
-
issues
|
|
20599
|
-
};
|
|
20600
|
-
}
|
|
20601
|
-
function validateAgent(agent, rules, issues) {
|
|
20602
|
-
const isMeta = agent.tags.some((t) => rules.metaAgentTags.includes(t));
|
|
20603
|
-
if (rules.requireOwnedPaths && !isMeta && agent.ownedPaths.length === 0) {
|
|
20604
|
-
issues.push(
|
|
20605
|
-
issue(
|
|
20606
|
-
"warning",
|
|
20607
|
-
"NO_OWNED_PATHS",
|
|
20608
|
-
`Agent "${agent.id}" has no ownedPaths. Add paths or tag as meta/guardian.`,
|
|
20609
|
-
agent.id
|
|
20610
|
-
)
|
|
20611
|
-
);
|
|
20612
|
-
}
|
|
20613
|
-
if (agent.targets.length === 0) {
|
|
20614
|
-
issues.push(
|
|
20615
|
-
issue("warning", "NO_TARGETS", `Agent "${agent.id}" has no output targets configured.`, agent.id)
|
|
20616
|
-
);
|
|
20617
|
-
}
|
|
20618
|
-
}
|
|
20619
|
-
function checkOverlappingOwnership(agents, issues) {
|
|
20620
|
-
const pathToAgents = /* @__PURE__ */ new Map();
|
|
20621
|
-
for (const agent of agents) {
|
|
20622
|
-
for (const p of agent.ownedPaths) {
|
|
20623
|
-
const owners = pathToAgents.get(p) ?? [];
|
|
20624
|
-
owners.push(agent.id);
|
|
20625
|
-
pathToAgents.set(p, owners);
|
|
20626
|
-
}
|
|
20627
|
-
}
|
|
20628
|
-
for (const [p, owners] of pathToAgents) {
|
|
20629
|
-
if (owners.length > 1) {
|
|
20630
|
-
issues.push(
|
|
20631
|
-
issue(
|
|
20632
|
-
"error",
|
|
20633
|
-
"OVERLAPPING_OWNERSHIP",
|
|
20634
|
-
`Path "${p}" is claimed by multiple agents: ${owners.join(", ")}`
|
|
20635
|
-
)
|
|
20636
|
-
);
|
|
20637
|
-
}
|
|
20638
|
-
}
|
|
20639
|
-
}
|
|
20640
|
-
function validateProjectConfig(config) {
|
|
20641
|
-
const issues = [];
|
|
20642
|
-
if (config.targets.length === 0) {
|
|
20643
|
-
issues.push(issue("error", "NO_TARGETS", "No output targets configured in project.yaml"));
|
|
20644
|
-
}
|
|
20645
|
-
const enabled = config.targets.filter((t) => {
|
|
20646
|
-
if (typeof t === "string") return true;
|
|
20647
|
-
return t.enabled !== false;
|
|
20648
|
-
});
|
|
20649
|
-
if (enabled.length === 0) {
|
|
20650
|
-
issues.push(issue("error", "NO_ENABLED_TARGETS", "All configured targets are disabled"));
|
|
20651
|
-
}
|
|
20652
|
-
return {
|
|
20653
|
-
valid: issues.every((i) => i.severity !== "error"),
|
|
20654
|
-
issues
|
|
20655
|
-
};
|
|
20656
|
-
}
|
|
20657
|
-
function listRules2() {
|
|
20658
|
-
const extensions = loadProjectExtensions();
|
|
20659
|
-
registerBuiltinRules();
|
|
20660
|
-
registerPackRules(extensions.rules);
|
|
20661
|
-
return ruleSequence();
|
|
20662
|
-
}
|
|
20663
19547
|
function validateSddTree(rulesOrOptions, projectType = "backend") {
|
|
20664
19548
|
let rules = rulesOrOptions;
|
|
20665
19549
|
let scopeSubsystem;
|
|
@@ -20897,22 +19781,6 @@ function settledStatusBearing(loaded) {
|
|
|
20897
19781
|
take(loaded.implementations, index.paths.implementation);
|
|
20898
19782
|
return out;
|
|
20899
19783
|
}
|
|
20900
|
-
function validateAsComplete(options) {
|
|
20901
|
-
return validateSddTree({ ...options ?? {}, treatAllAsComplete: true });
|
|
20902
|
-
}
|
|
20903
|
-
function computeGateStateId() {
|
|
20904
|
-
const content = computeStateId2();
|
|
20905
|
-
const extensions = loadProjectExtensions();
|
|
20906
|
-
let gate = {};
|
|
20907
|
-
try {
|
|
20908
|
-
const config = loadProjectConfig2();
|
|
20909
|
-
if (config) gate = { projectType: config.projectType, rules: config.rules };
|
|
20910
|
-
} catch {
|
|
20911
|
-
}
|
|
20912
|
-
const inputs = consumedContractInputs2();
|
|
20913
|
-
registerBuiltinRules();
|
|
20914
|
-
return computeGateIdentity(content, extensions, ruleSequence(), inputs, gate);
|
|
20915
|
-
}
|
|
20916
19784
|
|
|
20917
19785
|
// src/core/diagram.ts
|
|
20918
19786
|
function renderDiagram(format) {
|
|
@@ -22058,13 +20926,13 @@ function ineffectiveDeltaPaths(delta, merged, stored) {
|
|
|
22058
20926
|
const isPlain = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
22059
20927
|
const same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
22060
20928
|
const at = (prefix, key) => prefix ? `${prefix}.${key}` : key;
|
|
22061
|
-
const say = (
|
|
22062
|
-
out.push(`${
|
|
20929
|
+
const say = (path28, why) => {
|
|
20930
|
+
out.push(`${path28} \u2014 ${why}`);
|
|
22063
20931
|
};
|
|
22064
|
-
const walkValue = (d, m, s,
|
|
20932
|
+
const walkValue = (d, m, s, path28, field) => {
|
|
22065
20933
|
if (Array.isArray(d)) {
|
|
22066
20934
|
if (!Array.isArray(m)) {
|
|
22067
|
-
say(
|
|
20935
|
+
say(path28, "the level does not have this field, so the write dropped it");
|
|
22068
20936
|
return;
|
|
22069
20937
|
}
|
|
22070
20938
|
if (field === "narrative" && d.some(carriesEditMarker)) return;
|
|
@@ -22072,32 +20940,32 @@ function ineffectiveDeltaPaths(delta, merged, stored) {
|
|
|
22072
20940
|
if (carriesEditMarker(element)) continue;
|
|
22073
20941
|
const key = reportIdentityOf(field, element);
|
|
22074
20942
|
if (key === null) {
|
|
22075
|
-
if (!same(m, d)) say(
|
|
22076
|
-
else if (same(s, d)) say(
|
|
20943
|
+
if (!same(m, d)) say(path28, "the level does not keep this value, so the write dropped it");
|
|
20944
|
+
else if (same(s, d)) say(path28, "the stored spec already held this value");
|
|
22077
20945
|
return;
|
|
22078
20946
|
}
|
|
22079
20947
|
const mMatch = m.find((i) => reportIdentityOf(field, i) === key);
|
|
22080
20948
|
const sMatch = Array.isArray(s) ? s.find((i) => reportIdentityOf(field, i) === key) : void 0;
|
|
22081
20949
|
if (mMatch === void 0) {
|
|
22082
|
-
say(at(
|
|
20950
|
+
say(at(path28, key), "the write did not store this element");
|
|
22083
20951
|
continue;
|
|
22084
20952
|
}
|
|
22085
|
-
walk2(element, mMatch, sMatch, at(
|
|
20953
|
+
walk2(element, mMatch, sMatch, at(path28, key), field);
|
|
22086
20954
|
}
|
|
22087
20955
|
return;
|
|
22088
20956
|
}
|
|
22089
20957
|
if (isPlain(d)) {
|
|
22090
20958
|
if (!isPlain(m)) {
|
|
22091
|
-
say(
|
|
20959
|
+
say(path28, "the level does not have this field, so the write dropped it");
|
|
22092
20960
|
return;
|
|
22093
20961
|
}
|
|
22094
|
-
walk2(d, m, s,
|
|
20962
|
+
walk2(d, m, s, path28, field);
|
|
22095
20963
|
return;
|
|
22096
20964
|
}
|
|
22097
|
-
if (!same(m, d)) say(
|
|
22098
|
-
else if (same(s, d)) say(
|
|
20965
|
+
if (!same(m, d)) say(path28, "the write did not store it \u2014 the level's schema does not keep this value");
|
|
20966
|
+
else if (same(s, d)) say(path28, "the stored spec already held this value");
|
|
22099
20967
|
};
|
|
22100
|
-
function walk2(d, m, s,
|
|
20968
|
+
function walk2(d, m, s, path28, container) {
|
|
22101
20969
|
for (const [key, value] of Object.entries(d)) {
|
|
22102
20970
|
if (DELTA_VERBS.has(key) || JUMP_LABEL_TWINS.has(key)) continue;
|
|
22103
20971
|
if (key === "label" && LABEL_TWIN_CONTAINERS.has(container)) continue;
|
|
@@ -22107,13 +20975,13 @@ function ineffectiveDeltaPaths(delta, merged, stored) {
|
|
|
22107
20975
|
if (typeof name !== "string") continue;
|
|
22108
20976
|
const had = isPlain(s) && s[name] !== void 0;
|
|
22109
20977
|
const still = isPlain(m) && m[name] !== void 0;
|
|
22110
|
-
if (!had) say(at(
|
|
22111
|
-
else if (still) say(at(
|
|
20978
|
+
if (!had) say(at(path28, name), "unset named a field the stored spec did not have");
|
|
20979
|
+
else if (still) say(at(path28, name), "unset did not remove it");
|
|
22112
20980
|
}
|
|
22113
20981
|
continue;
|
|
22114
20982
|
}
|
|
22115
20983
|
if (value === void 0 || value === null) continue;
|
|
22116
|
-
const here = at(
|
|
20984
|
+
const here = at(path28, key);
|
|
22117
20985
|
const mValue = isPlain(m) ? m[key] : void 0;
|
|
22118
20986
|
const sValue = isPlain(s) ? s[key] : void 0;
|
|
22119
20987
|
if (mValue === void 0) {
|
|
@@ -24452,9 +23320,6 @@ function scanAllSpecs(options) {
|
|
|
24452
23320
|
function resolveSubprojectForNamespace(namespace) {
|
|
24453
23321
|
return current().resolveSubprojectForNamespace(namespace);
|
|
24454
23322
|
}
|
|
24455
|
-
function getSubprojectPrefix(qualifiedId) {
|
|
24456
|
-
return current().getSubprojectPrefix(qualifiedId);
|
|
24457
|
-
}
|
|
24458
23323
|
function getSubsystemPath(id) {
|
|
24459
23324
|
return current().getSubsystemPath(id);
|
|
24460
23325
|
}
|
|
@@ -24467,12 +23332,6 @@ function getInterfacePath(id, componentId) {
|
|
|
24467
23332
|
function getImplementationPath(id, contractId) {
|
|
24468
23333
|
return current().getImplementationPath(id, contractId);
|
|
24469
23334
|
}
|
|
24470
|
-
function getTypePath(id, subsystemId, group) {
|
|
24471
|
-
return current().getTypePath(id, subsystemId, group);
|
|
24472
|
-
}
|
|
24473
|
-
function getGroupPath(id, subsystemId) {
|
|
24474
|
-
return current().getGroupPath(id, subsystemId);
|
|
24475
|
-
}
|
|
24476
23335
|
function loadSystemSpec() {
|
|
24477
23336
|
return current().loadSystemSpec();
|
|
24478
23337
|
}
|
|
@@ -24503,9 +23362,6 @@ function saveComponentSpec(spec, opts) {
|
|
|
24503
23362
|
function deleteComponentSpec(id) {
|
|
24504
23363
|
return current().deleteComponentSpec(id);
|
|
24505
23364
|
}
|
|
24506
|
-
function normalizeComponentLayout() {
|
|
24507
|
-
return current().normalizeComponentLayout();
|
|
24508
|
-
}
|
|
24509
23365
|
function loadInterfaceSpecs() {
|
|
24510
23366
|
return current().loadInterfaceSpecs();
|
|
24511
23367
|
}
|
|
@@ -24617,38 +23473,12 @@ function computeStateIdAt(root) {
|
|
|
24617
23473
|
function deleteTypeSpec(id) {
|
|
24618
23474
|
return current().deleteTypeSpec(id);
|
|
24619
23475
|
}
|
|
24620
|
-
function loadGroupSpecs() {
|
|
24621
|
-
return current().loadGroupSpecs();
|
|
24622
|
-
}
|
|
24623
|
-
function loadGroupSpec(id) {
|
|
24624
|
-
return current().loadGroupSpec(id);
|
|
24625
|
-
}
|
|
24626
|
-
function saveGroupSpec(spec) {
|
|
24627
|
-
current().saveGroupSpec(spec);
|
|
24628
|
-
}
|
|
24629
|
-
function deleteGroupSpec(id) {
|
|
24630
|
-
return current().deleteGroupSpec(id);
|
|
24631
|
-
}
|
|
24632
|
-
function collectPromotableSpecs(scopeSubsystem) {
|
|
24633
|
-
return current().collectPromotableSpecs(scopeSubsystem);
|
|
24634
|
-
}
|
|
24635
|
-
function applySpecStatus(kind, id, status) {
|
|
24636
|
-
current().applySpecStatus(kind, id, status);
|
|
24637
|
-
}
|
|
24638
23476
|
function specPathsInScope(scopeSubsystem) {
|
|
24639
23477
|
return current().specPathsInScope(scopeSubsystem);
|
|
24640
23478
|
}
|
|
24641
23479
|
function snapshotSpecFiles() {
|
|
24642
23480
|
return current().snapshotSpecFiles();
|
|
24643
23481
|
}
|
|
24644
|
-
function restoreSpecFiles(snapshot) {
|
|
24645
|
-
for (const [file, content] of snapshot) {
|
|
24646
|
-
fs12.writeFileSync(file, content);
|
|
24647
|
-
}
|
|
24648
|
-
}
|
|
24649
|
-
function findLegacySpecFiles() {
|
|
24650
|
-
return current().findLegacySpecFiles();
|
|
24651
|
-
}
|
|
24652
23482
|
function updateSpec(kind, id, delta, hooks, dryRun) {
|
|
24653
23483
|
return current().updateSpec(kind, id, delta, hooks, dryRun);
|
|
24654
23484
|
}
|
|
@@ -24742,219 +23572,9 @@ function unregisterDomain(id) {
|
|
|
24742
23572
|
removeFreeStanding(id);
|
|
24743
23573
|
}
|
|
24744
23574
|
|
|
24745
|
-
// src/core/
|
|
23575
|
+
// src/core/provision.ts
|
|
24746
23576
|
var fs13 = __toESM(require("fs"));
|
|
24747
23577
|
var path17 = __toESM(require("path"));
|
|
24748
|
-
var PACKAGE_MARKERS = [
|
|
24749
|
-
"package.json",
|
|
24750
|
-
"pyproject.toml",
|
|
24751
|
-
"Cargo.toml",
|
|
24752
|
-
"go.mod",
|
|
24753
|
-
"build.gradle",
|
|
24754
|
-
"build.gradle.kts",
|
|
24755
|
-
"pom.xml"
|
|
24756
|
-
];
|
|
24757
|
-
var MAX_SCAN_DEPTH = 5;
|
|
24758
|
-
function detectDomainCandidates(projectRoot, alreadyTrackedPaths = /* @__PURE__ */ new Set(), alreadyTrackedIds = /* @__PURE__ */ new Set()) {
|
|
24759
|
-
const candidates = /* @__PURE__ */ new Map();
|
|
24760
|
-
for (const c of detectGitSubmodules(projectRoot)) {
|
|
24761
|
-
candidates.set(c.path, { ...c, alreadyTracked: alreadyTrackedPaths.has(c.path) });
|
|
24762
|
-
}
|
|
24763
|
-
for (const c of detectNestedGitRepos(projectRoot)) {
|
|
24764
|
-
if (!candidates.has(c.path)) {
|
|
24765
|
-
candidates.set(c.path, { ...c, alreadyTracked: alreadyTrackedPaths.has(c.path) });
|
|
24766
|
-
}
|
|
24767
|
-
}
|
|
24768
|
-
const gitPaths = new Set(
|
|
24769
|
-
Array.from(candidates.values()).filter((c) => c.type === "git-submodule" || c.type === "git-repo").map((c) => c.path)
|
|
24770
|
-
);
|
|
24771
|
-
for (const c of detectPackageRoots(projectRoot)) {
|
|
24772
|
-
if (candidates.has(c.path)) continue;
|
|
24773
|
-
const insideGit = Array.from(gitPaths).some(
|
|
24774
|
-
(gp) => c.path === gp || c.path.startsWith(gp + "/")
|
|
24775
|
-
);
|
|
24776
|
-
if (insideGit) continue;
|
|
24777
|
-
candidates.set(c.path, { ...c, alreadyTracked: alreadyTrackedPaths.has(c.path) });
|
|
24778
|
-
}
|
|
24779
|
-
const sorted = Array.from(candidates.values()).sort((a, b) => a.path.localeCompare(b.path));
|
|
24780
|
-
return deduplicateIds(sorted, alreadyTrackedIds);
|
|
24781
|
-
}
|
|
24782
|
-
function deduplicateIds(candidates, existingIds = /* @__PURE__ */ new Set()) {
|
|
24783
|
-
const idCount = /* @__PURE__ */ new Map();
|
|
24784
|
-
for (const id of existingIds) {
|
|
24785
|
-
idCount.set(id, (idCount.get(id) ?? 0) + 1);
|
|
24786
|
-
}
|
|
24787
|
-
for (const c of candidates) {
|
|
24788
|
-
idCount.set(c.suggestedId, (idCount.get(c.suggestedId) ?? 0) + 1);
|
|
24789
|
-
}
|
|
24790
|
-
return candidates.map((c) => {
|
|
24791
|
-
if ((idCount.get(c.suggestedId) ?? 0) <= 1) return c;
|
|
24792
|
-
const parts = c.path.split("/");
|
|
24793
|
-
const qualifiedId = parts.length >= 2 ? pathToId(`${parts[parts.length - 2]}-${parts[parts.length - 1]}`) : c.suggestedId;
|
|
24794
|
-
return { ...c, suggestedId: qualifiedId };
|
|
24795
|
-
});
|
|
24796
|
-
}
|
|
24797
|
-
function parseGitmodules(filePath) {
|
|
24798
|
-
const content = fs13.readFileSync(filePath, "utf-8");
|
|
24799
|
-
const entries = [];
|
|
24800
|
-
let current2 = {};
|
|
24801
|
-
for (const line of content.split("\n")) {
|
|
24802
|
-
const trimmed = line.trim();
|
|
24803
|
-
const headerMatch = trimmed.match(/^\[submodule "(.+)"\]$/);
|
|
24804
|
-
if (headerMatch) {
|
|
24805
|
-
if (current2.path) entries.push(current2);
|
|
24806
|
-
current2 = { name: headerMatch[1] };
|
|
24807
|
-
continue;
|
|
24808
|
-
}
|
|
24809
|
-
const keyVal = trimmed.match(/^(\w+)\s*=\s*(.+)$/);
|
|
24810
|
-
if (keyVal) {
|
|
24811
|
-
const [, key, value] = keyVal;
|
|
24812
|
-
if (key === "path") current2.path = value.trim();
|
|
24813
|
-
if (key === "url") current2.url = value.trim();
|
|
24814
|
-
}
|
|
24815
|
-
}
|
|
24816
|
-
if (current2.path) entries.push(current2);
|
|
24817
|
-
return entries;
|
|
24818
|
-
}
|
|
24819
|
-
function detectGitSubmodules(projectRoot) {
|
|
24820
|
-
const gitmodulesPath = path17.join(projectRoot, ".gitmodules");
|
|
24821
|
-
if (!fs13.existsSync(gitmodulesPath)) return [];
|
|
24822
|
-
return parseGitmodules(gitmodulesPath).map((entry) => ({
|
|
24823
|
-
suggestedId: pathToId(entry.path),
|
|
24824
|
-
suggestedName: pathToName(entry.path),
|
|
24825
|
-
path: normalizePath(entry.path),
|
|
24826
|
-
type: "git-submodule",
|
|
24827
|
-
alreadyTracked: false
|
|
24828
|
-
}));
|
|
24829
|
-
}
|
|
24830
|
-
function detectNestedGitRepos(projectRoot) {
|
|
24831
|
-
const results = [];
|
|
24832
|
-
walkForGit(projectRoot, projectRoot, 0, results);
|
|
24833
|
-
return results;
|
|
24834
|
-
}
|
|
24835
|
-
function walkForGit(projectRoot, currentDir, depth, results) {
|
|
24836
|
-
if (depth > MAX_SCAN_DEPTH) return;
|
|
24837
|
-
let entries;
|
|
24838
|
-
try {
|
|
24839
|
-
entries = fs13.readdirSync(currentDir, { withFileTypes: true });
|
|
24840
|
-
} catch {
|
|
24841
|
-
return;
|
|
24842
|
-
}
|
|
24843
|
-
for (const entry of entries) {
|
|
24844
|
-
if (!entry.isDirectory()) continue;
|
|
24845
|
-
if (SCAN_EXCLUDE_DIRS.has(entry.name)) continue;
|
|
24846
|
-
const fullPath = path17.join(currentDir, entry.name);
|
|
24847
|
-
const relPath = normalizePath(path17.relative(projectRoot, fullPath));
|
|
24848
|
-
if (relPath === "" || relPath === ".") continue;
|
|
24849
|
-
const gitPath = path17.join(fullPath, ".git");
|
|
24850
|
-
if (fs13.existsSync(gitPath)) {
|
|
24851
|
-
results.push({
|
|
24852
|
-
suggestedId: pathToId(relPath),
|
|
24853
|
-
suggestedName: pathToName(relPath),
|
|
24854
|
-
path: relPath,
|
|
24855
|
-
type: "git-repo",
|
|
24856
|
-
alreadyTracked: false
|
|
24857
|
-
});
|
|
24858
|
-
continue;
|
|
24859
|
-
}
|
|
24860
|
-
walkForGit(projectRoot, fullPath, depth + 1, results);
|
|
24861
|
-
}
|
|
24862
|
-
}
|
|
24863
|
-
function detectPackageRoots(projectRoot) {
|
|
24864
|
-
const results = [];
|
|
24865
|
-
walkForPackages(projectRoot, projectRoot, 0, results);
|
|
24866
|
-
return results;
|
|
24867
|
-
}
|
|
24868
|
-
function walkForPackages(projectRoot, currentDir, depth, results) {
|
|
24869
|
-
if (depth > MAX_SCAN_DEPTH) return;
|
|
24870
|
-
let entries;
|
|
24871
|
-
try {
|
|
24872
|
-
entries = fs13.readdirSync(currentDir, { withFileTypes: true });
|
|
24873
|
-
} catch {
|
|
24874
|
-
return;
|
|
24875
|
-
}
|
|
24876
|
-
for (const entry of entries) {
|
|
24877
|
-
if (!entry.isDirectory()) continue;
|
|
24878
|
-
if (SCAN_EXCLUDE_DIRS.has(entry.name)) continue;
|
|
24879
|
-
const fullPath = path17.join(currentDir, entry.name);
|
|
24880
|
-
const relPath = normalizePath(path17.relative(projectRoot, fullPath));
|
|
24881
|
-
if (relPath === "" || relPath === ".") continue;
|
|
24882
|
-
const hasMarker = PACKAGE_MARKERS.some((m) => fs13.existsSync(path17.join(fullPath, m)));
|
|
24883
|
-
if (hasMarker) {
|
|
24884
|
-
results.push({
|
|
24885
|
-
suggestedId: pathToId(relPath),
|
|
24886
|
-
suggestedName: pathToName(relPath),
|
|
24887
|
-
path: relPath,
|
|
24888
|
-
type: "package-root",
|
|
24889
|
-
alreadyTracked: false
|
|
24890
|
-
});
|
|
24891
|
-
}
|
|
24892
|
-
walkForPackages(projectRoot, fullPath, depth + 1, results);
|
|
24893
|
-
}
|
|
24894
|
-
}
|
|
24895
|
-
function pathToId(relPath) {
|
|
24896
|
-
const basename11 = path17.basename(relPath);
|
|
24897
|
-
return basename11.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
24898
|
-
}
|
|
24899
|
-
function pathToName(relPath) {
|
|
24900
|
-
const id = pathToId(relPath);
|
|
24901
|
-
return id.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
24902
|
-
}
|
|
24903
|
-
function normalizePath(p) {
|
|
24904
|
-
return p.replace(/\\/g, "/");
|
|
24905
|
-
}
|
|
24906
|
-
|
|
24907
|
-
// src/core/templates.ts
|
|
24908
|
-
var path18 = __toESM(require("path"));
|
|
24909
|
-
function builtinTemplatesDir() {
|
|
24910
|
-
return path18.resolve(__dirname, "..", "templates");
|
|
24911
|
-
}
|
|
24912
|
-
function loadTemplate(id, globalOverride) {
|
|
24913
|
-
const dirs = templateSearchDirs(globalOverride);
|
|
24914
|
-
for (const dir of dirs) {
|
|
24915
|
-
const filePath = path18.join(dir, `${id}.yaml`);
|
|
24916
|
-
if (pathExists(filePath)) {
|
|
24917
|
-
const raw = readYamlFile(filePath);
|
|
24918
|
-
return { ...TemplateSchema.parse(raw), templateName: id };
|
|
24919
|
-
}
|
|
24920
|
-
}
|
|
24921
|
-
throw new TemplateNotFoundError(id);
|
|
24922
|
-
}
|
|
24923
|
-
function loadAgentOverride(agentId) {
|
|
24924
|
-
const filePath = path18.join(AI_PATHS.root(), "agents", `${agentId}.md`);
|
|
24925
|
-
return readFileOrNull(filePath);
|
|
24926
|
-
}
|
|
24927
|
-
function listTemplateIds(globalOverride) {
|
|
24928
|
-
const seen = /* @__PURE__ */ new Set();
|
|
24929
|
-
for (const dir of templateSearchDirs(globalOverride)) {
|
|
24930
|
-
for (const file of listFiles(dir, ".yaml")) {
|
|
24931
|
-
seen.add(path18.basename(file, ".yaml"));
|
|
24932
|
-
}
|
|
24933
|
-
}
|
|
24934
|
-
return Array.from(seen).sort();
|
|
24935
|
-
}
|
|
24936
|
-
function templateSearchDirs(globalOverride) {
|
|
24937
|
-
return [
|
|
24938
|
-
AI_PATHS.templatesDir(),
|
|
24939
|
-
// 1. project-local
|
|
24940
|
-
globalTemplatesDir(globalOverride),
|
|
24941
|
-
// 2. global user/org
|
|
24942
|
-
builtinTemplatesDir()
|
|
24943
|
-
// 3. built-in fallback
|
|
24944
|
-
];
|
|
24945
|
-
}
|
|
24946
|
-
function renderTemplateInstructions(template, vars) {
|
|
24947
|
-
return template.instructions.replace(/\{\{(\w+)\}\}/g, (_match, key) => {
|
|
24948
|
-
return key in vars ? vars[key] : `{{${key}}}`;
|
|
24949
|
-
});
|
|
24950
|
-
}
|
|
24951
|
-
function parseTemplate(yamlContent) {
|
|
24952
|
-
return TemplateSchema.parse(parseYaml(yamlContent));
|
|
24953
|
-
}
|
|
24954
|
-
|
|
24955
|
-
// src/core/provision.ts
|
|
24956
|
-
var fs14 = __toESM(require("fs"));
|
|
24957
|
-
var path19 = __toESM(require("path"));
|
|
24958
23578
|
function defaultProjectConfig(name, now) {
|
|
24959
23579
|
return {
|
|
24960
23580
|
schemaVersion: "1.0.0",
|
|
@@ -25002,7 +23622,7 @@ function provisionProject(name) {
|
|
|
25002
23622
|
function ensureProjectInitialized(fallbackName) {
|
|
25003
23623
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
25004
23624
|
const paths = aiPathsAt(getProjectRoot());
|
|
25005
|
-
const hasSystem =
|
|
23625
|
+
const hasSystem = fs13.existsSync(paths.specsSystem());
|
|
25006
23626
|
let name = fallbackName;
|
|
25007
23627
|
if (hasSystem) {
|
|
25008
23628
|
const existing = loadSystemSpec();
|
|
@@ -25021,41 +23641,10 @@ function ensureProjectInitialized(fallbackName) {
|
|
|
25021
23641
|
if (wroteConfig || wroteSystem) invalidateSpecCache();
|
|
25022
23642
|
return { wroteConfig, wroteSystem };
|
|
25023
23643
|
}
|
|
25024
|
-
function walkChainedSubprojects(projectRoot, onChild) {
|
|
25025
|
-
const visited = /* @__PURE__ */ new Set();
|
|
25026
|
-
const walk2 = (dir) => {
|
|
25027
|
-
const resolved = path19.resolve(dir);
|
|
25028
|
-
if (visited.has(resolved)) return;
|
|
25029
|
-
visited.add(resolved);
|
|
25030
|
-
const specsDir = aiPathsAt(dir).specsDir();
|
|
25031
|
-
if (!fs14.existsSync(specsDir)) return;
|
|
25032
|
-
for (const file of listFilesRecursive(specsDir, ".yaml")) {
|
|
25033
|
-
let raw;
|
|
25034
|
-
try {
|
|
25035
|
-
raw = readYamlFile(file);
|
|
25036
|
-
} catch {
|
|
25037
|
-
continue;
|
|
25038
|
-
}
|
|
25039
|
-
if (!(raw && typeof raw === "object" && "parentSystem" in raw)) continue;
|
|
25040
|
-
const pp = raw.projectPath;
|
|
25041
|
-
if (typeof pp !== "string" || pp.trim() === "") continue;
|
|
25042
|
-
let childDir;
|
|
25043
|
-
try {
|
|
25044
|
-
childDir = assertContainedProjectPath(dir, pp);
|
|
25045
|
-
} catch {
|
|
25046
|
-
continue;
|
|
25047
|
-
}
|
|
25048
|
-
const id = raw.id;
|
|
25049
|
-
onChild(childDir, typeof id === "string" ? id : path19.basename(childDir));
|
|
25050
|
-
walk2(childDir);
|
|
25051
|
-
}
|
|
25052
|
-
};
|
|
25053
|
-
walk2(projectRoot);
|
|
25054
|
-
}
|
|
25055
23644
|
function listDirectChainedSubprojects(projectRoot) {
|
|
25056
23645
|
const out = [];
|
|
25057
23646
|
const specsDir = aiPathsAt(projectRoot).specsDir();
|
|
25058
|
-
if (!
|
|
23647
|
+
if (!fs13.existsSync(specsDir)) return out;
|
|
25059
23648
|
for (const file of listFilesRecursive(specsDir, ".yaml")) {
|
|
25060
23649
|
let raw;
|
|
25061
23650
|
try {
|
|
@@ -25073,32 +23662,10 @@ function listDirectChainedSubprojects(projectRoot) {
|
|
|
25073
23662
|
continue;
|
|
25074
23663
|
}
|
|
25075
23664
|
const id = raw.id;
|
|
25076
|
-
out.push({ dir, subsystemId: typeof id === "string" ? id :
|
|
23665
|
+
out.push({ dir, subsystemId: typeof id === "string" ? id : path17.basename(dir) });
|
|
25077
23666
|
}
|
|
25078
23667
|
return out;
|
|
25079
23668
|
}
|
|
25080
|
-
function childHasSpecsButNoConfig(childDir) {
|
|
25081
|
-
return fs14.existsSync(aiPathsAt(childDir).specsDir()) && !projectConfigRepositoryAt(childDir).exists();
|
|
25082
|
-
}
|
|
25083
|
-
function findChainingSubprojectsMissingConfig(projectRoot) {
|
|
25084
|
-
const missing = [];
|
|
25085
|
-
walkChainedSubprojects(projectRoot, (childDir) => {
|
|
25086
|
-
if (childHasSpecsButNoConfig(childDir)) missing.push(childDir);
|
|
25087
|
-
});
|
|
25088
|
-
return missing;
|
|
25089
|
-
}
|
|
25090
|
-
function backfillChainedSubprojectConfigs(projectRoot) {
|
|
25091
|
-
const backfilled = [];
|
|
25092
|
-
walkChainedSubprojects(projectRoot, (childDir, subsystemId) => {
|
|
25093
|
-
if (childHasSpecsButNoConfig(childDir)) {
|
|
25094
|
-
runWithProjectRoot(childDir, () => {
|
|
25095
|
-
ensureProjectInitialized(subsystemId);
|
|
25096
|
-
});
|
|
25097
|
-
backfilled.push(childDir);
|
|
25098
|
-
}
|
|
25099
|
-
});
|
|
25100
|
-
return backfilled;
|
|
25101
|
-
}
|
|
25102
23669
|
function createChainedSubsystem(subsystem, projectName) {
|
|
25103
23670
|
if (!subsystem.projectPath || subsystem.projectPath.trim() === "") {
|
|
25104
23671
|
throw new WaironError("projectPath is required to create a chained subsystem.");
|
|
@@ -25127,14 +23694,14 @@ function moveSubsystemProject(subsystemId, newProjectPath) {
|
|
|
25127
23694
|
const oldDir = assertContainedProjectPath(root, sub.projectPath);
|
|
25128
23695
|
const newDir = assertContainedProjectPath(root, nextPath);
|
|
25129
23696
|
if (oldDir !== newDir) {
|
|
25130
|
-
if (!
|
|
23697
|
+
if (!fs13.existsSync(oldDir)) {
|
|
25131
23698
|
throw new WaironError(`Subproject directory not found at its current path: ${oldDir}`);
|
|
25132
23699
|
}
|
|
25133
|
-
if (
|
|
23700
|
+
if (fs13.existsSync(newDir)) {
|
|
25134
23701
|
throw new WaironError(`Target directory already exists: ${newDir}`);
|
|
25135
23702
|
}
|
|
25136
|
-
ensureDir(
|
|
25137
|
-
|
|
23703
|
+
ensureDir(path17.dirname(newDir));
|
|
23704
|
+
fs13.renameSync(oldDir, newDir);
|
|
25138
23705
|
}
|
|
25139
23706
|
saveSubsystemSpec({ ...sub, projectPath: nextPath, updatedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
25140
23707
|
invalidateSpecCache();
|
|
@@ -25143,9 +23710,9 @@ function toPosixPath(p) {
|
|
|
25143
23710
|
return p.replace(/\\/g, "/");
|
|
25144
23711
|
}
|
|
25145
23712
|
function isWithinDir(dir, file) {
|
|
25146
|
-
const d =
|
|
25147
|
-
const f =
|
|
25148
|
-
return f === d || f.startsWith(d +
|
|
23713
|
+
const d = path17.resolve(dir);
|
|
23714
|
+
const f = path17.resolve(file);
|
|
23715
|
+
return f === d || f.startsWith(d + path17.sep);
|
|
25149
23716
|
}
|
|
25150
23717
|
function externalizeSubsystem(subsystemId, projectPath) {
|
|
25151
23718
|
if (subsystemId.includes("::")) {
|
|
@@ -25157,14 +23724,14 @@ function externalizeSubsystem(subsystemId, projectPath) {
|
|
|
25157
23724
|
}
|
|
25158
23725
|
const parentRoot = getProjectRoot();
|
|
25159
23726
|
const parentSpecsDir = aiPathsAt(parentRoot).specsDir();
|
|
25160
|
-
const fooDir =
|
|
25161
|
-
if (!
|
|
23727
|
+
const fooDir = path17.join(parentSpecsDir, subsystemId);
|
|
23728
|
+
if (!fs13.existsSync(fooDir)) {
|
|
25162
23729
|
throw new WaironError(`subsystem specs directory not found: ${fooDir}`);
|
|
25163
23730
|
}
|
|
25164
23731
|
const relPath = toPosixPath(projectPath);
|
|
25165
23732
|
const childDir = assertContainedProjectPath(parentRoot, relPath);
|
|
25166
|
-
const childFooDir =
|
|
25167
|
-
if (
|
|
23733
|
+
const childFooDir = path17.join(childDir, ".wai", "specs", subsystemId);
|
|
23734
|
+
if (fs13.existsSync(childFooDir)) {
|
|
25168
23735
|
throw new WaironError(`target already contains a "${subsystemId}" subsystem: ${childFooDir}`);
|
|
25169
23736
|
}
|
|
25170
23737
|
const renameMap = buildRenameMap(
|
|
@@ -25176,18 +23743,18 @@ function externalizeSubsystem(subsystemId, projectPath) {
|
|
|
25176
23743
|
runWithProjectRoot(childDir, () => {
|
|
25177
23744
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
25178
23745
|
projectConfigRepository.create(defaultProjectConfig(childSystemName, now));
|
|
25179
|
-
ensureDir(
|
|
23746
|
+
ensureDir(path17.join(childDir, ".wai", "specs"));
|
|
25180
23747
|
saveSystemSpec(bootstrapSystemSpec(childSystemName, now));
|
|
25181
23748
|
});
|
|
25182
|
-
ensureDir(
|
|
25183
|
-
|
|
23749
|
+
ensureDir(path17.dirname(childFooDir));
|
|
23750
|
+
fs13.renameSync(fooDir, childFooDir);
|
|
25184
23751
|
rebaseImplementationPaths(childFooDir, parentRoot, childDir);
|
|
25185
|
-
patchSubsystemIndex(
|
|
23752
|
+
patchSubsystemIndex(path17.join(childFooDir, ".index.yaml"), (s) => {
|
|
25186
23753
|
s.parentSystem = childSystemName;
|
|
25187
23754
|
delete s.projectPath;
|
|
25188
23755
|
});
|
|
25189
23756
|
ensureDir(fooDir);
|
|
25190
|
-
writeYamlFile(
|
|
23757
|
+
writeYamlFile(path17.join(fooDir, ".index.yaml"), {
|
|
25191
23758
|
id: subsystemId,
|
|
25192
23759
|
name: foo.name,
|
|
25193
23760
|
description: foo.description,
|
|
@@ -25214,9 +23781,9 @@ function internalizeSubsystem(subsystemId) {
|
|
|
25214
23781
|
const parentRoot = getProjectRoot();
|
|
25215
23782
|
const parentSpecsDir = aiPathsAt(parentRoot).specsDir();
|
|
25216
23783
|
const childDir = assertContainedProjectPath(parentRoot, foo.projectPath);
|
|
25217
|
-
const childWai =
|
|
25218
|
-
const childFooDir =
|
|
25219
|
-
if (!
|
|
23784
|
+
const childWai = path17.join(childDir, ".wai");
|
|
23785
|
+
const childFooDir = path17.join(childDir, ".wai", "specs", subsystemId);
|
|
23786
|
+
if (!fs13.existsSync(childFooDir)) {
|
|
25220
23787
|
throw new WaironError(`external subproject missing subsystem "${subsystemId}": ${childFooDir}`);
|
|
25221
23788
|
}
|
|
25222
23789
|
const childOwnSubs = runWithProjectRoot(childDir, () => loadSubsystemSpecs()).filter((s) => !s.id.includes("::"));
|
|
@@ -25229,16 +23796,16 @@ function internalizeSubsystem(subsystemId) {
|
|
|
25229
23796
|
false
|
|
25230
23797
|
);
|
|
25231
23798
|
const parentSystemName = loadSystemSpec()?.name ?? foo.parentSystem;
|
|
25232
|
-
const fooDir =
|
|
25233
|
-
|
|
25234
|
-
ensureDir(
|
|
25235
|
-
|
|
23799
|
+
const fooDir = path17.join(parentSpecsDir, subsystemId);
|
|
23800
|
+
fs13.rmSync(fooDir, { recursive: true, force: true });
|
|
23801
|
+
ensureDir(path17.dirname(fooDir));
|
|
23802
|
+
fs13.renameSync(childFooDir, fooDir);
|
|
25236
23803
|
rebaseImplementationPaths(fooDir, childDir, parentRoot);
|
|
25237
|
-
patchSubsystemIndex(
|
|
23804
|
+
patchSubsystemIndex(path17.join(fooDir, ".index.yaml"), (s) => {
|
|
25238
23805
|
s.parentSystem = parentSystemName;
|
|
25239
23806
|
delete s.projectPath;
|
|
25240
23807
|
});
|
|
25241
|
-
|
|
23808
|
+
fs13.rmSync(childWai, { recursive: true, force: true });
|
|
25242
23809
|
rewriteRefsInDir(parentSpecsDir, renameMap, fooDir);
|
|
25243
23810
|
rebaseMovedRefs(fooDir, subsystemId, "outOf");
|
|
25244
23811
|
invalidateSpecCache();
|
|
@@ -25316,8 +23883,8 @@ function rebaseImplementationPaths(specsDir, fromRoot, toRoot) {
|
|
|
25316
23883
|
let changed = false;
|
|
25317
23884
|
const rebase = (holder, key) => {
|
|
25318
23885
|
const p = holder[key];
|
|
25319
|
-
if (typeof p !== "string" || p === "" ||
|
|
25320
|
-
const next = toPosixPath(
|
|
23886
|
+
if (typeof p !== "string" || p === "" || path17.isAbsolute(p)) return;
|
|
23887
|
+
const next = toPosixPath(path17.relative(toRoot, path17.resolve(fromRoot, p)));
|
|
25321
23888
|
if (next !== p) {
|
|
25322
23889
|
holder[key] = next;
|
|
25323
23890
|
changed = true;
|
|
@@ -25333,7 +23900,7 @@ function rebaseImplementationPaths(specsDir, fromRoot, toRoot) {
|
|
|
25333
23900
|
}
|
|
25334
23901
|
}
|
|
25335
23902
|
function patchSubsystemIndex(indexPath, mutate) {
|
|
25336
|
-
if (!
|
|
23903
|
+
if (!fs13.existsSync(indexPath)) return;
|
|
25337
23904
|
const raw = readYamlFile(indexPath);
|
|
25338
23905
|
mutate(raw);
|
|
25339
23906
|
raw.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -25394,8 +23961,8 @@ function moveRenamedSpecs(componentId, newId, component, movingInterface, moving
|
|
|
25394
23961
|
if (movedInterface) saveInterfaceSpec({ ...movedInterface, id: interfaceId, component: newId });
|
|
25395
23962
|
if (movedImplementation) {
|
|
25396
23963
|
const oldFile = getImplementationPath(movedImplementation.id);
|
|
25397
|
-
if (
|
|
25398
|
-
|
|
23964
|
+
if (path17.resolve(getImplementationPath(implementationId, movedImplementation.contract)) === path17.resolve(oldFile)) {
|
|
23965
|
+
fs13.unlinkSync(oldFile);
|
|
25399
23966
|
}
|
|
25400
23967
|
saveImplementationSpec({ ...movedImplementation, id: implementationId });
|
|
25401
23968
|
}
|
|
@@ -25405,17 +23972,17 @@ function moveRenamedSpecs(componentId, newId, component, movingInterface, moving
|
|
|
25405
23972
|
invalidateSpecCache();
|
|
25406
23973
|
}
|
|
25407
23974
|
function removeSpecFile2(file, id) {
|
|
25408
|
-
if (!
|
|
23975
|
+
if (!fs13.existsSync(file)) return;
|
|
25409
23976
|
try {
|
|
25410
23977
|
if (readYamlFile(file)?.id !== id) return;
|
|
25411
23978
|
} catch {
|
|
25412
23979
|
return;
|
|
25413
23980
|
}
|
|
25414
|
-
|
|
25415
|
-
const specsRoot =
|
|
25416
|
-
for (let dir =
|
|
25417
|
-
if (
|
|
25418
|
-
|
|
23981
|
+
fs13.unlinkSync(file);
|
|
23982
|
+
const specsRoot = path17.resolve(aiPathsAt(getProjectRoot()).specsDir());
|
|
23983
|
+
for (let dir = path17.dirname(path17.resolve(file)); dir !== specsRoot && isWithinDir(specsRoot, dir); dir = path17.dirname(dir)) {
|
|
23984
|
+
if (fs13.readdirSync(dir).length > 0) break;
|
|
23985
|
+
fs13.rmdirSync(dir);
|
|
25419
23986
|
}
|
|
25420
23987
|
}
|
|
25421
23988
|
var METHOD_NAME = /^[a-z][a-zA-Z0-9]*$/;
|
|
@@ -25525,10 +24092,208 @@ function identifierPattern(methodName) {
|
|
|
25525
24092
|
return new RegExp(`(?<![A-Za-z0-9_])${methodName}(?![A-Za-z0-9_])`);
|
|
25526
24093
|
}
|
|
25527
24094
|
|
|
24095
|
+
// src/core/detection.ts
|
|
24096
|
+
var fs14 = __toESM(require("fs"));
|
|
24097
|
+
var path18 = __toESM(require("path"));
|
|
24098
|
+
var PACKAGE_MARKERS = [
|
|
24099
|
+
"package.json",
|
|
24100
|
+
"pyproject.toml",
|
|
24101
|
+
"Cargo.toml",
|
|
24102
|
+
"go.mod",
|
|
24103
|
+
"build.gradle",
|
|
24104
|
+
"build.gradle.kts",
|
|
24105
|
+
"pom.xml"
|
|
24106
|
+
];
|
|
24107
|
+
var MAX_SCAN_DEPTH = 5;
|
|
24108
|
+
function detectDomainCandidates(projectRoot, alreadyTrackedPaths = /* @__PURE__ */ new Set(), alreadyTrackedIds = /* @__PURE__ */ new Set()) {
|
|
24109
|
+
const candidates = /* @__PURE__ */ new Map();
|
|
24110
|
+
for (const c of detectGitSubmodules(projectRoot)) {
|
|
24111
|
+
candidates.set(c.path, { ...c, alreadyTracked: alreadyTrackedPaths.has(c.path) });
|
|
24112
|
+
}
|
|
24113
|
+
for (const c of detectNestedGitRepos(projectRoot)) {
|
|
24114
|
+
if (!candidates.has(c.path)) {
|
|
24115
|
+
candidates.set(c.path, { ...c, alreadyTracked: alreadyTrackedPaths.has(c.path) });
|
|
24116
|
+
}
|
|
24117
|
+
}
|
|
24118
|
+
const gitPaths = new Set(
|
|
24119
|
+
Array.from(candidates.values()).filter((c) => c.type === "git-submodule" || c.type === "git-repo").map((c) => c.path)
|
|
24120
|
+
);
|
|
24121
|
+
for (const c of detectPackageRoots(projectRoot)) {
|
|
24122
|
+
if (candidates.has(c.path)) continue;
|
|
24123
|
+
const insideGit = Array.from(gitPaths).some(
|
|
24124
|
+
(gp) => c.path === gp || c.path.startsWith(gp + "/")
|
|
24125
|
+
);
|
|
24126
|
+
if (insideGit) continue;
|
|
24127
|
+
candidates.set(c.path, { ...c, alreadyTracked: alreadyTrackedPaths.has(c.path) });
|
|
24128
|
+
}
|
|
24129
|
+
const sorted = Array.from(candidates.values()).sort((a, b) => a.path.localeCompare(b.path));
|
|
24130
|
+
return deduplicateIds(sorted, alreadyTrackedIds);
|
|
24131
|
+
}
|
|
24132
|
+
function deduplicateIds(candidates, existingIds = /* @__PURE__ */ new Set()) {
|
|
24133
|
+
const idCount = /* @__PURE__ */ new Map();
|
|
24134
|
+
for (const id of existingIds) {
|
|
24135
|
+
idCount.set(id, (idCount.get(id) ?? 0) + 1);
|
|
24136
|
+
}
|
|
24137
|
+
for (const c of candidates) {
|
|
24138
|
+
idCount.set(c.suggestedId, (idCount.get(c.suggestedId) ?? 0) + 1);
|
|
24139
|
+
}
|
|
24140
|
+
return candidates.map((c) => {
|
|
24141
|
+
if ((idCount.get(c.suggestedId) ?? 0) <= 1) return c;
|
|
24142
|
+
const parts = c.path.split("/");
|
|
24143
|
+
const qualifiedId = parts.length >= 2 ? pathToId(`${parts[parts.length - 2]}-${parts[parts.length - 1]}`) : c.suggestedId;
|
|
24144
|
+
return { ...c, suggestedId: qualifiedId };
|
|
24145
|
+
});
|
|
24146
|
+
}
|
|
24147
|
+
function parseGitmodules(filePath) {
|
|
24148
|
+
const content = fs14.readFileSync(filePath, "utf-8");
|
|
24149
|
+
const entries = [];
|
|
24150
|
+
let current2 = {};
|
|
24151
|
+
for (const line of content.split("\n")) {
|
|
24152
|
+
const trimmed = line.trim();
|
|
24153
|
+
const headerMatch = trimmed.match(/^\[submodule "(.+)"\]$/);
|
|
24154
|
+
if (headerMatch) {
|
|
24155
|
+
if (current2.path) entries.push(current2);
|
|
24156
|
+
current2 = { name: headerMatch[1] };
|
|
24157
|
+
continue;
|
|
24158
|
+
}
|
|
24159
|
+
const keyVal = trimmed.match(/^(\w+)\s*=\s*(.+)$/);
|
|
24160
|
+
if (keyVal) {
|
|
24161
|
+
const [, key, value] = keyVal;
|
|
24162
|
+
if (key === "path") current2.path = value.trim();
|
|
24163
|
+
if (key === "url") current2.url = value.trim();
|
|
24164
|
+
}
|
|
24165
|
+
}
|
|
24166
|
+
if (current2.path) entries.push(current2);
|
|
24167
|
+
return entries;
|
|
24168
|
+
}
|
|
24169
|
+
function detectGitSubmodules(projectRoot) {
|
|
24170
|
+
const gitmodulesPath = path18.join(projectRoot, ".gitmodules");
|
|
24171
|
+
if (!fs14.existsSync(gitmodulesPath)) return [];
|
|
24172
|
+
return parseGitmodules(gitmodulesPath).map((entry) => ({
|
|
24173
|
+
suggestedId: pathToId(entry.path),
|
|
24174
|
+
suggestedName: pathToName(entry.path),
|
|
24175
|
+
path: normalizePath(entry.path),
|
|
24176
|
+
type: "git-submodule",
|
|
24177
|
+
alreadyTracked: false
|
|
24178
|
+
}));
|
|
24179
|
+
}
|
|
24180
|
+
function detectNestedGitRepos(projectRoot) {
|
|
24181
|
+
const results = [];
|
|
24182
|
+
walkForGit(projectRoot, projectRoot, 0, results);
|
|
24183
|
+
return results;
|
|
24184
|
+
}
|
|
24185
|
+
function walkForGit(projectRoot, currentDir, depth, results) {
|
|
24186
|
+
if (depth > MAX_SCAN_DEPTH) return;
|
|
24187
|
+
let entries;
|
|
24188
|
+
try {
|
|
24189
|
+
entries = fs14.readdirSync(currentDir, { withFileTypes: true });
|
|
24190
|
+
} catch {
|
|
24191
|
+
return;
|
|
24192
|
+
}
|
|
24193
|
+
for (const entry of entries) {
|
|
24194
|
+
if (!entry.isDirectory()) continue;
|
|
24195
|
+
if (SCAN_EXCLUDE_DIRS.has(entry.name)) continue;
|
|
24196
|
+
const fullPath = path18.join(currentDir, entry.name);
|
|
24197
|
+
const relPath = normalizePath(path18.relative(projectRoot, fullPath));
|
|
24198
|
+
if (relPath === "" || relPath === ".") continue;
|
|
24199
|
+
const gitPath = path18.join(fullPath, ".git");
|
|
24200
|
+
if (fs14.existsSync(gitPath)) {
|
|
24201
|
+
results.push({
|
|
24202
|
+
suggestedId: pathToId(relPath),
|
|
24203
|
+
suggestedName: pathToName(relPath),
|
|
24204
|
+
path: relPath,
|
|
24205
|
+
type: "git-repo",
|
|
24206
|
+
alreadyTracked: false
|
|
24207
|
+
});
|
|
24208
|
+
continue;
|
|
24209
|
+
}
|
|
24210
|
+
walkForGit(projectRoot, fullPath, depth + 1, results);
|
|
24211
|
+
}
|
|
24212
|
+
}
|
|
24213
|
+
function detectPackageRoots(projectRoot) {
|
|
24214
|
+
const results = [];
|
|
24215
|
+
walkForPackages(projectRoot, projectRoot, 0, results);
|
|
24216
|
+
return results;
|
|
24217
|
+
}
|
|
24218
|
+
function walkForPackages(projectRoot, currentDir, depth, results) {
|
|
24219
|
+
if (depth > MAX_SCAN_DEPTH) return;
|
|
24220
|
+
let entries;
|
|
24221
|
+
try {
|
|
24222
|
+
entries = fs14.readdirSync(currentDir, { withFileTypes: true });
|
|
24223
|
+
} catch {
|
|
24224
|
+
return;
|
|
24225
|
+
}
|
|
24226
|
+
for (const entry of entries) {
|
|
24227
|
+
if (!entry.isDirectory()) continue;
|
|
24228
|
+
if (SCAN_EXCLUDE_DIRS.has(entry.name)) continue;
|
|
24229
|
+
const fullPath = path18.join(currentDir, entry.name);
|
|
24230
|
+
const relPath = normalizePath(path18.relative(projectRoot, fullPath));
|
|
24231
|
+
if (relPath === "" || relPath === ".") continue;
|
|
24232
|
+
const hasMarker = PACKAGE_MARKERS.some((m) => fs14.existsSync(path18.join(fullPath, m)));
|
|
24233
|
+
if (hasMarker) {
|
|
24234
|
+
results.push({
|
|
24235
|
+
suggestedId: pathToId(relPath),
|
|
24236
|
+
suggestedName: pathToName(relPath),
|
|
24237
|
+
path: relPath,
|
|
24238
|
+
type: "package-root",
|
|
24239
|
+
alreadyTracked: false
|
|
24240
|
+
});
|
|
24241
|
+
}
|
|
24242
|
+
walkForPackages(projectRoot, fullPath, depth + 1, results);
|
|
24243
|
+
}
|
|
24244
|
+
}
|
|
24245
|
+
function pathToId(relPath) {
|
|
24246
|
+
const basename11 = path18.basename(relPath);
|
|
24247
|
+
return basename11.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
24248
|
+
}
|
|
24249
|
+
function pathToName(relPath) {
|
|
24250
|
+
const id = pathToId(relPath);
|
|
24251
|
+
return id.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
24252
|
+
}
|
|
24253
|
+
function normalizePath(p) {
|
|
24254
|
+
return p.replace(/\\/g, "/");
|
|
24255
|
+
}
|
|
24256
|
+
|
|
25528
24257
|
// src/core/agent_resolver.ts
|
|
25529
24258
|
var path20 = __toESM(require("path"));
|
|
25530
24259
|
var fs15 = __toESM(require("fs"));
|
|
25531
24260
|
|
|
24261
|
+
// src/core/templates.ts
|
|
24262
|
+
var path19 = __toESM(require("path"));
|
|
24263
|
+
function builtinTemplatesDir() {
|
|
24264
|
+
return path19.resolve(__dirname, "..", "templates");
|
|
24265
|
+
}
|
|
24266
|
+
function loadTemplate(id, globalOverride) {
|
|
24267
|
+
const dirs = templateSearchDirs(globalOverride);
|
|
24268
|
+
for (const dir of dirs) {
|
|
24269
|
+
const filePath = path19.join(dir, `${id}.yaml`);
|
|
24270
|
+
if (pathExists(filePath)) {
|
|
24271
|
+
const raw = readYamlFile(filePath);
|
|
24272
|
+
return { ...TemplateSchema.parse(raw), templateName: id };
|
|
24273
|
+
}
|
|
24274
|
+
}
|
|
24275
|
+
throw new TemplateNotFoundError(id);
|
|
24276
|
+
}
|
|
24277
|
+
function loadAgentOverride(agentId) {
|
|
24278
|
+
const filePath = path19.join(AI_PATHS.root(), "agents", `${agentId}.md`);
|
|
24279
|
+
return readFileOrNull(filePath);
|
|
24280
|
+
}
|
|
24281
|
+
function templateSearchDirs(globalOverride) {
|
|
24282
|
+
return [
|
|
24283
|
+
AI_PATHS.templatesDir(),
|
|
24284
|
+
// 1. project-local
|
|
24285
|
+
globalTemplatesDir(globalOverride),
|
|
24286
|
+
// 2. global user/org
|
|
24287
|
+
builtinTemplatesDir()
|
|
24288
|
+
// 3. built-in fallback
|
|
24289
|
+
];
|
|
24290
|
+
}
|
|
24291
|
+
function renderTemplateInstructions(template, vars) {
|
|
24292
|
+
return template.instructions.replace(/\{\{(\w+)\}\}/g, (_match, key) => {
|
|
24293
|
+
return key in vars ? vars[key] : `{{${key}}}`;
|
|
24294
|
+
});
|
|
24295
|
+
}
|
|
24296
|
+
|
|
25532
24297
|
// src/core/execution_profile.ts
|
|
25533
24298
|
var MECHANICAL_STEREOTYPES = /* @__PURE__ */ new Set(["store", "index", "registry", "adapter"]);
|
|
25534
24299
|
var DEEP_STEREOTYPES = /* @__PURE__ */ new Set(["orchestrator", "supervisor", "specialist"]);
|
|
@@ -26040,609 +24805,228 @@ function loadRegistry() {
|
|
|
26040
24805
|
};
|
|
26041
24806
|
}
|
|
26042
24807
|
|
|
26043
|
-
// src/
|
|
26044
|
-
var
|
|
26045
|
-
var fs16 = __toESM(require("fs"));
|
|
24808
|
+
// src/exporters/generate.ts
|
|
24809
|
+
var path24 = __toESM(require("path"));
|
|
26046
24810
|
|
|
26047
|
-
// src/
|
|
26048
|
-
|
|
26049
|
-
|
|
26050
|
-
|
|
26051
|
-
|
|
26052
|
-
|
|
26053
|
-
|
|
26054
|
-
}
|
|
26055
|
-
|
|
26056
|
-
|
|
26057
|
-
|
|
26058
|
-
|
|
26059
|
-
|
|
26060
|
-
|
|
26061
|
-
|
|
26062
|
-
|
|
26063
|
-
|
|
26064
|
-
|
|
26065
|
-
|
|
26066
|
-
|
|
26067
|
-
and machine-checked. Author it ONLY through this server's \`sdd_*\` tools \u2014 never by
|
|
26068
|
-
writing spec files directly, and never via the \`wairon\` CLI (that is the human
|
|
26069
|
-
developer's tool).
|
|
26070
|
-
|
|
26071
|
-
## The tree: L0 \u2192 L5
|
|
26072
|
-
|
|
26073
|
-
- **L0 System** \u2014 vision, boundaries, global requirements, target language.
|
|
26074
|
-
- **L1 Subsystem** \u2014 an isolated service, its \`publicInterfaces\`, its trusted links.
|
|
26075
|
-
- **L2 Component** \u2014 ONE building block (\`Portal\`, \`Orchestrator\`, \`Supervisor\`,
|
|
26076
|
-
\`Actor\`, \`Store\`, \`Index\`, \`Query\`, \`Registry\`, \`Adapter\`, \`Observer\`, and
|
|
26077
|
-
\`View\` for UIs) or pattern (\`Repository\`, and \`FeatureComponent\` or
|
|
26078
|
-
\`RouterComponent\` for UIs), plus \`owns\` (a pattern's private members) and
|
|
26079
|
-
\`dependsOn\` (collaborators). Logic is an \`Orchestrator\` whose \`dependencyClass\`
|
|
26080
|
-
(\`pure\` or \`read\`; unset, a workflow) bounds what it may depend on; a gateway is
|
|
26081
|
-
a \`Portal\` with the \`gateway\` variant. \`Specialist\` and \`Gateway\` are retired.
|
|
26082
|
-
- **L3 Interface** \u2014 the contract: method signatures with structured \`params\`,
|
|
26083
|
-
plus wire \`endpoint\` bindings for a Portal's methods.
|
|
26084
|
-
- **L4 Implementation** \u2014 a concrete realization of one L3 contract: narrative
|
|
26085
|
-
detail level, bound \`technologies\` (the vendor swap seam), optional \`sourcePath\`.
|
|
26086
|
-
- **L5 Narrative** \u2014 each method's logic as a FLAT numbered step list; \`call\` steps
|
|
26087
|
-
resolve to real dependency methods, and flow steps jump by step number.
|
|
26088
|
-
|
|
26089
|
-
These stereotypes are not labels \u2014 they carry enforced dependency rules (e.g. a
|
|
26090
|
-
Portal may not depend on a Store; state lives in a Store, never as fields inside
|
|
26091
|
-
an Orchestrator). \`sdd_validate_tree\` is the gate, and it is the authority on
|
|
26092
|
-
whether a design is legal.
|
|
26093
|
-
|
|
26094
|
-
## Authoring order
|
|
26095
|
-
|
|
26096
|
-
1. \`sdd_initialize_system\` (L0), then \`sdd_add_subsystem\` (L1).
|
|
26097
|
-
2. Then, **one subsystem at a time**: \`sdd_add_component\` (L2) \u2192 \`sdd_define_interface\`
|
|
26098
|
-
(L3) \u2192 \`sdd_set_endpoints\` for Portals \u2192 \`sdd_write_narrative\` (L4+L5).
|
|
26099
|
-
3. Run \`sdd_validate_tree\` as you go \u2014 early and per subsystem, not once at the end.
|
|
26100
|
-
\`sdd_get_status\` reports completeness; \`sdd_get_spec\` reads any spec back as JSON.
|
|
26101
|
-
4. Edit granularly with \`sdd_update_spec\` (it renumbers narrative steps and
|
|
26102
|
-
relocates jump targets for you).
|
|
26103
|
-
|
|
26104
|
-
## The tool schemas are the field reference
|
|
26105
|
-
|
|
26106
|
-
Every \`sdd_*\` tool's input schema is self-describing and authoritative \u2014 read the
|
|
26107
|
-
schema rather than guessing field names, and prefer structured \`params\` over prose
|
|
26108
|
-
signatures. Specs are ${profile === null ? "validated against the project's configured profile" : `governed by the **\`${profile}\`** profile`}, which decides which stereotypes are legal
|
|
26109
|
-
here, which narrative flow constructs the target language supports, and which
|
|
26110
|
-
extra rules apply. A subsystem may override the profile for itself.
|
|
26111
|
-
|
|
26112
|
-
## Loaded extension packs
|
|
26113
|
-
|
|
26114
|
-
${packNames.length === 0 ? "None \u2014 only wairon's built-in doctrine applies." : `${packNames.map((n) => `\`${n}\``).join(", ")} \u2014 these inject profiles, language tables, patterns, and
|
|
26115
|
-
additional conformance rules. Their doctrine is enforced by the same gate.`}
|
|
26116
|
-
|
|
26117
|
-
${variants.length === 0 ? "" : `## Component variants in play
|
|
26118
|
-
|
|
26119
|
-
This project defines variants \u2014 named, base-anchored kinds carrying implementation
|
|
26120
|
-
guidance, so every component of the same kind is built alike: ${variants.map((v) => `\`${v.id}\` (a kind of ${v.base})`).join(", ")}.
|
|
26121
|
-
Tag a component with \`variant\` where it fits, and read a component's resolved
|
|
26122
|
-
guidance and its same-variant siblings from \`sdd_get_spec\` (kind: component).
|
|
26123
|
-
|
|
26124
|
-
`}## Read the skills BEFORE authoring
|
|
26125
|
-
|
|
26126
|
-
This server publishes its skills as MCP resources. **Read \`wairon-skill://sdd-architect\`
|
|
26127
|
-
before you design anything**, and the others when their turn comes \u2014 they carry the
|
|
26128
|
-
architecture standard, the narrative step reference, and the review checklist that
|
|
26129
|
-
this briefing only points at:
|
|
26130
|
-
|
|
26131
|
-
${skillPointers(skills)}
|
|
26132
|
-
|
|
26133
|
-
## Delegating implementation
|
|
26134
|
-
|
|
26135
|
-
Delegate component work from a LIVE agent brief, never a generated file: discover
|
|
26136
|
-
agents via \`listAgents\` (or the \`wairon-agent://\` resources), fetch the target's
|
|
26137
|
-
brief with \`sdd_get_agent_brief\`, and spawn a scoped subagent from it \u2014 its
|
|
26138
|
-
\`instructions\` as prompt, its \`ownedPaths\` as write fence. Briefs are composed
|
|
26139
|
-
from the current spec tree on every call, so a re-lock never requires a session
|
|
26140
|
-
restart \u2014 fetch fresh per delegation. \`wairon-skill://sdd-delegate\` carries the
|
|
26141
|
-
full flow.`;
|
|
26142
|
-
}
|
|
26143
|
-
function buildServerInstructions() {
|
|
26144
|
-
const profile = governingProfile();
|
|
26145
|
-
let skills = [];
|
|
26146
|
-
let blocks = [];
|
|
26147
|
-
let packNames = [];
|
|
26148
|
-
const variants = [];
|
|
26149
|
-
try {
|
|
26150
|
-
skills = listSkillResources();
|
|
26151
|
-
const extensions = loadProjectExtensions2();
|
|
26152
|
-
blocks = extensions.instructions;
|
|
26153
|
-
packNames = extensions.packNames;
|
|
26154
|
-
} catch {
|
|
24811
|
+
// src/exporters/claude.ts
|
|
24812
|
+
var path21 = __toESM(require("path"));
|
|
24813
|
+
var MODEL_BY_TIER = {
|
|
24814
|
+
small: "haiku",
|
|
24815
|
+
standard: "sonnet",
|
|
24816
|
+
large: "opus",
|
|
24817
|
+
frontier: "fable"
|
|
24818
|
+
};
|
|
24819
|
+
var TOOLS_BY_CLASS = {
|
|
24820
|
+
"read-only": ["Read", "Grep", "Glob"],
|
|
24821
|
+
implement: ["Read", "Grep", "Glob", "Edit", "Write", "Bash"],
|
|
24822
|
+
orchestrate: ["Agent", "SendMessage", "TodoWrite"],
|
|
24823
|
+
// `full` means "inherit everything" — expressed by omitting the field.
|
|
24824
|
+
full: void 0
|
|
24825
|
+
};
|
|
24826
|
+
function toolsFor(budget) {
|
|
24827
|
+
const base = TOOLS_BY_CLASS[budget.toolClass];
|
|
24828
|
+
if (!base) return void 0;
|
|
24829
|
+
if (budget.allowNestedDelegation && !base.includes("Agent")) {
|
|
24830
|
+
return [...base, "Agent"];
|
|
26155
24831
|
}
|
|
26156
|
-
|
|
26157
|
-
|
|
26158
|
-
if (!blockApplies(block, profile)) continue;
|
|
26159
|
-
sections.push(`## From pack "${block.pack}"
|
|
26160
|
-
|
|
26161
|
-
${block.text.trim()}`);
|
|
24832
|
+
if (!budget.allowNestedDelegation) {
|
|
24833
|
+
return base.filter((t) => t !== "Agent");
|
|
26162
24834
|
}
|
|
26163
|
-
return
|
|
26164
|
-
}
|
|
26165
|
-
|
|
26166
|
-
// src/core/skills.ts
|
|
26167
|
-
var SKILL_NAMES = ["sdd-architect", "sdd-narrative", "sdd-auditor", "sdd-implement", "sdd-delegate"];
|
|
26168
|
-
function loadProjectExtensions2() {
|
|
26169
|
-
return loadProjectExtensions();
|
|
26170
|
-
}
|
|
26171
|
-
function loadProjectConfig3() {
|
|
26172
|
-
return loadProjectConfig();
|
|
26173
|
-
}
|
|
26174
|
-
function packSkillId(skill) {
|
|
26175
|
-
return `${packNamespace(skill.pack)}-${skill.id}`;
|
|
26176
|
-
}
|
|
26177
|
-
function packNamespace(pack) {
|
|
26178
|
-
return pack.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
24835
|
+
return base;
|
|
26179
24836
|
}
|
|
26180
|
-
function
|
|
26181
|
-
return
|
|
24837
|
+
function mcpServersFor(access) {
|
|
24838
|
+
return access === "none" ? "[]" : void 0;
|
|
26182
24839
|
}
|
|
26183
|
-
function
|
|
26184
|
-
|
|
26185
|
-
const base = fs16.existsSync(srcPath) ? fs16.readFileSync(srcPath, "utf-8") : "";
|
|
26186
|
-
const sections = extensionsFor(name, packSkills);
|
|
26187
|
-
if (sections.length === 0) return base;
|
|
26188
|
-
const parts = [base.trimEnd()];
|
|
26189
|
-
for (const section of sections) {
|
|
26190
|
-
const body = fs16.readFileSync(section.sourcePath, "utf-8").replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, "");
|
|
26191
|
-
parts.push(`## Platform: ${section.pack}`, body.trim());
|
|
26192
|
-
}
|
|
26193
|
-
return `${parts.join("\n\n")}
|
|
26194
|
-
`;
|
|
24840
|
+
function yamlScalar(value) {
|
|
24841
|
+
return /[:#\n]/.test(value) ? `"${value.replace(/"/g, '\\"')}"` : value;
|
|
26195
24842
|
}
|
|
26196
|
-
|
|
26197
|
-
|
|
26198
|
-
|
|
26199
|
-
|
|
26200
|
-
const m = new RegExp(`^${key}:\\s*(.*)$`, "m").exec(block);
|
|
26201
|
-
return m ? m[1].trim() : "";
|
|
26202
|
-
};
|
|
26203
|
-
return { name: field("name") || fallbackName, description: field("description") };
|
|
26204
|
-
}
|
|
26205
|
-
function builtinSkillsDir() {
|
|
26206
|
-
return path21.resolve(__dirname, "..", "templates", "skills");
|
|
26207
|
-
}
|
|
26208
|
-
function skillTemplatePath(name) {
|
|
26209
|
-
return path21.join(builtinSkillsDir(), `${name}.md`);
|
|
26210
|
-
}
|
|
26211
|
-
function skillDestPath(type, destDir, name) {
|
|
26212
|
-
if (type === "claude" || type === "codex" || type === "gemini" || type === "agy") {
|
|
26213
|
-
return path21.join(destDir, name, "SKILL.md");
|
|
26214
|
-
}
|
|
26215
|
-
return path21.join(destDir, `${name}.md`);
|
|
26216
|
-
}
|
|
26217
|
-
function skillsDirForTarget(type) {
|
|
26218
|
-
switch (type) {
|
|
26219
|
-
case "claude":
|
|
26220
|
-
return fromProjectRoot(".claude", "skills");
|
|
26221
|
-
case "gemini":
|
|
26222
|
-
// Gemini-based Antigravity
|
|
26223
|
-
case "agy":
|
|
26224
|
-
case "codex":
|
|
26225
|
-
return fromProjectRoot(".agents", "skills");
|
|
26226
|
-
case "cursor":
|
|
26227
|
-
return fromProjectRoot(".cursor", "skills");
|
|
26228
|
-
default:
|
|
26229
|
-
return null;
|
|
24843
|
+
var ClaudeExporter = class {
|
|
24844
|
+
constructor(options = {}) {
|
|
24845
|
+
this.options = options;
|
|
24846
|
+
this.targetType = "claude";
|
|
26230
24847
|
}
|
|
26231
|
-
|
|
26232
|
-
|
|
26233
|
-
|
|
26234
|
-
}
|
|
26235
|
-
function exportSddSkills(targetTypes) {
|
|
26236
|
-
const types = targetTypes ?? activeTargetTypes2();
|
|
26237
|
-
const destinations = [];
|
|
26238
|
-
const skipped = [];
|
|
26239
|
-
let fileCount = 0;
|
|
26240
|
-
const packSkills = loadProjectExtensions2().skills;
|
|
26241
|
-
for (const type of types) {
|
|
26242
|
-
const destDir = skillsDirForTarget(type);
|
|
26243
|
-
if (!destDir) {
|
|
26244
|
-
skipped.push(type);
|
|
26245
|
-
continue;
|
|
26246
|
-
}
|
|
26247
|
-
ensureDir(destDir);
|
|
26248
|
-
destinations.push(destDir);
|
|
26249
|
-
for (const name of SKILL_NAMES) {
|
|
26250
|
-
if (!fs16.existsSync(skillTemplatePath(name))) continue;
|
|
26251
|
-
const content = composeBuiltinSkill(name, packSkills.filter((s) => s.targets.includes(type)));
|
|
26252
|
-
const destPath = skillDestPath(type, destDir, name);
|
|
26253
|
-
ensureDir(path21.dirname(destPath));
|
|
26254
|
-
fs16.writeFileSync(destPath, content, "utf-8");
|
|
26255
|
-
fileCount++;
|
|
26256
|
-
}
|
|
26257
|
-
for (const skill of packSkills) {
|
|
26258
|
-
if (skill.extends !== void 0) continue;
|
|
26259
|
-
if (!skill.targets.includes(type)) continue;
|
|
26260
|
-
if (!fs16.existsSync(skill.sourcePath)) continue;
|
|
26261
|
-
const id = packSkillId(skill);
|
|
26262
|
-
const content = fs16.readFileSync(skill.sourcePath, "utf-8");
|
|
26263
|
-
const destPath = skillDestPath(type, destDir, id);
|
|
26264
|
-
ensureDir(path21.dirname(destPath));
|
|
26265
|
-
fs16.writeFileSync(destPath, content, "utf-8");
|
|
26266
|
-
fileCount++;
|
|
26267
|
-
}
|
|
26268
|
-
}
|
|
26269
|
-
return { destinations, fileCount, skipped };
|
|
26270
|
-
}
|
|
26271
|
-
function checkSkillFreshness(type) {
|
|
26272
|
-
const dir = skillsDirForTarget(type);
|
|
26273
|
-
const result = { dir, missing: [], stale: [], ok: [] };
|
|
26274
|
-
if (!dir) return result;
|
|
26275
|
-
const packSkills = loadProjectExtensions2().skills.filter((s) => s.targets.includes(type));
|
|
26276
|
-
for (const name of SKILL_NAMES) {
|
|
26277
|
-
const destPath = skillDestPath(type, dir, name);
|
|
26278
|
-
if (!fs16.existsSync(destPath)) {
|
|
26279
|
-
result.missing.push(name);
|
|
26280
|
-
continue;
|
|
26281
|
-
}
|
|
26282
|
-
const want = composeBuiltinSkill(name, packSkills);
|
|
26283
|
-
const have = fs16.readFileSync(destPath, "utf-8");
|
|
26284
|
-
if (have === want) result.ok.push(name);
|
|
26285
|
-
else result.stale.push(name);
|
|
24848
|
+
outputPath(ctx) {
|
|
24849
|
+
const { agent, target, projectRoot } = ctx;
|
|
24850
|
+
const outputDir = "outputDir" in target ? target.outputDir : ".claude/agents";
|
|
24851
|
+
return path21.resolve(projectRoot, outputDir, `${agent.id.replace(/::/g, "--")}.md`);
|
|
26286
24852
|
}
|
|
26287
|
-
|
|
26288
|
-
}
|
|
26289
|
-
|
|
26290
|
-
|
|
26291
|
-
|
|
26292
|
-
|
|
26293
|
-
|
|
26294
|
-
|
|
26295
|
-
|
|
26296
|
-
|
|
26297
|
-
|
|
26298
|
-
|
|
26299
|
-
|
|
24853
|
+
export(ctx) {
|
|
24854
|
+
const { agent, renderedInstructions, budget } = ctx;
|
|
24855
|
+
const filePath = this.outputPath(ctx);
|
|
24856
|
+
const frontmatter = [
|
|
24857
|
+
`name: ${agent.name}`,
|
|
24858
|
+
`description: ${yamlScalar(agent.description)}`
|
|
24859
|
+
];
|
|
24860
|
+
if (budget && this.options.emitBudget) {
|
|
24861
|
+
if (budget.modelTier) frontmatter.push(`model: ${MODEL_BY_TIER[budget.modelTier]}`);
|
|
24862
|
+
if (budget.effort) frontmatter.push(`effort: ${budget.effort}`);
|
|
24863
|
+
if (budget.maxTurns !== void 0) frontmatter.push(`maxTurns: ${budget.maxTurns}`);
|
|
24864
|
+
const tools = toolsFor(budget);
|
|
24865
|
+
if (tools) frontmatter.push(`tools: ${tools.join(", ")}`);
|
|
24866
|
+
const servers = mcpServersFor(budget.mcp);
|
|
24867
|
+
if (servers) frontmatter.push(`mcpServers: ${servers}`);
|
|
24868
|
+
}
|
|
24869
|
+
const content = ["---", ...frontmatter, "---", "", renderedInstructions, ""].join("\n");
|
|
24870
|
+
const changed = writeFileIfChanged(filePath, content);
|
|
24871
|
+
return { outputPath: filePath, content, unchanged: !changed };
|
|
26300
24872
|
}
|
|
26301
24873
|
};
|
|
26302
|
-
function readSkillFrontmatter(name) {
|
|
26303
|
-
return readFrontmatter(fs16.readFileSync(skillTemplatePath(name), "utf-8"), name);
|
|
26304
|
-
}
|
|
26305
|
-
function listSkillResources() {
|
|
26306
|
-
const builtin = RESOURCE_SKILL_IDS.map((id) => {
|
|
26307
|
-
const fm = readSkillFrontmatter(id);
|
|
26308
|
-
return {
|
|
26309
|
-
id,
|
|
26310
|
-
name: fm.name,
|
|
26311
|
-
description: fm.description,
|
|
26312
|
-
version: WAIRON_VERSION,
|
|
26313
|
-
resourceUri: `${SKILL_RESOURCE_SCHEME}://${id}`,
|
|
26314
|
-
defaultForHostedMcp: true
|
|
26315
|
-
};
|
|
26316
|
-
});
|
|
26317
|
-
const pack = loadProjectExtensions2().skills.filter((s) => s.extends === void 0 && fs16.existsSync(s.sourcePath)).map((skill) => {
|
|
26318
|
-
const id = packSkillId(skill);
|
|
26319
|
-
const fm = readFrontmatter(fs16.readFileSync(skill.sourcePath, "utf-8"), id);
|
|
26320
|
-
return {
|
|
26321
|
-
id,
|
|
26322
|
-
name: fm.name,
|
|
26323
|
-
description: fm.description,
|
|
26324
|
-
version: skill.packVersion ?? WAIRON_VERSION,
|
|
26325
|
-
resourceUri: `${SKILL_RESOURCE_SCHEME}://${id}`,
|
|
26326
|
-
defaultForHostedMcp: true
|
|
26327
|
-
};
|
|
26328
|
-
});
|
|
26329
|
-
return [...builtin, ...pack];
|
|
26330
|
-
}
|
|
26331
|
-
function readSkillResource(resourceId) {
|
|
26332
|
-
const packSkills = loadProjectExtensions2().skills;
|
|
26333
|
-
if (SKILL_NAMES.includes(resourceId)) return composeBuiltinSkill(resourceId, packSkills);
|
|
26334
|
-
const packSkill = packSkills.find((s) => s.extends === void 0 && packSkillId(s) === resourceId);
|
|
26335
|
-
if (packSkill) return fs16.readFileSync(packSkill.sourcePath, "utf-8");
|
|
26336
|
-
return fs16.readFileSync(skillTemplatePath(resourceId), "utf-8");
|
|
26337
|
-
}
|
|
26338
|
-
function listResources() {
|
|
26339
|
-
return listSkillResources();
|
|
26340
|
-
}
|
|
26341
|
-
function buildServerInstructions2() {
|
|
26342
|
-
return buildServerInstructions();
|
|
26343
|
-
}
|
|
26344
|
-
function readResource(resourceId) {
|
|
26345
|
-
const known = listSkillResources().some((d) => d.id === resourceId);
|
|
26346
|
-
if (!known) throw new SkillResourceNotFoundError(resourceId);
|
|
26347
|
-
return readSkillResource(resourceId);
|
|
26348
|
-
}
|
|
26349
24874
|
|
|
26350
|
-
// src/
|
|
26351
|
-
var fs17 = __toESM(require("fs"));
|
|
26352
|
-
var os4 = __toESM(require("os"));
|
|
24875
|
+
// src/exporters/custom.ts
|
|
26353
24876
|
var path22 = __toESM(require("path"));
|
|
24877
|
+
var CustomExporter = class {
|
|
24878
|
+
constructor() {
|
|
24879
|
+
this.targetType = "custom";
|
|
24880
|
+
}
|
|
24881
|
+
outputPath(ctx) {
|
|
24882
|
+
const { agent, target, projectRoot } = ctx;
|
|
24883
|
+
if (!("outputDir" in target)) {
|
|
24884
|
+
throw new Error("CustomExporter requires target.outputDir");
|
|
24885
|
+
}
|
|
24886
|
+
return path22.resolve(projectRoot, target.outputDir, `${agent.id.replace(/::/g, "--")}.md`);
|
|
24887
|
+
}
|
|
24888
|
+
export(ctx) {
|
|
24889
|
+
const { agent, target, renderedInstructions } = ctx;
|
|
24890
|
+
const label = "label" in target ? target.label : "Custom";
|
|
24891
|
+
const filePath = this.outputPath(ctx);
|
|
24892
|
+
const content = [
|
|
24893
|
+
"---",
|
|
24894
|
+
`name: ${agent.name}`,
|
|
24895
|
+
`description: ${agent.description}`,
|
|
24896
|
+
`id: ${agent.id}`,
|
|
24897
|
+
`target: ${label}`,
|
|
24898
|
+
"---",
|
|
24899
|
+
"",
|
|
24900
|
+
renderedInstructions,
|
|
24901
|
+
""
|
|
24902
|
+
].join("\n");
|
|
24903
|
+
const changed = writeFileIfChanged(filePath, content);
|
|
24904
|
+
return { outputPath: filePath, content, unchanged: !changed };
|
|
24905
|
+
}
|
|
24906
|
+
};
|
|
26354
24907
|
|
|
26355
|
-
// src/
|
|
26356
|
-
|
|
26357
|
-
|
|
26358
|
-
|
|
26359
|
-
|
|
26360
|
-
|
|
26361
|
-
|
|
26362
|
-
|
|
24908
|
+
// src/exporters/gemini.ts
|
|
24909
|
+
var path23 = __toESM(require("path"));
|
|
24910
|
+
var GeminiExporter = class {
|
|
24911
|
+
constructor() {
|
|
24912
|
+
this.targetType = "gemini";
|
|
24913
|
+
}
|
|
24914
|
+
outputPath(ctx) {
|
|
24915
|
+
const { agent, target, projectRoot } = ctx;
|
|
24916
|
+
const outputDir = "outputDir" in target ? target.outputDir : ".gemini/agents";
|
|
24917
|
+
return path23.resolve(projectRoot, outputDir, `${agent.id.replace(/::/g, "--")}.yaml`);
|
|
24918
|
+
}
|
|
24919
|
+
export(ctx) {
|
|
24920
|
+
const { agent, renderedInstructions } = ctx;
|
|
24921
|
+
const filePath = this.outputPath(ctx);
|
|
24922
|
+
const indentedInstructions = renderedInstructions.split("\n").map((line) => line.length > 0 ? ` ${line}` : "").join("\n");
|
|
24923
|
+
const content = [
|
|
24924
|
+
`name: ${yamlString(agent.name)}`,
|
|
24925
|
+
`description: ${yamlString(agent.description)}`,
|
|
24926
|
+
`system_prompt: |`,
|
|
24927
|
+
indentedInstructions,
|
|
24928
|
+
""
|
|
24929
|
+
].join("\n");
|
|
24930
|
+
const changed = writeFileIfChanged(filePath, content);
|
|
24931
|
+
return { outputPath: filePath, content, unchanged: !changed };
|
|
24932
|
+
}
|
|
24933
|
+
};
|
|
24934
|
+
function yamlString(value) {
|
|
24935
|
+
if (/[:#\[\]{},&*!|>'"%@`]/.test(value) || value.startsWith(" ") || value.endsWith(" ")) {
|
|
24936
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
24937
|
+
}
|
|
24938
|
+
return value;
|
|
26363
24939
|
}
|
|
26364
24940
|
|
|
26365
|
-
// src/
|
|
26366
|
-
var
|
|
26367
|
-
|
|
26368
|
-
|
|
26369
|
-
|
|
26370
|
-
|
|
26371
|
-
|
|
26372
|
-
|
|
26373
|
-
|
|
26374
|
-
|
|
26375
|
-
|
|
26376
|
-
|
|
26377
|
-
|
|
26378
|
-
|
|
26379
|
-
|
|
26380
|
-
|
|
26381
|
-
|
|
26382
|
-
|
|
26383
|
-
|
|
26384
|
-
|
|
26385
|
-
|
|
26386
|
-
|
|
26387
|
-
**Do NOT search files or read agent configs to learn about wairon or SDD. Use the context here and the \`sdd-architect\` skill to start.**
|
|
26388
|
-
|
|
26389
|
-
**Your first move: call the \`sdd_get_status\` MCP tool** (or \`wairon/sdd_get_status\`) to see the spec tree. Do not parse files or run CLI commands manually.
|
|
26390
|
-
|
|
26391
|
-
### How you operate
|
|
26392
|
-
- **To design/modify specs**: Use **\`sdd-architect\`** skill (in \`.claude/skills/\` or \`.gemini/skills/\`).
|
|
26393
|
-
- **Manage specs via MCP tools only**: Use \`sdd_initialize_system\`, \`sdd_add_subsystem\`, \`sdd_add_component\`, \`sdd_define_interface\`, \`sdd_write_narrative\`, \`sdd_add_type\`, \`sdd_get_spec\`, \`sdd_delete_spec\`, \`sdd_validate_tree\`, and \`sdd_get_status\` (namespaced if needed). Do not edit specs manually.
|
|
26394
|
-
- **Subprojects & Namespacing (Chaining)**: If a subsystem defines a \`projectPath\`, its entire \`.wai/\` spec tree is recursively loaded and namespaced with the subsystem ID as a prefix (using \`::\`, e.g. \`billing::invoice::invoice_portal\`). Use the qualified namespaced ID with the parent MCP tools; wairon will resolve the path and strip the prefix automatically.
|
|
26395
|
-
- **Leading \`::\`**: Bypasses the local subsystem prefix to resolve absolute from the system root (e.g. \`::shared::error-type\`).
|
|
26396
|
-
- **\`super::\`**: Goes up one parent subsystem level (e.g. \`super::sibling_comp\`, \`super::super::parent_sibling\`).
|
|
26397
|
-
- **Do not run the \`wairon\` CLI**: Use \`sdd_validate_tree\` and \`sdd_get_status\` instead of CLI commands.
|
|
26398
|
-
- **Handoff to implementation**: Once design is complete and validates cleanly, tell the human: *"The specs are complete and validate. Please run \`wairon lock\` to confirm and freeze them."* No session restart is needed after the lock \u2014 delegate implementation right away via the \`sdd-delegate\` skill.
|
|
26399
|
-
- **To implement code**: Delegate via the \`sdd-delegate\` skill: fetch the component's live brief with the \`sdd_get_agent_brief\` MCP tool (or the \`wairon-agent://\` resource) and spawn a subagent from it. Briefs are composed per call from the current spec tree, so they are always current \u2014 never wait for a restart. Implementations must match L3 interfaces and L5 narratives exactly. Generated agent files under \`.claude/agents/\` are an optional materialized view of the same topology \u2014 the live briefs are canonical.
|
|
24941
|
+
// src/exporters/registry.ts
|
|
24942
|
+
var EXPORTERS = /* @__PURE__ */ new Map([
|
|
24943
|
+
["claude", new ClaudeExporter({ emitBudget: true })],
|
|
24944
|
+
["gemini", new GeminiExporter()],
|
|
24945
|
+
["agy", new GeminiExporter()],
|
|
24946
|
+
["cursor", new ClaudeExporter()],
|
|
24947
|
+
["copilot", new ClaudeExporter()],
|
|
24948
|
+
["codex", new ClaudeExporter()],
|
|
24949
|
+
["custom", new CustomExporter()]
|
|
24950
|
+
]);
|
|
24951
|
+
function getExporter(target) {
|
|
24952
|
+
const type = typeof target === "string" ? target : target.type;
|
|
24953
|
+
const exporter = EXPORTERS.get(type);
|
|
24954
|
+
if (!exporter) {
|
|
24955
|
+
throw new WaironError(`No exporter registered for target type: "${type}"`);
|
|
24956
|
+
}
|
|
24957
|
+
return exporter;
|
|
24958
|
+
}
|
|
24959
|
+
function registerExporter(type, exporter) {
|
|
24960
|
+
EXPORTERS.set(type, exporter);
|
|
24961
|
+
}
|
|
26400
24962
|
|
|
26401
|
-
|
|
26402
|
-
|
|
26403
|
-
|
|
26404
|
-
3. **Spec consistency**: If a 1:1 narrative match is incorrect or conflicts with L0 requirements, escalate a spec revision first. Never ship mismatched code.
|
|
26405
|
-
4. **No persistence shortcuts & strict layers**: A Portal must never depend directly on a Store, Registry, or Adapter. Portal reads MAY go through a Repository/Index facade (passthrough reads need no per-entity Orchestrator ceremony), but a Portal narrative call or dispatch-table binding that reaches a write-effect facade method is an error (\`PORTAL_WRITE_SHORTCUT\`) \u2014 writes always route through an Orchestrator. Held domain state always lives in a dedicated data component, never as fields inside an Orchestrator. Two sanctioned shapes: the RECOMMENDED Repository pattern (owns Store + Registry + Index; consumers depend on the facade), or \u2014 for genuinely simple state \u2014 a deliberately standalone Store (workflow-layer consumers only, acknowledged with a lint.allow reason on the UNOWNED_STORE warning). Never combine Store/Registry/Index roles into one component, and never fold state into a consuming component because a link was refused.
|
|
24963
|
+
// src/exporters/base.ts
|
|
24964
|
+
var WAIRON_MANAGED_MARKER = "wairon:managed";
|
|
24965
|
+
var WAIRON_MANAGED_BANNER = `<!-- ${WAIRON_MANAGED_MARKER} \u2014 generated by \`wairon generate\`; do not edit, changes are overwritten -->`;
|
|
26406
24966
|
|
|
26407
|
-
|
|
26408
|
-
|
|
26409
|
-
|
|
26410
|
-
|
|
26411
|
-
|
|
26412
|
-
|
|
26413
|
-
|
|
26414
|
-
|
|
26415
|
-
|
|
24967
|
+
// src/exporters/generate.ts
|
|
24968
|
+
function generateAgent(agent, projectConfig, options = {}) {
|
|
24969
|
+
const projectRoot = options.projectRoot ?? getProjectRoot();
|
|
24970
|
+
const template = loadTemplate(agent.template, projectConfig.globalTemplatesDir);
|
|
24971
|
+
const rendered = `${WAIRON_MANAGED_BANNER}
|
|
24972
|
+
${composeAgentBrief(agent.id).instructions}`;
|
|
24973
|
+
const results = [];
|
|
24974
|
+
const budget = resolveBudget(
|
|
24975
|
+
deriveExecutionProfile(agent),
|
|
24976
|
+
projectConfig.execution,
|
|
24977
|
+
agent.id
|
|
24978
|
+
);
|
|
24979
|
+
for (const agentTarget of agent.targets) {
|
|
24980
|
+
const targetConfig = resolveTargetConfig(agentTarget, projectConfig);
|
|
24981
|
+
if (!targetConfig) continue;
|
|
24982
|
+
if (options.filterTargets) {
|
|
24983
|
+
const type = "type" in targetConfig ? targetConfig.type : targetConfig;
|
|
24984
|
+
if (!options.filterTargets.includes(type)) continue;
|
|
24985
|
+
}
|
|
24986
|
+
if (!options.dryRun) {
|
|
24987
|
+
results.push(getExporter(targetConfig).export({
|
|
24988
|
+
agent,
|
|
24989
|
+
template,
|
|
24990
|
+
renderedInstructions: rendered,
|
|
24991
|
+
projectRoot,
|
|
24992
|
+
target: targetConfig,
|
|
24993
|
+
budget
|
|
24994
|
+
}));
|
|
24995
|
+
}
|
|
24996
|
+
}
|
|
24997
|
+
return { agent, results };
|
|
26416
24998
|
}
|
|
26417
|
-
function
|
|
26418
|
-
|
|
26419
|
-
if (
|
|
26420
|
-
|
|
24999
|
+
function generateAll(agents, projectConfig, options = {}) {
|
|
25000
|
+
let pool = agents;
|
|
25001
|
+
if (options.filterDomainIds && options.filterDomainIds.length > 0) {
|
|
25002
|
+
const ids = new Set(options.filterDomainIds);
|
|
25003
|
+
pool = agents.filter((a) => ids.has(a.domainRoot ?? "root"));
|
|
25004
|
+
}
|
|
25005
|
+
return pool.map((agent) => generateAgent(agent, projectConfig, options));
|
|
26421
25006
|
}
|
|
26422
|
-
function
|
|
26423
|
-
const
|
|
26424
|
-
const
|
|
26425
|
-
|
|
26426
|
-
|
|
26427
|
-
|
|
26428
|
-
|
|
26429
|
-
|
|
26430
|
-
|
|
26431
|
-
|
|
26432
|
-
|
|
26433
|
-
const newContent = stripped.trimEnd() + section;
|
|
26434
|
-
fs17.mkdirSync(path22.dirname(filePath), { recursive: true });
|
|
26435
|
-
fs17.writeFileSync(filePath, newContent, "utf-8");
|
|
25007
|
+
function resolveExpectedOutputPaths(agents, projectConfig, projectRoot = getProjectRoot()) {
|
|
25008
|
+
const expected = /* @__PURE__ */ new Set();
|
|
25009
|
+
for (const agent of agents) {
|
|
25010
|
+
for (const agentTarget of agent.targets) {
|
|
25011
|
+
const targetConfig = resolveTargetConfig(agentTarget, projectConfig);
|
|
25012
|
+
if (!targetConfig) continue;
|
|
25013
|
+
const ctx = { agent, projectRoot, target: targetConfig };
|
|
25014
|
+
expected.add(path24.resolve(getExporter(targetConfig).outputPath(ctx)));
|
|
25015
|
+
}
|
|
25016
|
+
}
|
|
25017
|
+
return expected;
|
|
26436
25018
|
}
|
|
26437
|
-
function
|
|
26438
|
-
const
|
|
26439
|
-
|
|
26440
|
-
|
|
26441
|
-
|
|
26442
|
-
}
|
|
26443
|
-
function writeRootGuideDelegator(projectRoot, targetType) {
|
|
26444
|
-
if (targetType === "claude") {
|
|
26445
|
-
const filePath = path22.join(projectRoot, "CLAUDE.md");
|
|
26446
|
-
const content = `@.claude/CLAUDE.md
|
|
26447
|
-
|
|
26448
|
-
# Wairon SDD Project
|
|
26449
|
-
|
|
26450
|
-
This project uses the Wairon Spec-Driven Development (SDD) framework. The imported
|
|
26451
|
-
\`.claude/CLAUDE.md\` above is your complete operating guide \u2014 you already have the
|
|
26452
|
-
full context, so don't search the project to learn how wairon or SDD works.
|
|
26453
|
-
|
|
26454
|
-
To design or modify the system, invoke the **\`sdd-architect\`** skill
|
|
26455
|
-
(in \`.claude/skills/\`). Author and validate specs with the \`sdd_*\` MCP tools;
|
|
26456
|
-
the \`wairon\` CLI is the human developer's tool, not yours.
|
|
26457
|
-
`;
|
|
26458
|
-
fs17.writeFileSync(filePath, content, "utf-8");
|
|
26459
|
-
} else if (targetType === "gemini" || targetType === "agy") {
|
|
26460
|
-
const filePath = path22.join(projectRoot, "GEMINI.md");
|
|
26461
|
-
const content = `# Wairon SDD Project
|
|
26462
|
-
${GUIDE_MARKER_START}
|
|
26463
|
-
${versionStamp()}
|
|
26464
|
-
${LOCAL_GUIDE_BODY}
|
|
26465
|
-
${GUIDE_MARKER_END}
|
|
26466
|
-
`;
|
|
26467
|
-
fs17.writeFileSync(filePath, content, "utf-8");
|
|
26468
|
-
} else if (targetType === "cursor") {
|
|
26469
|
-
const filePath = path22.join(projectRoot, ".cursorrules");
|
|
26470
|
-
const content = `# Wairon SDD Project
|
|
26471
|
-
|
|
26472
|
-
This project uses the Wairon Spec-Driven Development (SDD) framework.
|
|
26473
|
-
|
|
26474
|
-
Refer to the rules in [.cursor/rules/](.cursor/rules/) for full instructions.
|
|
26475
|
-
`;
|
|
26476
|
-
fs17.writeFileSync(filePath, content, "utf-8");
|
|
26477
|
-
} else if (targetType === "copilot") {
|
|
26478
|
-
const filePath = path22.join(projectRoot, ".github", "copilot-instructions.md");
|
|
26479
|
-
fs17.mkdirSync(path22.dirname(filePath), { recursive: true });
|
|
26480
|
-
const content = `# Wairon SDD Project
|
|
26481
|
-
|
|
26482
|
-
This project uses the Wairon Spec-Driven Development (SDD) framework.
|
|
26483
|
-
|
|
26484
|
-
Refer to the prompts in [.github/prompts/](.github/prompts/) for instructions.
|
|
26485
|
-
`;
|
|
26486
|
-
fs17.writeFileSync(filePath, content, "utf-8");
|
|
26487
|
-
} else if (targetType === "codex") {
|
|
26488
|
-
const filePath = path22.join(projectRoot, ".codexrules");
|
|
26489
|
-
const content = `# Wairon SDD Project
|
|
26490
|
-
|
|
26491
|
-
Refer to [.codex/agents/](.codex/agents/) for full instructions.
|
|
26492
|
-
`;
|
|
26493
|
-
fs17.writeFileSync(filePath, content, "utf-8");
|
|
26494
|
-
}
|
|
26495
|
-
}
|
|
26496
|
-
var GUIDE_TARGETS = ["claude", "gemini", "agy", "cursor", "copilot", "codex"];
|
|
26497
|
-
function reinjectLocalGuides(projectRoot, targetTypes) {
|
|
26498
|
-
const written = [];
|
|
26499
|
-
for (const type of targetTypes) {
|
|
26500
|
-
if (!GUIDE_TARGETS.includes(type)) continue;
|
|
26501
|
-
const guidePath = localGuideFilePath(projectRoot, type);
|
|
26502
|
-
if (guidePath) {
|
|
26503
|
-
injectGuide(guidePath, "local");
|
|
26504
|
-
if (!written.includes(guidePath)) written.push(guidePath);
|
|
26505
|
-
}
|
|
26506
|
-
writeRootGuideDelegator(projectRoot, type);
|
|
26507
|
-
}
|
|
26508
|
-
return written;
|
|
26509
|
-
}
|
|
26510
|
-
|
|
26511
|
-
// src/core/context.ts
|
|
26512
|
-
function contextDir(...segments) {
|
|
26513
|
-
return aiDir("context", ...segments);
|
|
26514
|
-
}
|
|
26515
|
-
var CONTEXT_PATHS = {
|
|
26516
|
-
dir: () => contextDir(),
|
|
26517
|
-
projectMd: () => contextDir("project.md"),
|
|
26518
|
-
architectureMd: () => contextDir("architecture.md"),
|
|
26519
|
-
domainsMd: () => contextDir("domains.md"),
|
|
26520
|
-
waironGuideMd: () => contextDir("wairon-guide.md")
|
|
26521
|
-
};
|
|
26522
|
-
function hasContext() {
|
|
26523
|
-
return pathExists(CONTEXT_PATHS.projectMd());
|
|
26524
|
-
}
|
|
26525
|
-
function hasArchitectureContext() {
|
|
26526
|
-
return pathExists(CONTEXT_PATHS.architectureMd());
|
|
26527
|
-
}
|
|
26528
|
-
function readProjectContext() {
|
|
26529
|
-
return readFileOrNull(CONTEXT_PATHS.projectMd());
|
|
26530
|
-
}
|
|
26531
|
-
function readArchitectureContext() {
|
|
26532
|
-
return readFileOrNull(CONTEXT_PATHS.architectureMd());
|
|
26533
|
-
}
|
|
26534
|
-
function writeProjectContext(content) {
|
|
26535
|
-
writeFile(CONTEXT_PATHS.projectMd(), content);
|
|
26536
|
-
}
|
|
26537
|
-
function writeArchitectureContext(content) {
|
|
26538
|
-
writeFile(CONTEXT_PATHS.architectureMd(), content);
|
|
26539
|
-
}
|
|
26540
|
-
function renderDomainsDoc() {
|
|
26541
|
-
const domains = resolveDomains();
|
|
26542
|
-
const lines = [
|
|
26543
|
-
versionStamp(),
|
|
26544
|
-
`# Domains`,
|
|
26545
|
-
``,
|
|
26546
|
-
`> Auto-generated by wairon. The human developer rebuilds this with \`wairon generate\`. `,
|
|
26547
|
-
``
|
|
26548
|
-
];
|
|
26549
|
-
if (domains.length === 0) {
|
|
26550
|
-
lines.push("_No domains yet. Define subsystems in the spec tree, or add free-standing domains with `wairon domains add`._");
|
|
26551
|
-
} else {
|
|
26552
|
-
lines.push(`**${domains.length} domain(s).**`);
|
|
26553
|
-
lines.push("");
|
|
26554
|
-
lines.push("| ID | Name | Source | Owned paths |");
|
|
26555
|
-
lines.push("|----|------|--------|-------------|");
|
|
26556
|
-
for (const d of domains) {
|
|
26557
|
-
const name = d.name ?? d.id;
|
|
26558
|
-
const source = d.boundTo ? `subsystem \`${d.boundTo}\`` : "free-standing";
|
|
26559
|
-
lines.push(`| \`${d.id}\` | ${name} | ${source} | \`${d.ownedPaths.join("`, `") || "\u2014"}\` |`);
|
|
26560
|
-
}
|
|
26561
|
-
}
|
|
26562
|
-
return lines.join("\n") + "\n";
|
|
26563
|
-
}
|
|
26564
|
-
function renderWaironGuide() {
|
|
26565
|
-
const domains = resolveDomains();
|
|
26566
|
-
let projectName = "this project";
|
|
26567
|
-
try {
|
|
26568
|
-
projectName = projectConfigRepository.load()?.name ?? projectName;
|
|
26569
|
-
} catch {
|
|
26570
|
-
}
|
|
26571
|
-
const projectCtx = readProjectContext();
|
|
26572
|
-
const archCtx = readArchitectureContext();
|
|
26573
|
-
const lines = [
|
|
26574
|
-
versionStamp(),
|
|
26575
|
-
`<!-- wairon-generated \u2014 do not edit directly; the human developer rebuilds this with \`wairon generate\` -->`,
|
|
26576
|
-
``
|
|
26577
|
-
];
|
|
26578
|
-
if (projectCtx) {
|
|
26579
|
-
lines.push(`# Project Context \u2014 ${projectName}`);
|
|
26580
|
-
lines.push("");
|
|
26581
|
-
lines.push(projectCtx.trim());
|
|
26582
|
-
lines.push("");
|
|
26583
|
-
lines.push("---");
|
|
26584
|
-
lines.push("");
|
|
26585
|
-
}
|
|
26586
|
-
if (archCtx) {
|
|
26587
|
-
lines.push("# Architecture");
|
|
26588
|
-
lines.push("");
|
|
26589
|
-
lines.push(archCtx.trim());
|
|
26590
|
-
lines.push("");
|
|
26591
|
-
lines.push("---");
|
|
26592
|
-
lines.push("");
|
|
26593
|
-
}
|
|
26594
|
-
lines.push(`# Domain Map (${domains.length} domain${domains.length !== 1 ? "s" : ""})`);
|
|
26595
|
-
lines.push("");
|
|
26596
|
-
if (domains.length === 0) {
|
|
26597
|
-
lines.push("_No domains yet._");
|
|
26598
|
-
} else {
|
|
26599
|
-
lines.push("| ID | Source | Name |");
|
|
26600
|
-
lines.push("|----|--------|------|");
|
|
26601
|
-
for (const d of domains) {
|
|
26602
|
-
const name = d.name ?? d.id;
|
|
26603
|
-
const source = d.boundTo ? `subsystem \`${d.boundTo}\`` : "free-standing";
|
|
26604
|
-
lines.push(`| \`${d.id}\` | ${source} | ${name} |`);
|
|
26605
|
-
}
|
|
26606
|
-
}
|
|
26607
|
-
lines.push("");
|
|
26608
|
-
lines.push("---");
|
|
26609
|
-
lines.push("");
|
|
26610
|
-
const mcpSettingsPath = require("path").join(process.cwd(), ".claude", "settings.json");
|
|
26611
|
-
let mcpInstalled = false;
|
|
26612
|
-
try {
|
|
26613
|
-
const s = JSON.parse(require("fs").readFileSync(mcpSettingsPath, "utf8"));
|
|
26614
|
-
mcpInstalled = !!s?.mcpServers?.wairon;
|
|
26615
|
-
} catch {
|
|
26616
|
-
}
|
|
26617
|
-
if (mcpInstalled) {
|
|
26618
|
-
lines.push("# wairon MCP Tools");
|
|
26619
|
-
lines.push("");
|
|
26620
|
-
lines.push("The **wairon MCP server** is active in this project. The tools are self-describing; call them directly:");
|
|
26621
|
-
lines.push("");
|
|
26622
|
-
lines.push("- Authoring: `sdd_initialize_system`, `sdd_add_subsystem`, `sdd_set_public_interfaces`, `sdd_set_subsystem_project_path`, `sdd_add_component`, `sdd_define_interface`, `sdd_set_endpoints`, `sdd_write_narrative`, `sdd_add_type`.");
|
|
26623
|
-
lines.push("- Reading & maintenance: `sdd_get_spec`, `sdd_update_spec`, `sdd_delete_spec`, `sdd_validate_tree`, `sdd_get_status`.");
|
|
26624
|
-
lines.push("- Topology: `listAgents`, `getAgent`, `listDomains`, `validateTopology`, `getProjectConfig`.");
|
|
26625
|
-
lines.push("");
|
|
26626
|
-
lines.push("Use these MCP tools to query and change project state \u2014 never the `wairon` CLI (that is the human developer's tool).");
|
|
26627
|
-
lines.push("");
|
|
26628
|
-
lines.push("---");
|
|
26629
|
-
lines.push("");
|
|
26630
|
-
}
|
|
26631
|
-
lines.push(GLOBAL_GUIDE_BODY);
|
|
26632
|
-
lines.push("");
|
|
26633
|
-
return lines.join("\n");
|
|
26634
|
-
}
|
|
26635
|
-
function syncContextFiles() {
|
|
26636
|
-
const domainsContent = renderDomainsDoc();
|
|
26637
|
-
const guideContent = renderWaironGuide();
|
|
26638
|
-
const domainsUpdated = writeFileIfChanged(CONTEXT_PATHS.domainsMd(), domainsContent);
|
|
26639
|
-
const guideUpdated = writeFileIfChanged(CONTEXT_PATHS.waironGuideMd(), guideContent);
|
|
26640
|
-
return { domainsUpdated, guideUpdated };
|
|
25019
|
+
function resolveTargetConfig(agentTarget, projectConfig) {
|
|
25020
|
+
const targetType = typeof agentTarget === "string" ? agentTarget : agentTarget.type;
|
|
25021
|
+
return projectConfig.targets.find((t) => {
|
|
25022
|
+
if (typeof t === "string") return t === targetType;
|
|
25023
|
+
return t.type === targetType;
|
|
25024
|
+
});
|
|
26641
25025
|
}
|
|
26642
25026
|
|
|
26643
25027
|
// src/core/treetransfer.ts
|
|
26644
|
-
var
|
|
26645
|
-
var
|
|
25028
|
+
var fs16 = __toESM(require("fs"));
|
|
25029
|
+
var path25 = __toESM(require("path"));
|
|
26646
25030
|
var sdkPortal = __toESM(require_dist());
|
|
26647
25031
|
var STAGING_PREFIX = ".wai-staging-";
|
|
26648
25032
|
var BACKUP_DIR = ".wai-backups";
|
|
@@ -26668,41 +25052,41 @@ function hasAuthoredSpecs(root) {
|
|
|
26668
25052
|
if (!pathExists(specsDir)) {
|
|
26669
25053
|
return false;
|
|
26670
25054
|
}
|
|
26671
|
-
const systemIndex =
|
|
25055
|
+
const systemIndex = path25.resolve(paths.specsSystem());
|
|
26672
25056
|
for (const file of listFilesRecursive(specsDir, ".yaml")) {
|
|
26673
|
-
if (
|
|
25057
|
+
if (path25.resolve(file) !== systemIndex) {
|
|
26674
25058
|
return true;
|
|
26675
25059
|
}
|
|
26676
25060
|
}
|
|
26677
25061
|
return false;
|
|
26678
25062
|
}
|
|
26679
25063
|
function createStagingDir(destDir) {
|
|
26680
|
-
const root =
|
|
26681
|
-
|
|
26682
|
-
const stagingDir =
|
|
25064
|
+
const root = path25.resolve(destDir);
|
|
25065
|
+
fs16.mkdirSync(root, { recursive: true });
|
|
25066
|
+
const stagingDir = fs16.mkdtempSync(path25.join(root, STAGING_PREFIX));
|
|
26683
25067
|
return stagingDir;
|
|
26684
25068
|
}
|
|
26685
25069
|
function commitStagedTree(stagingDir, destDir, roots, backupExisting) {
|
|
26686
|
-
const root =
|
|
26687
|
-
const backupDir =
|
|
25070
|
+
const root = path25.resolve(destDir);
|
|
25071
|
+
const backupDir = path25.join(root, BACKUP_DIR, timestampSlug());
|
|
26688
25072
|
let backedUp = false;
|
|
26689
25073
|
for (const rootRel of roots) {
|
|
26690
25074
|
const relative9 = rootRel === "." ? "" : rootRel;
|
|
26691
|
-
const stagedSpecDir =
|
|
26692
|
-
if (!
|
|
26693
|
-
const liveSpecDir = liveSpecDirFor(
|
|
26694
|
-
if (backupExisting && liveSpecDir &&
|
|
26695
|
-
const backupTarget =
|
|
26696
|
-
|
|
26697
|
-
|
|
25075
|
+
const stagedSpecDir = path25.join(stagingDir, relative9, ".wai");
|
|
25076
|
+
if (!fs16.existsSync(stagedSpecDir)) continue;
|
|
25077
|
+
const liveSpecDir = liveSpecDirFor(path25.join(root, relative9));
|
|
25078
|
+
if (backupExisting && liveSpecDir && fs16.existsSync(liveSpecDir)) {
|
|
25079
|
+
const backupTarget = path25.join(backupDir, relative9, path25.basename(liveSpecDir));
|
|
25080
|
+
fs16.mkdirSync(path25.dirname(backupTarget), { recursive: true });
|
|
25081
|
+
fs16.renameSync(liveSpecDir, backupTarget);
|
|
26698
25082
|
backedUp = true;
|
|
26699
|
-
} else if (liveSpecDir &&
|
|
26700
|
-
|
|
25083
|
+
} else if (liveSpecDir && fs16.existsSync(liveSpecDir)) {
|
|
25084
|
+
fs16.rmSync(liveSpecDir, { recursive: true, force: true });
|
|
26701
25085
|
}
|
|
26702
|
-
const target =
|
|
26703
|
-
|
|
26704
|
-
if (
|
|
26705
|
-
|
|
25086
|
+
const target = path25.join(root, relative9, ".wai");
|
|
25087
|
+
fs16.mkdirSync(path25.dirname(target), { recursive: true });
|
|
25088
|
+
if (fs16.existsSync(target)) fs16.rmSync(target, { recursive: true, force: true });
|
|
25089
|
+
fs16.renameSync(stagedSpecDir, target);
|
|
26706
25090
|
}
|
|
26707
25091
|
if (backedUp) {
|
|
26708
25092
|
return backupDir;
|
|
@@ -26711,7 +25095,7 @@ function commitStagedTree(stagingDir, destDir, roots, backupExisting) {
|
|
|
26711
25095
|
}
|
|
26712
25096
|
function discardStagingDir(stagingDir) {
|
|
26713
25097
|
try {
|
|
26714
|
-
|
|
25098
|
+
fs16.rmSync(stagingDir, { recursive: true, force: true });
|
|
26715
25099
|
} catch {
|
|
26716
25100
|
}
|
|
26717
25101
|
}
|
|
@@ -26725,7 +25109,7 @@ function exportSpecTree(includeDerived, allowPartial) {
|
|
|
26725
25109
|
const skipped = [...inspection.skipped];
|
|
26726
25110
|
const roots = [{ relativePath: ".", waiDir: aiPathsAt(root).root() }];
|
|
26727
25111
|
for (const rel2 of inspection.roots) {
|
|
26728
|
-
const waiDir = aiPathsAt(
|
|
25112
|
+
const waiDir = aiPathsAt(path25.resolve(root, rel2)).root();
|
|
26729
25113
|
if (pathExists(waiDir)) {
|
|
26730
25114
|
roots.push({ relativePath: rel2, waiDir });
|
|
26731
25115
|
} else {
|
|
@@ -26756,7 +25140,7 @@ function importSpecTree(archive, options) {
|
|
|
26756
25140
|
if (!info.compatible) {
|
|
26757
25141
|
throw new Error("incompatible .waitree archive (format or minimum wairon version)");
|
|
26758
25142
|
}
|
|
26759
|
-
const destDir =
|
|
25143
|
+
const destDir = path25.resolve(options.destDir ?? getProjectRoot());
|
|
26760
25144
|
const occupied = hasSpecTree(destDir);
|
|
26761
25145
|
const authored = hasAuthoredSpecs(destDir);
|
|
26762
25146
|
if (authored && options.replaceExisting !== true) {
|
|
@@ -26787,249 +25171,30 @@ function importSpecTree(archive, options) {
|
|
|
26787
25171
|
return result;
|
|
26788
25172
|
}
|
|
26789
25173
|
function liveSpecDirFor(rootDir) {
|
|
26790
|
-
const modern =
|
|
26791
|
-
if (
|
|
26792
|
-
const legacy =
|
|
26793
|
-
if (
|
|
25174
|
+
const modern = path25.join(rootDir, ".wai");
|
|
25175
|
+
if (fs16.existsSync(modern)) return modern;
|
|
25176
|
+
const legacy = path25.join(rootDir, ".wairon");
|
|
25177
|
+
if (fs16.existsSync(legacy)) return legacy;
|
|
26794
25178
|
return null;
|
|
26795
25179
|
}
|
|
26796
25180
|
function timestampSlug() {
|
|
26797
25181
|
return (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
26798
25182
|
}
|
|
26799
25183
|
|
|
26800
|
-
// src/
|
|
26801
|
-
var
|
|
26802
|
-
|
|
26803
|
-
|
|
26804
|
-
|
|
26805
|
-
|
|
26806
|
-
|
|
26807
|
-
|
|
26808
|
-
|
|
26809
|
-
|
|
26810
|
-
|
|
26811
|
-
|
|
26812
|
-
|
|
26813
|
-
|
|
26814
|
-
orchestrate: ["Agent", "SendMessage", "TodoWrite"],
|
|
26815
|
-
// `full` means "inherit everything" — expressed by omitting the field.
|
|
26816
|
-
full: void 0
|
|
26817
|
-
};
|
|
26818
|
-
function toolsFor(budget) {
|
|
26819
|
-
const base = TOOLS_BY_CLASS[budget.toolClass];
|
|
26820
|
-
if (!base) return void 0;
|
|
26821
|
-
if (budget.allowNestedDelegation && !base.includes("Agent")) {
|
|
26822
|
-
return [...base, "Agent"];
|
|
26823
|
-
}
|
|
26824
|
-
if (!budget.allowNestedDelegation) {
|
|
26825
|
-
return base.filter((t) => t !== "Agent");
|
|
26826
|
-
}
|
|
26827
|
-
return base;
|
|
26828
|
-
}
|
|
26829
|
-
function mcpServersFor(access) {
|
|
26830
|
-
return access === "none" ? "[]" : void 0;
|
|
26831
|
-
}
|
|
26832
|
-
function yamlScalar(value) {
|
|
26833
|
-
return /[:#\n]/.test(value) ? `"${value.replace(/"/g, '\\"')}"` : value;
|
|
26834
|
-
}
|
|
26835
|
-
var ClaudeExporter = class {
|
|
26836
|
-
constructor(options = {}) {
|
|
26837
|
-
this.options = options;
|
|
26838
|
-
this.targetType = "claude";
|
|
26839
|
-
}
|
|
26840
|
-
outputPath(ctx) {
|
|
26841
|
-
const { agent, target, projectRoot } = ctx;
|
|
26842
|
-
const outputDir = "outputDir" in target ? target.outputDir : ".claude/agents";
|
|
26843
|
-
return path24.resolve(projectRoot, outputDir, `${agent.id.replace(/::/g, "--")}.md`);
|
|
26844
|
-
}
|
|
26845
|
-
export(ctx) {
|
|
26846
|
-
const { agent, renderedInstructions, budget } = ctx;
|
|
26847
|
-
const filePath = this.outputPath(ctx);
|
|
26848
|
-
const frontmatter = [
|
|
26849
|
-
`name: ${agent.name}`,
|
|
26850
|
-
`description: ${yamlScalar(agent.description)}`
|
|
26851
|
-
];
|
|
26852
|
-
if (budget && this.options.emitBudget) {
|
|
26853
|
-
if (budget.modelTier) frontmatter.push(`model: ${MODEL_BY_TIER[budget.modelTier]}`);
|
|
26854
|
-
if (budget.effort) frontmatter.push(`effort: ${budget.effort}`);
|
|
26855
|
-
if (budget.maxTurns !== void 0) frontmatter.push(`maxTurns: ${budget.maxTurns}`);
|
|
26856
|
-
const tools = toolsFor(budget);
|
|
26857
|
-
if (tools) frontmatter.push(`tools: ${tools.join(", ")}`);
|
|
26858
|
-
const servers = mcpServersFor(budget.mcp);
|
|
26859
|
-
if (servers) frontmatter.push(`mcpServers: ${servers}`);
|
|
26860
|
-
}
|
|
26861
|
-
const content = ["---", ...frontmatter, "---", "", renderedInstructions, ""].join("\n");
|
|
26862
|
-
const changed = writeFileIfChanged(filePath, content);
|
|
26863
|
-
return { outputPath: filePath, content, unchanged: !changed };
|
|
26864
|
-
}
|
|
26865
|
-
};
|
|
26866
|
-
|
|
26867
|
-
// src/exporters/custom.ts
|
|
26868
|
-
var path25 = __toESM(require("path"));
|
|
26869
|
-
var CustomExporter = class {
|
|
26870
|
-
constructor() {
|
|
26871
|
-
this.targetType = "custom";
|
|
26872
|
-
}
|
|
26873
|
-
outputPath(ctx) {
|
|
26874
|
-
const { agent, target, projectRoot } = ctx;
|
|
26875
|
-
if (!("outputDir" in target)) {
|
|
26876
|
-
throw new Error("CustomExporter requires target.outputDir");
|
|
26877
|
-
}
|
|
26878
|
-
return path25.resolve(projectRoot, target.outputDir, `${agent.id.replace(/::/g, "--")}.md`);
|
|
26879
|
-
}
|
|
26880
|
-
export(ctx) {
|
|
26881
|
-
const { agent, target, renderedInstructions } = ctx;
|
|
26882
|
-
const label = "label" in target ? target.label : "Custom";
|
|
26883
|
-
const filePath = this.outputPath(ctx);
|
|
26884
|
-
const content = [
|
|
26885
|
-
"---",
|
|
26886
|
-
`name: ${agent.name}`,
|
|
26887
|
-
`description: ${agent.description}`,
|
|
26888
|
-
`id: ${agent.id}`,
|
|
26889
|
-
`target: ${label}`,
|
|
26890
|
-
"---",
|
|
26891
|
-
"",
|
|
26892
|
-
renderedInstructions,
|
|
26893
|
-
""
|
|
26894
|
-
].join("\n");
|
|
26895
|
-
const changed = writeFileIfChanged(filePath, content);
|
|
26896
|
-
return { outputPath: filePath, content, unchanged: !changed };
|
|
26897
|
-
}
|
|
26898
|
-
};
|
|
26899
|
-
|
|
26900
|
-
// src/exporters/gemini.ts
|
|
26901
|
-
var path26 = __toESM(require("path"));
|
|
26902
|
-
var GeminiExporter = class {
|
|
26903
|
-
constructor() {
|
|
26904
|
-
this.targetType = "gemini";
|
|
26905
|
-
}
|
|
26906
|
-
outputPath(ctx) {
|
|
26907
|
-
const { agent, target, projectRoot } = ctx;
|
|
26908
|
-
const outputDir = "outputDir" in target ? target.outputDir : ".gemini/agents";
|
|
26909
|
-
return path26.resolve(projectRoot, outputDir, `${agent.id.replace(/::/g, "--")}.yaml`);
|
|
26910
|
-
}
|
|
26911
|
-
export(ctx) {
|
|
26912
|
-
const { agent, renderedInstructions } = ctx;
|
|
26913
|
-
const filePath = this.outputPath(ctx);
|
|
26914
|
-
const indentedInstructions = renderedInstructions.split("\n").map((line) => line.length > 0 ? ` ${line}` : "").join("\n");
|
|
26915
|
-
const content = [
|
|
26916
|
-
`name: ${yamlString(agent.name)}`,
|
|
26917
|
-
`description: ${yamlString(agent.description)}`,
|
|
26918
|
-
`system_prompt: |`,
|
|
26919
|
-
indentedInstructions,
|
|
26920
|
-
""
|
|
26921
|
-
].join("\n");
|
|
26922
|
-
const changed = writeFileIfChanged(filePath, content);
|
|
26923
|
-
return { outputPath: filePath, content, unchanged: !changed };
|
|
26924
|
-
}
|
|
26925
|
-
};
|
|
26926
|
-
function yamlString(value) {
|
|
26927
|
-
if (/[:#\[\]{},&*!|>'"%@`]/.test(value) || value.startsWith(" ") || value.endsWith(" ")) {
|
|
26928
|
-
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
26929
|
-
}
|
|
26930
|
-
return value;
|
|
26931
|
-
}
|
|
26932
|
-
|
|
26933
|
-
// src/exporters/registry.ts
|
|
26934
|
-
var EXPORTERS = /* @__PURE__ */ new Map([
|
|
26935
|
-
["claude", new ClaudeExporter({ emitBudget: true })],
|
|
26936
|
-
["gemini", new GeminiExporter()],
|
|
26937
|
-
["agy", new GeminiExporter()],
|
|
26938
|
-
["cursor", new ClaudeExporter()],
|
|
26939
|
-
["copilot", new ClaudeExporter()],
|
|
26940
|
-
["codex", new ClaudeExporter()],
|
|
26941
|
-
["custom", new CustomExporter()]
|
|
26942
|
-
]);
|
|
26943
|
-
function getExporter(target) {
|
|
26944
|
-
const type = typeof target === "string" ? target : target.type;
|
|
26945
|
-
const exporter = EXPORTERS.get(type);
|
|
26946
|
-
if (!exporter) {
|
|
26947
|
-
throw new WaironError(`No exporter registered for target type: "${type}"`);
|
|
26948
|
-
}
|
|
26949
|
-
return exporter;
|
|
26950
|
-
}
|
|
26951
|
-
function registerExporter(type, exporter) {
|
|
26952
|
-
EXPORTERS.set(type, exporter);
|
|
26953
|
-
}
|
|
26954
|
-
|
|
26955
|
-
// src/exporters/base.ts
|
|
26956
|
-
var WAIRON_MANAGED_MARKER = "wairon:managed";
|
|
26957
|
-
var WAIRON_MANAGED_BANNER = `<!-- ${WAIRON_MANAGED_MARKER} \u2014 generated by \`wairon generate\`; do not edit, changes are overwritten -->`;
|
|
26958
|
-
|
|
26959
|
-
// src/exporters/generate.ts
|
|
26960
|
-
function generateAgent(agent, projectConfig, options = {}) {
|
|
26961
|
-
const projectRoot = options.projectRoot ?? getProjectRoot();
|
|
26962
|
-
const template = loadTemplate(agent.template, projectConfig.globalTemplatesDir);
|
|
26963
|
-
const rendered = `${WAIRON_MANAGED_BANNER}
|
|
26964
|
-
${composeAgentBrief(agent.id).instructions}`;
|
|
26965
|
-
const results = [];
|
|
26966
|
-
const budget = resolveBudget(
|
|
26967
|
-
deriveExecutionProfile(agent),
|
|
26968
|
-
projectConfig.execution,
|
|
26969
|
-
agent.id
|
|
26970
|
-
);
|
|
26971
|
-
for (const agentTarget of agent.targets) {
|
|
26972
|
-
const targetConfig = resolveTargetConfig(agentTarget, projectConfig);
|
|
26973
|
-
if (!targetConfig) continue;
|
|
26974
|
-
if (options.filterTargets) {
|
|
26975
|
-
const type = "type" in targetConfig ? targetConfig.type : targetConfig;
|
|
26976
|
-
if (!options.filterTargets.includes(type)) continue;
|
|
26977
|
-
}
|
|
26978
|
-
if (!options.dryRun) {
|
|
26979
|
-
results.push(getExporter(targetConfig).export({
|
|
26980
|
-
agent,
|
|
26981
|
-
template,
|
|
26982
|
-
renderedInstructions: rendered,
|
|
26983
|
-
projectRoot,
|
|
26984
|
-
target: targetConfig,
|
|
26985
|
-
budget
|
|
26986
|
-
}));
|
|
26987
|
-
}
|
|
26988
|
-
}
|
|
26989
|
-
return { agent, results };
|
|
26990
|
-
}
|
|
26991
|
-
function generateAll(agents, projectConfig, options = {}) {
|
|
26992
|
-
let pool = agents;
|
|
26993
|
-
if (options.filterDomainIds && options.filterDomainIds.length > 0) {
|
|
26994
|
-
const ids = new Set(options.filterDomainIds);
|
|
26995
|
-
pool = agents.filter((a) => ids.has(a.domainRoot ?? "root"));
|
|
26996
|
-
}
|
|
26997
|
-
return pool.map((agent) => generateAgent(agent, projectConfig, options));
|
|
26998
|
-
}
|
|
26999
|
-
function resolveExpectedOutputPaths(agents, projectConfig, projectRoot = getProjectRoot()) {
|
|
27000
|
-
const expected = /* @__PURE__ */ new Set();
|
|
27001
|
-
for (const agent of agents) {
|
|
27002
|
-
for (const agentTarget of agent.targets) {
|
|
27003
|
-
const targetConfig = resolveTargetConfig(agentTarget, projectConfig);
|
|
27004
|
-
if (!targetConfig) continue;
|
|
27005
|
-
const ctx = { agent, projectRoot, target: targetConfig };
|
|
27006
|
-
expected.add(path27.resolve(getExporter(targetConfig).outputPath(ctx)));
|
|
27007
|
-
}
|
|
27008
|
-
}
|
|
27009
|
-
return expected;
|
|
27010
|
-
}
|
|
27011
|
-
function resolveTargetConfig(agentTarget, projectConfig) {
|
|
27012
|
-
const targetType = typeof agentTarget === "string" ? agentTarget : agentTarget.type;
|
|
27013
|
-
return projectConfig.targets.find((t) => {
|
|
27014
|
-
if (typeof t === "string") return t === targetType;
|
|
27015
|
-
return t.type === targetType;
|
|
27016
|
-
});
|
|
27017
|
-
}
|
|
27018
|
-
|
|
27019
|
-
// src/core/stereotype-migration.ts
|
|
27020
|
-
var DATA_FACADES = /* @__PURE__ */ new Set(["Repository", "Index", "Adapter"]);
|
|
27021
|
-
function retireSpecialists(apply) {
|
|
27022
|
-
const components = loadComponentSpecs();
|
|
27023
|
-
const byId = new Map(components.map((c) => [c.id, c]));
|
|
27024
|
-
const specialists = components.filter((c) => c.componentType === "Specialist" && !c.id.includes("::")).sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
|
|
27025
|
-
const specialistIds = new Set(specialists.map((s) => s.id));
|
|
27026
|
-
const decided = /* @__PURE__ */ new Map();
|
|
27027
|
-
const reasons = /* @__PURE__ */ new Map();
|
|
27028
|
-
const fitOf = (id) => {
|
|
27029
|
-
if (specialistIds.has(id)) {
|
|
27030
|
-
const decision = decided.get(id);
|
|
27031
|
-
if (decision === void 0) return "pending";
|
|
27032
|
-
return decision === "unset" ? "neither" : decision;
|
|
25184
|
+
// src/core/stereotype-migration.ts
|
|
25185
|
+
var DATA_FACADES = /* @__PURE__ */ new Set(["Repository", "Index", "Adapter"]);
|
|
25186
|
+
function retireSpecialists(apply) {
|
|
25187
|
+
const components = loadComponentSpecs();
|
|
25188
|
+
const byId = new Map(components.map((c) => [c.id, c]));
|
|
25189
|
+
const specialists = components.filter((c) => c.componentType === "Specialist" && !c.id.includes("::")).sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
|
|
25190
|
+
const specialistIds = new Set(specialists.map((s) => s.id));
|
|
25191
|
+
const decided = /* @__PURE__ */ new Map();
|
|
25192
|
+
const reasons = /* @__PURE__ */ new Map();
|
|
25193
|
+
const fitOf = (id) => {
|
|
25194
|
+
if (specialistIds.has(id)) {
|
|
25195
|
+
const decision = decided.get(id);
|
|
25196
|
+
if (decision === void 0) return "pending";
|
|
25197
|
+
return decision === "unset" ? "neither" : decision;
|
|
27033
25198
|
}
|
|
27034
25199
|
const dependency = byId.get(id);
|
|
27035
25200
|
if (dependency?.componentType === "Orchestrator" && dependency.dependencyClass) return dependency.dependencyClass;
|
|
@@ -27149,130 +25314,610 @@ function repairForeignStepFields(apply) {
|
|
|
27149
25314
|
}
|
|
27150
25315
|
|
|
27151
25316
|
// src/core/approval.ts
|
|
27152
|
-
var
|
|
27153
|
-
var
|
|
25317
|
+
var crypto3 = __toESM(require("crypto"));
|
|
25318
|
+
var path26 = __toESM(require("path"));
|
|
25319
|
+
|
|
25320
|
+
// src/models/lock.ts
|
|
25321
|
+
function describeApprover(who) {
|
|
25322
|
+
const label = who.name ? `${who.name} (${who.id})` : who.id;
|
|
25323
|
+
return who.source === "hosted" ? `${label} [authenticated]` : label;
|
|
25324
|
+
}
|
|
25325
|
+
|
|
25326
|
+
// src/core/approval.ts
|
|
27154
25327
|
function diffSize(d) {
|
|
27155
25328
|
return d.added.length + d.changed.length + d.removed.length;
|
|
27156
25329
|
}
|
|
27157
25330
|
function digest(content) {
|
|
27158
25331
|
const normalized = content.replace(/\r\n/g, "\n");
|
|
27159
|
-
return
|
|
25332
|
+
return crypto3.createHash("sha256").update(normalized, "utf8").digest("hex");
|
|
27160
25333
|
}
|
|
27161
25334
|
function currentSpecDigests(root = getProjectRoot()) {
|
|
27162
|
-
const mountDirs = loadSubsystemSpecs().filter((s) => s.projectPath && !s.id.includes("::")).map((s) => `${
|
|
25335
|
+
const mountDirs = loadSubsystemSpecs().filter((s) => s.projectPath && !s.id.includes("::")).map((s) => `${path26.resolve(root, s.projectPath).split(path26.sep).join("/")}/`);
|
|
27163
25336
|
const out = {};
|
|
27164
25337
|
for (const [abs, content] of snapshotSpecFiles()) {
|
|
27165
|
-
const normalized =
|
|
25338
|
+
const normalized = path26.resolve(abs).split(path26.sep).join("/");
|
|
27166
25339
|
if (mountDirs.some((dir) => normalized.startsWith(dir))) continue;
|
|
27167
|
-
out[
|
|
25340
|
+
out[path26.relative(root, abs).split(path26.sep).join("/")] = digest(content);
|
|
25341
|
+
}
|
|
25342
|
+
return out;
|
|
25343
|
+
}
|
|
25344
|
+
function captureApprovedSpecs(root = getProjectRoot(), scope) {
|
|
25345
|
+
const current2 = currentSpecDigests(root);
|
|
25346
|
+
if (!scope) return current2;
|
|
25347
|
+
const previous = readLockRecord()?.specs ?? {};
|
|
25348
|
+
const specs = { ...previous };
|
|
25349
|
+
for (const rel2 of Object.keys(previous)) {
|
|
25350
|
+
if (scope.paths.has(rel2) && current2[rel2] === void 0) delete specs[rel2];
|
|
25351
|
+
}
|
|
25352
|
+
for (const rel2 of scope.paths) {
|
|
25353
|
+
if (current2[rel2] !== void 0) specs[rel2] = current2[rel2];
|
|
25354
|
+
}
|
|
25355
|
+
return specs;
|
|
25356
|
+
}
|
|
25357
|
+
function diffAgainstApproval(root = getProjectRoot()) {
|
|
25358
|
+
const approved = approvedSpecs(root);
|
|
25359
|
+
if (!approved) return null;
|
|
25360
|
+
const current2 = currentSpecDigests(root);
|
|
25361
|
+
const added = [];
|
|
25362
|
+
const changed = [];
|
|
25363
|
+
const removed = [];
|
|
25364
|
+
const unchangedPaths = [];
|
|
25365
|
+
for (const [rel2, d] of Object.entries(current2)) {
|
|
25366
|
+
const before = approved[rel2];
|
|
25367
|
+
if (before === void 0) added.push(rel2);
|
|
25368
|
+
else if (before !== d) changed.push(rel2);
|
|
25369
|
+
else unchangedPaths.push(rel2);
|
|
25370
|
+
}
|
|
25371
|
+
for (const rel2 of Object.keys(approved)) {
|
|
25372
|
+
if (current2[rel2] === void 0) removed.push(rel2);
|
|
25373
|
+
}
|
|
25374
|
+
return {
|
|
25375
|
+
added: added.sort(),
|
|
25376
|
+
changed: changed.sort(),
|
|
25377
|
+
removed: removed.sort(),
|
|
25378
|
+
unchangedPaths: unchangedPaths.sort()
|
|
25379
|
+
};
|
|
25380
|
+
}
|
|
25381
|
+
function approvedSpecs(root) {
|
|
25382
|
+
return approvalRecord(root)?.specs ?? null;
|
|
25383
|
+
}
|
|
25384
|
+
function approvalRecord(root = getProjectRoot()) {
|
|
25385
|
+
return readLockRecordAt(root);
|
|
25386
|
+
}
|
|
25387
|
+
function settledSpecPaths(root = getProjectRoot()) {
|
|
25388
|
+
const diff = diffAgainstApproval(root);
|
|
25389
|
+
return diff ? new Set(diff.unchangedPaths) : null;
|
|
25390
|
+
}
|
|
25391
|
+
function pinOf(stateId) {
|
|
25392
|
+
return `${stateId.algorithm}:${stateId.digest}`;
|
|
25393
|
+
}
|
|
25394
|
+
function currentChildPins(mounts, root = getProjectRoot()) {
|
|
25395
|
+
const pins = {};
|
|
25396
|
+
for (const mount of mounts) {
|
|
25397
|
+
if (!mount.projectPath || mount.id.includes("::")) continue;
|
|
25398
|
+
const child = readLockRecordAt(path26.resolve(root, mount.projectPath));
|
|
25399
|
+
if (child) pins[mount.id] = pinOf(child.stateId);
|
|
25400
|
+
}
|
|
25401
|
+
return pins;
|
|
25402
|
+
}
|
|
25403
|
+
function movedChildren(mounts, root = getProjectRoot()) {
|
|
25404
|
+
const pinned = approvalRecord(root)?.children;
|
|
25405
|
+
if (!pinned) return [];
|
|
25406
|
+
const now = currentChildPins(mounts, root);
|
|
25407
|
+
const moved = [];
|
|
25408
|
+
for (const [id, was] of Object.entries(pinned)) {
|
|
25409
|
+
const current2 = now[id] ?? null;
|
|
25410
|
+
if (current2 !== was) moved.push({ id, pinned: was, now: current2 });
|
|
25411
|
+
}
|
|
25412
|
+
return moved;
|
|
25413
|
+
}
|
|
25414
|
+
function approvalVerdict() {
|
|
25415
|
+
const quiet = { text: "", drifted: false };
|
|
25416
|
+
try {
|
|
25417
|
+
const approval = approvalRecord();
|
|
25418
|
+
if (!approval) return quiet;
|
|
25419
|
+
const by = describeApprover(approval.lockedBy);
|
|
25420
|
+
const moved = movedChildren(loadSubsystemSpecs());
|
|
25421
|
+
const childNote = moved.length ? `
|
|
25422
|
+
${moved.length} chained child project(s) moved since approval: ${moved.map((m) => m.id).join(", ")}.` : "";
|
|
25423
|
+
const diff = diffAgainstApproval();
|
|
25424
|
+
if (!diff) {
|
|
25425
|
+
return {
|
|
25426
|
+
text: `
|
|
25427
|
+
Approved: ${approval.lockedAt} by ${by} \u2014 this lock predates per-spec approval, so drift is only visible at whole-tree level. Re-lock to record it.${childNote}
|
|
25428
|
+
`,
|
|
25429
|
+
drifted: moved.length > 0
|
|
25430
|
+
};
|
|
25431
|
+
}
|
|
25432
|
+
if (diffSize(diff) === 0) {
|
|
25433
|
+
return {
|
|
25434
|
+
text: `
|
|
25435
|
+
Approved: ${approval.lockedAt} by ${by} \u2014 no spec has changed since.${childNote}
|
|
25436
|
+
`,
|
|
25437
|
+
drifted: moved.length > 0
|
|
25438
|
+
};
|
|
25439
|
+
}
|
|
25440
|
+
const parts = [];
|
|
25441
|
+
if (diff.changed.length) parts.push(`${diff.changed.length} changed`);
|
|
25442
|
+
if (diff.added.length) parts.push(`${diff.added.length} added`);
|
|
25443
|
+
if (diff.removed.length) parts.push(`${diff.removed.length} removed`);
|
|
25444
|
+
const named = [...diff.changed, ...diff.added, ...diff.removed].slice(0, 5);
|
|
25445
|
+
const rest = diffSize(diff) - named.length;
|
|
25446
|
+
const n = diffSize(diff);
|
|
25447
|
+
const noun = `${n} spec${n === 1 ? "" : "s"}`;
|
|
25448
|
+
const headline = parts.length === 1 ? `${noun} ${parts[0].slice(String(diffSize(diff)).length + 1)} since approval` : `${noun} changed since approval (${parts.join(", ")})`;
|
|
25449
|
+
return {
|
|
25450
|
+
text: `
|
|
25451
|
+
${headline} \u2014 approved ${approval.lockedAt} by ${by}:
|
|
25452
|
+
` + named.map((p) => ` ${p}`).join("\n") + (rest > 0 ? `
|
|
25453
|
+
\u2026 and ${rest} more` : "") + childNote + "\n",
|
|
25454
|
+
drifted: true
|
|
25455
|
+
};
|
|
25456
|
+
} catch {
|
|
25457
|
+
return quiet;
|
|
25458
|
+
}
|
|
25459
|
+
}
|
|
25460
|
+
|
|
25461
|
+
// src/core/approver.ts
|
|
25462
|
+
var import_child_process = require("child_process");
|
|
25463
|
+
var os4 = __toESM(require("os"));
|
|
25464
|
+
function gitConfig(key) {
|
|
25465
|
+
try {
|
|
25466
|
+
const value = (0, import_child_process.execFileSync)("git", ["config", "--get", key], {
|
|
25467
|
+
encoding: "utf8",
|
|
25468
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
25469
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: "0" }
|
|
25470
|
+
}).trim();
|
|
25471
|
+
return value || void 0;
|
|
25472
|
+
} catch {
|
|
25473
|
+
return void 0;
|
|
25474
|
+
}
|
|
25475
|
+
}
|
|
25476
|
+
function machineIdentity() {
|
|
25477
|
+
let user = "unknown";
|
|
25478
|
+
try {
|
|
25479
|
+
user = os4.userInfo().username || user;
|
|
25480
|
+
} catch {
|
|
25481
|
+
}
|
|
25482
|
+
let host = "";
|
|
25483
|
+
try {
|
|
25484
|
+
host = os4.hostname();
|
|
25485
|
+
} catch {
|
|
25486
|
+
}
|
|
25487
|
+
return { id: host ? `${user}@${host}` : user, source: "os" };
|
|
25488
|
+
}
|
|
25489
|
+
function localApprover() {
|
|
25490
|
+
const name = gitConfig("user.name");
|
|
25491
|
+
const email = gitConfig("user.email");
|
|
25492
|
+
if (name && email) return { id: `${name} <${email}>`, source: "git" };
|
|
25493
|
+
if (email) return { id: email, source: "git" };
|
|
25494
|
+
return machineIdentity();
|
|
25495
|
+
}
|
|
25496
|
+
|
|
25497
|
+
// src/utils/ai-guide.ts
|
|
25498
|
+
var fs17 = __toESM(require("fs"));
|
|
25499
|
+
var os5 = __toESM(require("os"));
|
|
25500
|
+
var path27 = __toESM(require("path"));
|
|
25501
|
+
|
|
25502
|
+
// src/core/stamp.ts
|
|
25503
|
+
function versionStamp() {
|
|
25504
|
+
return `<!-- wairon-version: ${WAIRON_VERSION} -->`;
|
|
25505
|
+
}
|
|
25506
|
+
var STAMP_RE = /<!--\s*wairon-version:\s*([^\s]+)\s*-->/;
|
|
25507
|
+
function readStampVersion(content) {
|
|
25508
|
+
const m = content.match(STAMP_RE);
|
|
25509
|
+
return m ? m[1] : null;
|
|
25510
|
+
}
|
|
25511
|
+
|
|
25512
|
+
// src/utils/ai-guide.ts
|
|
25513
|
+
var GUIDE_MARKER_START = "<!-- wairon-guide-start -->";
|
|
25514
|
+
var GUIDE_MARKER_END = "<!-- wairon-guide-end -->";
|
|
25515
|
+
var GLOBAL_GUIDE_BODY = `## wairon \u2014 Spec-Driven Development (optional)
|
|
25516
|
+
|
|
25517
|
+
If \`.wai/specs/\` exists, the wairon SDD workflow is active; otherwise ignore it. wairon does not orchestrate sessions \u2014 it equips yours.
|
|
25518
|
+
|
|
25519
|
+
### In SDD Projects:
|
|
25520
|
+
- **Source of Truth**: All architecture lives in the spec tree under \`.wai/specs/\` (L0 System \u2192 L1 Subsystem \u2192 L2 Component \u2192 L3 Interface \u2192 L4 Implementation \u2192 L5 Narrative). Do not edit generated agent config files under \`.claude/agents/\` (rebuilt via \`wairon generate\`).
|
|
25521
|
+
- **Validation**: Conformance checks (stereotype rules, cycle checks, reference integrity) are run via the \`sdd_validate_tree\` MCP tool.
|
|
25522
|
+
- **Operating Rules**:
|
|
25523
|
+
1. **Skills**: Use \`sdd-architect\` to design (and \`sdd-implement\`, \`sdd-narrative\`, \`sdd-auditor\`). Refer to project's local guide file for detailed constraints.
|
|
25524
|
+
2. **MCP Tools Only**: Author/validate specs *only* via \`sdd_*\` tools (e.g. \`sdd_initialize_system\`, \`sdd_validate_tree\`).
|
|
25525
|
+
3. **No CLI Exec**: Do not run the \`wairon\` CLI (human tool). Use MCP tools \`sdd_validate_tree\` and \`sdd_get_status\` instead.
|
|
25526
|
+
4. **Delegation**: Delegate implementation via the \`sdd-delegate\` skill \u2014 live agent briefs (\`sdd_get_agent_brief\` MCP tool / \`wairon-agent://\` resource) are composed per call and always current; no session restart. Generated agent files are an optional materialized view of the same topology. User-owned per-agent guidance may live in \`.wai/agents/<agent-id>.md\` (folded into every brief; scaffold via \`wairon agent customize <id>\`).
|
|
25527
|
+
5. **Design First**: Complete spec and pass \`sdd_validate_tree\` before writing code.
|
|
25528
|
+
6. **Consistency**: Code must match L3 interfaces and L5 narratives exactly. If the spec is wrong, stop and update the spec.
|
|
25529
|
+
7. **Subprojects & Namespacing**: If a subsystem uses \`projectPath\` delegation, target its specs using namespaced IDs (e.g. \`subsystem::component\`). Use leading \`::\` to target root (e.g. \`::shared::type\`) and \`super::\` to go up a level (e.g. \`super::sibling\`). wairon automatically resolves the path and strips the prefix on writes.`;
|
|
25530
|
+
var LOCAL_GUIDE_BODY = `## Wairon \u2014 Spec-Driven Development (you are operating inside it)
|
|
25531
|
+
|
|
25532
|
+
This project uses **wairon**. System specs live under \`.wai/specs/\` (L0 System \u2192 L1 Subsystem \u2192 L2 Component \u2192 L3 Interface \u2192 L4 Implementation \u2192 Narrative); agent topology and code are derived from it.
|
|
25533
|
+
|
|
25534
|
+
**Do NOT search files or read agent configs to learn about wairon or SDD. Use the context here and the \`sdd-architect\` skill to start.**
|
|
25535
|
+
|
|
25536
|
+
**Your first move: call the \`sdd_get_status\` MCP tool** (or \`wairon/sdd_get_status\`) to see the spec tree. Do not parse files or run CLI commands manually.
|
|
25537
|
+
|
|
25538
|
+
### How you operate
|
|
25539
|
+
- **To design/modify specs**: Use **\`sdd-architect\`** skill (in \`.claude/skills/\` or \`.gemini/skills/\`).
|
|
25540
|
+
- **Manage specs via MCP tools only**: Use \`sdd_initialize_system\`, \`sdd_add_subsystem\`, \`sdd_add_component\`, \`sdd_define_interface\`, \`sdd_write_narrative\`, \`sdd_add_type\`, \`sdd_get_spec\`, \`sdd_delete_spec\`, \`sdd_validate_tree\`, and \`sdd_get_status\` (namespaced if needed). Do not edit specs manually.
|
|
25541
|
+
- **Subprojects & Namespacing (Chaining)**: If a subsystem defines a \`projectPath\`, its entire \`.wai/\` spec tree is recursively loaded and namespaced with the subsystem ID as a prefix (using \`::\`, e.g. \`billing::invoice::invoice_portal\`). Use the qualified namespaced ID with the parent MCP tools; wairon will resolve the path and strip the prefix automatically.
|
|
25542
|
+
- **Leading \`::\`**: Bypasses the local subsystem prefix to resolve absolute from the system root (e.g. \`::shared::error-type\`).
|
|
25543
|
+
- **\`super::\`**: Goes up one parent subsystem level (e.g. \`super::sibling_comp\`, \`super::super::parent_sibling\`).
|
|
25544
|
+
- **Do not run the \`wairon\` CLI**: Use \`sdd_validate_tree\` and \`sdd_get_status\` instead of CLI commands.
|
|
25545
|
+
- **Handoff to implementation**: Once design is complete and validates cleanly, tell the human: *"The specs are complete and validate. Please run \`wairon lock\` to confirm and freeze them."* No session restart is needed after the lock \u2014 delegate implementation right away via the \`sdd-delegate\` skill.
|
|
25546
|
+
- **To implement code**: Delegate via the \`sdd-delegate\` skill: fetch the component's live brief with the \`sdd_get_agent_brief\` MCP tool (or the \`wairon-agent://\` resource) and spawn a subagent from it. Briefs are composed per call from the current spec tree, so they are always current \u2014 never wait for a restart. Implementations must match L3 interfaces and L5 narratives exactly. Generated agent files under \`.claude/agents/\` are an optional materialized view of the same topology \u2014 the live briefs are canonical.
|
|
25547
|
+
|
|
25548
|
+
### Rules (enforced by \`sdd_validate_tree\`)
|
|
25549
|
+
1. **Design before code**: Complete spec and pass validator before writing source code.
|
|
25550
|
+
2. **Human-in-the-loop**: Ask user approval for each spec layer before proceeding.
|
|
25551
|
+
3. **Spec consistency**: If a 1:1 narrative match is incorrect or conflicts with L0 requirements, escalate a spec revision first. Never ship mismatched code.
|
|
25552
|
+
4. **No persistence shortcuts & strict layers**: A Portal must never depend directly on a Store, Registry, or Adapter. Portal reads MAY go through a Repository/Index facade (passthrough reads need no per-entity Orchestrator ceremony), but a Portal narrative call or dispatch-table binding that reaches a write-effect facade method is an error (\`PORTAL_WRITE_SHORTCUT\`) \u2014 writes always route through an Orchestrator. Held domain state always lives in a dedicated data component, never as fields inside an Orchestrator. Two sanctioned shapes: the RECOMMENDED Repository pattern (owns Store + Registry + Index; consumers depend on the facade), or \u2014 for genuinely simple state \u2014 a deliberately standalone Store (workflow-layer consumers only, acknowledged with a lint.allow reason on the UNOWNED_STORE warning). Never combine Store/Registry/Index roles into one component, and never fold state into a consuming component because a link was refused.
|
|
25553
|
+
|
|
25554
|
+
### Component Vocabulary
|
|
25555
|
+
* **Blocks**: Portal, Orchestrator, Supervisor, Actor, Store, Index, Query, Registry, Adapter, Observer.
|
|
25556
|
+
* **Patterns**: Repository \u2014 the composable pattern that \`owns\` its member blocks: one Store with its Registry, Indexes and Queries, and optionally an Adapter.
|
|
25557
|
+
* **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.
|
|
25558
|
+
* Use \`owns\` for private member containment (exactly one hop) and \`dependsOn\` for collaborators. Never use generic suffixes like "Manager", "Helper", or "Utils".`;
|
|
25559
|
+
function globalGuideFilePath(targetType) {
|
|
25560
|
+
if (targetType === "claude") return path27.join(process.env["CLAUDE_CONFIG_DIR"] || path27.join(os5.homedir(), ".claude"), "CLAUDE.md");
|
|
25561
|
+
if (targetType === "gemini") return path27.join(process.env["GEMINI_CONFIG_DIR"] || path27.join(os5.homedir(), ".gemini"), "GEMINI.md");
|
|
25562
|
+
return null;
|
|
25563
|
+
}
|
|
25564
|
+
function localGuideFilePath(projectRoot, targetType) {
|
|
25565
|
+
if (targetType === "claude") return path27.join(projectRoot, ".claude", "CLAUDE.md");
|
|
25566
|
+
if (targetType === "gemini" || targetType === "agy") return path27.join(projectRoot, ".gemini", "GEMINI.md");
|
|
25567
|
+
return null;
|
|
25568
|
+
}
|
|
25569
|
+
function injectGuide(filePath, scope) {
|
|
25570
|
+
const body = scope === "global" ? GLOBAL_GUIDE_BODY : LOCAL_GUIDE_BODY;
|
|
25571
|
+
const section = `
|
|
25572
|
+
|
|
25573
|
+
${GUIDE_MARKER_START}
|
|
25574
|
+
${versionStamp()}
|
|
25575
|
+
${body}
|
|
25576
|
+
${GUIDE_MARKER_END}
|
|
25577
|
+
`;
|
|
25578
|
+
const existing = fs17.existsSync(filePath) ? fs17.readFileSync(filePath, "utf-8") : "";
|
|
25579
|
+
const stripped = stripGuideSection(existing);
|
|
25580
|
+
const newContent = stripped.trimEnd() + section;
|
|
25581
|
+
fs17.mkdirSync(path27.dirname(filePath), { recursive: true });
|
|
25582
|
+
fs17.writeFileSync(filePath, newContent, "utf-8");
|
|
25583
|
+
}
|
|
25584
|
+
function stripGuideSection(content) {
|
|
25585
|
+
const start = content.indexOf(GUIDE_MARKER_START);
|
|
25586
|
+
const end = content.indexOf(GUIDE_MARKER_END);
|
|
25587
|
+
if (start === -1 || end === -1) return content;
|
|
25588
|
+
return content.slice(0, start) + content.slice(end + GUIDE_MARKER_END.length);
|
|
25589
|
+
}
|
|
25590
|
+
function writeRootGuideDelegator(projectRoot, targetType) {
|
|
25591
|
+
if (targetType === "claude") {
|
|
25592
|
+
const filePath = path27.join(projectRoot, "CLAUDE.md");
|
|
25593
|
+
const content = `@.claude/CLAUDE.md
|
|
25594
|
+
|
|
25595
|
+
# Wairon SDD Project
|
|
25596
|
+
|
|
25597
|
+
This project uses the Wairon Spec-Driven Development (SDD) framework. The imported
|
|
25598
|
+
\`.claude/CLAUDE.md\` above is your complete operating guide \u2014 you already have the
|
|
25599
|
+
full context, so don't search the project to learn how wairon or SDD works.
|
|
25600
|
+
|
|
25601
|
+
To design or modify the system, invoke the **\`sdd-architect\`** skill
|
|
25602
|
+
(in \`.claude/skills/\`). Author and validate specs with the \`sdd_*\` MCP tools;
|
|
25603
|
+
the \`wairon\` CLI is the human developer's tool, not yours.
|
|
25604
|
+
`;
|
|
25605
|
+
fs17.writeFileSync(filePath, content, "utf-8");
|
|
25606
|
+
} else if (targetType === "gemini" || targetType === "agy") {
|
|
25607
|
+
const filePath = path27.join(projectRoot, "GEMINI.md");
|
|
25608
|
+
const content = `# Wairon SDD Project
|
|
25609
|
+
${GUIDE_MARKER_START}
|
|
25610
|
+
${versionStamp()}
|
|
25611
|
+
${LOCAL_GUIDE_BODY}
|
|
25612
|
+
${GUIDE_MARKER_END}
|
|
25613
|
+
`;
|
|
25614
|
+
fs17.writeFileSync(filePath, content, "utf-8");
|
|
25615
|
+
} else if (targetType === "cursor") {
|
|
25616
|
+
const filePath = path27.join(projectRoot, ".cursorrules");
|
|
25617
|
+
const content = `# Wairon SDD Project
|
|
25618
|
+
|
|
25619
|
+
This project uses the Wairon Spec-Driven Development (SDD) framework.
|
|
25620
|
+
|
|
25621
|
+
Refer to the rules in [.cursor/rules/](.cursor/rules/) for full instructions.
|
|
25622
|
+
`;
|
|
25623
|
+
fs17.writeFileSync(filePath, content, "utf-8");
|
|
25624
|
+
} else if (targetType === "copilot") {
|
|
25625
|
+
const filePath = path27.join(projectRoot, ".github", "copilot-instructions.md");
|
|
25626
|
+
fs17.mkdirSync(path27.dirname(filePath), { recursive: true });
|
|
25627
|
+
const content = `# Wairon SDD Project
|
|
25628
|
+
|
|
25629
|
+
This project uses the Wairon Spec-Driven Development (SDD) framework.
|
|
25630
|
+
|
|
25631
|
+
Refer to the prompts in [.github/prompts/](.github/prompts/) for instructions.
|
|
25632
|
+
`;
|
|
25633
|
+
fs17.writeFileSync(filePath, content, "utf-8");
|
|
25634
|
+
} else if (targetType === "codex") {
|
|
25635
|
+
const filePath = path27.join(projectRoot, ".codexrules");
|
|
25636
|
+
const content = `# Wairon SDD Project
|
|
25637
|
+
|
|
25638
|
+
Refer to [.codex/agents/](.codex/agents/) for full instructions.
|
|
25639
|
+
`;
|
|
25640
|
+
fs17.writeFileSync(filePath, content, "utf-8");
|
|
27168
25641
|
}
|
|
27169
|
-
return out;
|
|
27170
25642
|
}
|
|
27171
|
-
|
|
27172
|
-
|
|
27173
|
-
|
|
27174
|
-
const
|
|
27175
|
-
|
|
27176
|
-
|
|
27177
|
-
if (
|
|
27178
|
-
|
|
27179
|
-
|
|
27180
|
-
|
|
25643
|
+
var GUIDE_TARGETS = ["claude", "gemini", "agy", "cursor", "copilot", "codex"];
|
|
25644
|
+
function reinjectLocalGuides(projectRoot, targetTypes) {
|
|
25645
|
+
const written = [];
|
|
25646
|
+
for (const type of targetTypes) {
|
|
25647
|
+
if (!GUIDE_TARGETS.includes(type)) continue;
|
|
25648
|
+
const guidePath = localGuideFilePath(projectRoot, type);
|
|
25649
|
+
if (guidePath) {
|
|
25650
|
+
injectGuide(guidePath, "local");
|
|
25651
|
+
if (!written.includes(guidePath)) written.push(guidePath);
|
|
25652
|
+
}
|
|
25653
|
+
writeRootGuideDelegator(projectRoot, type);
|
|
27181
25654
|
}
|
|
27182
|
-
return
|
|
25655
|
+
return written;
|
|
27183
25656
|
}
|
|
27184
|
-
|
|
27185
|
-
|
|
27186
|
-
|
|
27187
|
-
|
|
27188
|
-
const added = [];
|
|
27189
|
-
const changed = [];
|
|
27190
|
-
const removed = [];
|
|
27191
|
-
const unchangedPaths = [];
|
|
27192
|
-
for (const [rel2, d] of Object.entries(current2)) {
|
|
27193
|
-
const before = approved[rel2];
|
|
27194
|
-
if (before === void 0) added.push(rel2);
|
|
27195
|
-
else if (before !== d) changed.push(rel2);
|
|
27196
|
-
else unchangedPaths.push(rel2);
|
|
27197
|
-
}
|
|
27198
|
-
for (const rel2 of Object.keys(approved)) {
|
|
27199
|
-
if (current2[rel2] === void 0) removed.push(rel2);
|
|
27200
|
-
}
|
|
27201
|
-
return {
|
|
27202
|
-
added: added.sort(),
|
|
27203
|
-
changed: changed.sort(),
|
|
27204
|
-
removed: removed.sort(),
|
|
27205
|
-
unchangedPaths: unchangedPaths.sort()
|
|
27206
|
-
};
|
|
25657
|
+
|
|
25658
|
+
// src/core/context.ts
|
|
25659
|
+
function contextDir(...segments) {
|
|
25660
|
+
return aiDir("context", ...segments);
|
|
27207
25661
|
}
|
|
27208
|
-
|
|
27209
|
-
|
|
25662
|
+
var CONTEXT_PATHS = {
|
|
25663
|
+
dir: () => contextDir(),
|
|
25664
|
+
projectMd: () => contextDir("project.md"),
|
|
25665
|
+
architectureMd: () => contextDir("architecture.md"),
|
|
25666
|
+
domainsMd: () => contextDir("domains.md"),
|
|
25667
|
+
waironGuideMd: () => contextDir("wairon-guide.md")
|
|
25668
|
+
};
|
|
25669
|
+
function hasContext() {
|
|
25670
|
+
return pathExists(CONTEXT_PATHS.projectMd());
|
|
27210
25671
|
}
|
|
27211
|
-
function
|
|
27212
|
-
return
|
|
25672
|
+
function readProjectContext() {
|
|
25673
|
+
return readFileOrNull(CONTEXT_PATHS.projectMd());
|
|
27213
25674
|
}
|
|
27214
|
-
function
|
|
27215
|
-
|
|
27216
|
-
return diff ? new Set(diff.unchangedPaths) : null;
|
|
25675
|
+
function readArchitectureContext() {
|
|
25676
|
+
return readFileOrNull(CONTEXT_PATHS.architectureMd());
|
|
27217
25677
|
}
|
|
27218
|
-
function
|
|
27219
|
-
return
|
|
25678
|
+
function writeDomainsDoc(content) {
|
|
25679
|
+
return writeFileIfChanged(CONTEXT_PATHS.domainsMd(), content);
|
|
27220
25680
|
}
|
|
27221
|
-
function
|
|
27222
|
-
|
|
27223
|
-
for (const mount of mounts) {
|
|
27224
|
-
if (!mount.projectPath || mount.id.includes("::")) continue;
|
|
27225
|
-
const child = readLockRecordAt(path28.resolve(root, mount.projectPath));
|
|
27226
|
-
if (child) pins[mount.id] = pinOf(child.stateId);
|
|
27227
|
-
}
|
|
27228
|
-
return pins;
|
|
25681
|
+
function writeGuideDoc(content) {
|
|
25682
|
+
return writeFileIfChanged(CONTEXT_PATHS.waironGuideMd(), content);
|
|
27229
25683
|
}
|
|
27230
|
-
function
|
|
27231
|
-
|
|
27232
|
-
if (!pinned) return [];
|
|
27233
|
-
const now = currentChildPins(mounts, root);
|
|
27234
|
-
const moved = [];
|
|
27235
|
-
for (const [id, was] of Object.entries(pinned)) {
|
|
27236
|
-
const current2 = now[id] ?? null;
|
|
27237
|
-
if (current2 !== was) moved.push({ id, pinned: was, now: current2 });
|
|
27238
|
-
}
|
|
27239
|
-
return moved;
|
|
25684
|
+
function derivedDocPaths() {
|
|
25685
|
+
return [CONTEXT_PATHS.waironGuideMd(), CONTEXT_PATHS.domainsMd()];
|
|
27240
25686
|
}
|
|
27241
|
-
|
|
27242
|
-
|
|
27243
|
-
|
|
27244
|
-
|
|
27245
|
-
|
|
27246
|
-
|
|
27247
|
-
|
|
27248
|
-
|
|
27249
|
-
|
|
27250
|
-
|
|
27251
|
-
|
|
27252
|
-
|
|
27253
|
-
|
|
27254
|
-
|
|
25687
|
+
function renderDomainsDoc() {
|
|
25688
|
+
const domains = resolveDomains();
|
|
25689
|
+
const lines = [
|
|
25690
|
+
versionStamp(),
|
|
25691
|
+
`# Domains`,
|
|
25692
|
+
``,
|
|
25693
|
+
`> Auto-generated by wairon. The human developer rebuilds this with \`wairon generate\`. `,
|
|
25694
|
+
``
|
|
25695
|
+
];
|
|
25696
|
+
if (domains.length === 0) {
|
|
25697
|
+
lines.push("_No domains yet. Define subsystems in the spec tree, or add free-standing domains with `wairon domains add`._");
|
|
25698
|
+
} else {
|
|
25699
|
+
lines.push(`**${domains.length} domain(s).**`);
|
|
25700
|
+
lines.push("");
|
|
25701
|
+
lines.push("| ID | Name | Source | Owned paths |");
|
|
25702
|
+
lines.push("|----|------|--------|-------------|");
|
|
25703
|
+
for (const d of domains) {
|
|
25704
|
+
const name = d.name ?? d.id;
|
|
25705
|
+
const source = d.boundTo ? `subsystem \`${d.boundTo}\`` : "free-standing";
|
|
25706
|
+
lines.push(`| \`${d.id}\` | ${name} | ${source} | \`${d.ownedPaths.join("`, `") || "\u2014"}\` |`);
|
|
25707
|
+
}
|
|
27255
25708
|
}
|
|
25709
|
+
return lines.join("\n") + "\n";
|
|
27256
25710
|
}
|
|
27257
|
-
function
|
|
27258
|
-
|
|
25711
|
+
function renderWaironGuide() {
|
|
25712
|
+
const domains = resolveDomains();
|
|
25713
|
+
let projectName = "this project";
|
|
27259
25714
|
try {
|
|
27260
|
-
|
|
25715
|
+
projectName = projectConfigRepository.load()?.name ?? projectName;
|
|
27261
25716
|
} catch {
|
|
27262
25717
|
}
|
|
27263
|
-
|
|
25718
|
+
const projectCtx = readProjectContext();
|
|
25719
|
+
const archCtx = readArchitectureContext();
|
|
25720
|
+
const lines = [
|
|
25721
|
+
versionStamp(),
|
|
25722
|
+
`<!-- wairon-generated \u2014 do not edit directly; the human developer rebuilds this with \`wairon generate\` -->`,
|
|
25723
|
+
``
|
|
25724
|
+
];
|
|
25725
|
+
if (projectCtx) {
|
|
25726
|
+
lines.push(`# Project Context \u2014 ${projectName}`);
|
|
25727
|
+
lines.push("");
|
|
25728
|
+
lines.push(projectCtx.trim());
|
|
25729
|
+
lines.push("");
|
|
25730
|
+
lines.push("---");
|
|
25731
|
+
lines.push("");
|
|
25732
|
+
}
|
|
25733
|
+
if (archCtx) {
|
|
25734
|
+
lines.push("# Architecture");
|
|
25735
|
+
lines.push("");
|
|
25736
|
+
lines.push(archCtx.trim());
|
|
25737
|
+
lines.push("");
|
|
25738
|
+
lines.push("---");
|
|
25739
|
+
lines.push("");
|
|
25740
|
+
}
|
|
25741
|
+
lines.push(`# Domain Map (${domains.length} domain${domains.length !== 1 ? "s" : ""})`);
|
|
25742
|
+
lines.push("");
|
|
25743
|
+
if (domains.length === 0) {
|
|
25744
|
+
lines.push("_No domains yet._");
|
|
25745
|
+
} else {
|
|
25746
|
+
lines.push("| ID | Source | Name |");
|
|
25747
|
+
lines.push("|----|--------|------|");
|
|
25748
|
+
for (const d of domains) {
|
|
25749
|
+
const name = d.name ?? d.id;
|
|
25750
|
+
const source = d.boundTo ? `subsystem \`${d.boundTo}\`` : "free-standing";
|
|
25751
|
+
lines.push(`| \`${d.id}\` | ${source} | ${name} |`);
|
|
25752
|
+
}
|
|
25753
|
+
}
|
|
25754
|
+
lines.push("");
|
|
25755
|
+
lines.push("---");
|
|
25756
|
+
lines.push("");
|
|
25757
|
+
const mcpSettingsPath = require("path").join(process.cwd(), ".claude", "settings.json");
|
|
25758
|
+
let mcpInstalled = false;
|
|
27264
25759
|
try {
|
|
27265
|
-
|
|
25760
|
+
const s = JSON.parse(require("fs").readFileSync(mcpSettingsPath, "utf8"));
|
|
25761
|
+
mcpInstalled = !!s?.mcpServers?.wairon;
|
|
27266
25762
|
} catch {
|
|
27267
25763
|
}
|
|
27268
|
-
|
|
25764
|
+
if (mcpInstalled) {
|
|
25765
|
+
lines.push("# wairon MCP Tools");
|
|
25766
|
+
lines.push("");
|
|
25767
|
+
lines.push("The **wairon MCP server** is active in this project. The tools are self-describing; call them directly:");
|
|
25768
|
+
lines.push("");
|
|
25769
|
+
lines.push("- Authoring: `sdd_initialize_system`, `sdd_add_subsystem`, `sdd_set_public_interfaces`, `sdd_set_subsystem_project_path`, `sdd_add_component`, `sdd_define_interface`, `sdd_set_endpoints`, `sdd_write_narrative`, `sdd_add_type`.");
|
|
25770
|
+
lines.push("- Reading & maintenance: `sdd_get_spec`, `sdd_update_spec`, `sdd_delete_spec`, `sdd_validate_tree`, `sdd_get_status`.");
|
|
25771
|
+
lines.push("- Topology: `listAgents`, `getAgent`, `listDomains`, `validateTopology`, `getProjectConfig`.");
|
|
25772
|
+
lines.push("");
|
|
25773
|
+
lines.push("Use these MCP tools to query and change project state \u2014 never the `wairon` CLI (that is the human developer's tool).");
|
|
25774
|
+
lines.push("");
|
|
25775
|
+
lines.push("---");
|
|
25776
|
+
lines.push("");
|
|
25777
|
+
}
|
|
25778
|
+
lines.push(GLOBAL_GUIDE_BODY);
|
|
25779
|
+
lines.push("");
|
|
25780
|
+
return lines.join("\n");
|
|
27269
25781
|
}
|
|
27270
|
-
function
|
|
27271
|
-
const
|
|
27272
|
-
const
|
|
27273
|
-
|
|
27274
|
-
|
|
27275
|
-
return
|
|
25782
|
+
function syncContextFiles() {
|
|
25783
|
+
const domainsContent = renderDomainsDoc();
|
|
25784
|
+
const guideContent = renderWaironGuide();
|
|
25785
|
+
const domainsUpdated = writeDomainsDoc(domainsContent);
|
|
25786
|
+
const guideUpdated = writeGuideDoc(guideContent);
|
|
25787
|
+
return { domainsUpdated, guideUpdated };
|
|
25788
|
+
}
|
|
25789
|
+
|
|
25790
|
+
// src/core/status.ts
|
|
25791
|
+
function getStatusReport(options = {}) {
|
|
25792
|
+
scanAllSpecs({ recursive: options.recursive ?? true });
|
|
25793
|
+
const system = loadSystemSpec();
|
|
25794
|
+
const loaderErrors = getLoaderIssues();
|
|
25795
|
+
if (loaderErrors.length > 0) {
|
|
25796
|
+
let errText = "Failed to parse specification files:\n";
|
|
25797
|
+
for (const issue2 of loaderErrors) {
|
|
25798
|
+
const prefix = issue2.specId ? `[${issue2.specId}] ` : "";
|
|
25799
|
+
errText += `${prefix}[${issue2.code}] ${issue2.message}
|
|
25800
|
+
`;
|
|
25801
|
+
}
|
|
25802
|
+
return errText;
|
|
25803
|
+
}
|
|
25804
|
+
if (!system) {
|
|
25805
|
+
return "L0 System specification (system.yaml) is missing.";
|
|
25806
|
+
}
|
|
25807
|
+
let subsystems = loadSubsystemSpecs();
|
|
25808
|
+
let components = loadComponentSpecs();
|
|
25809
|
+
let interfaces = loadInterfaceSpecs();
|
|
25810
|
+
let implementations = loadImplementationSpecs();
|
|
25811
|
+
if (options.subsystem) {
|
|
25812
|
+
subsystems = subsystems.filter((s) => s.id === options.subsystem || s.id.startsWith(`${options.subsystem}::`));
|
|
25813
|
+
components = components.filter((c) => c.subsystem === options.subsystem || c.subsystem.startsWith(`${options.subsystem}::`));
|
|
25814
|
+
interfaces = interfaces.filter((i) => {
|
|
25815
|
+
const c = components.find((comp) => comp.id === i.component);
|
|
25816
|
+
return c !== void 0;
|
|
25817
|
+
});
|
|
25818
|
+
implementations = implementations.filter((im) => {
|
|
25819
|
+
const inf = interfaces.find((i) => i.id === im.contract);
|
|
25820
|
+
return inf !== void 0;
|
|
25821
|
+
});
|
|
25822
|
+
}
|
|
25823
|
+
let output = "";
|
|
25824
|
+
const componentScores = /* @__PURE__ */ new Map();
|
|
25825
|
+
for (const comp of components) {
|
|
25826
|
+
let score = 20;
|
|
25827
|
+
const intf = interfaces.find((i) => i.component === comp.id);
|
|
25828
|
+
if (intf) {
|
|
25829
|
+
score += 30;
|
|
25830
|
+
}
|
|
25831
|
+
const impl = implementations.find((im) => intf && im.contract === intf.id);
|
|
25832
|
+
if (impl) {
|
|
25833
|
+
score += 30;
|
|
25834
|
+
const sourceFiles = implementationSourceFiles(impl);
|
|
25835
|
+
if (sourceFiles.length > 0 && sourceFiles.every((f) => pathExists(fromProjectRoot(f)))) {
|
|
25836
|
+
score += 20;
|
|
25837
|
+
}
|
|
25838
|
+
}
|
|
25839
|
+
const isDraft = comp.status === "draft" || comp.status === "design" || intf && (intf.status === "draft" || intf.status === "design") || impl && (impl.status === "draft" || impl.status === "design");
|
|
25840
|
+
if (isDraft) {
|
|
25841
|
+
score = Math.min(score, 50);
|
|
25842
|
+
}
|
|
25843
|
+
componentScores.set(comp.id, score);
|
|
25844
|
+
}
|
|
25845
|
+
const getSubsystemScore = (subId) => {
|
|
25846
|
+
const sub = subsystems.find((s) => s.id === subId);
|
|
25847
|
+
if (!sub) return 0;
|
|
25848
|
+
const subComps = components.filter((c) => c.subsystem === subId);
|
|
25849
|
+
if (subComps.length === 0) return 0;
|
|
25850
|
+
const totalScore = subComps.reduce((acc, c) => acc + (componentScores.get(c.id) ?? 0), 0);
|
|
25851
|
+
let avg = Math.round(totalScore / subComps.length);
|
|
25852
|
+
if (sub.status === "draft" || sub.status === "design") {
|
|
25853
|
+
avg = Math.min(avg, 50);
|
|
25854
|
+
}
|
|
25855
|
+
return avg;
|
|
25856
|
+
};
|
|
25857
|
+
const totalSubsystemsScore = subsystems.reduce((acc, s) => acc + getSubsystemScore(s.id), 0);
|
|
25858
|
+
const systemScore = subsystems.length > 0 ? Math.round(totalSubsystemsScore / subsystems.length) : 0;
|
|
25859
|
+
output += `\u25CF System: ${system.name} (${systemScore}% Complete)
|
|
25860
|
+
`;
|
|
25861
|
+
for (let i = 0; i < subsystems.length; i++) {
|
|
25862
|
+
const sub = subsystems[i];
|
|
25863
|
+
const isLastSub = i === subsystems.length - 1;
|
|
25864
|
+
const subPrefix = isLastSub ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
25865
|
+
const subIndent = isLastSub ? " " : "\u2502 ";
|
|
25866
|
+
const subScore = getSubsystemScore(sub.id);
|
|
25867
|
+
const subStatusStr = sub.status !== "complete" ? ` [${sub.status}]` : "";
|
|
25868
|
+
output += `${subPrefix}[Subsystem] ${sub.id}${subStatusStr} (${subScore}%)
|
|
25869
|
+
`;
|
|
25870
|
+
const subComps = components.filter((c) => c.subsystem === sub.id);
|
|
25871
|
+
for (let j = 0; j < subComps.length; j++) {
|
|
25872
|
+
const comp = subComps[j];
|
|
25873
|
+
const isLastComp = j === subComps.length - 1;
|
|
25874
|
+
const compPrefix = isLastComp ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
25875
|
+
const compIndent = isLastComp ? " " : "\u2502 ";
|
|
25876
|
+
const compScore = componentScores.get(comp.id) ?? 0;
|
|
25877
|
+
const compStatusStr = comp.status !== "complete" ? ` [${comp.status}]` : "";
|
|
25878
|
+
output += `${subIndent}${compPrefix}[Component: ${comp.componentType}] ${comp.id}${compStatusStr} (${compScore}%)
|
|
25879
|
+
`;
|
|
25880
|
+
const intf = interfaces.find((inf) => inf.component === comp.id);
|
|
25881
|
+
const impl = implementations.find((im) => intf && im.contract === intf.id);
|
|
25882
|
+
const intfPrefix = intf && impl ? "\u251C\u2500\u2500 " : "\u2514\u2500\u2500 ";
|
|
25883
|
+
if (intf) {
|
|
25884
|
+
const intfStatusStr = intf.status !== "complete" ? ` [${intf.status}]` : "";
|
|
25885
|
+
output += `${subIndent}${compIndent}${intfPrefix}Interface: ${intf.id}${intfStatusStr} (${intf.methods.length} methods)
|
|
25886
|
+
`;
|
|
25887
|
+
} else {
|
|
25888
|
+
output += `${subIndent}${compIndent}${intfPrefix}Interface: Missing (-30%)
|
|
25889
|
+
`;
|
|
25890
|
+
}
|
|
25891
|
+
if (impl) {
|
|
25892
|
+
const implStatusStr = impl.status !== "complete" ? ` [${impl.status}]` : "";
|
|
25893
|
+
const methodsWithOwnPath = impl.methods.filter((m) => m.sourcePath);
|
|
25894
|
+
let pathStr;
|
|
25895
|
+
if (impl.sourcePath) {
|
|
25896
|
+
pathStr = pathExists(fromProjectRoot(impl.sourcePath)) ? ` -> ${impl.sourcePath}` : ` -> ${impl.sourcePath} (File Missing!)`;
|
|
25897
|
+
} else if (methodsWithOwnPath.length > 0) {
|
|
25898
|
+
pathStr = "";
|
|
25899
|
+
} else {
|
|
25900
|
+
pathStr = " (No source path)";
|
|
25901
|
+
}
|
|
25902
|
+
output += `${subIndent}${compIndent}\u2514\u2500\u2500 Implementation: ${impl.id}${implStatusStr}${pathStr}
|
|
25903
|
+
`;
|
|
25904
|
+
const methodIndent = `${subIndent}${compIndent} `;
|
|
25905
|
+
for (let k = 0; k < methodsWithOwnPath.length; k++) {
|
|
25906
|
+
const method = methodsWithOwnPath[k];
|
|
25907
|
+
const isLastMethod = k === methodsWithOwnPath.length - 1;
|
|
25908
|
+
const methodPrefix = isLastMethod ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
25909
|
+
const methodPath = method.sourcePath;
|
|
25910
|
+
const fileMissing = !pathExists(fromProjectRoot(methodPath));
|
|
25911
|
+
output += `${methodIndent}${methodPrefix}method ${method.name} -> ${methodPath}${fileMissing ? " (File Missing!)" : ""}
|
|
25912
|
+
`;
|
|
25913
|
+
}
|
|
25914
|
+
} else {
|
|
25915
|
+
output += `${subIndent}${compIndent}\u2514\u2500\u2500 Implementation: Missing (-30%)
|
|
25916
|
+
`;
|
|
25917
|
+
}
|
|
25918
|
+
}
|
|
25919
|
+
}
|
|
25920
|
+
return output;
|
|
27276
25921
|
}
|
|
27277
25922
|
|
|
27278
25923
|
// src/core/index.ts
|
|
@@ -27348,6 +25993,18 @@ var logger = {
|
|
|
27348
25993
|
}
|
|
27349
25994
|
};
|
|
27350
25995
|
|
|
25996
|
+
// src/core/skills.ts
|
|
25997
|
+
var SKILL_NAMES = ["sdd-architect", "sdd-narrative", "sdd-auditor", "sdd-implement", "sdd-delegate"];
|
|
25998
|
+
function loadProjectConfig3() {
|
|
25999
|
+
return loadProjectConfig();
|
|
26000
|
+
}
|
|
26001
|
+
function activeTargetTypes2() {
|
|
26002
|
+
const config = loadProjectConfig3();
|
|
26003
|
+
if (!config) return [];
|
|
26004
|
+
return activeTargetTypes(config);
|
|
26005
|
+
}
|
|
26006
|
+
var RESOURCE_SKILL_IDS = [...SKILL_NAMES].sort();
|
|
26007
|
+
|
|
27351
26008
|
// src/index.ts
|
|
27352
26009
|
function loadProjectConfig4() {
|
|
27353
26010
|
const config = loadProjectConfig();
|
|
@@ -27363,7 +26020,6 @@ function loadProjectConfig4() {
|
|
|
27363
26020
|
AgentRecordSchema,
|
|
27364
26021
|
AgentStatusSchema,
|
|
27365
26022
|
AgentTemplateSchema,
|
|
27366
|
-
AssertionSelectorSchema,
|
|
27367
26023
|
BACKEND_COMMANDS,
|
|
27368
26024
|
BUILTIN_PROFILES,
|
|
27369
26025
|
BUILTIN_TYPES,
|
|
@@ -27371,8 +26027,6 @@ function loadProjectConfig4() {
|
|
|
27371
26027
|
BuiltinTargetConfigSchema,
|
|
27372
26028
|
BuiltinTargetSchema,
|
|
27373
26029
|
BundleNotFoundError,
|
|
27374
|
-
COMPONENT_AUTH_SOURCE,
|
|
27375
|
-
CONTEXT_PATHS,
|
|
27376
26030
|
CarriedDebtKindSchema,
|
|
27377
26031
|
CarriedDebtSchema,
|
|
27378
26032
|
CarriedFindingSchema,
|
|
@@ -27389,7 +26043,6 @@ function loadProjectConfig4() {
|
|
|
27389
26043
|
CustomTargetSchema,
|
|
27390
26044
|
DEFAULT_TARGET_DIRS,
|
|
27391
26045
|
DatabaseSpecSchema,
|
|
27392
|
-
DeclarativePackSchema,
|
|
27393
26046
|
DependencyClassSchema,
|
|
27394
26047
|
DesignDepthSchema,
|
|
27395
26048
|
DiagramConfigSchema,
|
|
@@ -27405,7 +26058,6 @@ function loadProjectConfig4() {
|
|
|
27405
26058
|
ExternalLinkTypeSchema,
|
|
27406
26059
|
FindingDeclarationSchema,
|
|
27407
26060
|
GITHUB_REPO,
|
|
27408
|
-
GLOBAL_PACKS_DEFAULT,
|
|
27409
26061
|
GeminiExporter,
|
|
27410
26062
|
GroupSpecSchema,
|
|
27411
26063
|
GuaranteeSchema,
|
|
@@ -27413,7 +26065,6 @@ function loadProjectConfig4() {
|
|
|
27413
26065
|
ImplementationSpecSchema,
|
|
27414
26066
|
InterfaceSpecSchema,
|
|
27415
26067
|
InvariantSchema,
|
|
27416
|
-
LanguagePackDefSchema,
|
|
27417
26068
|
LifecycleEntrypointSchema,
|
|
27418
26069
|
LintAllowSchema,
|
|
27419
26070
|
LintConfigSchema,
|
|
@@ -27427,21 +26078,15 @@ function loadProjectConfig4() {
|
|
|
27427
26078
|
NarrativeStepSchema,
|
|
27428
26079
|
NarrativeStepTypeSchema,
|
|
27429
26080
|
OutputTargetSchema,
|
|
27430
|
-
PACK_DIR_ENTRIES,
|
|
27431
26081
|
PATTERN_TYPES,
|
|
27432
26082
|
PROJECT_KINDS,
|
|
27433
|
-
PackAssertionSchema,
|
|
27434
|
-
PackInstructionBlockSchema,
|
|
27435
26083
|
PackSelectionSchema,
|
|
27436
|
-
PackSkillSchema,
|
|
27437
26084
|
ParallelBranchSchema,
|
|
27438
26085
|
PathsConfigSchema,
|
|
27439
|
-
PatternDefSchema,
|
|
27440
26086
|
PatternRefSchema,
|
|
27441
26087
|
PortalAuthSchema,
|
|
27442
26088
|
PortalAuthSchemeSchema,
|
|
27443
26089
|
PortalTypeSchema,
|
|
27444
|
-
ProfileDefSchema,
|
|
27445
26090
|
ProfileSelectionSubjectSchema,
|
|
27446
26091
|
ProjectConfigSchema,
|
|
27447
26092
|
ProjectNotInitializedError,
|
|
@@ -27460,10 +26105,8 @@ function loadProjectConfig4() {
|
|
|
27460
26105
|
STEP_TYPE_FIELDS,
|
|
27461
26106
|
SUPPORTED_ALIASES,
|
|
27462
26107
|
SURFACE_AUDIENCES,
|
|
27463
|
-
SkillResourceNotFoundError,
|
|
27464
26108
|
SpecIdSchema,
|
|
27465
26109
|
SpecStatusSchema,
|
|
27466
|
-
SpecWorkspace,
|
|
27467
26110
|
SubsystemSpecSchema,
|
|
27468
26111
|
SurfaceAudienceSchema,
|
|
27469
26112
|
SurfaceContractEntrySchema,
|
|
@@ -27483,9 +26126,6 @@ function loadProjectConfig4() {
|
|
|
27483
26126
|
TypeKindSchema,
|
|
27484
26127
|
TypeMethodSchema,
|
|
27485
26128
|
TypeSpecSchema,
|
|
27486
|
-
UNVERSIONED,
|
|
27487
|
-
UnknownAgentError,
|
|
27488
|
-
VariantDefSchema,
|
|
27489
26129
|
WAIRON_MANAGED_BANNER,
|
|
27490
26130
|
WAIRON_MANAGED_MARKER,
|
|
27491
26131
|
WAIRON_VERSION,
|
|
@@ -27496,44 +26136,28 @@ function loadProjectConfig4() {
|
|
|
27496
26136
|
aiDirAt,
|
|
27497
26137
|
aiPathsAt,
|
|
27498
26138
|
ambiguityMessage,
|
|
27499
|
-
applySpecStatus,
|
|
27500
26139
|
approvalRecord,
|
|
27501
|
-
|
|
26140
|
+
approvalVerdict,
|
|
27502
26141
|
assertProjectInitialized,
|
|
27503
|
-
assertionFullCode,
|
|
27504
|
-
audienceRank,
|
|
27505
26142
|
backendCommand,
|
|
27506
|
-
backfillChainedSubprojectConfigs,
|
|
27507
26143
|
buildCanvasDataModel,
|
|
27508
|
-
buildGraphModel,
|
|
27509
26144
|
buildProjectGraph,
|
|
27510
26145
|
buildRuleContext,
|
|
27511
|
-
buildServerInstructions,
|
|
27512
|
-
buildTreeArchive,
|
|
27513
26146
|
callSitesOf,
|
|
27514
26147
|
captureApprovedSpecs,
|
|
27515
|
-
checkSkillFreshness,
|
|
27516
|
-
clearLoaderIssues,
|
|
27517
26148
|
cognitiveScore,
|
|
27518
|
-
collectPromotableSpecs,
|
|
27519
|
-
commitStagedTree,
|
|
27520
26149
|
complexityLevel,
|
|
27521
26150
|
composeAgentBrief,
|
|
27522
26151
|
composeRuleSequence,
|
|
27523
|
-
composeVariantGuidance,
|
|
27524
|
-
computeGateStateId,
|
|
27525
|
-
computePackDigest,
|
|
27526
26152
|
computeStateId,
|
|
27527
26153
|
computeStateIdAt,
|
|
27528
26154
|
conceptNoun,
|
|
27529
26155
|
consumedContractInputs,
|
|
27530
|
-
contextDir,
|
|
27531
26156
|
createAgentRecord,
|
|
27532
26157
|
createChainedSubsystem,
|
|
27533
26158
|
createEmptyRegistry,
|
|
27534
26159
|
createEmptyTopologyConfig,
|
|
27535
26160
|
createProjectConfig,
|
|
27536
|
-
createStagingDir,
|
|
27537
26161
|
currentChildPins,
|
|
27538
26162
|
declaredPackNames,
|
|
27539
26163
|
declaredProfileIds,
|
|
@@ -27543,129 +26167,82 @@ function loadProjectConfig4() {
|
|
|
27543
26167
|
defaultPackSelections,
|
|
27544
26168
|
defaultTargetConfig,
|
|
27545
26169
|
deleteComponentSpec,
|
|
27546
|
-
deleteGroupSpec,
|
|
27547
26170
|
deleteImplementationSpec,
|
|
27548
26171
|
deleteInterfaceSpec,
|
|
27549
26172
|
deleteSubsystemSpec,
|
|
27550
26173
|
deleteTypeSpec,
|
|
27551
26174
|
deregisterPackRef,
|
|
27552
26175
|
deriveExecutionProfile,
|
|
27553
|
-
|
|
26176
|
+
derivedDocPaths,
|
|
27554
26177
|
detectDomainCandidates,
|
|
27555
|
-
diagnoseProjectPacks,
|
|
27556
26178
|
diagramSetIndex,
|
|
27557
26179
|
diffAgainstApproval,
|
|
27558
26180
|
diffSize,
|
|
27559
|
-
discardStagingDir,
|
|
27560
26181
|
discoverPacks,
|
|
27561
26182
|
dryRunSerializeSpecs,
|
|
27562
26183
|
effectiveDetail,
|
|
27563
26184
|
emptyExtensions,
|
|
27564
26185
|
ensureDir,
|
|
27565
26186
|
ensureProjectInitialized,
|
|
27566
|
-
exportSddSkills,
|
|
27567
26187
|
exportSpecTree,
|
|
27568
|
-
exportSurface,
|
|
27569
26188
|
externalizeSubsystem,
|
|
27570
|
-
extractTreeArchive,
|
|
27571
26189
|
extractTypeIdentifiers,
|
|
27572
26190
|
factsFor,
|
|
27573
26191
|
fieldTypeRefs,
|
|
27574
26192
|
fieldTypesOf,
|
|
27575
|
-
findChainingParent,
|
|
27576
|
-
findChainingSubprojectsMissingConfig,
|
|
27577
|
-
findLegacySpecFiles,
|
|
27578
26193
|
findProjectRoot,
|
|
27579
26194
|
findSystemRoot,
|
|
27580
|
-
findTestsReferencing,
|
|
27581
|
-
fromOpenApi,
|
|
27582
26195
|
fromProjectRoot,
|
|
27583
26196
|
generateAgent,
|
|
27584
26197
|
generateAll,
|
|
27585
26198
|
generateComponentDiagram,
|
|
27586
26199
|
generateDiagramSet,
|
|
27587
26200
|
generateSequenceDiagram,
|
|
27588
|
-
getComponentPath,
|
|
27589
26201
|
getExporter,
|
|
27590
|
-
getGroupPath,
|
|
27591
|
-
getImplementationPath,
|
|
27592
|
-
getInterfacePath,
|
|
27593
|
-
getLoaderIssues,
|
|
27594
26202
|
getProjectRoot,
|
|
27595
26203
|
getProjectRootOverride,
|
|
27596
26204
|
getRequestParentReach,
|
|
27597
26205
|
getRequestProjectRoot,
|
|
27598
|
-
|
|
27599
|
-
getSubprojectPrefix,
|
|
27600
|
-
getSubsystemPath,
|
|
27601
|
-
getTypePath,
|
|
26206
|
+
getStatusReport,
|
|
27602
26207
|
globalGuideFilePath,
|
|
27603
26208
|
globalPacksDir,
|
|
27604
|
-
globalPacksEnabled,
|
|
27605
26209
|
globalTemplatesDir,
|
|
27606
|
-
globalVariantsDir,
|
|
27607
|
-
hasArchitectureContext,
|
|
27608
|
-
hasAuthoredSpecs,
|
|
27609
26210
|
hasContext,
|
|
27610
26211
|
hasFunctionBody,
|
|
27611
|
-
hasSpecTree,
|
|
27612
26212
|
headNoun,
|
|
27613
26213
|
holdsState,
|
|
27614
26214
|
implementationSourceFiles,
|
|
27615
26215
|
importBindingOf,
|
|
27616
26216
|
importSpecTree,
|
|
27617
|
-
importSurface,
|
|
27618
|
-
ineffectiveDeltaPaths,
|
|
27619
26217
|
injectGuide,
|
|
27620
|
-
inspectChainedRoots,
|
|
27621
|
-
inspectTreeArchive,
|
|
27622
26218
|
installPackFromDirectory,
|
|
27623
26219
|
interfaceGenericParameters,
|
|
27624
26220
|
internalizeSubsystem,
|
|
27625
|
-
invalidateSpecCache,
|
|
27626
26221
|
isDraftSubsystem,
|
|
27627
26222
|
isLogic,
|
|
27628
|
-
isOpenApiDocument,
|
|
27629
26223
|
isPattern,
|
|
27630
26224
|
isProjectInitialized,
|
|
27631
26225
|
isProvidedBy,
|
|
27632
26226
|
isRetired,
|
|
27633
|
-
listChainedRoots,
|
|
27634
26227
|
listDirectChainedSubprojects,
|
|
27635
|
-
listExternalInterfaces,
|
|
27636
26228
|
listFiles,
|
|
27637
26229
|
listFilesRecursive,
|
|
27638
26230
|
listInstalledPacks,
|
|
27639
|
-
listMountSnapshots,
|
|
27640
|
-
listProjectVariants,
|
|
27641
|
-
listResources,
|
|
27642
|
-
listRules,
|
|
27643
|
-
listSkillNames,
|
|
27644
|
-
listSkillResources,
|
|
27645
|
-
listSnapshots,
|
|
27646
|
-
listTemplateIds,
|
|
27647
|
-
loadAgentOverride,
|
|
27648
26231
|
loadComponentSpec,
|
|
27649
26232
|
loadComponentSpecs,
|
|
27650
26233
|
loadExtensionPacks,
|
|
27651
26234
|
loadExtensions,
|
|
27652
|
-
loadGroupSpec,
|
|
27653
|
-
loadGroupSpecs,
|
|
27654
26235
|
loadImplementationSpec,
|
|
27655
26236
|
loadImplementationSpecs,
|
|
27656
26237
|
loadInterfaceSpec,
|
|
27657
26238
|
loadInterfaceSpecs,
|
|
27658
|
-
loadMountSurfaceSnapshots,
|
|
27659
26239
|
loadProjectConfig,
|
|
27660
26240
|
loadProjectExtensions,
|
|
27661
|
-
loadProjectVariants,
|
|
27662
26241
|
loadRegistry,
|
|
27663
26242
|
loadSpecGraph,
|
|
27664
26243
|
loadSubsystemSpec,
|
|
27665
26244
|
loadSubsystemSpecs,
|
|
27666
|
-
loadSurfaceSnapshots,
|
|
27667
26245
|
loadSystemSpec,
|
|
27668
|
-
loadTemplate,
|
|
27669
26246
|
loadTopologyConfig,
|
|
27670
26247
|
loadTypeSpec,
|
|
27671
26248
|
loadTypeSpecs,
|
|
@@ -27683,53 +26260,30 @@ function loadProjectConfig4() {
|
|
|
27683
26260
|
moveSubsystemProject,
|
|
27684
26261
|
movedChildren,
|
|
27685
26262
|
narrativeStepForeignFields,
|
|
27686
|
-
normalizeApprover,
|
|
27687
|
-
normalizeComponentLayout,
|
|
27688
|
-
packDirEntry,
|
|
27689
|
-
packEntryLabel,
|
|
27690
|
-
packEntryRef,
|
|
27691
26263
|
packStoreDir,
|
|
27692
26264
|
parseDeclaredCall,
|
|
27693
|
-
parseTemplate,
|
|
27694
26265
|
parseYaml,
|
|
27695
26266
|
passesIntentFloor,
|
|
27696
26267
|
pathExists,
|
|
27697
26268
|
pathKey,
|
|
27698
|
-
pinFamilySurfaces,
|
|
27699
|
-
pinInstalledPacksAsSelections,
|
|
27700
|
-
projectChildSurface,
|
|
27701
26269
|
projectConfigExists,
|
|
27702
|
-
projectOwnSurface,
|
|
27703
|
-
projectSubsystemSurface,
|
|
27704
26270
|
provisionProject,
|
|
27705
26271
|
qualifiedTypeId,
|
|
27706
|
-
readArchitectureContext,
|
|
27707
26272
|
readFileOrNull,
|
|
27708
26273
|
readJsonFile,
|
|
27709
26274
|
readLockRecord,
|
|
27710
|
-
readLockRecordAt,
|
|
27711
26275
|
readLockState,
|
|
27712
|
-
readManifest,
|
|
27713
|
-
readProjectContext,
|
|
27714
|
-
readResource,
|
|
27715
|
-
readSkillResource,
|
|
27716
26276
|
readStampVersion,
|
|
27717
26277
|
readYamlFile,
|
|
27718
|
-
rebaseProjectVariants,
|
|
27719
|
-
rebaseReference,
|
|
27720
26278
|
recordProfileSelection,
|
|
27721
26279
|
registerExporter,
|
|
27722
26280
|
registerPackRef,
|
|
27723
26281
|
reinjectLocalGuides,
|
|
27724
26282
|
removeDomain,
|
|
27725
26283
|
removePackSelection,
|
|
27726
|
-
removeSnapshot,
|
|
27727
26284
|
renameComponent,
|
|
27728
26285
|
renameMethod,
|
|
27729
26286
|
renderDiagram,
|
|
27730
|
-
renderDomainsDoc,
|
|
27731
|
-
renderTemplateInstructions,
|
|
27732
|
-
renderWaironGuide,
|
|
27733
26287
|
repairForeignStepFields,
|
|
27734
26288
|
resolveAgentTopology,
|
|
27735
26289
|
resolveBudget,
|
|
@@ -27738,47 +26292,31 @@ function loadProjectConfig4() {
|
|
|
27738
26292
|
resolveExpectedOutputPaths,
|
|
27739
26293
|
resolveImport,
|
|
27740
26294
|
resolveInstalledPack,
|
|
27741
|
-
resolvePackRef,
|
|
27742
26295
|
resolveSubprojectForNamespace,
|
|
27743
|
-
resolveVariantGuidance,
|
|
27744
|
-
restoreSpecFiles,
|
|
27745
26296
|
retireSpecialists,
|
|
27746
|
-
rewriteSpecRefs,
|
|
27747
26297
|
runWithProjectBinding,
|
|
27748
26298
|
runWithProjectRoot,
|
|
27749
26299
|
sameContract,
|
|
27750
26300
|
saveComponentSpec,
|
|
27751
|
-
saveGroupSpec,
|
|
27752
26301
|
saveImplementationSpec,
|
|
27753
26302
|
saveInterfaceSpec,
|
|
27754
|
-
saveSnapshot,
|
|
27755
26303
|
saveSubsystemSpec,
|
|
27756
26304
|
saveSystemSpec,
|
|
27757
26305
|
saveTopologyConfig,
|
|
27758
26306
|
saveTypeSpec,
|
|
27759
|
-
scanAllSpecs,
|
|
27760
26307
|
serializeYaml,
|
|
27761
26308
|
setExecutionTier,
|
|
27762
26309
|
setLogLevel,
|
|
27763
26310
|
setProjectRoot,
|
|
27764
26311
|
setProjectType,
|
|
27765
26312
|
settledSpecPaths,
|
|
27766
|
-
skillExtendErrors,
|
|
27767
|
-
skillsDirForTarget,
|
|
27768
|
-
snapshotSpecFiles,
|
|
27769
|
-
specChanges,
|
|
27770
|
-
specKind,
|
|
27771
26313
|
specPathsInScope,
|
|
27772
26314
|
splitNamespace,
|
|
27773
|
-
stateIdEquals,
|
|
27774
|
-
stateIdString,
|
|
27775
26315
|
stepConfigVerdict,
|
|
27776
26316
|
stepFieldsFor,
|
|
27777
26317
|
stepGraph,
|
|
27778
26318
|
syncContextFiles,
|
|
27779
26319
|
toMarkdown,
|
|
27780
|
-
toOpenApi,
|
|
27781
|
-
toOpenApiSet,
|
|
27782
26320
|
typeBindingOf,
|
|
27783
26321
|
typeGenericParameters,
|
|
27784
26322
|
typeMatchesRef,
|
|
@@ -27786,18 +26324,11 @@ function loadProjectConfig4() {
|
|
|
27786
26324
|
uninstallPack,
|
|
27787
26325
|
updateSpec,
|
|
27788
26326
|
upsertPackSelection,
|
|
27789
|
-
validateAsComplete,
|
|
27790
|
-
validateComponentCandidate,
|
|
27791
|
-
validateProjectConfig,
|
|
27792
|
-
validateRegistry,
|
|
27793
26327
|
validateSddTree,
|
|
27794
|
-
workspaceFor,
|
|
27795
|
-
writeArchitectureContext,
|
|
27796
26328
|
writeFile,
|
|
27797
26329
|
writeFileIfChanged,
|
|
27798
26330
|
writeJsonFile,
|
|
27799
26331
|
writeLockRecord,
|
|
27800
|
-
writeProjectContext,
|
|
27801
26332
|
writeRootGuideDelegator,
|
|
27802
26333
|
writeYamlFile
|
|
27803
26334
|
});
|