@wairon/cli 5.1.1-dev.54 → 5.1.1-dev.56
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 +11791 -11748
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +1620 -1566
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1233,7 +1233,7 @@ var init_defaults = __esm({
|
|
|
1233
1233
|
copilot: ".github/prompts",
|
|
1234
1234
|
codex: ".codex/agents"
|
|
1235
1235
|
};
|
|
1236
|
-
WAIRON_VERSION = "5.1.1-dev.
|
|
1236
|
+
WAIRON_VERSION = "5.1.1-dev.56";
|
|
1237
1237
|
GITHUB_REPO = "SYW-Apps/Waffle-AIron";
|
|
1238
1238
|
ARCHITECT_AGENT_ID = "agent-architect";
|
|
1239
1239
|
ARCHITECT_TEMPLATE_ID = "architect";
|
|
@@ -3053,204 +3053,97 @@ var init_models = __esm({
|
|
|
3053
3053
|
}
|
|
3054
3054
|
});
|
|
3055
3055
|
|
|
3056
|
-
// src/
|
|
3057
|
-
function
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3056
|
+
// src/config/paths.ts
|
|
3057
|
+
function aiPathsAt(rootDir) {
|
|
3058
|
+
const resolvedRoot = path6.resolve(rootDir);
|
|
3059
|
+
const aiDirAt2 = (...segments) => {
|
|
3060
|
+
const waiPath = path6.join(resolvedRoot, ".wai");
|
|
3061
|
+
const waironPath = path6.join(resolvedRoot, ".wairon");
|
|
3062
|
+
const base = !fs4.existsSync(waiPath) && fs4.existsSync(waironPath) ? waironPath : waiPath;
|
|
3063
|
+
return path6.join(base, ...segments);
|
|
3064
|
+
};
|
|
3065
|
+
const specsDir = () => projectConfigRepositoryAt(resolvedRoot).specsDir();
|
|
3066
|
+
return {
|
|
3067
|
+
root: () => aiDirAt2(),
|
|
3068
|
+
projectConfig: () => aiDirAt2("project.yaml"),
|
|
3069
|
+
topologyConfig: () => aiDirAt2("topology.yaml"),
|
|
3070
|
+
templatesDir: () => aiDirAt2("templates"),
|
|
3071
|
+
rulesDir: () => aiDirAt2("rules"),
|
|
3072
|
+
docsDir: () => aiDirAt2("docs"),
|
|
3073
|
+
generatedDir: () => aiDirAt2("generated"),
|
|
3074
|
+
contextDir: () => aiDirAt2("context"),
|
|
3075
|
+
contextProjectMd: () => aiDirAt2("context", "project.md"),
|
|
3076
|
+
contextArchitectureMd: () => aiDirAt2("context", "architecture.md"),
|
|
3077
|
+
contextDomainsMd: () => aiDirAt2("context", "domains.md"),
|
|
3078
|
+
contextWaironGuideMd: () => aiDirAt2("context", "wairon-guide.md"),
|
|
3079
|
+
specsDir,
|
|
3080
|
+
specsSystem: () => path6.join(specsDir(), ".index.yaml"),
|
|
3081
|
+
specsSubsystemsDir: () => path6.join(specsDir(), "subsystems"),
|
|
3082
|
+
specsComponentsDir: () => path6.join(specsDir(), "components"),
|
|
3083
|
+
specsInterfacesDir: () => path6.join(specsDir(), "interfaces"),
|
|
3084
|
+
specsImplementationsDir: () => path6.join(specsDir(), "implementations"),
|
|
3085
|
+
specsTypesDir: () => path6.join(specsDir(), "types")
|
|
3086
|
+
};
|
|
3070
3087
|
}
|
|
3071
|
-
function
|
|
3072
|
-
|
|
3073
|
-
return readFileOrNull(filePath);
|
|
3088
|
+
function isProjectInitialized() {
|
|
3089
|
+
return projectConfigRepository.exists();
|
|
3074
3090
|
}
|
|
3075
|
-
function
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
for (const file of listFiles(dir, ".yaml")) {
|
|
3079
|
-
seen.add(path6.basename(file, ".yaml"));
|
|
3080
|
-
}
|
|
3091
|
+
function assertProjectInitialized() {
|
|
3092
|
+
if (!isProjectInitialized()) {
|
|
3093
|
+
throw new ProjectNotInitializedError();
|
|
3081
3094
|
}
|
|
3082
|
-
return Array.from(seen).sort();
|
|
3083
|
-
}
|
|
3084
|
-
function templateSearchDirs(globalOverride) {
|
|
3085
|
-
return [
|
|
3086
|
-
AI_PATHS.templatesDir(),
|
|
3087
|
-
// 1. project-local
|
|
3088
|
-
globalTemplatesDir(globalOverride),
|
|
3089
|
-
// 2. global user/org
|
|
3090
|
-
builtinTemplatesDir()
|
|
3091
|
-
// 3. built-in fallback
|
|
3092
|
-
];
|
|
3093
|
-
}
|
|
3094
|
-
function renderTemplateInstructions(template, vars) {
|
|
3095
|
-
return template.instructions.replace(/\{\{(\w+)\}\}/g, (_match, key) => {
|
|
3096
|
-
return key in vars ? vars[key] : `{{${key}}}`;
|
|
3097
|
-
});
|
|
3098
|
-
}
|
|
3099
|
-
function parseTemplate(yamlContent) {
|
|
3100
|
-
return TemplateSchema.parse(parseYaml(yamlContent));
|
|
3101
3095
|
}
|
|
3102
|
-
var path6;
|
|
3103
|
-
var
|
|
3104
|
-
"src/
|
|
3096
|
+
var fs4, path6, AI_PATHS;
|
|
3097
|
+
var init_paths = __esm({
|
|
3098
|
+
"src/config/paths.ts"() {
|
|
3105
3099
|
"use strict";
|
|
3100
|
+
fs4 = __toESM(require("fs"));
|
|
3106
3101
|
path6 = __toESM(require("path"));
|
|
3107
3102
|
init_fs();
|
|
3108
|
-
init_yaml();
|
|
3109
3103
|
init_errors();
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
if (MECHANICAL_STEREOTYPES.has(tag)) return "mechanical";
|
|
3133
|
-
}
|
|
3134
|
-
if (MANAGER_TEMPLATES.has(agent.template)) return "deep";
|
|
3135
|
-
if (agent.template === "reviewer") return "deep";
|
|
3136
|
-
if (agent.template === "tester") return "standard";
|
|
3137
|
-
return "standard";
|
|
3138
|
-
}
|
|
3139
|
-
function deriveWrites(agent) {
|
|
3140
|
-
return !READ_ONLY_TEMPLATES.has(agent.template);
|
|
3141
|
-
}
|
|
3142
|
-
function deriveExecutionProfile(agent) {
|
|
3143
|
-
const breadth = deriveBreadth(agent);
|
|
3144
|
-
const reasoningDepth = deriveReasoningDepth(agent);
|
|
3145
|
-
const writes = deriveWrites(agent);
|
|
3146
|
-
const delegates = MANAGER_TEMPLATES.has(agent.template);
|
|
3147
|
-
const because = [];
|
|
3148
|
-
if (delegates) {
|
|
3149
|
-
because.push(`${agent.template} routes work rather than performing it`);
|
|
3150
|
-
}
|
|
3151
|
-
const stereotype = agent.tags.find(
|
|
3152
|
-
(t) => MECHANICAL_STEREOTYPES.has(t) || DEEP_STEREOTYPES.has(t)
|
|
3153
|
-
);
|
|
3154
|
-
if (stereotype) {
|
|
3155
|
-
because.push(
|
|
3156
|
-
MECHANICAL_STEREOTYPES.has(stereotype) ? `${stereotype} work is specified by its contract and narrative` : `${stereotype} carries decision logic`
|
|
3157
|
-
);
|
|
3158
|
-
}
|
|
3159
|
-
because.push(
|
|
3160
|
-
breadth === "wide" ? "reads broadly across the tree" : breadth === "moderate" ? `spans ${agent.ownedPaths.length} owned path(s)` : "scoped to a small owned set"
|
|
3161
|
-
);
|
|
3162
|
-
if (!writes) because.push("read-only");
|
|
3163
|
-
return {
|
|
3164
|
-
breadth,
|
|
3165
|
-
writes,
|
|
3166
|
-
reasoningDepth,
|
|
3167
|
-
delegates,
|
|
3168
|
-
rationale: because.join("; ")
|
|
3169
|
-
};
|
|
3170
|
-
}
|
|
3171
|
-
var MECHANICAL_STEREOTYPES, DEEP_STEREOTYPES, MANAGER_TEMPLATES, READ_ONLY_TEMPLATES, WIDE_PATH_COUNT, MODERATE_PATH_COUNT;
|
|
3172
|
-
var init_execution_profile = __esm({
|
|
3173
|
-
"src/core/execution_profile.ts"() {
|
|
3174
|
-
"use strict";
|
|
3175
|
-
MECHANICAL_STEREOTYPES = /* @__PURE__ */ new Set(["store", "index", "registry", "adapter"]);
|
|
3176
|
-
DEEP_STEREOTYPES = /* @__PURE__ */ new Set(["orchestrator", "supervisor", "specialist"]);
|
|
3177
|
-
MANAGER_TEMPLATES = /* @__PURE__ */ new Set(["architect", "domain-owner"]);
|
|
3178
|
-
READ_ONLY_TEMPLATES = /* @__PURE__ */ new Set(["reviewer", "guardian"]);
|
|
3179
|
-
WIDE_PATH_COUNT = 12;
|
|
3180
|
-
MODERATE_PATH_COUNT = 4;
|
|
3104
|
+
init_project_config();
|
|
3105
|
+
AI_PATHS = {
|
|
3106
|
+
root: () => aiPathsAt(getProjectRoot()).root(),
|
|
3107
|
+
projectConfig: () => aiPathsAt(getProjectRoot()).projectConfig(),
|
|
3108
|
+
topologyConfig: () => aiPathsAt(getProjectRoot()).topologyConfig(),
|
|
3109
|
+
templatesDir: () => aiPathsAt(getProjectRoot()).templatesDir(),
|
|
3110
|
+
rulesDir: () => aiPathsAt(getProjectRoot()).rulesDir(),
|
|
3111
|
+
docsDir: () => aiPathsAt(getProjectRoot()).docsDir(),
|
|
3112
|
+
generatedDir: () => aiPathsAt(getProjectRoot()).generatedDir(),
|
|
3113
|
+
contextDir: () => aiPathsAt(getProjectRoot()).contextDir(),
|
|
3114
|
+
contextProjectMd: () => aiPathsAt(getProjectRoot()).contextProjectMd(),
|
|
3115
|
+
contextArchitectureMd: () => aiPathsAt(getProjectRoot()).contextArchitectureMd(),
|
|
3116
|
+
contextDomainsMd: () => aiPathsAt(getProjectRoot()).contextDomainsMd(),
|
|
3117
|
+
contextWaironGuideMd: () => aiPathsAt(getProjectRoot()).contextWaironGuideMd(),
|
|
3118
|
+
specsDir: () => aiPathsAt(getProjectRoot()).specsDir(),
|
|
3119
|
+
specsSystem: () => aiPathsAt(getProjectRoot()).specsSystem(),
|
|
3120
|
+
specsSubsystemsDir: () => aiPathsAt(getProjectRoot()).specsSubsystemsDir(),
|
|
3121
|
+
specsComponentsDir: () => aiPathsAt(getProjectRoot()).specsComponentsDir(),
|
|
3122
|
+
specsInterfacesDir: () => aiPathsAt(getProjectRoot()).specsInterfacesDir(),
|
|
3123
|
+
specsImplementationsDir: () => aiPathsAt(getProjectRoot()).specsImplementationsDir(),
|
|
3124
|
+
specsTypesDir: () => aiPathsAt(getProjectRoot()).specsTypesDir()
|
|
3125
|
+
};
|
|
3181
3126
|
}
|
|
3182
3127
|
});
|
|
3183
3128
|
|
|
3184
|
-
// src/
|
|
3185
|
-
function
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
return "small";
|
|
3192
|
-
case "standard":
|
|
3193
|
-
return "standard";
|
|
3194
|
-
case "deep":
|
|
3195
|
-
return "large";
|
|
3196
|
-
}
|
|
3197
|
-
}
|
|
3198
|
-
function stepDown(tier, steps) {
|
|
3199
|
-
const i = TIER_STEPS.indexOf(tier);
|
|
3200
|
-
return TIER_STEPS[Math.max(0, i - steps)];
|
|
3201
|
-
}
|
|
3202
|
-
function maxTurnsFor(profile, tier) {
|
|
3203
|
-
if (!atLeast(tier, "default")) return void 0;
|
|
3204
|
-
const ceiling = profile.breadth === "wide" ? 60 : profile.breadth === "moderate" ? 40 : 25;
|
|
3205
|
-
return atLeast(tier, "aggressive") ? Math.round(ceiling / 2) : ceiling;
|
|
3206
|
-
}
|
|
3207
|
-
function effortFor(profile, tier) {
|
|
3208
|
-
if (!atLeast(tier, "trade")) return void 0;
|
|
3209
|
-
if (profile.reasoningDepth === "mechanical") {
|
|
3210
|
-
return atLeast(tier, "aggressive") ? "low" : "medium";
|
|
3211
|
-
}
|
|
3212
|
-
return void 0;
|
|
3213
|
-
}
|
|
3214
|
-
function toolClassFor(profile) {
|
|
3215
|
-
return profile.writes ? "implement" : "read-only";
|
|
3216
|
-
}
|
|
3217
|
-
function mcpFor(profile, tier) {
|
|
3218
|
-
if (!atLeast(tier, "free")) return "all";
|
|
3219
|
-
if (profile.delegates) return "project";
|
|
3220
|
-
return profile.breadth === "wide" ? "project" : "none";
|
|
3129
|
+
// src/config/loader.ts
|
|
3130
|
+
function loadTopologyConfig() {
|
|
3131
|
+
assertProjectInitialized();
|
|
3132
|
+
if (!pathExists(AI_PATHS.topologyConfig())) return createEmptyTopologyConfig();
|
|
3133
|
+
const raw = readYamlFile(AI_PATHS.topologyConfig());
|
|
3134
|
+
if (!raw) return createEmptyTopologyConfig();
|
|
3135
|
+
return TopologyConfigSchema.parse(raw);
|
|
3221
3136
|
}
|
|
3222
|
-
function
|
|
3223
|
-
|
|
3224
|
-
if (tier === "off") return void 0;
|
|
3225
|
-
let modelTier = baseModelTier(profile);
|
|
3226
|
-
if (atLeast(tier, "trade") && profile.reasoningDepth === "standard") {
|
|
3227
|
-
modelTier = stepDown(modelTier, 1);
|
|
3228
|
-
}
|
|
3229
|
-
if (atLeast(tier, "aggressive") && profile.reasoningDepth !== "deep") {
|
|
3230
|
-
modelTier = "small";
|
|
3231
|
-
}
|
|
3232
|
-
const budget = {
|
|
3233
|
-
// At `free` no model selection is expressed at all — that tier is defined
|
|
3234
|
-
// as having no quality tradeoff, and choosing a model is a quality
|
|
3235
|
-
// decision. Leaving it absent is not the same as choosing a default.
|
|
3236
|
-
modelTier: atLeast(tier, "default") ? modelTier : void 0,
|
|
3237
|
-
effort: effortFor(profile, tier),
|
|
3238
|
-
maxTurns: maxTurnsFor(profile, tier),
|
|
3239
|
-
toolClass: toolClassFor(profile),
|
|
3240
|
-
// Only managers may spawn. Withholding the tool from workers is what stops
|
|
3241
|
-
// a worker quietly becoming a second orchestrator three levels down.
|
|
3242
|
-
allowNestedDelegation: profile.delegates,
|
|
3243
|
-
mcp: mcpFor(profile, tier)
|
|
3244
|
-
};
|
|
3245
|
-
const override = config.overrides[agentId];
|
|
3246
|
-
return override ? { ...budget, ...override } : budget;
|
|
3137
|
+
function saveTopologyConfig(config) {
|
|
3138
|
+
writeYamlFile(AI_PATHS.topologyConfig(), config);
|
|
3247
3139
|
}
|
|
3248
|
-
var
|
|
3249
|
-
|
|
3250
|
-
"src/core/budget_policy.ts"() {
|
|
3140
|
+
var init_loader = __esm({
|
|
3141
|
+
"src/config/loader.ts"() {
|
|
3251
3142
|
"use strict";
|
|
3252
|
-
|
|
3253
|
-
|
|
3143
|
+
init_fs();
|
|
3144
|
+
init_yaml();
|
|
3145
|
+
init_models();
|
|
3146
|
+
init_paths();
|
|
3254
3147
|
}
|
|
3255
3148
|
});
|
|
3256
3149
|
|
|
@@ -3329,14 +3222,14 @@ function describeApprover(who) {
|
|
|
3329
3222
|
}
|
|
3330
3223
|
function readLockRecord() {
|
|
3331
3224
|
try {
|
|
3332
|
-
return normalizeRecord(JSON.parse(
|
|
3225
|
+
return normalizeRecord(JSON.parse(fs5.readFileSync(lockPath(), "utf8")));
|
|
3333
3226
|
} catch {
|
|
3334
3227
|
return null;
|
|
3335
3228
|
}
|
|
3336
3229
|
}
|
|
3337
3230
|
function readLockRecordAt(root) {
|
|
3338
3231
|
try {
|
|
3339
|
-
return normalizeRecord(JSON.parse(
|
|
3232
|
+
return normalizeRecord(JSON.parse(fs5.readFileSync(aiDirAt(root, "lock.json"), "utf8")));
|
|
3340
3233
|
} catch {
|
|
3341
3234
|
return null;
|
|
3342
3235
|
}
|
|
@@ -3347,10 +3240,10 @@ function normalizeRecord(raw) {
|
|
|
3347
3240
|
}
|
|
3348
3241
|
function writeLockRecord(record) {
|
|
3349
3242
|
const p = lockPath();
|
|
3350
|
-
|
|
3243
|
+
fs5.mkdirSync(path7.dirname(p), { recursive: true });
|
|
3351
3244
|
const tmp = `${p}.tmp`;
|
|
3352
|
-
|
|
3353
|
-
|
|
3245
|
+
fs5.writeFileSync(tmp, JSON.stringify(withSortedMaps(record), null, 2) + "\n");
|
|
3246
|
+
fs5.renameSync(tmp, p);
|
|
3354
3247
|
}
|
|
3355
3248
|
function withSortedMaps(record) {
|
|
3356
3249
|
const sorted = (m) => {
|
|
@@ -3367,11 +3260,11 @@ function withSortedMaps(record) {
|
|
|
3367
3260
|
...children ? { children } : {}
|
|
3368
3261
|
};
|
|
3369
3262
|
}
|
|
3370
|
-
var
|
|
3263
|
+
var fs5, path7;
|
|
3371
3264
|
var init_lockfile = __esm({
|
|
3372
3265
|
"src/core/lockfile.ts"() {
|
|
3373
3266
|
"use strict";
|
|
3374
|
-
|
|
3267
|
+
fs5 = __toESM(require("fs"));
|
|
3375
3268
|
path7 = __toESM(require("path"));
|
|
3376
3269
|
init_fs();
|
|
3377
3270
|
}
|
|
@@ -3388,24 +3281,24 @@ function listSpecFiles(specsDir) {
|
|
|
3388
3281
|
return listFilesRecursive(specsDir, SPEC_FILE_EXTENSION);
|
|
3389
3282
|
}
|
|
3390
3283
|
function removeSpecFile(filePath, specsRoot) {
|
|
3391
|
-
if (!
|
|
3392
|
-
|
|
3284
|
+
if (!fs6.existsSync(filePath)) return false;
|
|
3285
|
+
fs6.unlinkSync(filePath);
|
|
3393
3286
|
pruneEmptyDirs(path8.dirname(filePath), path8.resolve(specsRoot));
|
|
3394
3287
|
return true;
|
|
3395
3288
|
}
|
|
3396
3289
|
function pruneEmptyDirs(dir, specsRoot) {
|
|
3397
3290
|
let at = dir;
|
|
3398
3291
|
while (at !== specsRoot && at.startsWith(specsRoot)) {
|
|
3399
|
-
if (!
|
|
3400
|
-
|
|
3292
|
+
if (!fs6.existsSync(at) || fs6.readdirSync(at).length > 0) return;
|
|
3293
|
+
fs6.rmdirSync(at);
|
|
3401
3294
|
at = path8.dirname(at);
|
|
3402
3295
|
}
|
|
3403
3296
|
}
|
|
3404
|
-
var
|
|
3297
|
+
var fs6, path8, SPEC_FILE_EXTENSION;
|
|
3405
3298
|
var init_spec_files = __esm({
|
|
3406
3299
|
"src/core/spec-files.ts"() {
|
|
3407
3300
|
"use strict";
|
|
3408
|
-
|
|
3301
|
+
fs6 = __toESM(require("fs"));
|
|
3409
3302
|
path8 = __toESM(require("path"));
|
|
3410
3303
|
init_fs();
|
|
3411
3304
|
init_yaml();
|
|
@@ -4157,8 +4050,8 @@ function loadCytoscapeLib() {
|
|
|
4157
4050
|
// dist (library entry)
|
|
4158
4051
|
];
|
|
4159
4052
|
for (const p of candidates) {
|
|
4160
|
-
if (
|
|
4161
|
-
return
|
|
4053
|
+
if (fs7.existsSync(p)) {
|
|
4054
|
+
return fs7.readFileSync(p, "utf-8").replace(/<\/script/gi, "<\\/script");
|
|
4162
4055
|
}
|
|
4163
4056
|
}
|
|
4164
4057
|
throw new Error("Vendored cytoscape bundle not found (templates/canvas/cytoscape.min.js) \u2014 the wairon installation is incomplete.");
|
|
@@ -4170,11 +4063,11 @@ function renderCanvasHtml(model) {
|
|
|
4170
4063
|
function escapeHtml(s) {
|
|
4171
4064
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
4172
4065
|
}
|
|
4173
|
-
var
|
|
4066
|
+
var fs7, path9, CANVAS_TEMPLATE;
|
|
4174
4067
|
var init_canvas = __esm({
|
|
4175
4068
|
"src/core/canvas.ts"() {
|
|
4176
4069
|
"use strict";
|
|
4177
|
-
|
|
4070
|
+
fs7 = __toESM(require("fs"));
|
|
4178
4071
|
path9 = __toESM(require("path"));
|
|
4179
4072
|
init_specs2();
|
|
4180
4073
|
init_models();
|
|
@@ -8370,7 +8263,7 @@ function packStoreDir() {
|
|
|
8370
8263
|
function packFiles(dir, prefix = "") {
|
|
8371
8264
|
let entries;
|
|
8372
8265
|
try {
|
|
8373
|
-
entries =
|
|
8266
|
+
entries = fs8.readdirSync(dir, { withFileTypes: true });
|
|
8374
8267
|
} catch {
|
|
8375
8268
|
return [];
|
|
8376
8269
|
}
|
|
@@ -8388,7 +8281,7 @@ function computePackDigest(packDir) {
|
|
|
8388
8281
|
const abs = path10.resolve(packDir);
|
|
8389
8282
|
let isFile = false;
|
|
8390
8283
|
try {
|
|
8391
|
-
isFile =
|
|
8284
|
+
isFile = fs8.statSync(abs).isFile();
|
|
8392
8285
|
} catch {
|
|
8393
8286
|
}
|
|
8394
8287
|
const entries = isFile ? [[path10.basename(abs), abs]] : packFiles(abs).map((rel2) => [rel2, path10.join(abs, rel2)]);
|
|
@@ -8396,7 +8289,7 @@ function computePackDigest(packDir) {
|
|
|
8396
8289
|
hash.update(rel2);
|
|
8397
8290
|
hash.update("\0");
|
|
8398
8291
|
try {
|
|
8399
|
-
hash.update(
|
|
8292
|
+
hash.update(fs8.readFileSync(full));
|
|
8400
8293
|
} catch {
|
|
8401
8294
|
}
|
|
8402
8295
|
hash.update("\0");
|
|
@@ -8435,7 +8328,7 @@ function installedFrom(location, name, version) {
|
|
|
8435
8328
|
function versionedEntries(nameDir, fallbackName) {
|
|
8436
8329
|
let versions;
|
|
8437
8330
|
try {
|
|
8438
|
-
versions =
|
|
8331
|
+
versions = fs8.readdirSync(nameDir, { withFileTypes: true });
|
|
8439
8332
|
} catch {
|
|
8440
8333
|
return [];
|
|
8441
8334
|
}
|
|
@@ -8465,7 +8358,7 @@ function listInstalledPacks() {
|
|
|
8465
8358
|
const store = packStoreDir();
|
|
8466
8359
|
let entries;
|
|
8467
8360
|
try {
|
|
8468
|
-
entries =
|
|
8361
|
+
entries = fs8.readdirSync(store, { withFileTypes: true });
|
|
8469
8362
|
} catch {
|
|
8470
8363
|
return [];
|
|
8471
8364
|
}
|
|
@@ -8490,9 +8383,9 @@ function installPackFromDirectory(sourceDir, origin) {
|
|
|
8490
8383
|
const manifest = readManifest(entryFile, path10.dirname(entryFile));
|
|
8491
8384
|
const version = manifest.version && manifest.version.length > 0 ? manifest.version : UNVERSIONED;
|
|
8492
8385
|
const dest = path10.join(packStoreDir(), manifest.name, version);
|
|
8493
|
-
|
|
8494
|
-
|
|
8495
|
-
|
|
8386
|
+
fs8.rmSync(dest, { recursive: true, force: true });
|
|
8387
|
+
fs8.mkdirSync(path10.dirname(dest), { recursive: true });
|
|
8388
|
+
fs8.cpSync(abs, dest, { recursive: true });
|
|
8496
8389
|
const digest2 = computePackDigest(dest);
|
|
8497
8390
|
const record = {
|
|
8498
8391
|
origin,
|
|
@@ -8515,22 +8408,22 @@ function uninstallPack(name, version) {
|
|
|
8515
8408
|
const targets = listInstalledPacks().filter((p) => p.name === name && (!version || p.version === version));
|
|
8516
8409
|
if (targets.length === 0) return false;
|
|
8517
8410
|
for (const target of targets) {
|
|
8518
|
-
|
|
8411
|
+
fs8.rmSync(target.path, { recursive: true, force: true });
|
|
8519
8412
|
const parent = path10.dirname(target.path);
|
|
8520
8413
|
if (path10.resolve(parent) === path10.resolve(packStoreDir())) continue;
|
|
8521
8414
|
try {
|
|
8522
|
-
if (
|
|
8415
|
+
if (fs8.readdirSync(parent).length === 0) fs8.rmdirSync(parent);
|
|
8523
8416
|
} catch {
|
|
8524
8417
|
}
|
|
8525
8418
|
}
|
|
8526
8419
|
return true;
|
|
8527
8420
|
}
|
|
8528
|
-
var crypto2,
|
|
8421
|
+
var crypto2, fs8, path10, UNVERSIONED, INSTALL_RECORD, DIGEST_EXCLUDED, PACK_FILE_RE;
|
|
8529
8422
|
var init_packstore = __esm({
|
|
8530
8423
|
"src/core/packstore.ts"() {
|
|
8531
8424
|
"use strict";
|
|
8532
8425
|
crypto2 = __toESM(require("crypto"));
|
|
8533
|
-
|
|
8426
|
+
fs8 = __toESM(require("fs"));
|
|
8534
8427
|
path10 = __toESM(require("path"));
|
|
8535
8428
|
init_yaml();
|
|
8536
8429
|
init_defaults();
|
|
@@ -8563,14 +8456,14 @@ function globalPacksDir() {
|
|
|
8563
8456
|
function packDirEntry(dir) {
|
|
8564
8457
|
for (const name of PACK_DIR_ENTRIES) {
|
|
8565
8458
|
const p = path11.join(dir, name);
|
|
8566
|
-
if (
|
|
8459
|
+
if (fs9.existsSync(p)) return p;
|
|
8567
8460
|
}
|
|
8568
8461
|
return null;
|
|
8569
8462
|
}
|
|
8570
8463
|
function latestVersionDir(nameDir) {
|
|
8571
8464
|
let versions;
|
|
8572
8465
|
try {
|
|
8573
|
-
versions =
|
|
8466
|
+
versions = fs9.readdirSync(nameDir, { withFileTypes: true });
|
|
8574
8467
|
} catch {
|
|
8575
8468
|
return null;
|
|
8576
8469
|
}
|
|
@@ -8586,7 +8479,7 @@ function latestVersionDir(nameDir) {
|
|
|
8586
8479
|
function discoverPacks(dir) {
|
|
8587
8480
|
let entries;
|
|
8588
8481
|
try {
|
|
8589
|
-
entries =
|
|
8482
|
+
entries = fs9.readdirSync(dir, { withFileTypes: true });
|
|
8590
8483
|
} catch {
|
|
8591
8484
|
return [];
|
|
8592
8485
|
}
|
|
@@ -8632,7 +8525,7 @@ function resolvePackRef(ref, projectRoot) {
|
|
|
8632
8525
|
const pathLike = ref.startsWith(".") || path11.isAbsolute(ref) || isYamlPath(ref);
|
|
8633
8526
|
if (!pathLike) return ref;
|
|
8634
8527
|
const resolved = path11.resolve(projectRoot, ref);
|
|
8635
|
-
if (
|
|
8528
|
+
if (fs9.existsSync(resolved) && fs9.statSync(resolved).isDirectory()) {
|
|
8636
8529
|
const entry = packDirEntry(resolved);
|
|
8637
8530
|
if (!entry) throw new Error(`directory pack has no entry file (${PACK_DIR_ENTRIES.join(" | ")})`);
|
|
8638
8531
|
return entry;
|
|
@@ -8858,7 +8751,7 @@ function findBundledPack(projectRoot, selection) {
|
|
|
8858
8751
|
if (packDirEntry(base)) return base;
|
|
8859
8752
|
let versions;
|
|
8860
8753
|
try {
|
|
8861
|
-
versions =
|
|
8754
|
+
versions = fs9.readdirSync(base, { withFileTypes: true });
|
|
8862
8755
|
} catch {
|
|
8863
8756
|
return null;
|
|
8864
8757
|
}
|
|
@@ -8871,11 +8764,11 @@ function findBundledPack(projectRoot, selection) {
|
|
|
8871
8764
|
}
|
|
8872
8765
|
return best?.dir ?? null;
|
|
8873
8766
|
}
|
|
8874
|
-
var
|
|
8767
|
+
var fs9, os2, path11, import_module, import_zod9, ProfileDefSchema, LanguagePackDefSchema, PackSkillSchema, PackInstructionBlockSchema, PackInstructionsSchema, PatternDefSchema, AssertionSelectorSchema, assertionBase, PackAssertionSchema, DeclarativePackSchema, EXTENDABLE_BUILTIN_SKILLS, GLOBAL_PACKS_DEFAULT, PACK_DIR_ENTRIES, isYamlPath;
|
|
8875
8768
|
var init_extensions = __esm({
|
|
8876
8769
|
"src/core/extensions.ts"() {
|
|
8877
8770
|
"use strict";
|
|
8878
|
-
|
|
8771
|
+
fs9 = __toESM(require("fs"));
|
|
8879
8772
|
os2 = __toESM(require("os"));
|
|
8880
8773
|
path11 = __toESM(require("path"));
|
|
8881
8774
|
import_module = require("module");
|
|
@@ -16101,7 +15994,7 @@ function resolveRelativeModule(fromFile, specifier) {
|
|
|
16101
15994
|
];
|
|
16102
15995
|
for (const c of candidates) {
|
|
16103
15996
|
try {
|
|
16104
|
-
if (
|
|
15997
|
+
if (fs10.statSync(c).isFile()) return c;
|
|
16105
15998
|
} catch {
|
|
16106
15999
|
}
|
|
16107
16000
|
}
|
|
@@ -16113,7 +16006,7 @@ function reexportTarget(ts, filePath, specifier, projectRoot, visited, exactCach
|
|
|
16113
16006
|
let targetFacts = exactCache.get(target);
|
|
16114
16007
|
if (targetFacts === void 0) {
|
|
16115
16008
|
try {
|
|
16116
|
-
targetFacts = walkExact(ts,
|
|
16009
|
+
targetFacts = walkExact(ts, fs10.readFileSync(target, "utf8"), target);
|
|
16117
16010
|
} catch {
|
|
16118
16011
|
targetFacts = null;
|
|
16119
16012
|
}
|
|
@@ -16170,7 +16063,7 @@ function walkDeclaredRoots(roots, exclude, projectRoot) {
|
|
|
16170
16063
|
const descend = (dir) => {
|
|
16171
16064
|
let entries;
|
|
16172
16065
|
try {
|
|
16173
|
-
entries =
|
|
16066
|
+
entries = fs10.readdirSync(dir, { withFileTypes: true });
|
|
16174
16067
|
} catch {
|
|
16175
16068
|
return;
|
|
16176
16069
|
}
|
|
@@ -16193,7 +16086,7 @@ function walkDeclaredRoots(roots, exclude, projectRoot) {
|
|
|
16193
16086
|
if (isExcluded(key)) continue;
|
|
16194
16087
|
let stat;
|
|
16195
16088
|
try {
|
|
16196
|
-
stat =
|
|
16089
|
+
stat = fs10.statSync(absolute);
|
|
16197
16090
|
} catch {
|
|
16198
16091
|
continue;
|
|
16199
16092
|
}
|
|
@@ -16230,12 +16123,12 @@ function buildCodeModel(implementations, types, projectRoot, sourceRoots = [], e
|
|
|
16230
16123
|
}
|
|
16231
16124
|
let buffer;
|
|
16232
16125
|
try {
|
|
16233
|
-
const stat =
|
|
16126
|
+
const stat = fs10.statSync(absolute);
|
|
16234
16127
|
if (!stat.isFile()) {
|
|
16235
16128
|
files.push({ path: sourcePath, status: "missing", ...empty });
|
|
16236
16129
|
continue;
|
|
16237
16130
|
}
|
|
16238
|
-
buffer =
|
|
16131
|
+
buffer = fs10.readFileSync(absolute);
|
|
16239
16132
|
} catch {
|
|
16240
16133
|
files.push({ path: sourcePath, status: "missing", ...empty });
|
|
16241
16134
|
continue;
|
|
@@ -16289,7 +16182,7 @@ function readTestFiles(testRoots, projectRoot) {
|
|
|
16289
16182
|
for (const key of walkDeclaredRoots(testRoots, [], projectRoot)) {
|
|
16290
16183
|
let text;
|
|
16291
16184
|
try {
|
|
16292
|
-
const buffer =
|
|
16185
|
+
const buffer = fs10.readFileSync(path12.resolve(projectRoot, key));
|
|
16293
16186
|
if (looksBinary(buffer)) continue;
|
|
16294
16187
|
text = buffer.toString("utf8");
|
|
16295
16188
|
} catch {
|
|
@@ -16326,11 +16219,11 @@ function findTestsReferencing(methods, projectRoot, testRoots = []) {
|
|
|
16326
16219
|
}
|
|
16327
16220
|
return found;
|
|
16328
16221
|
}
|
|
16329
|
-
var
|
|
16222
|
+
var fs10, path12, import_module2, EXTENSION_LANGUAGE, C_FAMILY_COMMENTS, NAMED_IMPORT_BINDINGS_RE, JS_PATTERNS, LANGUAGE_PATTERNS, PATTERN_ANALYSIS_MAX_BYTES, IDENTIFIER_RE, STRING_RE, tsResolutionCache, TS_RESOLUTION_RETRY_MS;
|
|
16330
16223
|
var init_source_analysis = __esm({
|
|
16331
16224
|
"src/core/source-analysis.ts"() {
|
|
16332
16225
|
"use strict";
|
|
16333
|
-
|
|
16226
|
+
fs10 = __toESM(require("fs"));
|
|
16334
16227
|
path12 = __toESM(require("path"));
|
|
16335
16228
|
import_module2 = require("module");
|
|
16336
16229
|
init_models();
|
|
@@ -17107,7 +17000,7 @@ function builtinVariantsDir() {
|
|
|
17107
17000
|
path13.resolve(__dirname, "templates", "variants")
|
|
17108
17001
|
// dist (library entry)
|
|
17109
17002
|
];
|
|
17110
|
-
return candidates.find((dir) =>
|
|
17003
|
+
return candidates.find((dir) => fs11.existsSync(dir)) ?? candidates[0];
|
|
17111
17004
|
}
|
|
17112
17005
|
function projectVariantsDir() {
|
|
17113
17006
|
return path13.join(getProjectRoot(), ".wai", "variants");
|
|
@@ -17115,7 +17008,7 @@ function projectVariantsDir() {
|
|
|
17115
17008
|
function variantFiles(dir) {
|
|
17116
17009
|
let entries;
|
|
17117
17010
|
try {
|
|
17118
|
-
entries =
|
|
17011
|
+
entries = fs11.readdirSync(dir, { withFileTypes: true });
|
|
17119
17012
|
} catch {
|
|
17120
17013
|
return [];
|
|
17121
17014
|
}
|
|
@@ -17228,11 +17121,11 @@ function rebasedText(content, fromBase, toBase, rebasedContent) {
|
|
|
17228
17121
|
}
|
|
17229
17122
|
return serializeYaml(rebasedContent);
|
|
17230
17123
|
}
|
|
17231
|
-
var
|
|
17124
|
+
var fs11, os3, path13, import_zod10, VariantDefSchema;
|
|
17232
17125
|
var init_variants = __esm({
|
|
17233
17126
|
"src/core/variants.ts"() {
|
|
17234
17127
|
"use strict";
|
|
17235
|
-
|
|
17128
|
+
fs11 = __toESM(require("fs"));
|
|
17236
17129
|
os3 = __toESM(require("os"));
|
|
17237
17130
|
path13 = __toESM(require("path"));
|
|
17238
17131
|
import_zod10 = require("zod");
|
|
@@ -17782,9 +17675,9 @@ function projectSubsystemSurface(subsystemId) {
|
|
|
17782
17675
|
}
|
|
17783
17676
|
function listSnapshots(rootDir = getProjectRoot()) {
|
|
17784
17677
|
const dir = surfacesDir(rootDir);
|
|
17785
|
-
if (!
|
|
17678
|
+
if (!fs12.existsSync(dir)) return [];
|
|
17786
17679
|
const out = [];
|
|
17787
|
-
for (const file of
|
|
17680
|
+
for (const file of fs12.readdirSync(dir)) {
|
|
17788
17681
|
if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue;
|
|
17789
17682
|
try {
|
|
17790
17683
|
out.push(SurfaceSnapshotSchema.parse(readYamlFile(path14.join(dir, file))));
|
|
@@ -17801,10 +17694,10 @@ function snapshotFilename(projectName) {
|
|
|
17801
17694
|
}
|
|
17802
17695
|
function writeSnapshotIfChanged(snapshot, rootDir) {
|
|
17803
17696
|
const dir = surfacesDir(rootDir);
|
|
17804
|
-
|
|
17697
|
+
fs12.mkdirSync(dir, { recursive: true });
|
|
17805
17698
|
const p = path14.join(dir, snapshotFilename(snapshot.projectName));
|
|
17806
17699
|
const next = SurfaceSnapshotSchema.parse(snapshot);
|
|
17807
|
-
if (
|
|
17700
|
+
if (fs12.existsSync(p)) {
|
|
17808
17701
|
try {
|
|
17809
17702
|
const existing = SurfaceSnapshotSchema.parse(readYamlFile(p));
|
|
17810
17703
|
if (surfaceContentKey(existing) === surfaceContentKey(next)) {
|
|
@@ -17822,18 +17715,18 @@ function saveSnapshot(snapshot, rootDir = getProjectRoot()) {
|
|
|
17822
17715
|
function removeSnapshot(projectName, rootDir = getProjectRoot()) {
|
|
17823
17716
|
const dir = surfacesDir(rootDir);
|
|
17824
17717
|
const direct = path14.join(dir, snapshotFilename(projectName));
|
|
17825
|
-
if (
|
|
17826
|
-
|
|
17718
|
+
if (fs12.existsSync(direct)) {
|
|
17719
|
+
fs12.unlinkSync(direct);
|
|
17827
17720
|
return true;
|
|
17828
17721
|
}
|
|
17829
|
-
if (!
|
|
17830
|
-
for (const file of
|
|
17722
|
+
if (!fs12.existsSync(dir)) return false;
|
|
17723
|
+
for (const file of fs12.readdirSync(dir)) {
|
|
17831
17724
|
if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue;
|
|
17832
17725
|
const p = path14.join(dir, file);
|
|
17833
17726
|
try {
|
|
17834
17727
|
const snap = SurfaceSnapshotSchema.parse(readYamlFile(p));
|
|
17835
17728
|
if (snap.projectName === projectName) {
|
|
17836
|
-
|
|
17729
|
+
fs12.unlinkSync(p);
|
|
17837
17730
|
return true;
|
|
17838
17731
|
}
|
|
17839
17732
|
} catch {
|
|
@@ -17873,18 +17766,18 @@ function perPortalPath(resolvedOut, portalId) {
|
|
|
17873
17766
|
}
|
|
17874
17767
|
function writeSurfaceFile(outPath, snapshot, renderedSet) {
|
|
17875
17768
|
const resolved = path14.resolve(outPath);
|
|
17876
|
-
|
|
17769
|
+
fs12.mkdirSync(path14.dirname(resolved), { recursive: true });
|
|
17877
17770
|
if (!renderedSet || renderedSet.length === 0) {
|
|
17878
17771
|
writeYamlFile(resolved, snapshot);
|
|
17879
17772
|
return [resolved];
|
|
17880
17773
|
}
|
|
17881
17774
|
if (renderedSet.length === 1) {
|
|
17882
|
-
|
|
17775
|
+
fs12.writeFileSync(resolved, renderedSet[0].document);
|
|
17883
17776
|
return [resolved];
|
|
17884
17777
|
}
|
|
17885
17778
|
return renderedSet.map((spec) => {
|
|
17886
17779
|
const target = perPortalPath(resolved, spec.portalId);
|
|
17887
|
-
|
|
17780
|
+
fs12.writeFileSync(target, spec.document);
|
|
17888
17781
|
return target;
|
|
17889
17782
|
});
|
|
17890
17783
|
}
|
|
@@ -17907,10 +17800,10 @@ function exportSurface(maxAudience, format, outPath, portalId) {
|
|
|
17907
17800
|
}
|
|
17908
17801
|
function importSurface(sourcePath, origin) {
|
|
17909
17802
|
const resolved = path14.resolve(sourcePath);
|
|
17910
|
-
if (!
|
|
17803
|
+
if (!fs12.existsSync(resolved)) {
|
|
17911
17804
|
throw new Error(`Surface document not found: ${resolved}`);
|
|
17912
17805
|
}
|
|
17913
|
-
const body =
|
|
17806
|
+
const body = fs12.readFileSync(resolved, "utf8");
|
|
17914
17807
|
let snapshot;
|
|
17915
17808
|
if (isOpenApiDocument(body)) {
|
|
17916
17809
|
const projectName = path14.basename(resolved).replace(/\.(json|ya?ml)$/i, "");
|
|
@@ -17976,11 +17869,11 @@ function surfaceContentKey(snapshot) {
|
|
|
17976
17869
|
const { stateId, generatedAt, origin, ...content } = snapshot;
|
|
17977
17870
|
return JSON.stringify(content);
|
|
17978
17871
|
}
|
|
17979
|
-
var
|
|
17872
|
+
var fs12, path14, SURFACES_DIRNAME, CROSS_BOUNDARY_TARGETS;
|
|
17980
17873
|
var init_surfaces = __esm({
|
|
17981
17874
|
"src/core/surfaces.ts"() {
|
|
17982
17875
|
"use strict";
|
|
17983
|
-
|
|
17876
|
+
fs12 = __toESM(require("fs"));
|
|
17984
17877
|
path14 = __toESM(require("path"));
|
|
17985
17878
|
init_fs();
|
|
17986
17879
|
init_yaml();
|
|
@@ -19048,7 +18941,7 @@ function canonicalPath(target) {
|
|
|
19048
18941
|
const rest = [];
|
|
19049
18942
|
for (; ; ) {
|
|
19050
18943
|
try {
|
|
19051
|
-
|
|
18944
|
+
fs13.lstatSync(existing);
|
|
19052
18945
|
break;
|
|
19053
18946
|
} catch {
|
|
19054
18947
|
const up = path16.dirname(existing);
|
|
@@ -19058,7 +18951,7 @@ function canonicalPath(target) {
|
|
|
19058
18951
|
}
|
|
19059
18952
|
}
|
|
19060
18953
|
try {
|
|
19061
|
-
return path16.join(
|
|
18954
|
+
return path16.join(fs13.realpathSync.native(existing), ...rest);
|
|
19062
18955
|
} catch {
|
|
19063
18956
|
return null;
|
|
19064
18957
|
}
|
|
@@ -19150,7 +19043,7 @@ function inspectChainedRoots(rootDir = getProjectRoot()) {
|
|
|
19150
19043
|
let reason;
|
|
19151
19044
|
if (projectPathEscapesRoot(projectDir, projectPath, childDir)) reason = "escapes";
|
|
19152
19045
|
else if (ancestors.has(chainDirKey(childDir))) reason = "cyclic";
|
|
19153
|
-
else if (!
|
|
19046
|
+
else if (!fs13.existsSync(childDir)) reason = "missing";
|
|
19154
19047
|
else if (depth >= 32) reason = "too-deep";
|
|
19155
19048
|
if (reason) {
|
|
19156
19049
|
const mount = prefix ? qualifyDeclaredId(localId, prefix, true) : localId;
|
|
@@ -19284,9 +19177,9 @@ function findOwner(id, components) {
|
|
|
19284
19177
|
}
|
|
19285
19178
|
function moveComponentFolder(fromDir, toDir) {
|
|
19286
19179
|
if (path16.normalize(fromDir) === path16.normalize(toDir)) return false;
|
|
19287
|
-
if (!
|
|
19180
|
+
if (!fs13.existsSync(fromDir) || fs13.existsSync(toDir)) return false;
|
|
19288
19181
|
ensureDir(path16.dirname(toDir));
|
|
19289
|
-
|
|
19182
|
+
fs13.renameSync(fromDir, toDir);
|
|
19290
19183
|
return true;
|
|
19291
19184
|
}
|
|
19292
19185
|
function formatZodIssues(error) {
|
|
@@ -19302,13 +19195,13 @@ function parseOrThrow(schema, value, kind, id) {
|
|
|
19302
19195
|
function computeSpecTreeSignature(dirs) {
|
|
19303
19196
|
const parts = [];
|
|
19304
19197
|
for (const dir of dirs) {
|
|
19305
|
-
if (!
|
|
19198
|
+
if (!fs13.existsSync(dir)) {
|
|
19306
19199
|
parts.push(`${dir}:missing`);
|
|
19307
19200
|
continue;
|
|
19308
19201
|
}
|
|
19309
19202
|
for (const f of listSpecFiles(dir)) {
|
|
19310
19203
|
try {
|
|
19311
|
-
const st =
|
|
19204
|
+
const st = fs13.statSync(f);
|
|
19312
19205
|
parts.push(`${f}:${st.mtimeMs}:${st.size}`);
|
|
19313
19206
|
} catch {
|
|
19314
19207
|
parts.push(`${f}:gone`);
|
|
@@ -19834,7 +19727,7 @@ function consumedSurfaceInputsAt(rootDir) {
|
|
|
19834
19727
|
const dir = path16.join(rootDir, ".wai", "surfaces");
|
|
19835
19728
|
if (!pathExists(dir)) return [];
|
|
19836
19729
|
const keys = [];
|
|
19837
|
-
for (const file of
|
|
19730
|
+
for (const file of fs13.readdirSync(dir)) {
|
|
19838
19731
|
if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue;
|
|
19839
19732
|
try {
|
|
19840
19733
|
keys.push(snapshotInputKey(SurfaceSnapshotSchema.parse(readYamlFile(path16.join(dir, file)))));
|
|
@@ -19919,7 +19812,7 @@ function snapshotSpecFiles() {
|
|
|
19919
19812
|
}
|
|
19920
19813
|
function restoreSpecFiles(snapshot) {
|
|
19921
19814
|
for (const [file, content] of snapshot) {
|
|
19922
|
-
|
|
19815
|
+
fs13.writeFileSync(file, content);
|
|
19923
19816
|
}
|
|
19924
19817
|
}
|
|
19925
19818
|
function findLegacySpecFiles() {
|
|
@@ -19931,13 +19824,13 @@ function updateSpec(kind, id, delta, hooks, dryRun) {
|
|
|
19931
19824
|
function moveMethods(from, to, methods, hooks, dryRun) {
|
|
19932
19825
|
return current().moveMethods(from, to, methods, hooks, dryRun);
|
|
19933
19826
|
}
|
|
19934
|
-
var
|
|
19827
|
+
var fs13, path16, NO_ROOT_SUBSYSTEMS, SIGNATURE_TTL_MS, COMPONENT_AUTH_SOURCE, DELTA_VERBS, JUMP_LABEL_TWINS, LABEL_TWIN_CONTAINERS, SpecWorkspace, DEFAULT_DEPENDENCY_LIMIT, PROSE_FIELDS, workspaces;
|
|
19935
19828
|
var init_specs2 = __esm({
|
|
19936
19829
|
"src/core/specs.ts"() {
|
|
19937
19830
|
"use strict";
|
|
19938
|
-
|
|
19831
|
+
fs13 = __toESM(require("fs"));
|
|
19939
19832
|
path16 = __toESM(require("path"));
|
|
19940
|
-
|
|
19833
|
+
init_paths();
|
|
19941
19834
|
init_project_config();
|
|
19942
19835
|
init_fs();
|
|
19943
19836
|
init_statehash();
|
|
@@ -20218,7 +20111,7 @@ var init_specs2 = __esm({
|
|
|
20218
20111
|
});
|
|
20219
20112
|
continue;
|
|
20220
20113
|
}
|
|
20221
|
-
if (!
|
|
20114
|
+
if (!fs13.existsSync(childDir)) {
|
|
20222
20115
|
this.loaderIssues.push({
|
|
20223
20116
|
severity: "error",
|
|
20224
20117
|
code: "SUBPROJECT_NOT_FOUND",
|
|
@@ -21152,8 +21045,8 @@ var init_specs2 = __esm({
|
|
|
21152
21045
|
}
|
|
21153
21046
|
}
|
|
21154
21047
|
for (const file of files) {
|
|
21155
|
-
if (
|
|
21156
|
-
snapshot.set(file,
|
|
21048
|
+
if (fs13.existsSync(file)) {
|
|
21049
|
+
snapshot.set(file, fs13.readFileSync(file, "utf8"));
|
|
21157
21050
|
}
|
|
21158
21051
|
}
|
|
21159
21052
|
return snapshot;
|
|
@@ -22183,567 +22076,135 @@ var init_specs2 = __esm({
|
|
|
22183
22076
|
}
|
|
22184
22077
|
});
|
|
22185
22078
|
|
|
22186
|
-
// src/core/
|
|
22187
|
-
var
|
|
22188
|
-
__export(
|
|
22189
|
-
|
|
22190
|
-
|
|
22191
|
-
|
|
22079
|
+
// src/core/domains.ts
|
|
22080
|
+
var domains_exports = {};
|
|
22081
|
+
__export(domains_exports, {
|
|
22082
|
+
addFreeStandingDomain: () => addFreeStandingDomain,
|
|
22083
|
+
deriveSubsystemDomains: () => deriveSubsystemDomains,
|
|
22084
|
+
findDomain: () => findDomain,
|
|
22085
|
+
listFreeStandingDomains: () => listFreeStandingDomains,
|
|
22086
|
+
removeFreeStandingDomain: () => removeFreeStandingDomain,
|
|
22087
|
+
resolveDomains: () => resolveDomains
|
|
22192
22088
|
});
|
|
22193
|
-
function
|
|
22194
|
-
|
|
22195
|
-
|
|
22196
|
-
|
|
22197
|
-
|
|
22198
|
-
|
|
22199
|
-
|
|
22200
|
-
|
|
22201
|
-
|
|
22202
|
-
|
|
22203
|
-
|
|
22204
|
-
|
|
22205
|
-
|
|
22206
|
-
|
|
22207
|
-
|
|
22208
|
-
|
|
22209
|
-
|
|
22210
|
-
|
|
22211
|
-
|
|
22212
|
-
|
|
22213
|
-
|
|
22214
|
-
|
|
22215
|
-
|
|
22216
|
-
|
|
22217
|
-
|
|
22218
|
-
|
|
22089
|
+
function rel(p) {
|
|
22090
|
+
return path17.relative(process.cwd(), p).replace(/\\/g, "/");
|
|
22091
|
+
}
|
|
22092
|
+
function deriveSubsystemDomains() {
|
|
22093
|
+
const subsystems = loadSubsystemSpecs();
|
|
22094
|
+
const components = loadComponentSpecs();
|
|
22095
|
+
return subsystems.map((sub) => {
|
|
22096
|
+
const ownedPaths = [
|
|
22097
|
+
rel(getSubsystemPath(sub.id)),
|
|
22098
|
+
...components.filter((c) => c.subsystem === sub.id).map((c) => rel(getComponentPath(c.id, sub.id)))
|
|
22099
|
+
];
|
|
22100
|
+
return {
|
|
22101
|
+
id: sub.id,
|
|
22102
|
+
name: sub.name,
|
|
22103
|
+
description: sub.description,
|
|
22104
|
+
boundTo: sub.id,
|
|
22105
|
+
ownedPaths
|
|
22106
|
+
};
|
|
22107
|
+
});
|
|
22108
|
+
}
|
|
22109
|
+
function listFreeStandingDomains() {
|
|
22110
|
+
return loadTopologyConfig().domains;
|
|
22111
|
+
}
|
|
22112
|
+
function resolveDomains() {
|
|
22113
|
+
return [...deriveSubsystemDomains(), ...listFreeStandingDomains()];
|
|
22114
|
+
}
|
|
22115
|
+
function findDomain(id) {
|
|
22116
|
+
return resolveDomains().find((d) => d.id === id);
|
|
22117
|
+
}
|
|
22118
|
+
function addFreeStandingDomain(domain) {
|
|
22119
|
+
const config = loadTopologyConfig();
|
|
22120
|
+
if (config.domains.some((d) => d.id === domain.id)) {
|
|
22121
|
+
throw new WaironError(`A free-standing domain "${domain.id}" already exists in .wai/topology.yaml.`);
|
|
22219
22122
|
}
|
|
22220
|
-
|
|
22123
|
+
if (deriveSubsystemDomains().some((d) => d.id === domain.id)) {
|
|
22124
|
+
throw new WaironError(`Domain id "${domain.id}" collides with a subsystem-derived domain.`);
|
|
22125
|
+
}
|
|
22126
|
+
config.domains.push(domain);
|
|
22127
|
+
saveTopologyConfig(config);
|
|
22221
22128
|
}
|
|
22222
|
-
function
|
|
22223
|
-
|
|
22224
|
-
|
|
22225
|
-
|
|
22226
|
-
|
|
22227
|
-
|
|
22228
|
-
|
|
22229
|
-
if (pathExists(srcDir)) {
|
|
22230
|
-
searchDir = srcDir;
|
|
22231
|
-
} else if (pathExists(legacySrcDir)) {
|
|
22232
|
-
searchDir = legacySrcDir;
|
|
22233
|
-
} else if (projectDir === getProjectRoot()) {
|
|
22234
|
-
projectFilesCache.set(projectDir, []);
|
|
22235
|
-
return [];
|
|
22236
|
-
}
|
|
22237
|
-
const extensions = [".rs", ".ts", ".tsx", ".js", ".jsx", ".py", ".go", ".c", ".cpp", ".cs", ".java", ".kt", ".swift", ".rb", ".php", ".lua"];
|
|
22238
|
-
for (const ext of extensions) {
|
|
22239
|
-
files.push(...listFilesRecursiveSafe(searchDir, ext));
|
|
22240
|
-
}
|
|
22241
|
-
const rootDir = getProjectRoot();
|
|
22242
|
-
files = files.map((f) => path17.relative(rootDir, f).replace(/\\/g, "/"));
|
|
22243
|
-
projectFilesCache.set(projectDir, files);
|
|
22129
|
+
function removeFreeStandingDomain(id) {
|
|
22130
|
+
const config = loadTopologyConfig();
|
|
22131
|
+
const idx = config.domains.findIndex((d) => d.id === id);
|
|
22132
|
+
if (idx === -1) {
|
|
22133
|
+
throw new WaironError(
|
|
22134
|
+
`"${id}" is not a free-standing domain. Subsystem-backed domains are derived from the spec tree and cannot be removed here.`
|
|
22135
|
+
);
|
|
22244
22136
|
}
|
|
22245
|
-
|
|
22137
|
+
config.domains.splice(idx, 1);
|
|
22138
|
+
saveTopologyConfig(config);
|
|
22246
22139
|
}
|
|
22247
|
-
|
|
22248
|
-
|
|
22249
|
-
|
|
22250
|
-
|
|
22251
|
-
|
|
22252
|
-
|
|
22253
|
-
|
|
22254
|
-
|
|
22255
|
-
|
|
22256
|
-
|
|
22140
|
+
var path17;
|
|
22141
|
+
var init_domains = __esm({
|
|
22142
|
+
"src/core/domains.ts"() {
|
|
22143
|
+
"use strict";
|
|
22144
|
+
path17 = __toESM(require("path"));
|
|
22145
|
+
init_loader();
|
|
22146
|
+
init_specs2();
|
|
22147
|
+
init_errors();
|
|
22148
|
+
}
|
|
22149
|
+
});
|
|
22150
|
+
|
|
22151
|
+
// src/core/templates.ts
|
|
22152
|
+
function builtinTemplatesDir() {
|
|
22153
|
+
return path18.resolve(__dirname, "..", "templates");
|
|
22154
|
+
}
|
|
22155
|
+
function loadTemplate(id, globalOverride) {
|
|
22156
|
+
const dirs = templateSearchDirs(globalOverride);
|
|
22157
|
+
for (const dir of dirs) {
|
|
22158
|
+
const filePath = path18.join(dir, `${id}.yaml`);
|
|
22159
|
+
if (pathExists(filePath)) {
|
|
22160
|
+
const raw = readYamlFile(filePath);
|
|
22161
|
+
return { ...TemplateSchema.parse(raw), templateName: id };
|
|
22257
22162
|
}
|
|
22258
|
-
|
|
22259
|
-
|
|
22260
|
-
|
|
22261
|
-
|
|
22262
|
-
|
|
22263
|
-
|
|
22264
|
-
|
|
22265
|
-
|
|
22266
|
-
|
|
22267
|
-
|
|
22268
|
-
|
|
22269
|
-
|
|
22270
|
-
let score = 0;
|
|
22271
|
-
const normalizedPath = f.toLowerCase();
|
|
22272
|
-
const subPattern1 = `/${subRelativeId.toLowerCase()}/`;
|
|
22273
|
-
const subPattern2 = `/${subRelativeId.replace(/-/g, "_").toLowerCase()}/`;
|
|
22274
|
-
const hasSubsystemSegmentMatch = subRelativeId.split(/[-_]/).some((seg) => seg.length >= 3 && normalizedPath.includes(`/${seg.toLowerCase()}/`));
|
|
22275
|
-
const hasSubsystemMatch = normalizedPath.includes(subPattern1) || normalizedPath.includes(subPattern2) || hasSubsystemSegmentMatch;
|
|
22276
|
-
if (hasSubsystemMatch) {
|
|
22277
|
-
score += 10;
|
|
22278
|
-
}
|
|
22279
|
-
let belongsToOtherSubsystem = false;
|
|
22280
|
-
for (const otherSub of subsystems) {
|
|
22281
|
-
if (otherSub.id === comp.subsystem) continue;
|
|
22282
|
-
const otherSubRelativeId = otherSub.id.split("::").pop() || otherSub.id;
|
|
22283
|
-
const otherPattern1 = `/${otherSubRelativeId.toLowerCase()}/`;
|
|
22284
|
-
const otherPattern2 = `/${otherSubRelativeId.replace(/-/g, "_").toLowerCase()}/`;
|
|
22285
|
-
const otherSegmentMatch = otherSubRelativeId.split(/[-_]/).some((seg) => seg.length >= 3 && normalizedPath.includes(`/${seg.toLowerCase()}/`));
|
|
22286
|
-
if (normalizedPath.includes(otherPattern1) || normalizedPath.includes(otherPattern2) || otherSegmentMatch) {
|
|
22287
|
-
belongsToOtherSubsystem = true;
|
|
22288
|
-
break;
|
|
22289
|
-
}
|
|
22290
|
-
}
|
|
22291
|
-
if (belongsToOtherSubsystem) {
|
|
22292
|
-
continue;
|
|
22293
|
-
}
|
|
22294
|
-
const isCleanNameMatch = base === cleanName.toLowerCase() || base === cleanName.replace(/-/g, "_").toLowerCase();
|
|
22295
|
-
if (isCleanNameMatch) {
|
|
22296
|
-
score += 5;
|
|
22297
|
-
}
|
|
22298
|
-
const isIdMatch = base === compRelativeId.toLowerCase() || base === compRelativeId.replace(/-/g, "_").toLowerCase();
|
|
22299
|
-
if (isIdMatch) {
|
|
22300
|
-
score += 3;
|
|
22301
|
-
}
|
|
22302
|
-
const isSpecificNameMatch = isCleanNameMatch && cleanName.toLowerCase() !== comp.componentType.toLowerCase();
|
|
22303
|
-
if (!hasSubsystemMatch && !isSpecificNameMatch && !isIdMatch) {
|
|
22304
|
-
continue;
|
|
22305
|
-
}
|
|
22306
|
-
if (normalizedPath.startsWith("src/") || normalizedPath.includes("/src/") || normalizedPath.startsWith("legacy-src/") || normalizedPath.includes("/legacy-src/")) {
|
|
22307
|
-
score += 2;
|
|
22308
|
-
}
|
|
22309
|
-
if (base === comp.componentType.toLowerCase()) {
|
|
22310
|
-
score += 1;
|
|
22311
|
-
}
|
|
22312
|
-
if (score > bestScore) {
|
|
22313
|
-
bestScore = score;
|
|
22314
|
-
bestFile = f;
|
|
22315
|
-
}
|
|
22316
|
-
}
|
|
22163
|
+
}
|
|
22164
|
+
throw new TemplateNotFoundError(id);
|
|
22165
|
+
}
|
|
22166
|
+
function loadAgentOverride(agentId) {
|
|
22167
|
+
const filePath = path18.join(AI_PATHS.root(), "agents", `${agentId}.md`);
|
|
22168
|
+
return readFileOrNull(filePath);
|
|
22169
|
+
}
|
|
22170
|
+
function listTemplateIds(globalOverride) {
|
|
22171
|
+
const seen = /* @__PURE__ */ new Set();
|
|
22172
|
+
for (const dir of templateSearchDirs(globalOverride)) {
|
|
22173
|
+
for (const file of listFiles(dir, ".yaml")) {
|
|
22174
|
+
seen.add(path18.basename(file, ".yaml"));
|
|
22317
22175
|
}
|
|
22318
|
-
return bestFile;
|
|
22319
|
-
} catch {
|
|
22320
|
-
return null;
|
|
22321
22176
|
}
|
|
22177
|
+
return Array.from(seen).sort();
|
|
22322
22178
|
}
|
|
22323
|
-
function
|
|
22324
|
-
|
|
22325
|
-
|
|
22326
|
-
|
|
22327
|
-
|
|
22328
|
-
|
|
22179
|
+
function templateSearchDirs(globalOverride) {
|
|
22180
|
+
return [
|
|
22181
|
+
AI_PATHS.templatesDir(),
|
|
22182
|
+
// 1. project-local
|
|
22183
|
+
globalTemplatesDir(globalOverride),
|
|
22184
|
+
// 2. global user/org
|
|
22185
|
+
builtinTemplatesDir()
|
|
22186
|
+
// 3. built-in fallback
|
|
22187
|
+
];
|
|
22329
22188
|
}
|
|
22330
|
-
function
|
|
22331
|
-
return
|
|
22189
|
+
function renderTemplateInstructions(template, vars) {
|
|
22190
|
+
return template.instructions.replace(/\{\{(\w+)\}\}/g, (_match, key) => {
|
|
22191
|
+
return key in vars ? vars[key] : `{{${key}}}`;
|
|
22192
|
+
});
|
|
22332
22193
|
}
|
|
22333
|
-
function
|
|
22334
|
-
|
|
22335
|
-
const system = loadSystemSpec();
|
|
22336
|
-
if (!system) return [];
|
|
22337
|
-
const isLocal = (id) => !id.includes("::");
|
|
22338
|
-
const subsystems = loadSubsystemSpecs().filter((s) => isLocal(s.id));
|
|
22339
|
-
const components = loadComponentSpecs().filter((c) => isLocal(c.id) && isLocal(c.subsystem));
|
|
22340
|
-
const interfaces = loadInterfaceSpecs();
|
|
22341
|
-
const implementations = loadImplementationSpecs();
|
|
22342
|
-
const variantsById = new Map(loadProjectVariants().map((v) => [v.id, v]));
|
|
22343
|
-
const config = projectConfigRepository.load();
|
|
22344
|
-
if (!config) throw new ProjectNotInitializedError();
|
|
22345
|
-
const activeTargets = config.targets.filter((t) => !("enabled" in t) || t.enabled).map((t) => typeof t === "string" ? t : t.type);
|
|
22346
|
-
const agents = [];
|
|
22347
|
-
agents.push({
|
|
22348
|
-
id: "system-architect",
|
|
22349
|
-
name: `${system.name} Architect`,
|
|
22350
|
-
description: `Global architect for ${system.name} \u2014 owns the spec tree and topology. ${summarize(system.vision)}`,
|
|
22351
|
-
template: "architect",
|
|
22352
|
-
creationReason: "Automatically inferred from L0 system spec",
|
|
22353
|
-
ownedPaths: [".wai/specs/**"],
|
|
22354
|
-
readPaths: ["**"],
|
|
22355
|
-
writePaths: [".wai/specs/**"],
|
|
22356
|
-
tags: ["architect", "global", "sdd"],
|
|
22357
|
-
dependencies: subsystems.map((s) => `${s.id}-owner`),
|
|
22358
|
-
status: "active",
|
|
22359
|
-
targets: activeTargets,
|
|
22360
|
-
createdAt: system.createdAt,
|
|
22361
|
-
updatedAt: system.updatedAt
|
|
22362
|
-
});
|
|
22363
|
-
for (const sub of subsystems) {
|
|
22364
|
-
if (sub.projectPath) {
|
|
22365
|
-
const mountSpecPath = path17.relative(getProjectRoot(), getSubsystemPath(sub.id)).replace(/\\/g, "/");
|
|
22366
|
-
agents.push({
|
|
22367
|
-
id: `${sub.id}-owner`,
|
|
22368
|
-
name: `${sub.name} (chained subproject)`,
|
|
22369
|
-
description: `Delegates into the "${sub.id}" chained subproject at ${sub.projectPath}. Its own agents live in that subproject's .wai \u2014 run \`wairon generate\` there (or spawn from ${sub.projectPath}/.claude/agents). Do not implement its internals from this layer.`,
|
|
22370
|
-
template: "domain-owner",
|
|
22371
|
-
creationReason: `Automatically inferred from a chained subproject subsystem: ${sub.id}`,
|
|
22372
|
-
domainRoot: sub.id,
|
|
22373
|
-
ownedPaths: [mountSpecPath],
|
|
22374
|
-
readPaths: ["**"],
|
|
22375
|
-
writePaths: [mountSpecPath],
|
|
22376
|
-
tags: ["owner", "subproject", "delegate", "sdd"],
|
|
22377
|
-
dependencies: [],
|
|
22378
|
-
status: "active",
|
|
22379
|
-
targets: activeTargets,
|
|
22380
|
-
createdAt: sub.createdAt,
|
|
22381
|
-
updatedAt: sub.updatedAt
|
|
22382
|
-
});
|
|
22383
|
-
continue;
|
|
22384
|
-
}
|
|
22385
|
-
const subComponents = components.filter((c) => c.subsystem === sub.id);
|
|
22386
|
-
const ownedPaths = [];
|
|
22387
|
-
ownedPaths.push(path17.relative(getProjectRoot(), getSubsystemPath(sub.id)).replace(/\\/g, "/"));
|
|
22388
|
-
for (const c of subComponents) {
|
|
22389
|
-
ownedPaths.push(path17.relative(getProjectRoot(), getComponentPath(c.id, sub.id)).replace(/\\/g, "/"));
|
|
22390
|
-
}
|
|
22391
|
-
if (!config.rules.generateComponentImplementers) {
|
|
22392
|
-
for (const comp of subComponents) {
|
|
22393
|
-
const compInterfaces = interfaces.filter((i) => i.component === comp.id);
|
|
22394
|
-
const compInterfaceIds = compInterfaces.map((i) => i.id);
|
|
22395
|
-
const compImpls = implementations.filter((impl) => compInterfaceIds.includes(impl.contract));
|
|
22396
|
-
let hasExplicitSource = false;
|
|
22397
|
-
for (const impl of compImpls) {
|
|
22398
|
-
const files = implementationSourceFiles(impl);
|
|
22399
|
-
if (files.length > 0) hasExplicitSource = true;
|
|
22400
|
-
for (const file of files) {
|
|
22401
|
-
if (!ownedPaths.includes(file)) ownedPaths.push(file);
|
|
22402
|
-
}
|
|
22403
|
-
}
|
|
22404
|
-
if (!hasExplicitSource) {
|
|
22405
|
-
const inferred = inferSourcePathForComponent(comp, subsystems);
|
|
22406
|
-
if (inferred && !ownedPaths.includes(inferred)) {
|
|
22407
|
-
ownedPaths.push(inferred);
|
|
22408
|
-
}
|
|
22409
|
-
}
|
|
22410
|
-
}
|
|
22411
|
-
}
|
|
22412
|
-
let dependencies = [];
|
|
22413
|
-
if (config.rules.generateComponentImplementers) {
|
|
22414
|
-
dependencies = subComponents.map((c) => `${c.id}-implementer`);
|
|
22415
|
-
} else {
|
|
22416
|
-
const depSubsystems = /* @__PURE__ */ new Set();
|
|
22417
|
-
for (const c of subComponents) {
|
|
22418
|
-
for (const depId of c.dependsOn) {
|
|
22419
|
-
const depComp = components.find((other) => other.id === depId);
|
|
22420
|
-
if (depComp && depComp.subsystem !== sub.id) {
|
|
22421
|
-
depSubsystems.add(`${depComp.subsystem}-owner`);
|
|
22422
|
-
}
|
|
22423
|
-
}
|
|
22424
|
-
}
|
|
22425
|
-
dependencies = Array.from(depSubsystems);
|
|
22426
|
-
}
|
|
22427
|
-
agents.push({
|
|
22428
|
-
id: `${sub.id}-owner`,
|
|
22429
|
-
name: `${sub.name} Owner`,
|
|
22430
|
-
description: `Owns the ${sub.id} subsystem. ${summarize(sub.description)}`,
|
|
22431
|
-
template: "domain-owner",
|
|
22432
|
-
creationReason: `Automatically inferred from L1 subsystem spec: ${sub.id}`,
|
|
22433
|
-
domainRoot: sub.id,
|
|
22434
|
-
ownedPaths,
|
|
22435
|
-
readPaths: ["**"],
|
|
22436
|
-
writePaths: ownedPaths,
|
|
22437
|
-
tags: ["owner", "domain", "sdd"],
|
|
22438
|
-
dependencies,
|
|
22439
|
-
variantGuidance: buildVariantGuidance(subComponents, components, variantsById),
|
|
22440
|
-
status: "active",
|
|
22441
|
-
targets: activeTargets,
|
|
22442
|
-
createdAt: sub.createdAt,
|
|
22443
|
-
updatedAt: sub.updatedAt
|
|
22444
|
-
});
|
|
22445
|
-
}
|
|
22446
|
-
if (config.rules.generateComponentImplementers) {
|
|
22447
|
-
for (const comp of components) {
|
|
22448
|
-
const compInterfaces = interfaces.filter((i) => i.component === comp.id);
|
|
22449
|
-
const compInterfaceIds = compInterfaces.map((i) => i.id);
|
|
22450
|
-
const compImpls = implementations.filter((impl) => compInterfaceIds.includes(impl.contract));
|
|
22451
|
-
const ownedPaths = [];
|
|
22452
|
-
for (const impl of compImpls) {
|
|
22453
|
-
for (const file of implementationSourceFiles(impl)) {
|
|
22454
|
-
if (!ownedPaths.includes(file)) ownedPaths.push(file);
|
|
22455
|
-
}
|
|
22456
|
-
}
|
|
22457
|
-
if (ownedPaths.length === 0) {
|
|
22458
|
-
const inferred = inferSourcePathForComponent(comp, subsystems);
|
|
22459
|
-
if (inferred) {
|
|
22460
|
-
ownedPaths.push(inferred);
|
|
22461
|
-
}
|
|
22462
|
-
}
|
|
22463
|
-
const dependencies = comp.dependsOn.map((depId) => `${depId}-implementer`);
|
|
22464
|
-
const readPaths = [
|
|
22465
|
-
path17.relative(getProjectRoot(), AI_PATHS.specsSystem()).replace(/\\/g, "/"),
|
|
22466
|
-
path17.relative(getProjectRoot(), getComponentPath(comp.id, comp.subsystem)).replace(/\\/g, "/"),
|
|
22467
|
-
...compInterfaces.map((i) => path17.relative(getProjectRoot(), getInterfacePath(i.id, comp.id)).replace(/\\/g, "/")),
|
|
22468
|
-
...compImpls.map((impl) => path17.relative(getProjectRoot(), getImplementationPath(impl.id, impl.contract)).replace(/\\/g, "/"))
|
|
22469
|
-
];
|
|
22470
|
-
agents.push({
|
|
22471
|
-
id: `${comp.id}-implementer`,
|
|
22472
|
-
name: `${comp.name} Implementer`,
|
|
22473
|
-
description: `Developer agent implementing ${comp.name} (${comp.componentType})`,
|
|
22474
|
-
template: "implementer",
|
|
22475
|
-
creationReason: `Automatically inferred from L2 component spec: ${comp.id}`,
|
|
22476
|
-
domainRoot: comp.subsystem,
|
|
22477
|
-
ownedPaths,
|
|
22478
|
-
readPaths,
|
|
22479
|
-
writePaths: ownedPaths,
|
|
22480
|
-
tags: ["implementer", "component", "sdd", comp.componentType.toLowerCase()],
|
|
22481
|
-
dependencies,
|
|
22482
|
-
variantGuidance: buildVariantGuidance([comp], components, variantsById),
|
|
22483
|
-
status: "active",
|
|
22484
|
-
targets: activeTargets,
|
|
22485
|
-
createdAt: comp.createdAt,
|
|
22486
|
-
updatedAt: comp.updatedAt
|
|
22487
|
-
});
|
|
22488
|
-
}
|
|
22489
|
-
}
|
|
22490
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
22491
|
-
for (const dom of loadTopologyConfig().domains) {
|
|
22492
|
-
agents.push({
|
|
22493
|
-
id: `${dom.id}-owner`,
|
|
22494
|
-
name: `${dom.name ?? dom.id} Owner`,
|
|
22495
|
-
description: dom.description ? summarize(dom.description) : `Owner agent for the free-standing "${dom.id}" domain.`,
|
|
22496
|
-
template: "domain-owner",
|
|
22497
|
-
creationReason: "Inferred from a free-standing domain in .wai/topology.yaml",
|
|
22498
|
-
domainRoot: dom.id,
|
|
22499
|
-
ownedPaths: dom.ownedPaths,
|
|
22500
|
-
readPaths: ["**"],
|
|
22501
|
-
writePaths: dom.ownedPaths,
|
|
22502
|
-
tags: ["owner", "domain"],
|
|
22503
|
-
dependencies: [],
|
|
22504
|
-
status: "active",
|
|
22505
|
-
targets: activeTargets,
|
|
22506
|
-
createdAt: now,
|
|
22507
|
-
updatedAt: now
|
|
22508
|
-
});
|
|
22509
|
-
}
|
|
22510
|
-
return agents;
|
|
22511
|
-
}
|
|
22512
|
-
function composeAgentBrief(agentId) {
|
|
22513
|
-
const records = resolveAgentTopology();
|
|
22514
|
-
const record = records.find((r) => r.id === agentId);
|
|
22515
|
-
if (!record) {
|
|
22516
|
-
throw new UnknownAgentError(agentId, records.map((r) => r.id));
|
|
22517
|
-
}
|
|
22518
|
-
const config = projectConfigRepository.load();
|
|
22519
|
-
if (!config) throw new ProjectNotInitializedError();
|
|
22520
|
-
const template = loadTemplate(record.template, config.globalTemplatesDir);
|
|
22521
|
-
let instructions = renderTemplateInstructions(template, {
|
|
22522
|
-
agentId: record.id,
|
|
22523
|
-
agentName: record.name,
|
|
22524
|
-
agentDescription: record.description,
|
|
22525
|
-
ownedPaths: record.ownedPaths.join("\n"),
|
|
22526
|
-
tags: record.tags.join(", "),
|
|
22527
|
-
renderContext: "root",
|
|
22528
|
-
contextNote: "",
|
|
22529
|
-
domainPath: ".",
|
|
22530
|
-
domainName: "",
|
|
22531
|
-
variantGuidance: record.variantGuidance ?? ""
|
|
22532
|
-
});
|
|
22533
|
-
const guidance = loadAgentOverride(agentId);
|
|
22534
|
-
if (guidance !== null) {
|
|
22535
|
-
instructions = `${instructions.trimEnd()}
|
|
22536
|
-
|
|
22537
|
-
## Project guidance
|
|
22538
|
-
|
|
22539
|
-
${guidance.trim()}
|
|
22540
|
-
`;
|
|
22541
|
-
}
|
|
22542
|
-
const profile = deriveExecutionProfile(record);
|
|
22543
|
-
const budget = resolveBudget(profile, config.execution, record.id);
|
|
22544
|
-
return {
|
|
22545
|
-
agentId: record.id,
|
|
22546
|
-
name: record.name,
|
|
22547
|
-
template: record.template,
|
|
22548
|
-
domainRoot: record.domainRoot,
|
|
22549
|
-
ownedPaths: record.ownedPaths,
|
|
22550
|
-
readPaths: record.readPaths,
|
|
22551
|
-
instructions,
|
|
22552
|
-
variantGuidance: record.variantGuidance || void 0,
|
|
22553
|
-
profile: budget ? profile : void 0,
|
|
22554
|
-
budget
|
|
22555
|
-
};
|
|
22556
|
-
}
|
|
22557
|
-
var path17, fs13, projectFilesCache, UnknownAgentError;
|
|
22558
|
-
var init_agent_resolver = __esm({
|
|
22559
|
-
"src/core/agent_resolver.ts"() {
|
|
22560
|
-
"use strict";
|
|
22561
|
-
path17 = __toESM(require("path"));
|
|
22562
|
-
fs13 = __toESM(require("fs"));
|
|
22563
|
-
init_loader();
|
|
22564
|
-
init_project_config();
|
|
22565
|
-
init_fs();
|
|
22566
|
-
init_errors();
|
|
22567
|
-
init_templates();
|
|
22568
|
-
init_execution_profile();
|
|
22569
|
-
init_budget_policy();
|
|
22570
|
-
init_specs2();
|
|
22571
|
-
init_specs();
|
|
22572
|
-
init_variants();
|
|
22573
|
-
projectFilesCache = /* @__PURE__ */ new Map();
|
|
22574
|
-
UnknownAgentError = class extends WaironError {
|
|
22575
|
-
constructor(agentId, knownIds) {
|
|
22576
|
-
super(`Unknown agent id: "${agentId}". Known agent ids: ${knownIds.join(", ")}`);
|
|
22577
|
-
this.name = "UnknownAgentError";
|
|
22578
|
-
}
|
|
22579
|
-
};
|
|
22580
|
-
}
|
|
22581
|
-
});
|
|
22582
|
-
|
|
22583
|
-
// src/config/loader.ts
|
|
22584
|
-
function aiPathsAt(rootDir) {
|
|
22585
|
-
const resolvedRoot = path18.resolve(rootDir);
|
|
22586
|
-
const aiDirAt2 = (...segments) => {
|
|
22587
|
-
const waiPath = path18.join(resolvedRoot, ".wai");
|
|
22588
|
-
const waironPath = path18.join(resolvedRoot, ".wairon");
|
|
22589
|
-
const base = !fs14.existsSync(waiPath) && fs14.existsSync(waironPath) ? waironPath : waiPath;
|
|
22590
|
-
return path18.join(base, ...segments);
|
|
22591
|
-
};
|
|
22592
|
-
const specsDir = () => projectConfigRepositoryAt(resolvedRoot).specsDir();
|
|
22593
|
-
return {
|
|
22594
|
-
root: () => aiDirAt2(),
|
|
22595
|
-
projectConfig: () => aiDirAt2("project.yaml"),
|
|
22596
|
-
topologyConfig: () => aiDirAt2("topology.yaml"),
|
|
22597
|
-
templatesDir: () => aiDirAt2("templates"),
|
|
22598
|
-
rulesDir: () => aiDirAt2("rules"),
|
|
22599
|
-
docsDir: () => aiDirAt2("docs"),
|
|
22600
|
-
generatedDir: () => aiDirAt2("generated"),
|
|
22601
|
-
contextDir: () => aiDirAt2("context"),
|
|
22602
|
-
contextProjectMd: () => aiDirAt2("context", "project.md"),
|
|
22603
|
-
contextArchitectureMd: () => aiDirAt2("context", "architecture.md"),
|
|
22604
|
-
contextDomainsMd: () => aiDirAt2("context", "domains.md"),
|
|
22605
|
-
contextWaironGuideMd: () => aiDirAt2("context", "wairon-guide.md"),
|
|
22606
|
-
specsDir,
|
|
22607
|
-
specsSystem: () => path18.join(specsDir(), ".index.yaml"),
|
|
22608
|
-
specsSubsystemsDir: () => path18.join(specsDir(), "subsystems"),
|
|
22609
|
-
specsComponentsDir: () => path18.join(specsDir(), "components"),
|
|
22610
|
-
specsInterfacesDir: () => path18.join(specsDir(), "interfaces"),
|
|
22611
|
-
specsImplementationsDir: () => path18.join(specsDir(), "implementations"),
|
|
22612
|
-
specsTypesDir: () => path18.join(specsDir(), "types")
|
|
22613
|
-
};
|
|
22614
|
-
}
|
|
22615
|
-
function isProjectInitialized() {
|
|
22616
|
-
return projectConfigRepository.exists();
|
|
22617
|
-
}
|
|
22618
|
-
function assertProjectInitialized() {
|
|
22619
|
-
if (!isProjectInitialized()) {
|
|
22620
|
-
throw new ProjectNotInitializedError();
|
|
22621
|
-
}
|
|
22622
|
-
}
|
|
22623
|
-
function loadRegistry() {
|
|
22624
|
-
assertProjectInitialized();
|
|
22625
|
-
if (!pathExists(AI_PATHS.specsSystem())) return createEmptyRegistry();
|
|
22626
|
-
const { resolveAgentTopology: resolveAgentTopology2 } = (init_agent_resolver(), __toCommonJS(agent_resolver_exports));
|
|
22627
|
-
return {
|
|
22628
|
-
schemaVersion: "1.0.0",
|
|
22629
|
-
agents: resolveAgentTopology2(),
|
|
22630
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
22631
|
-
};
|
|
22632
|
-
}
|
|
22633
|
-
function loadTopologyConfig() {
|
|
22634
|
-
assertProjectInitialized();
|
|
22635
|
-
if (!pathExists(AI_PATHS.topologyConfig())) return createEmptyTopologyConfig();
|
|
22636
|
-
const raw = readYamlFile(AI_PATHS.topologyConfig());
|
|
22637
|
-
if (!raw) return createEmptyTopologyConfig();
|
|
22638
|
-
return TopologyConfigSchema.parse(raw);
|
|
22639
|
-
}
|
|
22640
|
-
function saveTopologyConfig(config) {
|
|
22641
|
-
writeYamlFile(AI_PATHS.topologyConfig(), config);
|
|
22642
|
-
}
|
|
22643
|
-
var fs14, path18, AI_PATHS;
|
|
22644
|
-
var init_loader = __esm({
|
|
22645
|
-
"src/config/loader.ts"() {
|
|
22646
|
-
"use strict";
|
|
22647
|
-
fs14 = __toESM(require("fs"));
|
|
22648
|
-
path18 = __toESM(require("path"));
|
|
22649
|
-
init_fs();
|
|
22650
|
-
init_yaml();
|
|
22651
|
-
init_errors();
|
|
22652
|
-
init_models();
|
|
22653
|
-
init_project_config();
|
|
22654
|
-
AI_PATHS = {
|
|
22655
|
-
root: () => aiPathsAt(getProjectRoot()).root(),
|
|
22656
|
-
projectConfig: () => aiPathsAt(getProjectRoot()).projectConfig(),
|
|
22657
|
-
topologyConfig: () => aiPathsAt(getProjectRoot()).topologyConfig(),
|
|
22658
|
-
templatesDir: () => aiPathsAt(getProjectRoot()).templatesDir(),
|
|
22659
|
-
rulesDir: () => aiPathsAt(getProjectRoot()).rulesDir(),
|
|
22660
|
-
docsDir: () => aiPathsAt(getProjectRoot()).docsDir(),
|
|
22661
|
-
generatedDir: () => aiPathsAt(getProjectRoot()).generatedDir(),
|
|
22662
|
-
contextDir: () => aiPathsAt(getProjectRoot()).contextDir(),
|
|
22663
|
-
contextProjectMd: () => aiPathsAt(getProjectRoot()).contextProjectMd(),
|
|
22664
|
-
contextArchitectureMd: () => aiPathsAt(getProjectRoot()).contextArchitectureMd(),
|
|
22665
|
-
contextDomainsMd: () => aiPathsAt(getProjectRoot()).contextDomainsMd(),
|
|
22666
|
-
contextWaironGuideMd: () => aiPathsAt(getProjectRoot()).contextWaironGuideMd(),
|
|
22667
|
-
specsDir: () => aiPathsAt(getProjectRoot()).specsDir(),
|
|
22668
|
-
specsSystem: () => aiPathsAt(getProjectRoot()).specsSystem(),
|
|
22669
|
-
specsSubsystemsDir: () => aiPathsAt(getProjectRoot()).specsSubsystemsDir(),
|
|
22670
|
-
specsComponentsDir: () => aiPathsAt(getProjectRoot()).specsComponentsDir(),
|
|
22671
|
-
specsInterfacesDir: () => aiPathsAt(getProjectRoot()).specsInterfacesDir(),
|
|
22672
|
-
specsImplementationsDir: () => aiPathsAt(getProjectRoot()).specsImplementationsDir(),
|
|
22673
|
-
specsTypesDir: () => aiPathsAt(getProjectRoot()).specsTypesDir()
|
|
22674
|
-
};
|
|
22675
|
-
}
|
|
22676
|
-
});
|
|
22677
|
-
|
|
22678
|
-
// src/core/domains.ts
|
|
22679
|
-
var domains_exports = {};
|
|
22680
|
-
__export(domains_exports, {
|
|
22681
|
-
addFreeStandingDomain: () => addFreeStandingDomain,
|
|
22682
|
-
deriveSubsystemDomains: () => deriveSubsystemDomains,
|
|
22683
|
-
findDomain: () => findDomain,
|
|
22684
|
-
listFreeStandingDomains: () => listFreeStandingDomains,
|
|
22685
|
-
removeFreeStandingDomain: () => removeFreeStandingDomain,
|
|
22686
|
-
resolveDomains: () => resolveDomains
|
|
22687
|
-
});
|
|
22688
|
-
function rel(p) {
|
|
22689
|
-
return path19.relative(process.cwd(), p).replace(/\\/g, "/");
|
|
22690
|
-
}
|
|
22691
|
-
function deriveSubsystemDomains() {
|
|
22692
|
-
const subsystems = loadSubsystemSpecs();
|
|
22693
|
-
const components = loadComponentSpecs();
|
|
22694
|
-
return subsystems.map((sub) => {
|
|
22695
|
-
const ownedPaths = [
|
|
22696
|
-
rel(getSubsystemPath(sub.id)),
|
|
22697
|
-
...components.filter((c) => c.subsystem === sub.id).map((c) => rel(getComponentPath(c.id, sub.id)))
|
|
22698
|
-
];
|
|
22699
|
-
return {
|
|
22700
|
-
id: sub.id,
|
|
22701
|
-
name: sub.name,
|
|
22702
|
-
description: sub.description,
|
|
22703
|
-
boundTo: sub.id,
|
|
22704
|
-
ownedPaths
|
|
22705
|
-
};
|
|
22706
|
-
});
|
|
22707
|
-
}
|
|
22708
|
-
function listFreeStandingDomains() {
|
|
22709
|
-
return loadTopologyConfig().domains;
|
|
22710
|
-
}
|
|
22711
|
-
function resolveDomains() {
|
|
22712
|
-
return [...deriveSubsystemDomains(), ...listFreeStandingDomains()];
|
|
22713
|
-
}
|
|
22714
|
-
function findDomain(id) {
|
|
22715
|
-
return resolveDomains().find((d) => d.id === id);
|
|
22716
|
-
}
|
|
22717
|
-
function addFreeStandingDomain(domain) {
|
|
22718
|
-
const config = loadTopologyConfig();
|
|
22719
|
-
if (config.domains.some((d) => d.id === domain.id)) {
|
|
22720
|
-
throw new WaironError(`A free-standing domain "${domain.id}" already exists in .wai/topology.yaml.`);
|
|
22721
|
-
}
|
|
22722
|
-
if (deriveSubsystemDomains().some((d) => d.id === domain.id)) {
|
|
22723
|
-
throw new WaironError(`Domain id "${domain.id}" collides with a subsystem-derived domain.`);
|
|
22724
|
-
}
|
|
22725
|
-
config.domains.push(domain);
|
|
22726
|
-
saveTopologyConfig(config);
|
|
22727
|
-
}
|
|
22728
|
-
function removeFreeStandingDomain(id) {
|
|
22729
|
-
const config = loadTopologyConfig();
|
|
22730
|
-
const idx = config.domains.findIndex((d) => d.id === id);
|
|
22731
|
-
if (idx === -1) {
|
|
22732
|
-
throw new WaironError(
|
|
22733
|
-
`"${id}" is not a free-standing domain. Subsystem-backed domains are derived from the spec tree and cannot be removed here.`
|
|
22734
|
-
);
|
|
22735
|
-
}
|
|
22736
|
-
config.domains.splice(idx, 1);
|
|
22737
|
-
saveTopologyConfig(config);
|
|
22194
|
+
function parseTemplate(yamlContent) {
|
|
22195
|
+
return TemplateSchema.parse(parseYaml(yamlContent));
|
|
22738
22196
|
}
|
|
22739
|
-
var
|
|
22740
|
-
var
|
|
22741
|
-
"src/core/
|
|
22197
|
+
var path18;
|
|
22198
|
+
var init_templates = __esm({
|
|
22199
|
+
"src/core/templates.ts"() {
|
|
22742
22200
|
"use strict";
|
|
22743
|
-
|
|
22744
|
-
|
|
22745
|
-
|
|
22201
|
+
path18 = __toESM(require("path"));
|
|
22202
|
+
init_fs();
|
|
22203
|
+
init_yaml();
|
|
22746
22204
|
init_errors();
|
|
22205
|
+
init_template();
|
|
22206
|
+
init_paths();
|
|
22207
|
+
init_defaults();
|
|
22747
22208
|
}
|
|
22748
22209
|
});
|
|
22749
22210
|
|
|
@@ -22795,7 +22256,7 @@ function provisionProject(name) {
|
|
|
22795
22256
|
function ensureProjectInitialized(fallbackName) {
|
|
22796
22257
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
22797
22258
|
const paths = aiPathsAt(getProjectRoot());
|
|
22798
|
-
const hasSystem =
|
|
22259
|
+
const hasSystem = fs14.existsSync(paths.specsSystem());
|
|
22799
22260
|
let name = fallbackName;
|
|
22800
22261
|
if (hasSystem) {
|
|
22801
22262
|
const existing = loadSystemSpec();
|
|
@@ -22817,11 +22278,11 @@ function ensureProjectInitialized(fallbackName) {
|
|
|
22817
22278
|
function walkChainedSubprojects(projectRoot, onChild) {
|
|
22818
22279
|
const visited = /* @__PURE__ */ new Set();
|
|
22819
22280
|
const walk2 = (dir) => {
|
|
22820
|
-
const resolved =
|
|
22281
|
+
const resolved = path19.resolve(dir);
|
|
22821
22282
|
if (visited.has(resolved)) return;
|
|
22822
22283
|
visited.add(resolved);
|
|
22823
22284
|
const specsDir = aiPathsAt(dir).specsDir();
|
|
22824
|
-
if (!
|
|
22285
|
+
if (!fs14.existsSync(specsDir)) return;
|
|
22825
22286
|
for (const file of listFilesRecursive(specsDir, ".yaml")) {
|
|
22826
22287
|
let raw;
|
|
22827
22288
|
try {
|
|
@@ -22839,497 +22300,1040 @@ function walkChainedSubprojects(projectRoot, onChild) {
|
|
|
22839
22300
|
continue;
|
|
22840
22301
|
}
|
|
22841
22302
|
const id = raw.id;
|
|
22842
|
-
onChild(childDir, typeof id === "string" ? id :
|
|
22303
|
+
onChild(childDir, typeof id === "string" ? id : path19.basename(childDir));
|
|
22843
22304
|
walk2(childDir);
|
|
22844
22305
|
}
|
|
22845
|
-
};
|
|
22846
|
-
walk2(projectRoot);
|
|
22306
|
+
};
|
|
22307
|
+
walk2(projectRoot);
|
|
22308
|
+
}
|
|
22309
|
+
function listDirectChainedSubprojects(projectRoot) {
|
|
22310
|
+
const out = [];
|
|
22311
|
+
const specsDir = aiPathsAt(projectRoot).specsDir();
|
|
22312
|
+
if (!fs14.existsSync(specsDir)) return out;
|
|
22313
|
+
for (const file of listFilesRecursive(specsDir, ".yaml")) {
|
|
22314
|
+
let raw;
|
|
22315
|
+
try {
|
|
22316
|
+
raw = readYamlFile(file);
|
|
22317
|
+
} catch {
|
|
22318
|
+
continue;
|
|
22319
|
+
}
|
|
22320
|
+
if (!(raw && typeof raw === "object" && "parentSystem" in raw)) continue;
|
|
22321
|
+
const pp = raw.projectPath;
|
|
22322
|
+
if (typeof pp !== "string" || pp.trim() === "") continue;
|
|
22323
|
+
let dir;
|
|
22324
|
+
try {
|
|
22325
|
+
dir = assertContainedProjectPath(projectRoot, pp);
|
|
22326
|
+
} catch {
|
|
22327
|
+
continue;
|
|
22328
|
+
}
|
|
22329
|
+
const id = raw.id;
|
|
22330
|
+
out.push({ dir, subsystemId: typeof id === "string" ? id : path19.basename(dir) });
|
|
22331
|
+
}
|
|
22332
|
+
return out;
|
|
22333
|
+
}
|
|
22334
|
+
function childHasSpecsButNoConfig(childDir) {
|
|
22335
|
+
return fs14.existsSync(aiPathsAt(childDir).specsDir()) && !projectConfigRepositoryAt(childDir).exists();
|
|
22336
|
+
}
|
|
22337
|
+
function findChainingSubprojectsMissingConfig(projectRoot) {
|
|
22338
|
+
const missing = [];
|
|
22339
|
+
walkChainedSubprojects(projectRoot, (childDir) => {
|
|
22340
|
+
if (childHasSpecsButNoConfig(childDir)) missing.push(childDir);
|
|
22341
|
+
});
|
|
22342
|
+
return missing;
|
|
22343
|
+
}
|
|
22344
|
+
function backfillChainedSubprojectConfigs(projectRoot) {
|
|
22345
|
+
const backfilled = [];
|
|
22346
|
+
walkChainedSubprojects(projectRoot, (childDir, subsystemId) => {
|
|
22347
|
+
if (childHasSpecsButNoConfig(childDir)) {
|
|
22348
|
+
runWithProjectRoot(childDir, () => {
|
|
22349
|
+
ensureProjectInitialized(subsystemId);
|
|
22350
|
+
});
|
|
22351
|
+
backfilled.push(childDir);
|
|
22352
|
+
}
|
|
22353
|
+
});
|
|
22354
|
+
return backfilled;
|
|
22355
|
+
}
|
|
22356
|
+
function createChainedSubsystem(subsystem, projectName) {
|
|
22357
|
+
if (!subsystem.projectPath || subsystem.projectPath.trim() === "") {
|
|
22358
|
+
throw new WaironError("projectPath is required to create a chained subsystem.");
|
|
22359
|
+
}
|
|
22360
|
+
const projectPath = toPosixPath(subsystem.projectPath);
|
|
22361
|
+
saveSubsystemSpec({ ...subsystem, projectPath });
|
|
22362
|
+
const childDir = assertContainedProjectPath(getProjectRoot(), projectPath);
|
|
22363
|
+
runWithProjectRoot(childDir, () => {
|
|
22364
|
+
ensureDir(aiPathsAt(childDir).specsDir());
|
|
22365
|
+
ensureProjectInitialized(projectName);
|
|
22366
|
+
});
|
|
22367
|
+
invalidateSpecCache();
|
|
22368
|
+
}
|
|
22369
|
+
function moveSubsystemProject(subsystemId, newProjectPath) {
|
|
22370
|
+
const sub = loadSubsystemSpec(subsystemId);
|
|
22371
|
+
if (!sub) {
|
|
22372
|
+
throw new WaironError(`Subsystem "${subsystemId}" does not exist.`);
|
|
22373
|
+
}
|
|
22374
|
+
if (!sub.projectPath || sub.projectPath.trim() === "") {
|
|
22375
|
+
throw new WaironError(
|
|
22376
|
+
`Subsystem "${subsystemId}" has no projectPath to move (not an external subproject).`
|
|
22377
|
+
);
|
|
22378
|
+
}
|
|
22379
|
+
const nextPath = toPosixPath(newProjectPath);
|
|
22380
|
+
const root = getProjectRoot();
|
|
22381
|
+
const oldDir = assertContainedProjectPath(root, sub.projectPath);
|
|
22382
|
+
const newDir = assertContainedProjectPath(root, nextPath);
|
|
22383
|
+
if (oldDir !== newDir) {
|
|
22384
|
+
if (!fs14.existsSync(oldDir)) {
|
|
22385
|
+
throw new WaironError(`Subproject directory not found at its current path: ${oldDir}`);
|
|
22386
|
+
}
|
|
22387
|
+
if (fs14.existsSync(newDir)) {
|
|
22388
|
+
throw new WaironError(`Target directory already exists: ${newDir}`);
|
|
22389
|
+
}
|
|
22390
|
+
ensureDir(path19.dirname(newDir));
|
|
22391
|
+
fs14.renameSync(oldDir, newDir);
|
|
22392
|
+
}
|
|
22393
|
+
saveSubsystemSpec({ ...sub, projectPath: nextPath, updatedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
22394
|
+
invalidateSpecCache();
|
|
22395
|
+
}
|
|
22396
|
+
function toPosixPath(p) {
|
|
22397
|
+
return p.replace(/\\/g, "/");
|
|
22398
|
+
}
|
|
22399
|
+
function isWithinDir(dir, file) {
|
|
22400
|
+
const d = path19.resolve(dir);
|
|
22401
|
+
const f = path19.resolve(file);
|
|
22402
|
+
return f === d || f.startsWith(d + path19.sep);
|
|
22403
|
+
}
|
|
22404
|
+
function externalizeSubsystem(subsystemId, projectPath) {
|
|
22405
|
+
if (subsystemId.includes("::")) {
|
|
22406
|
+
throw new WaironError("cannot externalize a nested/namespaced subsystem; run from its owning project.");
|
|
22407
|
+
}
|
|
22408
|
+
const foo = loadSubsystemSpec(subsystemId);
|
|
22409
|
+
if (!foo || foo.projectPath) {
|
|
22410
|
+
throw new WaironError(`cannot externalize: subsystem "${subsystemId}" is missing or already external.`);
|
|
22411
|
+
}
|
|
22412
|
+
const parentRoot = getProjectRoot();
|
|
22413
|
+
const parentSpecsDir = aiPathsAt(parentRoot).specsDir();
|
|
22414
|
+
const fooDir = path19.join(parentSpecsDir, subsystemId);
|
|
22415
|
+
if (!fs14.existsSync(fooDir)) {
|
|
22416
|
+
throw new WaironError(`subsystem specs directory not found: ${fooDir}`);
|
|
22417
|
+
}
|
|
22418
|
+
const relPath = toPosixPath(projectPath);
|
|
22419
|
+
const childDir = assertContainedProjectPath(parentRoot, relPath);
|
|
22420
|
+
const childFooDir = path19.join(childDir, ".wai", "specs", subsystemId);
|
|
22421
|
+
if (fs14.existsSync(childFooDir)) {
|
|
22422
|
+
throw new WaironError(`target already contains a "${subsystemId}" subsystem: ${childFooDir}`);
|
|
22423
|
+
}
|
|
22424
|
+
const renameMap = buildRenameMap(
|
|
22425
|
+
subsystemId,
|
|
22426
|
+
/* externalize */
|
|
22427
|
+
true
|
|
22428
|
+
);
|
|
22429
|
+
const childSystemName = foo.name || subsystemId;
|
|
22430
|
+
runWithProjectRoot(childDir, () => {
|
|
22431
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
22432
|
+
projectConfigRepository.create(defaultProjectConfig(childSystemName, now));
|
|
22433
|
+
ensureDir(path19.join(childDir, ".wai", "specs"));
|
|
22434
|
+
saveSystemSpec(bootstrapSystemSpec(childSystemName, now));
|
|
22435
|
+
});
|
|
22436
|
+
ensureDir(path19.dirname(childFooDir));
|
|
22437
|
+
fs14.renameSync(fooDir, childFooDir);
|
|
22438
|
+
rebaseImplementationPaths(childFooDir, parentRoot, childDir);
|
|
22439
|
+
patchSubsystemIndex(path19.join(childFooDir, ".index.yaml"), (s) => {
|
|
22440
|
+
s.parentSystem = childSystemName;
|
|
22441
|
+
delete s.projectPath;
|
|
22442
|
+
});
|
|
22443
|
+
ensureDir(fooDir);
|
|
22444
|
+
writeYamlFile(path19.join(fooDir, ".index.yaml"), {
|
|
22445
|
+
id: subsystemId,
|
|
22446
|
+
name: foo.name,
|
|
22447
|
+
description: foo.description,
|
|
22448
|
+
parentSystem: foo.parentSystem,
|
|
22449
|
+
publicInterfaces: [],
|
|
22450
|
+
projectPath: relPath,
|
|
22451
|
+
trustedLinks: [],
|
|
22452
|
+
status: foo.status ?? "draft",
|
|
22453
|
+
createdAt: foo.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
22454
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
22455
|
+
});
|
|
22456
|
+
rewriteRefsInDir(parentSpecsDir, renameMap, fooDir);
|
|
22457
|
+
rebaseMovedRefs(childFooDir, subsystemId, "into");
|
|
22458
|
+
invalidateSpecCache();
|
|
22459
|
+
}
|
|
22460
|
+
function internalizeSubsystem(subsystemId) {
|
|
22461
|
+
if (subsystemId.includes("::")) {
|
|
22462
|
+
throw new WaironError("cannot internalize a nested/namespaced subsystem; run from its owning project.");
|
|
22463
|
+
}
|
|
22464
|
+
const foo = loadSubsystemSpec(subsystemId);
|
|
22465
|
+
if (!foo || !foo.projectPath) {
|
|
22466
|
+
throw new WaironError(`cannot internalize: subsystem "${subsystemId}" is missing or not external.`);
|
|
22467
|
+
}
|
|
22468
|
+
const parentRoot = getProjectRoot();
|
|
22469
|
+
const parentSpecsDir = aiPathsAt(parentRoot).specsDir();
|
|
22470
|
+
const childDir = assertContainedProjectPath(parentRoot, foo.projectPath);
|
|
22471
|
+
const childWai = path19.join(childDir, ".wai");
|
|
22472
|
+
const childFooDir = path19.join(childDir, ".wai", "specs", subsystemId);
|
|
22473
|
+
if (!fs14.existsSync(childFooDir)) {
|
|
22474
|
+
throw new WaironError(`external subproject missing subsystem "${subsystemId}": ${childFooDir}`);
|
|
22475
|
+
}
|
|
22476
|
+
const childOwnSubs = runWithProjectRoot(childDir, () => loadSubsystemSpecs()).filter((s) => !s.id.includes("::"));
|
|
22477
|
+
if (childOwnSubs.length !== 1 || childOwnSubs[0].id !== subsystemId) {
|
|
22478
|
+
throw new WaironError(`cannot internalize: subproject is a multi-subsystem system, not a flat "${subsystemId}".`);
|
|
22479
|
+
}
|
|
22480
|
+
const renameMap = buildRenameMap(
|
|
22481
|
+
subsystemId,
|
|
22482
|
+
/* externalize */
|
|
22483
|
+
false
|
|
22484
|
+
);
|
|
22485
|
+
const parentSystemName = loadSystemSpec()?.name ?? foo.parentSystem;
|
|
22486
|
+
const fooDir = path19.join(parentSpecsDir, subsystemId);
|
|
22487
|
+
fs14.rmSync(fooDir, { recursive: true, force: true });
|
|
22488
|
+
ensureDir(path19.dirname(fooDir));
|
|
22489
|
+
fs14.renameSync(childFooDir, fooDir);
|
|
22490
|
+
rebaseImplementationPaths(fooDir, childDir, parentRoot);
|
|
22491
|
+
patchSubsystemIndex(path19.join(fooDir, ".index.yaml"), (s) => {
|
|
22492
|
+
s.parentSystem = parentSystemName;
|
|
22493
|
+
delete s.projectPath;
|
|
22494
|
+
});
|
|
22495
|
+
fs14.rmSync(childWai, { recursive: true, force: true });
|
|
22496
|
+
rewriteRefsInDir(parentSpecsDir, renameMap, fooDir);
|
|
22497
|
+
rebaseMovedRefs(fooDir, subsystemId, "outOf");
|
|
22498
|
+
invalidateSpecCache();
|
|
22499
|
+
}
|
|
22500
|
+
function buildRenameMap(subsystemId, externalize) {
|
|
22501
|
+
const map = /* @__PURE__ */ new Map();
|
|
22502
|
+
const prefix = `${subsystemId}::`;
|
|
22503
|
+
const add = (bare, namespaced) => externalize ? map.set(bare, namespaced) : map.set(namespaced, bare);
|
|
22504
|
+
const comps = loadComponentSpecs().filter((c) => c.subsystem === subsystemId);
|
|
22505
|
+
const compIds = new Set(comps.map((c) => c.id));
|
|
22506
|
+
for (const c of comps) {
|
|
22507
|
+
const bare = c.id.startsWith(prefix) ? c.id.slice(prefix.length) : c.id;
|
|
22508
|
+
add(bare, `${prefix}${bare}`);
|
|
22509
|
+
}
|
|
22510
|
+
for (const i of loadInterfaceSpecs()) {
|
|
22511
|
+
if (!compIds.has(i.component)) continue;
|
|
22512
|
+
const bare = i.id.startsWith(prefix) ? i.id.slice(prefix.length) : i.id;
|
|
22513
|
+
add(bare, `${prefix}${bare}`);
|
|
22514
|
+
}
|
|
22515
|
+
for (const t of loadTypeSpecs()) {
|
|
22516
|
+
if (t.subsystem !== subsystemId) continue;
|
|
22517
|
+
const bare = t.id.startsWith(prefix) ? t.id.slice(prefix.length) : t.id;
|
|
22518
|
+
add(bare, `${prefix}${bare}`);
|
|
22519
|
+
}
|
|
22520
|
+
return map;
|
|
22521
|
+
}
|
|
22522
|
+
function rewriteRefsInDir(specsDir, renameMap, excludeDir) {
|
|
22523
|
+
if (renameMap.size === 0) return;
|
|
22524
|
+
rewriteRefFields(specsDir, (ref) => renameMap.get(ref) ?? ref, excludeDir);
|
|
22525
|
+
}
|
|
22526
|
+
function rebaseMovedRefs(movedDir, mount, direction) {
|
|
22527
|
+
const declared = componentIdsUnder(movedDir);
|
|
22528
|
+
rewriteRefFields(movedDir, (ref, position) => position === "component" ? rebaseReference(ref, mount, direction, (id) => declared.has(id)) : ref);
|
|
22529
|
+
}
|
|
22530
|
+
function componentIdsUnder(dir) {
|
|
22531
|
+
const ids = /* @__PURE__ */ new Set();
|
|
22532
|
+
for (const file of listFilesRecursive(dir, ".yaml")) {
|
|
22533
|
+
let raw;
|
|
22534
|
+
try {
|
|
22535
|
+
raw = readYamlFile(file);
|
|
22536
|
+
} catch {
|
|
22537
|
+
continue;
|
|
22538
|
+
}
|
|
22539
|
+
if (raw && typeof raw === "object" && "componentType" in raw && typeof raw.id === "string") ids.add(raw.id);
|
|
22540
|
+
}
|
|
22541
|
+
return ids;
|
|
22847
22542
|
}
|
|
22848
|
-
function
|
|
22849
|
-
const
|
|
22850
|
-
const specsDir = aiPathsAt(projectRoot).specsDir();
|
|
22851
|
-
if (!fs15.existsSync(specsDir)) return out;
|
|
22543
|
+
function rewriteRefFields(specsDir, remap, excludeDir) {
|
|
22544
|
+
const rewritten = [];
|
|
22852
22545
|
for (const file of listFilesRecursive(specsDir, ".yaml")) {
|
|
22546
|
+
if (excludeDir && isWithinDir(excludeDir, file)) continue;
|
|
22853
22547
|
let raw;
|
|
22854
22548
|
try {
|
|
22855
22549
|
raw = readYamlFile(file);
|
|
22856
22550
|
} catch {
|
|
22857
22551
|
continue;
|
|
22858
22552
|
}
|
|
22859
|
-
if (!
|
|
22860
|
-
const
|
|
22861
|
-
if (
|
|
22862
|
-
|
|
22553
|
+
if (!raw || typeof raw !== "object") continue;
|
|
22554
|
+
const kind = specKind(raw);
|
|
22555
|
+
if (!rewriteSpecRefs(raw, remap) || !kind) continue;
|
|
22556
|
+
writeYamlFile(file, raw);
|
|
22557
|
+
rewritten.push({ kind, id: kind === "system" ? "system" : String(raw.id) });
|
|
22558
|
+
}
|
|
22559
|
+
return rewritten;
|
|
22560
|
+
}
|
|
22561
|
+
function rebaseImplementationPaths(specsDir, fromRoot, toRoot) {
|
|
22562
|
+
for (const file of listFilesRecursive(specsDir, ".yaml")) {
|
|
22563
|
+
let raw;
|
|
22863
22564
|
try {
|
|
22864
|
-
|
|
22565
|
+
raw = readYamlFile(file);
|
|
22865
22566
|
} catch {
|
|
22866
22567
|
continue;
|
|
22867
22568
|
}
|
|
22868
|
-
|
|
22869
|
-
|
|
22569
|
+
if (!raw || typeof raw !== "object" || !("contract" in raw)) continue;
|
|
22570
|
+
let changed = false;
|
|
22571
|
+
const rebase = (holder, key) => {
|
|
22572
|
+
const p = holder[key];
|
|
22573
|
+
if (typeof p !== "string" || p === "" || path19.isAbsolute(p)) return;
|
|
22574
|
+
const next = toPosixPath(path19.relative(toRoot, path19.resolve(fromRoot, p)));
|
|
22575
|
+
if (next !== p) {
|
|
22576
|
+
holder[key] = next;
|
|
22577
|
+
changed = true;
|
|
22578
|
+
}
|
|
22579
|
+
};
|
|
22580
|
+
for (const key of ["sourcePath", "simPath"]) rebase(raw, key);
|
|
22581
|
+
if (Array.isArray(raw.methods)) {
|
|
22582
|
+
for (const method of raw.methods) {
|
|
22583
|
+
if (method && typeof method === "object") rebase(method, "sourcePath");
|
|
22584
|
+
}
|
|
22585
|
+
}
|
|
22586
|
+
if (changed) writeYamlFile(file, raw);
|
|
22870
22587
|
}
|
|
22871
|
-
return out;
|
|
22872
|
-
}
|
|
22873
|
-
function childHasSpecsButNoConfig(childDir) {
|
|
22874
|
-
return fs15.existsSync(aiPathsAt(childDir).specsDir()) && !projectConfigRepositoryAt(childDir).exists();
|
|
22875
22588
|
}
|
|
22876
|
-
function
|
|
22877
|
-
|
|
22878
|
-
|
|
22879
|
-
|
|
22880
|
-
|
|
22881
|
-
|
|
22589
|
+
function patchSubsystemIndex(indexPath, mutate) {
|
|
22590
|
+
if (!fs14.existsSync(indexPath)) return;
|
|
22591
|
+
const raw = readYamlFile(indexPath);
|
|
22592
|
+
mutate(raw);
|
|
22593
|
+
raw.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
22594
|
+
writeYamlFile(indexPath, raw);
|
|
22882
22595
|
}
|
|
22883
|
-
function
|
|
22884
|
-
const
|
|
22885
|
-
|
|
22886
|
-
|
|
22887
|
-
|
|
22888
|
-
|
|
22889
|
-
|
|
22890
|
-
|
|
22596
|
+
function renameComponent(componentId, newId) {
|
|
22597
|
+
const component = loadComponentSpec(componentId);
|
|
22598
|
+
if (!component) {
|
|
22599
|
+
throw new WaironError(`component-missing: no component has the id "${componentId}".`);
|
|
22600
|
+
}
|
|
22601
|
+
if (componentId.includes("::")) {
|
|
22602
|
+
throw new WaironError(
|
|
22603
|
+
`chained-component: "${componentId}" lives in a chained subproject; rename it from that project's own root.`
|
|
22604
|
+
);
|
|
22605
|
+
}
|
|
22606
|
+
if (!SpecIdSchema.safeParse(newId).success) {
|
|
22607
|
+
throw new WaironError(`invalid-id: "${newId}" is not a lowercase identifier with no namespace separator.`);
|
|
22608
|
+
}
|
|
22609
|
+
const components = loadComponentSpecs();
|
|
22610
|
+
const interfaces = loadInterfaceSpecs();
|
|
22611
|
+
const implementations = loadImplementationSpecs();
|
|
22612
|
+
const interfaceId = `i${newId}`;
|
|
22613
|
+
const implementationId = `${newId}_impl`;
|
|
22614
|
+
const taken = [
|
|
22615
|
+
components.some((c) => c.id === newId) ? `component "${newId}"` : null,
|
|
22616
|
+
interfaces.some((i) => i.id === interfaceId) ? `interface "${interfaceId}"` : null,
|
|
22617
|
+
implementations.some((impl) => impl.id === implementationId) ? `implementation "${implementationId}"` : null
|
|
22618
|
+
].filter((holder) => holder !== null);
|
|
22619
|
+
if (taken.length > 0) {
|
|
22620
|
+
throw new WaironError(`id-taken: the new id, or an id it implies, is already in use: ${taken.join(", ")}.`);
|
|
22621
|
+
}
|
|
22622
|
+
const contracts = interfaces.filter((i) => i.component === componentId);
|
|
22623
|
+
const movingInterface = contracts.find((i) => i.id === `i${componentId}`);
|
|
22624
|
+
const movingImplementation = implementations.find((impl) => impl.id === `${componentId}_impl` && contracts.some((i) => i.id === impl.contract));
|
|
22625
|
+
const renamed = [
|
|
22626
|
+
{ kind: "component", from: componentId, to: newId },
|
|
22627
|
+
...movingInterface ? [{ kind: "interface", from: movingInterface.id, to: interfaceId }] : [],
|
|
22628
|
+
...movingImplementation ? [{ kind: "implementation", from: movingImplementation.id, to: implementationId }] : []
|
|
22629
|
+
];
|
|
22630
|
+
const rewritten = rewriteRefFields(aiPathsAt(getProjectRoot()).specsDir(), (ref, position) => {
|
|
22631
|
+
if (position === "component" || position === "entity-class" || position === "auth-source") {
|
|
22632
|
+
return ref === componentId ? newId : ref;
|
|
22891
22633
|
}
|
|
22892
|
-
|
|
22893
|
-
|
|
22634
|
+
if (position === "interface" && ref === movingInterface?.id) return interfaceId;
|
|
22635
|
+
return ref;
|
|
22636
|
+
}).filter((spec) => !renamed.some((moved) => moved.kind === spec.kind && moved.from === spec.id)).map((spec) => spec.id);
|
|
22637
|
+
invalidateSpecCache();
|
|
22638
|
+
moveRenamedSpecs(componentId, newId, component, movingInterface, movingImplementation);
|
|
22639
|
+
return { renamed, rewritten };
|
|
22894
22640
|
}
|
|
22895
|
-
function
|
|
22896
|
-
|
|
22897
|
-
|
|
22641
|
+
function moveRenamedSpecs(componentId, newId, component, movingInterface, movingImplementation) {
|
|
22642
|
+
const interfaceId = `i${newId}`;
|
|
22643
|
+
const implementationId = `${newId}_impl`;
|
|
22644
|
+
const movedComponent = loadComponentSpec(componentId) ?? component;
|
|
22645
|
+
const movedInterface = movingInterface ? loadInterfaceSpec(movingInterface.id) ?? movingInterface : null;
|
|
22646
|
+
const movedImplementation = movingImplementation ? loadImplementationSpec(movingImplementation.id) ?? movingImplementation : null;
|
|
22647
|
+
saveComponentSpec({ ...movedComponent, id: newId });
|
|
22648
|
+
if (movedInterface) saveInterfaceSpec({ ...movedInterface, id: interfaceId, component: newId });
|
|
22649
|
+
if (movedImplementation) {
|
|
22650
|
+
const oldFile = getImplementationPath(movedImplementation.id);
|
|
22651
|
+
if (path19.resolve(getImplementationPath(implementationId, movedImplementation.contract)) === path19.resolve(oldFile)) {
|
|
22652
|
+
fs14.unlinkSync(oldFile);
|
|
22653
|
+
}
|
|
22654
|
+
saveImplementationSpec({ ...movedImplementation, id: implementationId });
|
|
22898
22655
|
}
|
|
22899
|
-
|
|
22900
|
-
|
|
22901
|
-
|
|
22902
|
-
runWithProjectRoot(childDir, () => {
|
|
22903
|
-
ensureDir(aiPathsAt(childDir).specsDir());
|
|
22904
|
-
ensureProjectInitialized(projectName);
|
|
22905
|
-
});
|
|
22656
|
+
removeSpecFile2(getComponentPath(componentId), componentId);
|
|
22657
|
+
if (movingInterface) removeSpecFile2(getInterfacePath(movingInterface.id), movingInterface.id);
|
|
22658
|
+
if (movingImplementation) removeSpecFile2(getImplementationPath(movingImplementation.id), movingImplementation.id);
|
|
22906
22659
|
invalidateSpecCache();
|
|
22907
22660
|
}
|
|
22908
|
-
function
|
|
22909
|
-
|
|
22910
|
-
|
|
22911
|
-
|
|
22661
|
+
function removeSpecFile2(file, id) {
|
|
22662
|
+
if (!fs14.existsSync(file)) return;
|
|
22663
|
+
try {
|
|
22664
|
+
if (readYamlFile(file)?.id !== id) return;
|
|
22665
|
+
} catch {
|
|
22666
|
+
return;
|
|
22912
22667
|
}
|
|
22913
|
-
|
|
22668
|
+
fs14.unlinkSync(file);
|
|
22669
|
+
const specsRoot = path19.resolve(aiPathsAt(getProjectRoot()).specsDir());
|
|
22670
|
+
for (let dir = path19.dirname(path19.resolve(file)); dir !== specsRoot && isWithinDir(specsRoot, dir); dir = path19.dirname(dir)) {
|
|
22671
|
+
if (fs14.readdirSync(dir).length > 0) break;
|
|
22672
|
+
fs14.rmdirSync(dir);
|
|
22673
|
+
}
|
|
22674
|
+
}
|
|
22675
|
+
function renameMethod(componentId, methodName, newName, pinSymbol) {
|
|
22676
|
+
const component = loadComponentSpec(componentId);
|
|
22677
|
+
if (!component) {
|
|
22678
|
+
throw new WaironError(`component-missing: no component has the id "${componentId}".`);
|
|
22679
|
+
}
|
|
22680
|
+
if (componentId.includes("::")) {
|
|
22914
22681
|
throw new WaironError(
|
|
22915
|
-
`
|
|
22682
|
+
`chained-component: "${componentId}" lives in a chained subproject; rename its method from that project's own root.`
|
|
22916
22683
|
);
|
|
22917
22684
|
}
|
|
22918
|
-
|
|
22919
|
-
|
|
22920
|
-
|
|
22921
|
-
const
|
|
22922
|
-
|
|
22923
|
-
|
|
22924
|
-
|
|
22925
|
-
|
|
22926
|
-
|
|
22927
|
-
|
|
22928
|
-
}
|
|
22929
|
-
|
|
22930
|
-
|
|
22685
|
+
if (!METHOD_NAME.test(newName)) {
|
|
22686
|
+
throw new WaironError(`invalid-name: "${newName}" is not a camel-case identifier.`);
|
|
22687
|
+
}
|
|
22688
|
+
const contracts = loadInterfaceSpecs().filter((i) => i.component === componentId);
|
|
22689
|
+
const moving = contracts.filter((i) => i.methods.some((m) => m.name === methodName));
|
|
22690
|
+
if (moving.length === 0) {
|
|
22691
|
+
throw new WaironError(`method-missing: no contract of "${componentId}" declares the method "${methodName}".`);
|
|
22692
|
+
}
|
|
22693
|
+
const taken = moving.filter((i) => i.methods.some((m) => m.name === newName)).map((i) => `"${i.id}"`);
|
|
22694
|
+
if (taken.length > 0) {
|
|
22695
|
+
throw new WaironError(`name-taken: ${taken.join(", ")} already declares a method under the name "${newName}".`);
|
|
22696
|
+
}
|
|
22697
|
+
const implementations = loadImplementationSpecs();
|
|
22698
|
+
const movingContracts = new Set(moving.map((i) => i.id));
|
|
22699
|
+
const renamed = [];
|
|
22700
|
+
for (const contract of moving) {
|
|
22701
|
+
saveInterfaceSpec({
|
|
22702
|
+
...contract,
|
|
22703
|
+
methods: contract.methods.map((m) => m.name === methodName ? { ...m, name: newName, signature: renameInSignature(m.signature, methodName, newName) } : m)
|
|
22704
|
+
});
|
|
22705
|
+
renamed.push(contract.id);
|
|
22706
|
+
}
|
|
22707
|
+
let pinnedSymbol;
|
|
22708
|
+
for (const implementation of implementations) {
|
|
22709
|
+
if (!movingContracts.has(implementation.contract)) continue;
|
|
22710
|
+
const realization = implementation.methods.find((m) => m.name === methodName);
|
|
22711
|
+
if (!realization) continue;
|
|
22712
|
+
const pin = realization.symbol === void 0 && pinSymbol !== false;
|
|
22713
|
+
if (pin) pinnedSymbol = methodName;
|
|
22714
|
+
saveImplementationSpec({
|
|
22715
|
+
...implementation,
|
|
22716
|
+
methods: implementation.methods.map((m) => m.name === methodName ? { ...m, name: newName, ...pin ? { symbol: methodName } : {} } : m)
|
|
22717
|
+
});
|
|
22718
|
+
renamed.push(implementation.id);
|
|
22719
|
+
}
|
|
22720
|
+
invalidateSpecCache();
|
|
22721
|
+
const specsDir = aiPathsAt(getProjectRoot()).specsDir();
|
|
22722
|
+
const rewritten = rewriteRefFields(specsDir, (ref, position, owner) => position === "method" && owner === componentId && ref === methodName ? newName : ref).map((spec) => spec.id);
|
|
22723
|
+
const mentions = collectMentions(specsDir, methodName, moving);
|
|
22724
|
+
return {
|
|
22725
|
+
component: componentId,
|
|
22726
|
+
from: methodName,
|
|
22727
|
+
to: newName,
|
|
22728
|
+
renamed,
|
|
22729
|
+
rewritten,
|
|
22730
|
+
mentions,
|
|
22731
|
+
...pinnedSymbol ? { pinnedSymbol } : {}
|
|
22732
|
+
};
|
|
22733
|
+
}
|
|
22734
|
+
function renameInSignature(signature, from, to) {
|
|
22735
|
+
return signature.replace(identifierPattern(from), to);
|
|
22736
|
+
}
|
|
22737
|
+
function collectMentions(specsDir, methodName, moved) {
|
|
22738
|
+
const mentions = /* @__PURE__ */ new Set();
|
|
22739
|
+
for (const contract of moved) {
|
|
22740
|
+
const wireBound = contract.methods.some((m) => {
|
|
22741
|
+
const endpoint = m.endpoint;
|
|
22742
|
+
return endpoint?.transport === "gRPC" && endpoint.method === methodName;
|
|
22743
|
+
});
|
|
22744
|
+
if (wireBound) mentions.add(contract.id);
|
|
22745
|
+
}
|
|
22746
|
+
const named = identifierPattern(methodName);
|
|
22747
|
+
const namesMethod = (value) => {
|
|
22748
|
+
if (Array.isArray(value)) return value.some(namesMethod);
|
|
22749
|
+
if (!value || typeof value !== "object") return false;
|
|
22750
|
+
return Object.entries(value).some(([key, nested]) => typeof nested === "string" ? PROSE_FIELDS2.has(key) && named.test(nested) : namesMethod(nested));
|
|
22751
|
+
};
|
|
22752
|
+
for (const file of listFilesRecursive(specsDir, ".yaml")) {
|
|
22753
|
+
let raw;
|
|
22754
|
+
try {
|
|
22755
|
+
raw = readYamlFile(file);
|
|
22756
|
+
} catch {
|
|
22757
|
+
continue;
|
|
22758
|
+
}
|
|
22759
|
+
if (!raw || typeof raw !== "object") continue;
|
|
22760
|
+
const kind = specKind(raw);
|
|
22761
|
+
if (!kind || !namesMethod(raw)) continue;
|
|
22762
|
+
mentions.add(kind === "system" ? "system" : String(raw.id));
|
|
22763
|
+
}
|
|
22764
|
+
return [...mentions];
|
|
22765
|
+
}
|
|
22766
|
+
function identifierPattern(methodName) {
|
|
22767
|
+
return new RegExp(`(?<![A-Za-z0-9_])${methodName}(?![A-Za-z0-9_])`);
|
|
22768
|
+
}
|
|
22769
|
+
var fs14, path19, METHOD_NAME, PROSE_FIELDS2;
|
|
22770
|
+
var init_provision = __esm({
|
|
22771
|
+
"src/core/provision.ts"() {
|
|
22772
|
+
"use strict";
|
|
22773
|
+
fs14 = __toESM(require("fs"));
|
|
22774
|
+
path19 = __toESM(require("path"));
|
|
22775
|
+
init_specs2();
|
|
22776
|
+
init_paths();
|
|
22777
|
+
init_project_config();
|
|
22778
|
+
init_fs();
|
|
22779
|
+
init_yaml();
|
|
22780
|
+
init_errors();
|
|
22781
|
+
init_models();
|
|
22782
|
+
METHOD_NAME = /^[a-z][a-zA-Z0-9]*$/;
|
|
22783
|
+
PROSE_FIELDS2 = /* @__PURE__ */ new Set([
|
|
22784
|
+
"description",
|
|
22785
|
+
"intent",
|
|
22786
|
+
"summary",
|
|
22787
|
+
"condition",
|
|
22788
|
+
"over",
|
|
22789
|
+
"outcome",
|
|
22790
|
+
"error",
|
|
22791
|
+
"note",
|
|
22792
|
+
"caller"
|
|
22793
|
+
]);
|
|
22794
|
+
}
|
|
22795
|
+
});
|
|
22796
|
+
|
|
22797
|
+
// src/core/execution_profile.ts
|
|
22798
|
+
function isSweeping(p) {
|
|
22799
|
+
return p === "**" || p === "**/*" || p.startsWith("**/");
|
|
22800
|
+
}
|
|
22801
|
+
function deriveBreadth(agent) {
|
|
22802
|
+
if (agent.readPaths.some(isSweeping)) {
|
|
22803
|
+
return MANAGER_TEMPLATES.has(agent.template) || READ_ONLY_TEMPLATES.has(agent.template) ? "wide" : "moderate";
|
|
22931
22804
|
}
|
|
22932
|
-
|
|
22933
|
-
|
|
22805
|
+
const owned = agent.ownedPaths.length;
|
|
22806
|
+
if (owned >= WIDE_PATH_COUNT) return "wide";
|
|
22807
|
+
if (owned >= MODERATE_PATH_COUNT) return "moderate";
|
|
22808
|
+
return "narrow";
|
|
22934
22809
|
}
|
|
22935
|
-
function
|
|
22936
|
-
|
|
22810
|
+
function deriveReasoningDepth(agent) {
|
|
22811
|
+
for (const tag of agent.tags) {
|
|
22812
|
+
if (DEEP_STEREOTYPES.has(tag)) return "deep";
|
|
22813
|
+
if (MECHANICAL_STEREOTYPES.has(tag)) return "mechanical";
|
|
22814
|
+
}
|
|
22815
|
+
if (MANAGER_TEMPLATES.has(agent.template)) return "deep";
|
|
22816
|
+
if (agent.template === "reviewer") return "deep";
|
|
22817
|
+
if (agent.template === "tester") return "standard";
|
|
22818
|
+
return "standard";
|
|
22937
22819
|
}
|
|
22938
|
-
function
|
|
22939
|
-
|
|
22940
|
-
const f = path20.resolve(file);
|
|
22941
|
-
return f === d || f.startsWith(d + path20.sep);
|
|
22820
|
+
function deriveWrites(agent) {
|
|
22821
|
+
return !READ_ONLY_TEMPLATES.has(agent.template);
|
|
22942
22822
|
}
|
|
22943
|
-
function
|
|
22944
|
-
|
|
22945
|
-
|
|
22946
|
-
|
|
22947
|
-
const
|
|
22948
|
-
|
|
22949
|
-
|
|
22950
|
-
|
|
22951
|
-
const parentRoot = getProjectRoot();
|
|
22952
|
-
const parentSpecsDir = aiPathsAt(parentRoot).specsDir();
|
|
22953
|
-
const fooDir = path20.join(parentSpecsDir, subsystemId);
|
|
22954
|
-
if (!fs15.existsSync(fooDir)) {
|
|
22955
|
-
throw new WaironError(`subsystem specs directory not found: ${fooDir}`);
|
|
22956
|
-
}
|
|
22957
|
-
const relPath = toPosixPath(projectPath);
|
|
22958
|
-
const childDir = assertContainedProjectPath(parentRoot, relPath);
|
|
22959
|
-
const childFooDir = path20.join(childDir, ".wai", "specs", subsystemId);
|
|
22960
|
-
if (fs15.existsSync(childFooDir)) {
|
|
22961
|
-
throw new WaironError(`target already contains a "${subsystemId}" subsystem: ${childFooDir}`);
|
|
22823
|
+
function deriveExecutionProfile(agent) {
|
|
22824
|
+
const breadth = deriveBreadth(agent);
|
|
22825
|
+
const reasoningDepth = deriveReasoningDepth(agent);
|
|
22826
|
+
const writes = deriveWrites(agent);
|
|
22827
|
+
const delegates = MANAGER_TEMPLATES.has(agent.template);
|
|
22828
|
+
const because = [];
|
|
22829
|
+
if (delegates) {
|
|
22830
|
+
because.push(`${agent.template} routes work rather than performing it`);
|
|
22962
22831
|
}
|
|
22963
|
-
const
|
|
22964
|
-
|
|
22965
|
-
/* externalize */
|
|
22966
|
-
true
|
|
22832
|
+
const stereotype = agent.tags.find(
|
|
22833
|
+
(t) => MECHANICAL_STEREOTYPES.has(t) || DEEP_STEREOTYPES.has(t)
|
|
22967
22834
|
);
|
|
22968
|
-
|
|
22969
|
-
|
|
22970
|
-
|
|
22971
|
-
|
|
22972
|
-
ensureDir(path20.join(childDir, ".wai", "specs"));
|
|
22973
|
-
saveSystemSpec(bootstrapSystemSpec(childSystemName, now));
|
|
22974
|
-
});
|
|
22975
|
-
ensureDir(path20.dirname(childFooDir));
|
|
22976
|
-
fs15.renameSync(fooDir, childFooDir);
|
|
22977
|
-
rebaseImplementationPaths(childFooDir, parentRoot, childDir);
|
|
22978
|
-
patchSubsystemIndex(path20.join(childFooDir, ".index.yaml"), (s) => {
|
|
22979
|
-
s.parentSystem = childSystemName;
|
|
22980
|
-
delete s.projectPath;
|
|
22981
|
-
});
|
|
22982
|
-
ensureDir(fooDir);
|
|
22983
|
-
writeYamlFile(path20.join(fooDir, ".index.yaml"), {
|
|
22984
|
-
id: subsystemId,
|
|
22985
|
-
name: foo.name,
|
|
22986
|
-
description: foo.description,
|
|
22987
|
-
parentSystem: foo.parentSystem,
|
|
22988
|
-
publicInterfaces: [],
|
|
22989
|
-
projectPath: relPath,
|
|
22990
|
-
trustedLinks: [],
|
|
22991
|
-
status: foo.status ?? "draft",
|
|
22992
|
-
createdAt: foo.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
22993
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
22994
|
-
});
|
|
22995
|
-
rewriteRefsInDir(parentSpecsDir, renameMap, fooDir);
|
|
22996
|
-
rebaseMovedRefs(childFooDir, subsystemId, "into");
|
|
22997
|
-
invalidateSpecCache();
|
|
22998
|
-
}
|
|
22999
|
-
function internalizeSubsystem(subsystemId) {
|
|
23000
|
-
if (subsystemId.includes("::")) {
|
|
23001
|
-
throw new WaironError("cannot internalize a nested/namespaced subsystem; run from its owning project.");
|
|
23002
|
-
}
|
|
23003
|
-
const foo = loadSubsystemSpec(subsystemId);
|
|
23004
|
-
if (!foo || !foo.projectPath) {
|
|
23005
|
-
throw new WaironError(`cannot internalize: subsystem "${subsystemId}" is missing or not external.`);
|
|
23006
|
-
}
|
|
23007
|
-
const parentRoot = getProjectRoot();
|
|
23008
|
-
const parentSpecsDir = aiPathsAt(parentRoot).specsDir();
|
|
23009
|
-
const childDir = assertContainedProjectPath(parentRoot, foo.projectPath);
|
|
23010
|
-
const childWai = path20.join(childDir, ".wai");
|
|
23011
|
-
const childFooDir = path20.join(childDir, ".wai", "specs", subsystemId);
|
|
23012
|
-
if (!fs15.existsSync(childFooDir)) {
|
|
23013
|
-
throw new WaironError(`external subproject missing subsystem "${subsystemId}": ${childFooDir}`);
|
|
23014
|
-
}
|
|
23015
|
-
const childOwnSubs = runWithProjectRoot(childDir, () => loadSubsystemSpecs()).filter((s) => !s.id.includes("::"));
|
|
23016
|
-
if (childOwnSubs.length !== 1 || childOwnSubs[0].id !== subsystemId) {
|
|
23017
|
-
throw new WaironError(`cannot internalize: subproject is a multi-subsystem system, not a flat "${subsystemId}".`);
|
|
22835
|
+
if (stereotype) {
|
|
22836
|
+
because.push(
|
|
22837
|
+
MECHANICAL_STEREOTYPES.has(stereotype) ? `${stereotype} work is specified by its contract and narrative` : `${stereotype} carries decision logic`
|
|
22838
|
+
);
|
|
23018
22839
|
}
|
|
23019
|
-
|
|
23020
|
-
|
|
23021
|
-
/* externalize */
|
|
23022
|
-
false
|
|
22840
|
+
because.push(
|
|
22841
|
+
breadth === "wide" ? "reads broadly across the tree" : breadth === "moderate" ? `spans ${agent.ownedPaths.length} owned path(s)` : "scoped to a small owned set"
|
|
23023
22842
|
);
|
|
23024
|
-
|
|
23025
|
-
|
|
23026
|
-
|
|
23027
|
-
|
|
23028
|
-
|
|
23029
|
-
|
|
23030
|
-
|
|
23031
|
-
|
|
23032
|
-
delete s.projectPath;
|
|
23033
|
-
});
|
|
23034
|
-
fs15.rmSync(childWai, { recursive: true, force: true });
|
|
23035
|
-
rewriteRefsInDir(parentSpecsDir, renameMap, fooDir);
|
|
23036
|
-
rebaseMovedRefs(fooDir, subsystemId, "outOf");
|
|
23037
|
-
invalidateSpecCache();
|
|
22843
|
+
if (!writes) because.push("read-only");
|
|
22844
|
+
return {
|
|
22845
|
+
breadth,
|
|
22846
|
+
writes,
|
|
22847
|
+
reasoningDepth,
|
|
22848
|
+
delegates,
|
|
22849
|
+
rationale: because.join("; ")
|
|
22850
|
+
};
|
|
23038
22851
|
}
|
|
23039
|
-
|
|
23040
|
-
|
|
23041
|
-
|
|
23042
|
-
|
|
23043
|
-
|
|
23044
|
-
|
|
23045
|
-
|
|
23046
|
-
|
|
23047
|
-
|
|
22852
|
+
var MECHANICAL_STEREOTYPES, DEEP_STEREOTYPES, MANAGER_TEMPLATES, READ_ONLY_TEMPLATES, WIDE_PATH_COUNT, MODERATE_PATH_COUNT;
|
|
22853
|
+
var init_execution_profile = __esm({
|
|
22854
|
+
"src/core/execution_profile.ts"() {
|
|
22855
|
+
"use strict";
|
|
22856
|
+
MECHANICAL_STEREOTYPES = /* @__PURE__ */ new Set(["store", "index", "registry", "adapter"]);
|
|
22857
|
+
DEEP_STEREOTYPES = /* @__PURE__ */ new Set(["orchestrator", "supervisor", "specialist"]);
|
|
22858
|
+
MANAGER_TEMPLATES = /* @__PURE__ */ new Set(["architect", "domain-owner"]);
|
|
22859
|
+
READ_ONLY_TEMPLATES = /* @__PURE__ */ new Set(["reviewer", "guardian"]);
|
|
22860
|
+
WIDE_PATH_COUNT = 12;
|
|
22861
|
+
MODERATE_PATH_COUNT = 4;
|
|
23048
22862
|
}
|
|
23049
|
-
|
|
23050
|
-
|
|
23051
|
-
|
|
23052
|
-
|
|
22863
|
+
});
|
|
22864
|
+
|
|
22865
|
+
// src/core/budget_policy.ts
|
|
22866
|
+
function atLeast(tier, floor) {
|
|
22867
|
+
return TIER_ORDER.indexOf(tier) >= TIER_ORDER.indexOf(floor);
|
|
22868
|
+
}
|
|
22869
|
+
function baseModelTier(profile) {
|
|
22870
|
+
switch (profile.reasoningDepth) {
|
|
22871
|
+
case "mechanical":
|
|
22872
|
+
return "small";
|
|
22873
|
+
case "standard":
|
|
22874
|
+
return "standard";
|
|
22875
|
+
case "deep":
|
|
22876
|
+
return "large";
|
|
23053
22877
|
}
|
|
23054
|
-
|
|
23055
|
-
|
|
23056
|
-
|
|
23057
|
-
|
|
22878
|
+
}
|
|
22879
|
+
function stepDown(tier, steps) {
|
|
22880
|
+
const i = TIER_STEPS.indexOf(tier);
|
|
22881
|
+
return TIER_STEPS[Math.max(0, i - steps)];
|
|
22882
|
+
}
|
|
22883
|
+
function maxTurnsFor(profile, tier) {
|
|
22884
|
+
if (!atLeast(tier, "default")) return void 0;
|
|
22885
|
+
const ceiling = profile.breadth === "wide" ? 60 : profile.breadth === "moderate" ? 40 : 25;
|
|
22886
|
+
return atLeast(tier, "aggressive") ? Math.round(ceiling / 2) : ceiling;
|
|
22887
|
+
}
|
|
22888
|
+
function effortFor(profile, tier) {
|
|
22889
|
+
if (!atLeast(tier, "trade")) return void 0;
|
|
22890
|
+
if (profile.reasoningDepth === "mechanical") {
|
|
22891
|
+
return atLeast(tier, "aggressive") ? "low" : "medium";
|
|
23058
22892
|
}
|
|
23059
|
-
return
|
|
22893
|
+
return void 0;
|
|
23060
22894
|
}
|
|
23061
|
-
function
|
|
23062
|
-
|
|
23063
|
-
rewriteRefFields(specsDir, (ref) => renameMap.get(ref) ?? ref, excludeDir);
|
|
22895
|
+
function toolClassFor(profile) {
|
|
22896
|
+
return profile.writes ? "implement" : "read-only";
|
|
23064
22897
|
}
|
|
23065
|
-
function
|
|
23066
|
-
|
|
23067
|
-
|
|
22898
|
+
function mcpFor(profile, tier) {
|
|
22899
|
+
if (!atLeast(tier, "free")) return "all";
|
|
22900
|
+
if (profile.delegates) return "project";
|
|
22901
|
+
return profile.breadth === "wide" ? "project" : "none";
|
|
23068
22902
|
}
|
|
23069
|
-
function
|
|
23070
|
-
const
|
|
23071
|
-
|
|
23072
|
-
|
|
23073
|
-
|
|
23074
|
-
|
|
23075
|
-
|
|
23076
|
-
|
|
22903
|
+
function resolveBudget(profile, config, agentId) {
|
|
22904
|
+
const tier = config.tier;
|
|
22905
|
+
if (tier === "off") return void 0;
|
|
22906
|
+
let modelTier = baseModelTier(profile);
|
|
22907
|
+
if (atLeast(tier, "trade") && profile.reasoningDepth === "standard") {
|
|
22908
|
+
modelTier = stepDown(modelTier, 1);
|
|
22909
|
+
}
|
|
22910
|
+
if (atLeast(tier, "aggressive") && profile.reasoningDepth !== "deep") {
|
|
22911
|
+
modelTier = "small";
|
|
22912
|
+
}
|
|
22913
|
+
const budget = {
|
|
22914
|
+
// At `free` no model selection is expressed at all — that tier is defined
|
|
22915
|
+
// as having no quality tradeoff, and choosing a model is a quality
|
|
22916
|
+
// decision. Leaving it absent is not the same as choosing a default.
|
|
22917
|
+
modelTier: atLeast(tier, "default") ? modelTier : void 0,
|
|
22918
|
+
effort: effortFor(profile, tier),
|
|
22919
|
+
maxTurns: maxTurnsFor(profile, tier),
|
|
22920
|
+
toolClass: toolClassFor(profile),
|
|
22921
|
+
// Only managers may spawn. Withholding the tool from workers is what stops
|
|
22922
|
+
// a worker quietly becoming a second orchestrator three levels down.
|
|
22923
|
+
allowNestedDelegation: profile.delegates,
|
|
22924
|
+
mcp: mcpFor(profile, tier)
|
|
22925
|
+
};
|
|
22926
|
+
const override = config.overrides[agentId];
|
|
22927
|
+
return override ? { ...budget, ...override } : budget;
|
|
22928
|
+
}
|
|
22929
|
+
var TIER_ORDER, TIER_STEPS;
|
|
22930
|
+
var init_budget_policy = __esm({
|
|
22931
|
+
"src/core/budget_policy.ts"() {
|
|
22932
|
+
"use strict";
|
|
22933
|
+
TIER_ORDER = ["off", "free", "default", "trade", "aggressive"];
|
|
22934
|
+
TIER_STEPS = ["small", "standard", "large", "frontier"];
|
|
22935
|
+
}
|
|
22936
|
+
});
|
|
22937
|
+
|
|
22938
|
+
// src/core/agent_resolver.ts
|
|
22939
|
+
function listFilesRecursiveSafe(dirPath, ext) {
|
|
22940
|
+
if (!fs15.existsSync(dirPath)) return [];
|
|
22941
|
+
const nameLower = path20.basename(dirPath).toLowerCase();
|
|
22942
|
+
const IGNORED_DIRS = /* @__PURE__ */ new Set([
|
|
22943
|
+
"node_modules",
|
|
22944
|
+
"target",
|
|
22945
|
+
"dist",
|
|
22946
|
+
"build",
|
|
22947
|
+
".git",
|
|
22948
|
+
".wai",
|
|
22949
|
+
".claude",
|
|
22950
|
+
".gemini",
|
|
22951
|
+
".codex",
|
|
22952
|
+
".agents",
|
|
22953
|
+
".vscode"
|
|
22954
|
+
]);
|
|
22955
|
+
if (IGNORED_DIRS.has(nameLower)) return [];
|
|
22956
|
+
const entries = fs15.readdirSync(dirPath, { withFileTypes: true });
|
|
22957
|
+
const files = [];
|
|
22958
|
+
for (const entry of entries) {
|
|
22959
|
+
const fullPath = path20.join(dirPath, entry.name);
|
|
22960
|
+
if (entry.isDirectory()) {
|
|
22961
|
+
files.push(...listFilesRecursiveSafe(fullPath, ext));
|
|
22962
|
+
} else if (entry.isFile() && entry.name.endsWith(ext)) {
|
|
22963
|
+
files.push(fullPath);
|
|
23077
22964
|
}
|
|
23078
|
-
if (raw && typeof raw === "object" && "componentType" in raw && typeof raw.id === "string") ids.add(raw.id);
|
|
23079
22965
|
}
|
|
23080
|
-
return
|
|
22966
|
+
return files;
|
|
23081
22967
|
}
|
|
23082
|
-
function
|
|
23083
|
-
|
|
23084
|
-
|
|
23085
|
-
|
|
23086
|
-
|
|
23087
|
-
|
|
23088
|
-
|
|
23089
|
-
|
|
23090
|
-
|
|
22968
|
+
function getProjectFiles(projectDir) {
|
|
22969
|
+
let files = projectFilesCache.get(projectDir);
|
|
22970
|
+
if (!files) {
|
|
22971
|
+
files = [];
|
|
22972
|
+
const srcDir = path20.join(projectDir, "src");
|
|
22973
|
+
const legacySrcDir = path20.join(projectDir, "legacy-src");
|
|
22974
|
+
let searchDir = projectDir;
|
|
22975
|
+
if (pathExists(srcDir)) {
|
|
22976
|
+
searchDir = srcDir;
|
|
22977
|
+
} else if (pathExists(legacySrcDir)) {
|
|
22978
|
+
searchDir = legacySrcDir;
|
|
22979
|
+
} else if (projectDir === getProjectRoot()) {
|
|
22980
|
+
projectFilesCache.set(projectDir, []);
|
|
22981
|
+
return [];
|
|
23091
22982
|
}
|
|
23092
|
-
|
|
23093
|
-
const
|
|
23094
|
-
|
|
23095
|
-
|
|
23096
|
-
|
|
22983
|
+
const extensions = [".rs", ".ts", ".tsx", ".js", ".jsx", ".py", ".go", ".c", ".cpp", ".cs", ".java", ".kt", ".swift", ".rb", ".php", ".lua"];
|
|
22984
|
+
for (const ext of extensions) {
|
|
22985
|
+
files.push(...listFilesRecursiveSafe(searchDir, ext));
|
|
22986
|
+
}
|
|
22987
|
+
const rootDir = getProjectRoot();
|
|
22988
|
+
files = files.map((f) => path20.relative(rootDir, f).replace(/\\/g, "/"));
|
|
22989
|
+
projectFilesCache.set(projectDir, files);
|
|
23097
22990
|
}
|
|
23098
|
-
return
|
|
22991
|
+
return files;
|
|
23099
22992
|
}
|
|
23100
|
-
function
|
|
23101
|
-
|
|
23102
|
-
|
|
23103
|
-
|
|
23104
|
-
|
|
23105
|
-
|
|
23106
|
-
|
|
22993
|
+
function inferSourcePathForComponent(comp, subsystems) {
|
|
22994
|
+
try {
|
|
22995
|
+
const projectDir = resolveSubprojectForNamespace(comp.subsystem) || getProjectRoot();
|
|
22996
|
+
const files = getProjectFiles(projectDir);
|
|
22997
|
+
if (files.length === 0) return null;
|
|
22998
|
+
const compRelativeId = comp.id.split("::").pop() || comp.id;
|
|
22999
|
+
const subRelativeId = comp.subsystem.split("::").pop() || comp.subsystem;
|
|
23000
|
+
let cleanName = compRelativeId;
|
|
23001
|
+
if (cleanName.startsWith(`${subRelativeId}-`)) {
|
|
23002
|
+
cleanName = cleanName.slice(subRelativeId.length + 1);
|
|
23107
23003
|
}
|
|
23108
|
-
|
|
23109
|
-
|
|
23110
|
-
|
|
23111
|
-
|
|
23112
|
-
|
|
23113
|
-
|
|
23114
|
-
|
|
23115
|
-
|
|
23116
|
-
|
|
23117
|
-
|
|
23118
|
-
|
|
23119
|
-
|
|
23120
|
-
|
|
23121
|
-
|
|
23122
|
-
|
|
23004
|
+
const candidates = /* @__PURE__ */ new Set();
|
|
23005
|
+
candidates.add(cleanName.toLowerCase());
|
|
23006
|
+
candidates.add(cleanName.replace(/-/g, "_").toLowerCase());
|
|
23007
|
+
candidates.add(compRelativeId.toLowerCase());
|
|
23008
|
+
candidates.add(compRelativeId.replace(/-/g, "_").toLowerCase());
|
|
23009
|
+
candidates.add(comp.componentType.toLowerCase());
|
|
23010
|
+
let bestFile = null;
|
|
23011
|
+
let bestScore = -1;
|
|
23012
|
+
for (const f of files) {
|
|
23013
|
+
const ext = path20.extname(f);
|
|
23014
|
+
const base = path20.basename(f, ext).toLowerCase();
|
|
23015
|
+
if (candidates.has(base)) {
|
|
23016
|
+
let score = 0;
|
|
23017
|
+
const normalizedPath = f.toLowerCase();
|
|
23018
|
+
const subPattern1 = `/${subRelativeId.toLowerCase()}/`;
|
|
23019
|
+
const subPattern2 = `/${subRelativeId.replace(/-/g, "_").toLowerCase()}/`;
|
|
23020
|
+
const hasSubsystemSegmentMatch = subRelativeId.split(/[-_]/).some((seg) => seg.length >= 3 && normalizedPath.includes(`/${seg.toLowerCase()}/`));
|
|
23021
|
+
const hasSubsystemMatch = normalizedPath.includes(subPattern1) || normalizedPath.includes(subPattern2) || hasSubsystemSegmentMatch;
|
|
23022
|
+
if (hasSubsystemMatch) {
|
|
23023
|
+
score += 10;
|
|
23024
|
+
}
|
|
23025
|
+
let belongsToOtherSubsystem = false;
|
|
23026
|
+
for (const otherSub of subsystems) {
|
|
23027
|
+
if (otherSub.id === comp.subsystem) continue;
|
|
23028
|
+
const otherSubRelativeId = otherSub.id.split("::").pop() || otherSub.id;
|
|
23029
|
+
const otherPattern1 = `/${otherSubRelativeId.toLowerCase()}/`;
|
|
23030
|
+
const otherPattern2 = `/${otherSubRelativeId.replace(/-/g, "_").toLowerCase()}/`;
|
|
23031
|
+
const otherSegmentMatch = otherSubRelativeId.split(/[-_]/).some((seg) => seg.length >= 3 && normalizedPath.includes(`/${seg.toLowerCase()}/`));
|
|
23032
|
+
if (normalizedPath.includes(otherPattern1) || normalizedPath.includes(otherPattern2) || otherSegmentMatch) {
|
|
23033
|
+
belongsToOtherSubsystem = true;
|
|
23034
|
+
break;
|
|
23035
|
+
}
|
|
23036
|
+
}
|
|
23037
|
+
if (belongsToOtherSubsystem) {
|
|
23038
|
+
continue;
|
|
23039
|
+
}
|
|
23040
|
+
const isCleanNameMatch = base === cleanName.toLowerCase() || base === cleanName.replace(/-/g, "_").toLowerCase();
|
|
23041
|
+
if (isCleanNameMatch) {
|
|
23042
|
+
score += 5;
|
|
23043
|
+
}
|
|
23044
|
+
const isIdMatch = base === compRelativeId.toLowerCase() || base === compRelativeId.replace(/-/g, "_").toLowerCase();
|
|
23045
|
+
if (isIdMatch) {
|
|
23046
|
+
score += 3;
|
|
23047
|
+
}
|
|
23048
|
+
const isSpecificNameMatch = isCleanNameMatch && cleanName.toLowerCase() !== comp.componentType.toLowerCase();
|
|
23049
|
+
if (!hasSubsystemMatch && !isSpecificNameMatch && !isIdMatch) {
|
|
23050
|
+
continue;
|
|
23051
|
+
}
|
|
23052
|
+
if (normalizedPath.startsWith("src/") || normalizedPath.includes("/src/") || normalizedPath.startsWith("legacy-src/") || normalizedPath.includes("/legacy-src/")) {
|
|
23053
|
+
score += 2;
|
|
23054
|
+
}
|
|
23055
|
+
if (base === comp.componentType.toLowerCase()) {
|
|
23056
|
+
score += 1;
|
|
23057
|
+
}
|
|
23058
|
+
if (score > bestScore) {
|
|
23059
|
+
bestScore = score;
|
|
23060
|
+
bestFile = f;
|
|
23061
|
+
}
|
|
23123
23062
|
}
|
|
23124
23063
|
}
|
|
23125
|
-
|
|
23064
|
+
return bestFile;
|
|
23065
|
+
} catch {
|
|
23066
|
+
return null;
|
|
23126
23067
|
}
|
|
23127
23068
|
}
|
|
23128
|
-
function
|
|
23129
|
-
|
|
23130
|
-
const
|
|
23131
|
-
|
|
23132
|
-
|
|
23133
|
-
|
|
23069
|
+
function summarize(text, max = 140) {
|
|
23070
|
+
const clean = text.replace(/\s+/g, " ").trim();
|
|
23071
|
+
const period = clean.indexOf(". ");
|
|
23072
|
+
const firstSentence = period > 0 ? clean.slice(0, period + 1) : clean;
|
|
23073
|
+
if (firstSentence.length <= max) return firstSentence;
|
|
23074
|
+
return `${firstSentence.slice(0, max - 1).trimEnd()}\u2026`;
|
|
23134
23075
|
}
|
|
23135
|
-
function
|
|
23136
|
-
|
|
23137
|
-
|
|
23138
|
-
|
|
23139
|
-
|
|
23140
|
-
|
|
23141
|
-
|
|
23142
|
-
|
|
23143
|
-
|
|
23144
|
-
|
|
23145
|
-
if (!SpecIdSchema.safeParse(newId).success) {
|
|
23146
|
-
throw new WaironError(`invalid-id: "${newId}" is not a lowercase identifier with no namespace separator.`);
|
|
23147
|
-
}
|
|
23148
|
-
const components = loadComponentSpecs();
|
|
23076
|
+
function buildVariantGuidance(comps, allComponents, variantsById) {
|
|
23077
|
+
return composeVariantGuidance(comps, allComponents, variantsById);
|
|
23078
|
+
}
|
|
23079
|
+
function resolveAgentTopology() {
|
|
23080
|
+
projectFilesCache.clear();
|
|
23081
|
+
const system = loadSystemSpec();
|
|
23082
|
+
if (!system) return [];
|
|
23083
|
+
const isLocal = (id) => !id.includes("::");
|
|
23084
|
+
const subsystems = loadSubsystemSpecs().filter((s) => isLocal(s.id));
|
|
23085
|
+
const components = loadComponentSpecs().filter((c) => isLocal(c.id) && isLocal(c.subsystem));
|
|
23149
23086
|
const interfaces = loadInterfaceSpecs();
|
|
23150
23087
|
const implementations = loadImplementationSpecs();
|
|
23151
|
-
const
|
|
23152
|
-
const
|
|
23153
|
-
|
|
23154
|
-
|
|
23155
|
-
|
|
23156
|
-
|
|
23157
|
-
|
|
23158
|
-
|
|
23159
|
-
|
|
23160
|
-
|
|
23161
|
-
|
|
23162
|
-
|
|
23163
|
-
|
|
23164
|
-
|
|
23165
|
-
|
|
23166
|
-
|
|
23167
|
-
|
|
23168
|
-
|
|
23169
|
-
|
|
23170
|
-
|
|
23171
|
-
|
|
23088
|
+
const variantsById = new Map(loadProjectVariants().map((v) => [v.id, v]));
|
|
23089
|
+
const config = projectConfigRepository.load();
|
|
23090
|
+
if (!config) throw new ProjectNotInitializedError();
|
|
23091
|
+
const activeTargets = config.targets.filter((t) => !("enabled" in t) || t.enabled).map((t) => typeof t === "string" ? t : t.type);
|
|
23092
|
+
const agents = [];
|
|
23093
|
+
agents.push({
|
|
23094
|
+
id: "system-architect",
|
|
23095
|
+
name: `${system.name} Architect`,
|
|
23096
|
+
description: `Global architect for ${system.name} \u2014 owns the spec tree and topology. ${summarize(system.vision)}`,
|
|
23097
|
+
template: "architect",
|
|
23098
|
+
creationReason: "Automatically inferred from L0 system spec",
|
|
23099
|
+
ownedPaths: [".wai/specs/**"],
|
|
23100
|
+
readPaths: ["**"],
|
|
23101
|
+
writePaths: [".wai/specs/**"],
|
|
23102
|
+
tags: ["architect", "global", "sdd"],
|
|
23103
|
+
dependencies: subsystems.map((s) => `${s.id}-owner`),
|
|
23104
|
+
status: "active",
|
|
23105
|
+
targets: activeTargets,
|
|
23106
|
+
createdAt: system.createdAt,
|
|
23107
|
+
updatedAt: system.updatedAt
|
|
23108
|
+
});
|
|
23109
|
+
for (const sub of subsystems) {
|
|
23110
|
+
if (sub.projectPath) {
|
|
23111
|
+
const mountSpecPath = path20.relative(getProjectRoot(), getSubsystemPath(sub.id)).replace(/\\/g, "/");
|
|
23112
|
+
agents.push({
|
|
23113
|
+
id: `${sub.id}-owner`,
|
|
23114
|
+
name: `${sub.name} (chained subproject)`,
|
|
23115
|
+
description: `Delegates into the "${sub.id}" chained subproject at ${sub.projectPath}. Its own agents live in that subproject's .wai \u2014 run \`wairon generate\` there (or spawn from ${sub.projectPath}/.claude/agents). Do not implement its internals from this layer.`,
|
|
23116
|
+
template: "domain-owner",
|
|
23117
|
+
creationReason: `Automatically inferred from a chained subproject subsystem: ${sub.id}`,
|
|
23118
|
+
domainRoot: sub.id,
|
|
23119
|
+
ownedPaths: [mountSpecPath],
|
|
23120
|
+
readPaths: ["**"],
|
|
23121
|
+
writePaths: [mountSpecPath],
|
|
23122
|
+
tags: ["owner", "subproject", "delegate", "sdd"],
|
|
23123
|
+
dependencies: [],
|
|
23124
|
+
status: "active",
|
|
23125
|
+
targets: activeTargets,
|
|
23126
|
+
createdAt: sub.createdAt,
|
|
23127
|
+
updatedAt: sub.updatedAt
|
|
23128
|
+
});
|
|
23129
|
+
continue;
|
|
23130
|
+
}
|
|
23131
|
+
const subComponents = components.filter((c) => c.subsystem === sub.id);
|
|
23132
|
+
const ownedPaths = [];
|
|
23133
|
+
ownedPaths.push(path20.relative(getProjectRoot(), getSubsystemPath(sub.id)).replace(/\\/g, "/"));
|
|
23134
|
+
for (const c of subComponents) {
|
|
23135
|
+
ownedPaths.push(path20.relative(getProjectRoot(), getComponentPath(c.id, sub.id)).replace(/\\/g, "/"));
|
|
23136
|
+
}
|
|
23137
|
+
if (!config.rules.generateComponentImplementers) {
|
|
23138
|
+
for (const comp of subComponents) {
|
|
23139
|
+
const compInterfaces = interfaces.filter((i) => i.component === comp.id);
|
|
23140
|
+
const compInterfaceIds = compInterfaces.map((i) => i.id);
|
|
23141
|
+
const compImpls = implementations.filter((impl) => compInterfaceIds.includes(impl.contract));
|
|
23142
|
+
let hasExplicitSource = false;
|
|
23143
|
+
for (const impl of compImpls) {
|
|
23144
|
+
const files = implementationSourceFiles(impl);
|
|
23145
|
+
if (files.length > 0) hasExplicitSource = true;
|
|
23146
|
+
for (const file of files) {
|
|
23147
|
+
if (!ownedPaths.includes(file)) ownedPaths.push(file);
|
|
23148
|
+
}
|
|
23149
|
+
}
|
|
23150
|
+
if (!hasExplicitSource) {
|
|
23151
|
+
const inferred = inferSourcePathForComponent(comp, subsystems);
|
|
23152
|
+
if (inferred && !ownedPaths.includes(inferred)) {
|
|
23153
|
+
ownedPaths.push(inferred);
|
|
23154
|
+
}
|
|
23155
|
+
}
|
|
23156
|
+
}
|
|
23172
23157
|
}
|
|
23173
|
-
|
|
23174
|
-
|
|
23175
|
-
|
|
23176
|
-
|
|
23177
|
-
|
|
23178
|
-
|
|
23179
|
-
|
|
23180
|
-
|
|
23181
|
-
|
|
23182
|
-
|
|
23183
|
-
|
|
23184
|
-
|
|
23185
|
-
|
|
23186
|
-
|
|
23187
|
-
if (movedInterface) saveInterfaceSpec({ ...movedInterface, id: interfaceId, component: newId });
|
|
23188
|
-
if (movedImplementation) {
|
|
23189
|
-
const oldFile = getImplementationPath(movedImplementation.id);
|
|
23190
|
-
if (path20.resolve(getImplementationPath(implementationId, movedImplementation.contract)) === path20.resolve(oldFile)) {
|
|
23191
|
-
fs15.unlinkSync(oldFile);
|
|
23158
|
+
let dependencies = [];
|
|
23159
|
+
if (config.rules.generateComponentImplementers) {
|
|
23160
|
+
dependencies = subComponents.map((c) => `${c.id}-implementer`);
|
|
23161
|
+
} else {
|
|
23162
|
+
const depSubsystems = /* @__PURE__ */ new Set();
|
|
23163
|
+
for (const c of subComponents) {
|
|
23164
|
+
for (const depId of c.dependsOn) {
|
|
23165
|
+
const depComp = components.find((other) => other.id === depId);
|
|
23166
|
+
if (depComp && depComp.subsystem !== sub.id) {
|
|
23167
|
+
depSubsystems.add(`${depComp.subsystem}-owner`);
|
|
23168
|
+
}
|
|
23169
|
+
}
|
|
23170
|
+
}
|
|
23171
|
+
dependencies = Array.from(depSubsystems);
|
|
23192
23172
|
}
|
|
23193
|
-
|
|
23194
|
-
|
|
23195
|
-
|
|
23196
|
-
|
|
23197
|
-
|
|
23198
|
-
|
|
23199
|
-
|
|
23200
|
-
|
|
23201
|
-
|
|
23202
|
-
|
|
23203
|
-
|
|
23204
|
-
|
|
23205
|
-
|
|
23206
|
-
|
|
23207
|
-
|
|
23208
|
-
|
|
23209
|
-
|
|
23210
|
-
if (fs15.readdirSync(dir).length > 0) break;
|
|
23211
|
-
fs15.rmdirSync(dir);
|
|
23212
|
-
}
|
|
23213
|
-
}
|
|
23214
|
-
function renameMethod(componentId, methodName, newName, pinSymbol) {
|
|
23215
|
-
const component = loadComponentSpec(componentId);
|
|
23216
|
-
if (!component) {
|
|
23217
|
-
throw new WaironError(`component-missing: no component has the id "${componentId}".`);
|
|
23218
|
-
}
|
|
23219
|
-
if (componentId.includes("::")) {
|
|
23220
|
-
throw new WaironError(
|
|
23221
|
-
`chained-component: "${componentId}" lives in a chained subproject; rename its method from that project's own root.`
|
|
23222
|
-
);
|
|
23223
|
-
}
|
|
23224
|
-
if (!METHOD_NAME.test(newName)) {
|
|
23225
|
-
throw new WaironError(`invalid-name: "${newName}" is not a camel-case identifier.`);
|
|
23226
|
-
}
|
|
23227
|
-
const contracts = loadInterfaceSpecs().filter((i) => i.component === componentId);
|
|
23228
|
-
const moving = contracts.filter((i) => i.methods.some((m) => m.name === methodName));
|
|
23229
|
-
if (moving.length === 0) {
|
|
23230
|
-
throw new WaironError(`method-missing: no contract of "${componentId}" declares the method "${methodName}".`);
|
|
23231
|
-
}
|
|
23232
|
-
const taken = moving.filter((i) => i.methods.some((m) => m.name === newName)).map((i) => `"${i.id}"`);
|
|
23233
|
-
if (taken.length > 0) {
|
|
23234
|
-
throw new WaironError(`name-taken: ${taken.join(", ")} already declares a method under the name "${newName}".`);
|
|
23235
|
-
}
|
|
23236
|
-
const implementations = loadImplementationSpecs();
|
|
23237
|
-
const movingContracts = new Set(moving.map((i) => i.id));
|
|
23238
|
-
const renamed = [];
|
|
23239
|
-
for (const contract of moving) {
|
|
23240
|
-
saveInterfaceSpec({
|
|
23241
|
-
...contract,
|
|
23242
|
-
methods: contract.methods.map((m) => m.name === methodName ? { ...m, name: newName, signature: renameInSignature(m.signature, methodName, newName) } : m)
|
|
23173
|
+
agents.push({
|
|
23174
|
+
id: `${sub.id}-owner`,
|
|
23175
|
+
name: `${sub.name} Owner`,
|
|
23176
|
+
description: `Owns the ${sub.id} subsystem. ${summarize(sub.description)}`,
|
|
23177
|
+
template: "domain-owner",
|
|
23178
|
+
creationReason: `Automatically inferred from L1 subsystem spec: ${sub.id}`,
|
|
23179
|
+
domainRoot: sub.id,
|
|
23180
|
+
ownedPaths,
|
|
23181
|
+
readPaths: ["**"],
|
|
23182
|
+
writePaths: ownedPaths,
|
|
23183
|
+
tags: ["owner", "domain", "sdd"],
|
|
23184
|
+
dependencies,
|
|
23185
|
+
variantGuidance: buildVariantGuidance(subComponents, components, variantsById),
|
|
23186
|
+
status: "active",
|
|
23187
|
+
targets: activeTargets,
|
|
23188
|
+
createdAt: sub.createdAt,
|
|
23189
|
+
updatedAt: sub.updatedAt
|
|
23243
23190
|
});
|
|
23244
|
-
renamed.push(contract.id);
|
|
23245
23191
|
}
|
|
23246
|
-
|
|
23247
|
-
|
|
23248
|
-
|
|
23249
|
-
|
|
23250
|
-
|
|
23251
|
-
|
|
23252
|
-
|
|
23253
|
-
|
|
23254
|
-
|
|
23255
|
-
|
|
23192
|
+
if (config.rules.generateComponentImplementers) {
|
|
23193
|
+
for (const comp of components) {
|
|
23194
|
+
const compInterfaces = interfaces.filter((i) => i.component === comp.id);
|
|
23195
|
+
const compInterfaceIds = compInterfaces.map((i) => i.id);
|
|
23196
|
+
const compImpls = implementations.filter((impl) => compInterfaceIds.includes(impl.contract));
|
|
23197
|
+
const ownedPaths = [];
|
|
23198
|
+
for (const impl of compImpls) {
|
|
23199
|
+
for (const file of implementationSourceFiles(impl)) {
|
|
23200
|
+
if (!ownedPaths.includes(file)) ownedPaths.push(file);
|
|
23201
|
+
}
|
|
23202
|
+
}
|
|
23203
|
+
if (ownedPaths.length === 0) {
|
|
23204
|
+
const inferred = inferSourcePathForComponent(comp, subsystems);
|
|
23205
|
+
if (inferred) {
|
|
23206
|
+
ownedPaths.push(inferred);
|
|
23207
|
+
}
|
|
23208
|
+
}
|
|
23209
|
+
const dependencies = comp.dependsOn.map((depId) => `${depId}-implementer`);
|
|
23210
|
+
const readPaths = [
|
|
23211
|
+
path20.relative(getProjectRoot(), AI_PATHS.specsSystem()).replace(/\\/g, "/"),
|
|
23212
|
+
path20.relative(getProjectRoot(), getComponentPath(comp.id, comp.subsystem)).replace(/\\/g, "/"),
|
|
23213
|
+
...compInterfaces.map((i) => path20.relative(getProjectRoot(), getInterfacePath(i.id, comp.id)).replace(/\\/g, "/")),
|
|
23214
|
+
...compImpls.map((impl) => path20.relative(getProjectRoot(), getImplementationPath(impl.id, impl.contract)).replace(/\\/g, "/"))
|
|
23215
|
+
];
|
|
23216
|
+
agents.push({
|
|
23217
|
+
id: `${comp.id}-implementer`,
|
|
23218
|
+
name: `${comp.name} Implementer`,
|
|
23219
|
+
description: `Developer agent implementing ${comp.name} (${comp.componentType})`,
|
|
23220
|
+
template: "implementer",
|
|
23221
|
+
creationReason: `Automatically inferred from L2 component spec: ${comp.id}`,
|
|
23222
|
+
domainRoot: comp.subsystem,
|
|
23223
|
+
ownedPaths,
|
|
23224
|
+
readPaths,
|
|
23225
|
+
writePaths: ownedPaths,
|
|
23226
|
+
tags: ["implementer", "component", "sdd", comp.componentType.toLowerCase()],
|
|
23227
|
+
dependencies,
|
|
23228
|
+
variantGuidance: buildVariantGuidance([comp], components, variantsById),
|
|
23229
|
+
status: "active",
|
|
23230
|
+
targets: activeTargets,
|
|
23231
|
+
createdAt: comp.createdAt,
|
|
23232
|
+
updatedAt: comp.updatedAt
|
|
23233
|
+
});
|
|
23234
|
+
}
|
|
23235
|
+
}
|
|
23236
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
23237
|
+
for (const dom of loadTopologyConfig().domains) {
|
|
23238
|
+
agents.push({
|
|
23239
|
+
id: `${dom.id}-owner`,
|
|
23240
|
+
name: `${dom.name ?? dom.id} Owner`,
|
|
23241
|
+
description: dom.description ? summarize(dom.description) : `Owner agent for the free-standing "${dom.id}" domain.`,
|
|
23242
|
+
template: "domain-owner",
|
|
23243
|
+
creationReason: "Inferred from a free-standing domain in .wai/topology.yaml",
|
|
23244
|
+
domainRoot: dom.id,
|
|
23245
|
+
ownedPaths: dom.ownedPaths,
|
|
23246
|
+
readPaths: ["**"],
|
|
23247
|
+
writePaths: dom.ownedPaths,
|
|
23248
|
+
tags: ["owner", "domain"],
|
|
23249
|
+
dependencies: [],
|
|
23250
|
+
status: "active",
|
|
23251
|
+
targets: activeTargets,
|
|
23252
|
+
createdAt: now,
|
|
23253
|
+
updatedAt: now
|
|
23256
23254
|
});
|
|
23257
|
-
renamed.push(implementation.id);
|
|
23258
23255
|
}
|
|
23259
|
-
|
|
23260
|
-
const specsDir = aiPathsAt(getProjectRoot()).specsDir();
|
|
23261
|
-
const rewritten = rewriteRefFields(specsDir, (ref, position, owner) => position === "method" && owner === componentId && ref === methodName ? newName : ref).map((spec) => spec.id);
|
|
23262
|
-
const mentions = collectMentions(specsDir, methodName, moving);
|
|
23263
|
-
return {
|
|
23264
|
-
component: componentId,
|
|
23265
|
-
from: methodName,
|
|
23266
|
-
to: newName,
|
|
23267
|
-
renamed,
|
|
23268
|
-
rewritten,
|
|
23269
|
-
mentions,
|
|
23270
|
-
...pinnedSymbol ? { pinnedSymbol } : {}
|
|
23271
|
-
};
|
|
23272
|
-
}
|
|
23273
|
-
function renameInSignature(signature, from, to) {
|
|
23274
|
-
return signature.replace(identifierPattern(from), to);
|
|
23256
|
+
return agents;
|
|
23275
23257
|
}
|
|
23276
|
-
function
|
|
23277
|
-
const
|
|
23278
|
-
|
|
23279
|
-
|
|
23280
|
-
|
|
23281
|
-
return endpoint?.transport === "gRPC" && endpoint.method === methodName;
|
|
23282
|
-
});
|
|
23283
|
-
if (wireBound) mentions.add(contract.id);
|
|
23258
|
+
function composeAgentBrief(agentId) {
|
|
23259
|
+
const records = resolveAgentTopology();
|
|
23260
|
+
const record = records.find((r) => r.id === agentId);
|
|
23261
|
+
if (!record) {
|
|
23262
|
+
throw new UnknownAgentError(agentId, records.map((r) => r.id));
|
|
23284
23263
|
}
|
|
23285
|
-
const
|
|
23286
|
-
|
|
23287
|
-
|
|
23288
|
-
|
|
23289
|
-
|
|
23290
|
-
|
|
23291
|
-
|
|
23292
|
-
|
|
23293
|
-
|
|
23294
|
-
|
|
23295
|
-
|
|
23296
|
-
|
|
23297
|
-
|
|
23298
|
-
|
|
23299
|
-
|
|
23300
|
-
|
|
23301
|
-
|
|
23264
|
+
const config = projectConfigRepository.load();
|
|
23265
|
+
if (!config) throw new ProjectNotInitializedError();
|
|
23266
|
+
const template = loadTemplate(record.template, config.globalTemplatesDir);
|
|
23267
|
+
let instructions = renderTemplateInstructions(template, {
|
|
23268
|
+
agentId: record.id,
|
|
23269
|
+
agentName: record.name,
|
|
23270
|
+
agentDescription: record.description,
|
|
23271
|
+
ownedPaths: record.ownedPaths.join("\n"),
|
|
23272
|
+
tags: record.tags.join(", "),
|
|
23273
|
+
renderContext: "root",
|
|
23274
|
+
contextNote: "",
|
|
23275
|
+
domainPath: ".",
|
|
23276
|
+
domainName: "",
|
|
23277
|
+
variantGuidance: record.variantGuidance ?? ""
|
|
23278
|
+
});
|
|
23279
|
+
const guidance = loadAgentOverride(agentId);
|
|
23280
|
+
if (guidance !== null) {
|
|
23281
|
+
instructions = `${instructions.trimEnd()}
|
|
23282
|
+
|
|
23283
|
+
## Project guidance
|
|
23284
|
+
|
|
23285
|
+
${guidance.trim()}
|
|
23286
|
+
`;
|
|
23302
23287
|
}
|
|
23303
|
-
|
|
23288
|
+
const profile = deriveExecutionProfile(record);
|
|
23289
|
+
const budget = resolveBudget(profile, config.execution, record.id);
|
|
23290
|
+
return {
|
|
23291
|
+
agentId: record.id,
|
|
23292
|
+
name: record.name,
|
|
23293
|
+
template: record.template,
|
|
23294
|
+
domainRoot: record.domainRoot,
|
|
23295
|
+
ownedPaths: record.ownedPaths,
|
|
23296
|
+
readPaths: record.readPaths,
|
|
23297
|
+
instructions,
|
|
23298
|
+
variantGuidance: record.variantGuidance || void 0,
|
|
23299
|
+
profile: budget ? profile : void 0,
|
|
23300
|
+
budget
|
|
23301
|
+
};
|
|
23304
23302
|
}
|
|
23305
|
-
function
|
|
23306
|
-
|
|
23303
|
+
function loadRegistry() {
|
|
23304
|
+
assertProjectInitialized();
|
|
23305
|
+
if (!pathExists(AI_PATHS.specsSystem())) return createEmptyRegistry();
|
|
23306
|
+
return {
|
|
23307
|
+
schemaVersion: "1.0.0",
|
|
23308
|
+
agents: resolveAgentTopology(),
|
|
23309
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
23310
|
+
};
|
|
23307
23311
|
}
|
|
23308
|
-
var
|
|
23309
|
-
var
|
|
23310
|
-
"src/core/
|
|
23312
|
+
var path20, fs15, projectFilesCache, UnknownAgentError;
|
|
23313
|
+
var init_agent_resolver = __esm({
|
|
23314
|
+
"src/core/agent_resolver.ts"() {
|
|
23311
23315
|
"use strict";
|
|
23312
|
-
fs15 = __toESM(require("fs"));
|
|
23313
23316
|
path20 = __toESM(require("path"));
|
|
23314
|
-
|
|
23317
|
+
fs15 = __toESM(require("fs"));
|
|
23315
23318
|
init_loader();
|
|
23319
|
+
init_paths();
|
|
23320
|
+
init_registry();
|
|
23316
23321
|
init_project_config();
|
|
23317
23322
|
init_fs();
|
|
23318
|
-
init_yaml();
|
|
23319
23323
|
init_errors();
|
|
23320
|
-
|
|
23321
|
-
|
|
23322
|
-
|
|
23323
|
-
|
|
23324
|
-
|
|
23325
|
-
|
|
23326
|
-
|
|
23327
|
-
|
|
23328
|
-
|
|
23329
|
-
|
|
23330
|
-
|
|
23331
|
-
|
|
23332
|
-
|
|
23324
|
+
init_templates();
|
|
23325
|
+
init_execution_profile();
|
|
23326
|
+
init_budget_policy();
|
|
23327
|
+
init_specs2();
|
|
23328
|
+
init_specs();
|
|
23329
|
+
init_variants();
|
|
23330
|
+
projectFilesCache = /* @__PURE__ */ new Map();
|
|
23331
|
+
UnknownAgentError = class extends WaironError {
|
|
23332
|
+
constructor(agentId, knownIds) {
|
|
23333
|
+
super(`Unknown agent id: "${agentId}". Known agent ids: ${knownIds.join(", ")}`);
|
|
23334
|
+
this.name = "UnknownAgentError";
|
|
23335
|
+
}
|
|
23336
|
+
};
|
|
23333
23337
|
}
|
|
23334
23338
|
});
|
|
23335
23339
|
|
|
@@ -27241,116 +27245,383 @@ function commitStagedTree(stagingDir, destDir, roots, backupExisting) {
|
|
|
27241
27245
|
} else if (liveSpecDir && fs17.existsSync(liveSpecDir)) {
|
|
27242
27246
|
fs17.rmSync(liveSpecDir, { recursive: true, force: true });
|
|
27243
27247
|
}
|
|
27244
|
-
const target = path22.join(root, relative9, ".wai");
|
|
27245
|
-
fs17.mkdirSync(path22.dirname(target), { recursive: true });
|
|
27246
|
-
if (fs17.existsSync(target)) fs17.rmSync(target, { recursive: true, force: true });
|
|
27247
|
-
fs17.renameSync(stagedSpecDir, target);
|
|
27248
|
-
}
|
|
27249
|
-
if (backedUp) {
|
|
27250
|
-
return backupDir;
|
|
27248
|
+
const target = path22.join(root, relative9, ".wai");
|
|
27249
|
+
fs17.mkdirSync(path22.dirname(target), { recursive: true });
|
|
27250
|
+
if (fs17.existsSync(target)) fs17.rmSync(target, { recursive: true, force: true });
|
|
27251
|
+
fs17.renameSync(stagedSpecDir, target);
|
|
27252
|
+
}
|
|
27253
|
+
if (backedUp) {
|
|
27254
|
+
return backupDir;
|
|
27255
|
+
}
|
|
27256
|
+
return "";
|
|
27257
|
+
}
|
|
27258
|
+
function discardStagingDir(stagingDir) {
|
|
27259
|
+
try {
|
|
27260
|
+
fs17.rmSync(stagingDir, { recursive: true, force: true });
|
|
27261
|
+
} catch {
|
|
27262
|
+
}
|
|
27263
|
+
}
|
|
27264
|
+
function exportSpecTree(includeDerived, allowPartial) {
|
|
27265
|
+
const system = loadSystemSpec();
|
|
27266
|
+
if (!system) {
|
|
27267
|
+
throw new Error("no spec tree to export at this project root");
|
|
27268
|
+
}
|
|
27269
|
+
const inspection = inspectChainedRoots();
|
|
27270
|
+
const root = getProjectRoot();
|
|
27271
|
+
const skipped = [...inspection.skipped];
|
|
27272
|
+
const roots = [{ relativePath: ".", waiDir: aiPathsAt(root).root() }];
|
|
27273
|
+
for (const rel2 of inspection.roots) {
|
|
27274
|
+
const waiDir = aiPathsAt(path22.resolve(root, rel2)).root();
|
|
27275
|
+
if (pathExists(waiDir)) {
|
|
27276
|
+
roots.push({ relativePath: rel2, waiDir });
|
|
27277
|
+
} else {
|
|
27278
|
+
skipped.push({ mount: rel2, projectPath: rel2, reason: "no-spec-tree" });
|
|
27279
|
+
}
|
|
27280
|
+
}
|
|
27281
|
+
if (skipped.length > 0 && !allowPartial) {
|
|
27282
|
+
const detail = skipped.map((s) => `${s.mount} (${s.reason})`).join(", ");
|
|
27283
|
+
throw new Error(
|
|
27284
|
+
`cannot export the whole spec tree \u2014 skipped: ${detail}. Pass allowPartial to export the rest anyway.`
|
|
27285
|
+
);
|
|
27286
|
+
}
|
|
27287
|
+
const stateId = computeStateId();
|
|
27288
|
+
const built = buildTreeArchive2(roots, system.name, stateId.digest, includeDerived);
|
|
27289
|
+
const result = {
|
|
27290
|
+
archive: built.archive,
|
|
27291
|
+
suggestedFileName: built.suggestedFileName,
|
|
27292
|
+
projectName: built.manifest.projectName,
|
|
27293
|
+
roots: built.manifest.roots,
|
|
27294
|
+
fileCount: built.fileCount,
|
|
27295
|
+
stateId: stateId.digest,
|
|
27296
|
+
skipped
|
|
27297
|
+
};
|
|
27298
|
+
return result;
|
|
27299
|
+
}
|
|
27300
|
+
function importSpecTree(archive, options) {
|
|
27301
|
+
const info = inspectTreeArchive2(archive);
|
|
27302
|
+
if (!info.compatible) {
|
|
27303
|
+
throw new Error("incompatible .waitree archive (format or minimum wairon version)");
|
|
27304
|
+
}
|
|
27305
|
+
const destDir = path22.resolve(options.destDir ?? getProjectRoot());
|
|
27306
|
+
const occupied = hasSpecTree(destDir);
|
|
27307
|
+
const authored = hasAuthoredSpecs(destDir);
|
|
27308
|
+
if (authored && options.replaceExisting !== true) {
|
|
27309
|
+
throw new Error(
|
|
27310
|
+
"the destination already holds an authored spec tree; pass replaceExisting to move it aside and import over it"
|
|
27311
|
+
);
|
|
27312
|
+
}
|
|
27313
|
+
const stagingDir = createStagingDir(destDir);
|
|
27314
|
+
let extraction;
|
|
27315
|
+
try {
|
|
27316
|
+
extraction = extractTreeArchive2(archive, stagingDir, options.refuseExecutableEntries);
|
|
27317
|
+
} catch (err) {
|
|
27318
|
+
discardStagingDir(stagingDir);
|
|
27319
|
+
throw err;
|
|
27320
|
+
}
|
|
27321
|
+
const backupPath = commitStagedTree(stagingDir, destDir, extraction.roots, occupied);
|
|
27322
|
+
discardStagingDir(stagingDir);
|
|
27323
|
+
invalidateSpecCache();
|
|
27324
|
+
const result = {
|
|
27325
|
+
destDir,
|
|
27326
|
+
projectName: extraction.manifest.projectName,
|
|
27327
|
+
roots: extraction.roots,
|
|
27328
|
+
fileCount: extraction.writtenPaths.length,
|
|
27329
|
+
replaced: occupied
|
|
27330
|
+
};
|
|
27331
|
+
if (backupPath) result.backupPath = backupPath;
|
|
27332
|
+
if (extraction.manifest.stateId) result.stateId = extraction.manifest.stateId;
|
|
27333
|
+
return result;
|
|
27334
|
+
}
|
|
27335
|
+
function liveSpecDirFor(rootDir) {
|
|
27336
|
+
const modern = path22.join(rootDir, ".wai");
|
|
27337
|
+
if (fs17.existsSync(modern)) return modern;
|
|
27338
|
+
const legacy = path22.join(rootDir, ".wairon");
|
|
27339
|
+
if (fs17.existsSync(legacy)) return legacy;
|
|
27340
|
+
return null;
|
|
27341
|
+
}
|
|
27342
|
+
function timestampSlug() {
|
|
27343
|
+
return (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
27344
|
+
}
|
|
27345
|
+
var fs17, path22, sdkPortal, STAGING_PREFIX, BACKUP_DIR;
|
|
27346
|
+
var init_treetransfer = __esm({
|
|
27347
|
+
"src/core/treetransfer.ts"() {
|
|
27348
|
+
"use strict";
|
|
27349
|
+
fs17 = __toESM(require("fs"));
|
|
27350
|
+
path22 = __toESM(require("path"));
|
|
27351
|
+
sdkPortal = __toESM(require_dist());
|
|
27352
|
+
init_paths();
|
|
27353
|
+
init_fs();
|
|
27354
|
+
init_specs2();
|
|
27355
|
+
init_statehash();
|
|
27356
|
+
STAGING_PREFIX = ".wai-staging-";
|
|
27357
|
+
BACKUP_DIR = ".wai-backups";
|
|
27358
|
+
}
|
|
27359
|
+
});
|
|
27360
|
+
|
|
27361
|
+
// src/exporters/claude.ts
|
|
27362
|
+
function toolsFor(budget) {
|
|
27363
|
+
const base = TOOLS_BY_CLASS[budget.toolClass];
|
|
27364
|
+
if (!base) return void 0;
|
|
27365
|
+
if (budget.allowNestedDelegation && !base.includes("Agent")) {
|
|
27366
|
+
return [...base, "Agent"];
|
|
27367
|
+
}
|
|
27368
|
+
if (!budget.allowNestedDelegation) {
|
|
27369
|
+
return base.filter((t) => t !== "Agent");
|
|
27370
|
+
}
|
|
27371
|
+
return base;
|
|
27372
|
+
}
|
|
27373
|
+
function mcpServersFor(access) {
|
|
27374
|
+
return access === "none" ? "[]" : void 0;
|
|
27375
|
+
}
|
|
27376
|
+
function yamlScalar(value) {
|
|
27377
|
+
return /[:#\n]/.test(value) ? `"${value.replace(/"/g, '\\"')}"` : value;
|
|
27378
|
+
}
|
|
27379
|
+
var path23, MODEL_BY_TIER, TOOLS_BY_CLASS, ClaudeExporter;
|
|
27380
|
+
var init_claude = __esm({
|
|
27381
|
+
"src/exporters/claude.ts"() {
|
|
27382
|
+
"use strict";
|
|
27383
|
+
path23 = __toESM(require("path"));
|
|
27384
|
+
init_fs();
|
|
27385
|
+
MODEL_BY_TIER = {
|
|
27386
|
+
small: "haiku",
|
|
27387
|
+
standard: "sonnet",
|
|
27388
|
+
large: "opus",
|
|
27389
|
+
frontier: "fable"
|
|
27390
|
+
};
|
|
27391
|
+
TOOLS_BY_CLASS = {
|
|
27392
|
+
"read-only": ["Read", "Grep", "Glob"],
|
|
27393
|
+
implement: ["Read", "Grep", "Glob", "Edit", "Write", "Bash"],
|
|
27394
|
+
orchestrate: ["Agent", "SendMessage", "TodoWrite"],
|
|
27395
|
+
// `full` means "inherit everything" — expressed by omitting the field.
|
|
27396
|
+
full: void 0
|
|
27397
|
+
};
|
|
27398
|
+
ClaudeExporter = class {
|
|
27399
|
+
constructor(options = {}) {
|
|
27400
|
+
this.options = options;
|
|
27401
|
+
this.targetType = "claude";
|
|
27402
|
+
}
|
|
27403
|
+
outputPath(ctx) {
|
|
27404
|
+
const { agent, target, projectRoot } = ctx;
|
|
27405
|
+
const outputDir = "outputDir" in target ? target.outputDir : ".claude/agents";
|
|
27406
|
+
return path23.resolve(projectRoot, outputDir, `${agent.id.replace(/::/g, "--")}.md`);
|
|
27407
|
+
}
|
|
27408
|
+
export(ctx) {
|
|
27409
|
+
const { agent, renderedInstructions, budget } = ctx;
|
|
27410
|
+
const filePath = this.outputPath(ctx);
|
|
27411
|
+
const frontmatter = [
|
|
27412
|
+
`name: ${agent.name}`,
|
|
27413
|
+
`description: ${yamlScalar(agent.description)}`
|
|
27414
|
+
];
|
|
27415
|
+
if (budget && this.options.emitBudget) {
|
|
27416
|
+
if (budget.modelTier) frontmatter.push(`model: ${MODEL_BY_TIER[budget.modelTier]}`);
|
|
27417
|
+
if (budget.effort) frontmatter.push(`effort: ${budget.effort}`);
|
|
27418
|
+
if (budget.maxTurns !== void 0) frontmatter.push(`maxTurns: ${budget.maxTurns}`);
|
|
27419
|
+
const tools = toolsFor(budget);
|
|
27420
|
+
if (tools) frontmatter.push(`tools: ${tools.join(", ")}`);
|
|
27421
|
+
const servers = mcpServersFor(budget.mcp);
|
|
27422
|
+
if (servers) frontmatter.push(`mcpServers: ${servers}`);
|
|
27423
|
+
}
|
|
27424
|
+
const content = ["---", ...frontmatter, "---", "", renderedInstructions, ""].join("\n");
|
|
27425
|
+
const changed = writeFileIfChanged(filePath, content);
|
|
27426
|
+
return { outputPath: filePath, content, unchanged: !changed };
|
|
27427
|
+
}
|
|
27428
|
+
};
|
|
27429
|
+
}
|
|
27430
|
+
});
|
|
27431
|
+
|
|
27432
|
+
// src/exporters/custom.ts
|
|
27433
|
+
var path24, CustomExporter;
|
|
27434
|
+
var init_custom = __esm({
|
|
27435
|
+
"src/exporters/custom.ts"() {
|
|
27436
|
+
"use strict";
|
|
27437
|
+
path24 = __toESM(require("path"));
|
|
27438
|
+
init_fs();
|
|
27439
|
+
CustomExporter = class {
|
|
27440
|
+
constructor() {
|
|
27441
|
+
this.targetType = "custom";
|
|
27442
|
+
}
|
|
27443
|
+
outputPath(ctx) {
|
|
27444
|
+
const { agent, target, projectRoot } = ctx;
|
|
27445
|
+
if (!("outputDir" in target)) {
|
|
27446
|
+
throw new Error("CustomExporter requires target.outputDir");
|
|
27447
|
+
}
|
|
27448
|
+
return path24.resolve(projectRoot, target.outputDir, `${agent.id.replace(/::/g, "--")}.md`);
|
|
27449
|
+
}
|
|
27450
|
+
export(ctx) {
|
|
27451
|
+
const { agent, target, renderedInstructions } = ctx;
|
|
27452
|
+
const label = "label" in target ? target.label : "Custom";
|
|
27453
|
+
const filePath = this.outputPath(ctx);
|
|
27454
|
+
const content = [
|
|
27455
|
+
"---",
|
|
27456
|
+
`name: ${agent.name}`,
|
|
27457
|
+
`description: ${agent.description}`,
|
|
27458
|
+
`id: ${agent.id}`,
|
|
27459
|
+
`target: ${label}`,
|
|
27460
|
+
"---",
|
|
27461
|
+
"",
|
|
27462
|
+
renderedInstructions,
|
|
27463
|
+
""
|
|
27464
|
+
].join("\n");
|
|
27465
|
+
const changed = writeFileIfChanged(filePath, content);
|
|
27466
|
+
return { outputPath: filePath, content, unchanged: !changed };
|
|
27467
|
+
}
|
|
27468
|
+
};
|
|
27469
|
+
}
|
|
27470
|
+
});
|
|
27471
|
+
|
|
27472
|
+
// src/exporters/gemini.ts
|
|
27473
|
+
function yamlString(value) {
|
|
27474
|
+
if (/[:#\[\]{},&*!|>'"%@`]/.test(value) || value.startsWith(" ") || value.endsWith(" ")) {
|
|
27475
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
27476
|
+
}
|
|
27477
|
+
return value;
|
|
27478
|
+
}
|
|
27479
|
+
var path25, GeminiExporter;
|
|
27480
|
+
var init_gemini = __esm({
|
|
27481
|
+
"src/exporters/gemini.ts"() {
|
|
27482
|
+
"use strict";
|
|
27483
|
+
path25 = __toESM(require("path"));
|
|
27484
|
+
init_fs();
|
|
27485
|
+
GeminiExporter = class {
|
|
27486
|
+
constructor() {
|
|
27487
|
+
this.targetType = "gemini";
|
|
27488
|
+
}
|
|
27489
|
+
outputPath(ctx) {
|
|
27490
|
+
const { agent, target, projectRoot } = ctx;
|
|
27491
|
+
const outputDir = "outputDir" in target ? target.outputDir : ".gemini/agents";
|
|
27492
|
+
return path25.resolve(projectRoot, outputDir, `${agent.id.replace(/::/g, "--")}.yaml`);
|
|
27493
|
+
}
|
|
27494
|
+
export(ctx) {
|
|
27495
|
+
const { agent, renderedInstructions } = ctx;
|
|
27496
|
+
const filePath = this.outputPath(ctx);
|
|
27497
|
+
const indentedInstructions = renderedInstructions.split("\n").map((line) => line.length > 0 ? ` ${line}` : "").join("\n");
|
|
27498
|
+
const content = [
|
|
27499
|
+
`name: ${yamlString(agent.name)}`,
|
|
27500
|
+
`description: ${yamlString(agent.description)}`,
|
|
27501
|
+
`system_prompt: |`,
|
|
27502
|
+
indentedInstructions,
|
|
27503
|
+
""
|
|
27504
|
+
].join("\n");
|
|
27505
|
+
const changed = writeFileIfChanged(filePath, content);
|
|
27506
|
+
return { outputPath: filePath, content, unchanged: !changed };
|
|
27507
|
+
}
|
|
27508
|
+
};
|
|
27509
|
+
}
|
|
27510
|
+
});
|
|
27511
|
+
|
|
27512
|
+
// src/exporters/registry.ts
|
|
27513
|
+
function getExporter(target) {
|
|
27514
|
+
const type = typeof target === "string" ? target : target.type;
|
|
27515
|
+
const exporter = EXPORTERS.get(type);
|
|
27516
|
+
if (!exporter) {
|
|
27517
|
+
throw new WaironError(`No exporter registered for target type: "${type}"`);
|
|
27518
|
+
}
|
|
27519
|
+
return exporter;
|
|
27520
|
+
}
|
|
27521
|
+
function registerExporter(type, exporter) {
|
|
27522
|
+
EXPORTERS.set(type, exporter);
|
|
27523
|
+
}
|
|
27524
|
+
var EXPORTERS;
|
|
27525
|
+
var init_registry2 = __esm({
|
|
27526
|
+
"src/exporters/registry.ts"() {
|
|
27527
|
+
"use strict";
|
|
27528
|
+
init_claude();
|
|
27529
|
+
init_custom();
|
|
27530
|
+
init_gemini();
|
|
27531
|
+
init_errors();
|
|
27532
|
+
EXPORTERS = /* @__PURE__ */ new Map([
|
|
27533
|
+
["claude", new ClaudeExporter({ emitBudget: true })],
|
|
27534
|
+
["gemini", new GeminiExporter()],
|
|
27535
|
+
["agy", new GeminiExporter()],
|
|
27536
|
+
["cursor", new ClaudeExporter()],
|
|
27537
|
+
["copilot", new ClaudeExporter()],
|
|
27538
|
+
["codex", new ClaudeExporter()],
|
|
27539
|
+
["custom", new CustomExporter()]
|
|
27540
|
+
]);
|
|
27541
|
+
}
|
|
27542
|
+
});
|
|
27543
|
+
|
|
27544
|
+
// src/exporters/base.ts
|
|
27545
|
+
var WAIRON_MANAGED_MARKER, WAIRON_MANAGED_BANNER;
|
|
27546
|
+
var init_base = __esm({
|
|
27547
|
+
"src/exporters/base.ts"() {
|
|
27548
|
+
"use strict";
|
|
27549
|
+
WAIRON_MANAGED_MARKER = "wairon:managed";
|
|
27550
|
+
WAIRON_MANAGED_BANNER = `<!-- ${WAIRON_MANAGED_MARKER} \u2014 generated by \`wairon generate\`; do not edit, changes are overwritten -->`;
|
|
27551
|
+
}
|
|
27552
|
+
});
|
|
27553
|
+
|
|
27554
|
+
// src/exporters/generate.ts
|
|
27555
|
+
function generateAgent(agent, projectConfig, options = {}) {
|
|
27556
|
+
const projectRoot = options.projectRoot ?? getProjectRoot();
|
|
27557
|
+
const template = loadTemplate(agent.template, projectConfig.globalTemplatesDir);
|
|
27558
|
+
const rendered = `${WAIRON_MANAGED_BANNER}
|
|
27559
|
+
${composeAgentBrief(agent.id).instructions}`;
|
|
27560
|
+
const results = [];
|
|
27561
|
+
const budget = resolveBudget(
|
|
27562
|
+
deriveExecutionProfile(agent),
|
|
27563
|
+
projectConfig.execution,
|
|
27564
|
+
agent.id
|
|
27565
|
+
);
|
|
27566
|
+
for (const agentTarget of agent.targets) {
|
|
27567
|
+
const targetConfig = resolveTargetConfig(agentTarget, projectConfig);
|
|
27568
|
+
if (!targetConfig) continue;
|
|
27569
|
+
if (options.filterTargets) {
|
|
27570
|
+
const type = "type" in targetConfig ? targetConfig.type : targetConfig;
|
|
27571
|
+
if (!options.filterTargets.includes(type)) continue;
|
|
27572
|
+
}
|
|
27573
|
+
if (!options.dryRun) {
|
|
27574
|
+
results.push(getExporter(targetConfig).export({
|
|
27575
|
+
agent,
|
|
27576
|
+
template,
|
|
27577
|
+
renderedInstructions: rendered,
|
|
27578
|
+
projectRoot,
|
|
27579
|
+
target: targetConfig,
|
|
27580
|
+
budget
|
|
27581
|
+
}));
|
|
27582
|
+
}
|
|
27251
27583
|
}
|
|
27252
|
-
return
|
|
27584
|
+
return { agent, results };
|
|
27253
27585
|
}
|
|
27254
|
-
function
|
|
27255
|
-
|
|
27256
|
-
|
|
27257
|
-
|
|
27586
|
+
function generateAll(agents, projectConfig, options = {}) {
|
|
27587
|
+
let pool = agents;
|
|
27588
|
+
if (options.filterDomainIds && options.filterDomainIds.length > 0) {
|
|
27589
|
+
const ids = new Set(options.filterDomainIds);
|
|
27590
|
+
pool = agents.filter((a) => ids.has(a.domainRoot ?? "root"));
|
|
27258
27591
|
}
|
|
27592
|
+
return pool.map((agent) => generateAgent(agent, projectConfig, options));
|
|
27259
27593
|
}
|
|
27260
|
-
function
|
|
27261
|
-
const
|
|
27262
|
-
|
|
27263
|
-
|
|
27264
|
-
|
|
27265
|
-
|
|
27266
|
-
|
|
27267
|
-
|
|
27268
|
-
const roots = [{ relativePath: ".", waiDir: aiPathsAt(root).root() }];
|
|
27269
|
-
for (const rel2 of inspection.roots) {
|
|
27270
|
-
const waiDir = aiPathsAt(path22.resolve(root, rel2)).root();
|
|
27271
|
-
if (pathExists(waiDir)) {
|
|
27272
|
-
roots.push({ relativePath: rel2, waiDir });
|
|
27273
|
-
} else {
|
|
27274
|
-
skipped.push({ mount: rel2, projectPath: rel2, reason: "no-spec-tree" });
|
|
27594
|
+
function resolveExpectedOutputPaths(agents, projectConfig, projectRoot = getProjectRoot()) {
|
|
27595
|
+
const expected = /* @__PURE__ */ new Set();
|
|
27596
|
+
for (const agent of agents) {
|
|
27597
|
+
for (const agentTarget of agent.targets) {
|
|
27598
|
+
const targetConfig = resolveTargetConfig(agentTarget, projectConfig);
|
|
27599
|
+
if (!targetConfig) continue;
|
|
27600
|
+
const ctx = { agent, projectRoot, target: targetConfig };
|
|
27601
|
+
expected.add(path26.resolve(getExporter(targetConfig).outputPath(ctx)));
|
|
27275
27602
|
}
|
|
27276
27603
|
}
|
|
27277
|
-
|
|
27278
|
-
const detail = skipped.map((s) => `${s.mount} (${s.reason})`).join(", ");
|
|
27279
|
-
throw new Error(
|
|
27280
|
-
`cannot export the whole spec tree \u2014 skipped: ${detail}. Pass allowPartial to export the rest anyway.`
|
|
27281
|
-
);
|
|
27282
|
-
}
|
|
27283
|
-
const stateId = computeStateId();
|
|
27284
|
-
const built = buildTreeArchive2(roots, system.name, stateId.digest, includeDerived);
|
|
27285
|
-
const result = {
|
|
27286
|
-
archive: built.archive,
|
|
27287
|
-
suggestedFileName: built.suggestedFileName,
|
|
27288
|
-
projectName: built.manifest.projectName,
|
|
27289
|
-
roots: built.manifest.roots,
|
|
27290
|
-
fileCount: built.fileCount,
|
|
27291
|
-
stateId: stateId.digest,
|
|
27292
|
-
skipped
|
|
27293
|
-
};
|
|
27294
|
-
return result;
|
|
27295
|
-
}
|
|
27296
|
-
function importSpecTree(archive, options) {
|
|
27297
|
-
const info = inspectTreeArchive2(archive);
|
|
27298
|
-
if (!info.compatible) {
|
|
27299
|
-
throw new Error("incompatible .waitree archive (format or minimum wairon version)");
|
|
27300
|
-
}
|
|
27301
|
-
const destDir = path22.resolve(options.destDir ?? getProjectRoot());
|
|
27302
|
-
const occupied = hasSpecTree(destDir);
|
|
27303
|
-
const authored = hasAuthoredSpecs(destDir);
|
|
27304
|
-
if (authored && options.replaceExisting !== true) {
|
|
27305
|
-
throw new Error(
|
|
27306
|
-
"the destination already holds an authored spec tree; pass replaceExisting to move it aside and import over it"
|
|
27307
|
-
);
|
|
27308
|
-
}
|
|
27309
|
-
const stagingDir = createStagingDir(destDir);
|
|
27310
|
-
let extraction;
|
|
27311
|
-
try {
|
|
27312
|
-
extraction = extractTreeArchive2(archive, stagingDir, options.refuseExecutableEntries);
|
|
27313
|
-
} catch (err) {
|
|
27314
|
-
discardStagingDir(stagingDir);
|
|
27315
|
-
throw err;
|
|
27316
|
-
}
|
|
27317
|
-
const backupPath = commitStagedTree(stagingDir, destDir, extraction.roots, occupied);
|
|
27318
|
-
discardStagingDir(stagingDir);
|
|
27319
|
-
invalidateSpecCache();
|
|
27320
|
-
const result = {
|
|
27321
|
-
destDir,
|
|
27322
|
-
projectName: extraction.manifest.projectName,
|
|
27323
|
-
roots: extraction.roots,
|
|
27324
|
-
fileCount: extraction.writtenPaths.length,
|
|
27325
|
-
replaced: occupied
|
|
27326
|
-
};
|
|
27327
|
-
if (backupPath) result.backupPath = backupPath;
|
|
27328
|
-
if (extraction.manifest.stateId) result.stateId = extraction.manifest.stateId;
|
|
27329
|
-
return result;
|
|
27330
|
-
}
|
|
27331
|
-
function liveSpecDirFor(rootDir) {
|
|
27332
|
-
const modern = path22.join(rootDir, ".wai");
|
|
27333
|
-
if (fs17.existsSync(modern)) return modern;
|
|
27334
|
-
const legacy = path22.join(rootDir, ".wairon");
|
|
27335
|
-
if (fs17.existsSync(legacy)) return legacy;
|
|
27336
|
-
return null;
|
|
27604
|
+
return expected;
|
|
27337
27605
|
}
|
|
27338
|
-
function
|
|
27339
|
-
|
|
27606
|
+
function resolveTargetConfig(agentTarget, projectConfig) {
|
|
27607
|
+
const targetType = typeof agentTarget === "string" ? agentTarget : agentTarget.type;
|
|
27608
|
+
return projectConfig.targets.find((t) => {
|
|
27609
|
+
if (typeof t === "string") return t === targetType;
|
|
27610
|
+
return t.type === targetType;
|
|
27611
|
+
});
|
|
27340
27612
|
}
|
|
27341
|
-
var
|
|
27342
|
-
var
|
|
27343
|
-
"src/
|
|
27613
|
+
var path26;
|
|
27614
|
+
var init_generate = __esm({
|
|
27615
|
+
"src/exporters/generate.ts"() {
|
|
27344
27616
|
"use strict";
|
|
27345
|
-
|
|
27346
|
-
|
|
27347
|
-
|
|
27348
|
-
|
|
27617
|
+
path26 = __toESM(require("path"));
|
|
27618
|
+
init_templates();
|
|
27619
|
+
init_agent_resolver();
|
|
27620
|
+
init_execution_profile();
|
|
27621
|
+
init_budget_policy();
|
|
27349
27622
|
init_fs();
|
|
27350
|
-
|
|
27351
|
-
|
|
27352
|
-
STAGING_PREFIX = ".wai-staging-";
|
|
27353
|
-
BACKUP_DIR = ".wai-backups";
|
|
27623
|
+
init_registry2();
|
|
27624
|
+
init_base();
|
|
27354
27625
|
}
|
|
27355
27626
|
});
|
|
27356
27627
|
|
|
@@ -27510,12 +27781,12 @@ function digest(content) {
|
|
|
27510
27781
|
return crypto4.createHash("sha256").update(normalized, "utf8").digest("hex");
|
|
27511
27782
|
}
|
|
27512
27783
|
function currentSpecDigests(root = getProjectRoot()) {
|
|
27513
|
-
const mountDirs = loadSubsystemSpecs().filter((s) => s.projectPath && !s.id.includes("::")).map((s) => `${
|
|
27784
|
+
const mountDirs = loadSubsystemSpecs().filter((s) => s.projectPath && !s.id.includes("::")).map((s) => `${path27.resolve(root, s.projectPath).split(path27.sep).join("/")}/`);
|
|
27514
27785
|
const out = {};
|
|
27515
27786
|
for (const [abs, content] of snapshotSpecFiles()) {
|
|
27516
|
-
const normalized =
|
|
27787
|
+
const normalized = path27.resolve(abs).split(path27.sep).join("/");
|
|
27517
27788
|
if (mountDirs.some((dir) => normalized.startsWith(dir))) continue;
|
|
27518
|
-
out[
|
|
27789
|
+
out[path27.relative(root, abs).split(path27.sep).join("/")] = digest(content);
|
|
27519
27790
|
}
|
|
27520
27791
|
return out;
|
|
27521
27792
|
}
|
|
@@ -27573,7 +27844,7 @@ function currentChildPins(mounts, root = getProjectRoot()) {
|
|
|
27573
27844
|
const pins = {};
|
|
27574
27845
|
for (const mount of mounts) {
|
|
27575
27846
|
if (!mount.projectPath || mount.id.includes("::")) continue;
|
|
27576
|
-
const child = readLockRecordAt(
|
|
27847
|
+
const child = readLockRecordAt(path27.resolve(root, mount.projectPath));
|
|
27577
27848
|
if (child) pins[mount.id] = pinOf(child.stateId);
|
|
27578
27849
|
}
|
|
27579
27850
|
return pins;
|
|
@@ -27589,12 +27860,12 @@ function movedChildren(mounts, root = getProjectRoot()) {
|
|
|
27589
27860
|
}
|
|
27590
27861
|
return moved;
|
|
27591
27862
|
}
|
|
27592
|
-
var crypto4,
|
|
27863
|
+
var crypto4, path27;
|
|
27593
27864
|
var init_approval = __esm({
|
|
27594
27865
|
"src/core/approval.ts"() {
|
|
27595
27866
|
"use strict";
|
|
27596
27867
|
crypto4 = __toESM(require("crypto"));
|
|
27597
|
-
|
|
27868
|
+
path27 = __toESM(require("path"));
|
|
27598
27869
|
init_fs();
|
|
27599
27870
|
init_specs2();
|
|
27600
27871
|
init_lockfile();
|
|
@@ -27678,6 +27949,7 @@ var init_core = __esm({
|
|
|
27678
27949
|
init_treetransfer();
|
|
27679
27950
|
init_extensions();
|
|
27680
27951
|
init_agent_resolver();
|
|
27952
|
+
init_generate();
|
|
27681
27953
|
init_treetransfer();
|
|
27682
27954
|
init_provision();
|
|
27683
27955
|
init_stereotype_migration();
|
|
@@ -28140,236 +28412,18 @@ init_models();
|
|
|
28140
28412
|
// src/config/index.ts
|
|
28141
28413
|
init_defaults();
|
|
28142
28414
|
init_loader();
|
|
28415
|
+
init_paths();
|
|
28143
28416
|
|
|
28144
28417
|
// src/index.ts
|
|
28145
28418
|
init_core();
|
|
28146
28419
|
|
|
28147
|
-
// src/exporters/
|
|
28148
|
-
|
|
28149
|
-
|
|
28150
|
-
|
|
28151
|
-
|
|
28152
|
-
|
|
28153
|
-
|
|
28154
|
-
var MODEL_BY_TIER = {
|
|
28155
|
-
small: "haiku",
|
|
28156
|
-
standard: "sonnet",
|
|
28157
|
-
large: "opus",
|
|
28158
|
-
frontier: "fable"
|
|
28159
|
-
};
|
|
28160
|
-
var TOOLS_BY_CLASS = {
|
|
28161
|
-
"read-only": ["Read", "Grep", "Glob"],
|
|
28162
|
-
implement: ["Read", "Grep", "Glob", "Edit", "Write", "Bash"],
|
|
28163
|
-
orchestrate: ["Agent", "SendMessage", "TodoWrite"],
|
|
28164
|
-
// `full` means "inherit everything" — expressed by omitting the field.
|
|
28165
|
-
full: void 0
|
|
28166
|
-
};
|
|
28167
|
-
function toolsFor(budget) {
|
|
28168
|
-
const base = TOOLS_BY_CLASS[budget.toolClass];
|
|
28169
|
-
if (!base) return void 0;
|
|
28170
|
-
if (budget.allowNestedDelegation && !base.includes("Agent")) {
|
|
28171
|
-
return [...base, "Agent"];
|
|
28172
|
-
}
|
|
28173
|
-
if (!budget.allowNestedDelegation) {
|
|
28174
|
-
return base.filter((t) => t !== "Agent");
|
|
28175
|
-
}
|
|
28176
|
-
return base;
|
|
28177
|
-
}
|
|
28178
|
-
function mcpServersFor(access) {
|
|
28179
|
-
return access === "none" ? "[]" : void 0;
|
|
28180
|
-
}
|
|
28181
|
-
function yamlScalar(value) {
|
|
28182
|
-
return /[:#\n]/.test(value) ? `"${value.replace(/"/g, '\\"')}"` : value;
|
|
28183
|
-
}
|
|
28184
|
-
var ClaudeExporter = class {
|
|
28185
|
-
constructor(options = {}) {
|
|
28186
|
-
this.options = options;
|
|
28187
|
-
this.targetType = "claude";
|
|
28188
|
-
}
|
|
28189
|
-
outputPath(ctx) {
|
|
28190
|
-
const { agent, target, projectRoot } = ctx;
|
|
28191
|
-
const outputDir = "outputDir" in target ? target.outputDir : ".claude/agents";
|
|
28192
|
-
return path24.resolve(projectRoot, outputDir, `${agent.id.replace(/::/g, "--")}.md`);
|
|
28193
|
-
}
|
|
28194
|
-
export(ctx) {
|
|
28195
|
-
const { agent, renderedInstructions, budget } = ctx;
|
|
28196
|
-
const filePath = this.outputPath(ctx);
|
|
28197
|
-
const frontmatter = [
|
|
28198
|
-
`name: ${agent.name}`,
|
|
28199
|
-
`description: ${yamlScalar(agent.description)}`
|
|
28200
|
-
];
|
|
28201
|
-
if (budget && this.options.emitBudget) {
|
|
28202
|
-
if (budget.modelTier) frontmatter.push(`model: ${MODEL_BY_TIER[budget.modelTier]}`);
|
|
28203
|
-
if (budget.effort) frontmatter.push(`effort: ${budget.effort}`);
|
|
28204
|
-
if (budget.maxTurns !== void 0) frontmatter.push(`maxTurns: ${budget.maxTurns}`);
|
|
28205
|
-
const tools = toolsFor(budget);
|
|
28206
|
-
if (tools) frontmatter.push(`tools: ${tools.join(", ")}`);
|
|
28207
|
-
const servers = mcpServersFor(budget.mcp);
|
|
28208
|
-
if (servers) frontmatter.push(`mcpServers: ${servers}`);
|
|
28209
|
-
}
|
|
28210
|
-
const content = ["---", ...frontmatter, "---", "", renderedInstructions, ""].join("\n");
|
|
28211
|
-
const changed = writeFileIfChanged(filePath, content);
|
|
28212
|
-
return { outputPath: filePath, content, unchanged: !changed };
|
|
28213
|
-
}
|
|
28214
|
-
};
|
|
28215
|
-
|
|
28216
|
-
// src/exporters/custom.ts
|
|
28217
|
-
var path25 = __toESM(require("path"));
|
|
28218
|
-
init_fs();
|
|
28219
|
-
var CustomExporter = class {
|
|
28220
|
-
constructor() {
|
|
28221
|
-
this.targetType = "custom";
|
|
28222
|
-
}
|
|
28223
|
-
outputPath(ctx) {
|
|
28224
|
-
const { agent, target, projectRoot } = ctx;
|
|
28225
|
-
if (!("outputDir" in target)) {
|
|
28226
|
-
throw new Error("CustomExporter requires target.outputDir");
|
|
28227
|
-
}
|
|
28228
|
-
return path25.resolve(projectRoot, target.outputDir, `${agent.id.replace(/::/g, "--")}.md`);
|
|
28229
|
-
}
|
|
28230
|
-
export(ctx) {
|
|
28231
|
-
const { agent, target, renderedInstructions } = ctx;
|
|
28232
|
-
const label = "label" in target ? target.label : "Custom";
|
|
28233
|
-
const filePath = this.outputPath(ctx);
|
|
28234
|
-
const content = [
|
|
28235
|
-
"---",
|
|
28236
|
-
`name: ${agent.name}`,
|
|
28237
|
-
`description: ${agent.description}`,
|
|
28238
|
-
`id: ${agent.id}`,
|
|
28239
|
-
`target: ${label}`,
|
|
28240
|
-
"---",
|
|
28241
|
-
"",
|
|
28242
|
-
renderedInstructions,
|
|
28243
|
-
""
|
|
28244
|
-
].join("\n");
|
|
28245
|
-
const changed = writeFileIfChanged(filePath, content);
|
|
28246
|
-
return { outputPath: filePath, content, unchanged: !changed };
|
|
28247
|
-
}
|
|
28248
|
-
};
|
|
28249
|
-
|
|
28250
|
-
// src/exporters/gemini.ts
|
|
28251
|
-
var path26 = __toESM(require("path"));
|
|
28252
|
-
init_fs();
|
|
28253
|
-
var GeminiExporter = class {
|
|
28254
|
-
constructor() {
|
|
28255
|
-
this.targetType = "gemini";
|
|
28256
|
-
}
|
|
28257
|
-
outputPath(ctx) {
|
|
28258
|
-
const { agent, target, projectRoot } = ctx;
|
|
28259
|
-
const outputDir = "outputDir" in target ? target.outputDir : ".gemini/agents";
|
|
28260
|
-
return path26.resolve(projectRoot, outputDir, `${agent.id.replace(/::/g, "--")}.yaml`);
|
|
28261
|
-
}
|
|
28262
|
-
export(ctx) {
|
|
28263
|
-
const { agent, renderedInstructions } = ctx;
|
|
28264
|
-
const filePath = this.outputPath(ctx);
|
|
28265
|
-
const indentedInstructions = renderedInstructions.split("\n").map((line) => line.length > 0 ? ` ${line}` : "").join("\n");
|
|
28266
|
-
const content = [
|
|
28267
|
-
`name: ${yamlString(agent.name)}`,
|
|
28268
|
-
`description: ${yamlString(agent.description)}`,
|
|
28269
|
-
`system_prompt: |`,
|
|
28270
|
-
indentedInstructions,
|
|
28271
|
-
""
|
|
28272
|
-
].join("\n");
|
|
28273
|
-
const changed = writeFileIfChanged(filePath, content);
|
|
28274
|
-
return { outputPath: filePath, content, unchanged: !changed };
|
|
28275
|
-
}
|
|
28276
|
-
};
|
|
28277
|
-
function yamlString(value) {
|
|
28278
|
-
if (/[:#\[\]{},&*!|>'"%@`]/.test(value) || value.startsWith(" ") || value.endsWith(" ")) {
|
|
28279
|
-
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
28280
|
-
}
|
|
28281
|
-
return value;
|
|
28282
|
-
}
|
|
28283
|
-
|
|
28284
|
-
// src/exporters/generate.ts
|
|
28285
|
-
var path27 = __toESM(require("path"));
|
|
28286
|
-
init_core();
|
|
28287
|
-
init_execution_profile();
|
|
28288
|
-
init_budget_policy();
|
|
28289
|
-
init_fs();
|
|
28290
|
-
|
|
28291
|
-
// src/exporters/registry.ts
|
|
28292
|
-
init_errors();
|
|
28293
|
-
var EXPORTERS = /* @__PURE__ */ new Map([
|
|
28294
|
-
["claude", new ClaudeExporter({ emitBudget: true })],
|
|
28295
|
-
["gemini", new GeminiExporter()],
|
|
28296
|
-
["agy", new GeminiExporter()],
|
|
28297
|
-
["cursor", new ClaudeExporter()],
|
|
28298
|
-
["copilot", new ClaudeExporter()],
|
|
28299
|
-
["codex", new ClaudeExporter()],
|
|
28300
|
-
["custom", new CustomExporter()]
|
|
28301
|
-
]);
|
|
28302
|
-
function getExporter(target) {
|
|
28303
|
-
const type = typeof target === "string" ? target : target.type;
|
|
28304
|
-
const exporter = EXPORTERS.get(type);
|
|
28305
|
-
if (!exporter) {
|
|
28306
|
-
throw new WaironError(`No exporter registered for target type: "${type}"`);
|
|
28307
|
-
}
|
|
28308
|
-
return exporter;
|
|
28309
|
-
}
|
|
28310
|
-
function registerExporter(type, exporter) {
|
|
28311
|
-
EXPORTERS.set(type, exporter);
|
|
28312
|
-
}
|
|
28313
|
-
|
|
28314
|
-
// src/exporters/generate.ts
|
|
28315
|
-
function generateAgent(agent, projectConfig, options = {}) {
|
|
28316
|
-
const projectRoot = options.projectRoot ?? getProjectRoot();
|
|
28317
|
-
const template = loadTemplate(agent.template, projectConfig.globalTemplatesDir);
|
|
28318
|
-
const rendered = `${WAIRON_MANAGED_BANNER}
|
|
28319
|
-
${composeAgentBrief(agent.id).instructions}`;
|
|
28320
|
-
const results = [];
|
|
28321
|
-
const budget = resolveBudget(
|
|
28322
|
-
deriveExecutionProfile(agent),
|
|
28323
|
-
projectConfig.execution,
|
|
28324
|
-
agent.id
|
|
28325
|
-
);
|
|
28326
|
-
for (const agentTarget of agent.targets) {
|
|
28327
|
-
const targetConfig = resolveTargetConfig(agentTarget, projectConfig);
|
|
28328
|
-
if (!targetConfig) continue;
|
|
28329
|
-
if (options.filterTargets) {
|
|
28330
|
-
const type = "type" in targetConfig ? targetConfig.type : targetConfig;
|
|
28331
|
-
if (!options.filterTargets.includes(type)) continue;
|
|
28332
|
-
}
|
|
28333
|
-
if (!options.dryRun) {
|
|
28334
|
-
results.push(getExporter(targetConfig).export({
|
|
28335
|
-
agent,
|
|
28336
|
-
template,
|
|
28337
|
-
renderedInstructions: rendered,
|
|
28338
|
-
projectRoot,
|
|
28339
|
-
target: targetConfig,
|
|
28340
|
-
budget
|
|
28341
|
-
}));
|
|
28342
|
-
}
|
|
28343
|
-
}
|
|
28344
|
-
return { agent, results };
|
|
28345
|
-
}
|
|
28346
|
-
function generateAll(agents, projectConfig, options = {}) {
|
|
28347
|
-
let pool = agents;
|
|
28348
|
-
if (options.filterDomainIds && options.filterDomainIds.length > 0) {
|
|
28349
|
-
const ids = new Set(options.filterDomainIds);
|
|
28350
|
-
pool = agents.filter((a) => ids.has(a.domainRoot ?? "root"));
|
|
28351
|
-
}
|
|
28352
|
-
return pool.map((agent) => generateAgent(agent, projectConfig, options));
|
|
28353
|
-
}
|
|
28354
|
-
function resolveExpectedOutputPaths(agents, projectConfig, projectRoot = getProjectRoot()) {
|
|
28355
|
-
const expected = /* @__PURE__ */ new Set();
|
|
28356
|
-
for (const agent of agents) {
|
|
28357
|
-
for (const agentTarget of agent.targets) {
|
|
28358
|
-
const targetConfig = resolveTargetConfig(agentTarget, projectConfig);
|
|
28359
|
-
if (!targetConfig) continue;
|
|
28360
|
-
const ctx = { agent, projectRoot, target: targetConfig };
|
|
28361
|
-
expected.add(path27.resolve(getExporter(targetConfig).outputPath(ctx)));
|
|
28362
|
-
}
|
|
28363
|
-
}
|
|
28364
|
-
return expected;
|
|
28365
|
-
}
|
|
28366
|
-
function resolveTargetConfig(agentTarget, projectConfig) {
|
|
28367
|
-
const targetType = typeof agentTarget === "string" ? agentTarget : agentTarget.type;
|
|
28368
|
-
return projectConfig.targets.find((t) => {
|
|
28369
|
-
if (typeof t === "string") return t === targetType;
|
|
28370
|
-
return t.type === targetType;
|
|
28371
|
-
});
|
|
28372
|
-
}
|
|
28420
|
+
// src/exporters/index.ts
|
|
28421
|
+
init_base();
|
|
28422
|
+
init_claude();
|
|
28423
|
+
init_custom();
|
|
28424
|
+
init_gemini();
|
|
28425
|
+
init_generate();
|
|
28426
|
+
init_registry2();
|
|
28373
28427
|
|
|
28374
28428
|
// src/utils/index.ts
|
|
28375
28429
|
init_errors();
|