@wairon/cli 5.1.1-dev.2 → 5.1.1-dev.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -47,7 +47,7 @@ function createAgentRecord(partial) {
47
47
  ...partial
48
48
  });
49
49
  }
50
- var import_zod, BuiltinTargetSchema, CustomTargetSchema, OutputTargetSchema, AgentStatusSchema, AgentRecordSchema;
50
+ var import_zod, BuiltinTargetSchema, CustomTargetSchema, OutputTargetSchema, AgentStatusSchema, AgentRecordSchema, AgentTemplateSchema, AgentBriefSchema;
51
51
  var init_agent = __esm({
52
52
  "src/models/agent.ts"() {
53
53
  "use strict";
@@ -101,6 +101,30 @@ var init_agent = __esm({
101
101
  createdAt: import_zod.z.string().datetime(),
102
102
  updatedAt: import_zod.z.string().datetime()
103
103
  });
104
+ AgentTemplateSchema = import_zod.z.object({
105
+ /** Template identifier (architect, domain-owner, implementer, …) */
106
+ templateName: import_zod.z.string(),
107
+ /** The raw instruction body with {{variable}} placeholders, before rendering */
108
+ instructions: import_zod.z.string()
109
+ });
110
+ AgentBriefSchema = import_zod.z.object({
111
+ /** The resolved agent's stable id (e.g. sdd_core-owner, system-architect) */
112
+ agentId: import_zod.z.string(),
113
+ /** Human-readable display name of the agent */
114
+ name: import_zod.z.string(),
115
+ /** The instruction template the brief was rendered from */
116
+ template: import_zod.z.string(),
117
+ /** Domain the agent belongs to (absent = global root) */
118
+ domainRoot: import_zod.z.string().optional(),
119
+ /** Glob patterns of the files this agent owns — the write-scope fence */
120
+ ownedPaths: import_zod.z.array(import_zod.z.string()),
121
+ /** Spec paths the subagent should read first */
122
+ readPaths: import_zod.z.array(import_zod.z.string()).optional(),
123
+ /** The fully rendered instruction body — paste-ready as a subagent prompt */
124
+ instructions: import_zod.z.string(),
125
+ /** Rendered variant guidance, also folded into instructions */
126
+ variantGuidance: import_zod.z.string().optional()
127
+ });
104
128
  }
105
129
  });
106
130
 
@@ -254,6 +278,14 @@ var init_project = __esm({
254
278
  * per-component isolation.
255
279
  */
256
280
  generateComponentImplementers: import_zod3.z.boolean().default(false),
281
+ /**
282
+ * Whether `wairon generate` writes per-subsystem owner/architect agent FILES.
283
+ * Off by default: agents are served as LIVE briefs (sdd_get_agent_brief /
284
+ * wairon-agent://), and files are merely the opt-in materialized view of the
285
+ * same briefs. When off, generate reconciles to zero agent files — leftover
286
+ * wairon-managed files are removed (hand-authored files never are).
287
+ */
288
+ materializeAgentFiles: import_zod3.z.boolean().default(false),
257
289
  /**
258
290
  * Severity overrides for SDD validation rules.
259
291
  * Key: rule code (e.g. CIRCULAR_DEPENDENCY), Value: error | warning | off
@@ -773,6 +805,20 @@ var init_specs = __esm({
773
805
  * writes with hydration read-backs (MISSING_HYDRATION); optional elsewhere.
774
806
  */
775
807
  effect: import_zod6.z.enum(["read", "write"]).optional(),
808
+ /**
809
+ * Typed acknowledgment of a real caller OUTSIDE the modeled narrative graph
810
+ * (runtime timer/hook, external system, sibling subsystem). Unused-detection
811
+ * seeds the method as an entrypoint, so reachability PROPAGATES through its
812
+ * narrative — unlike a lint.allow, which only silences the finding. `caller`
813
+ * states WHO invokes it (placeholder-thin prose is INVOKED_BY_UNDESCRIBED;
814
+ * a method the internal walk already reaches is INVOKED_BY_REDUNDANT).
815
+ * Prefer a `register` narrative step when the wiring is internal — the
816
+ * registration itself is then a modeled, checkable edge.
817
+ */
818
+ invokedBy: import_zod6.z.object({
819
+ kind: import_zod6.z.enum(["runtime", "external", "sibling-subsystem"]),
820
+ caller: import_zod6.z.string().optional()
821
+ }).optional(),
776
822
  /** Opaque pack/tool extension data (see ExtDataSchema) — preserved verbatim. */
777
823
  ext: ExtDataSchema.optional()
778
824
  });
@@ -798,6 +844,8 @@ var init_specs = __esm({
798
844
  // cross-component call (targetComponent/targetMethod)
799
845
  "dispatch",
800
846
  // capability routed through a generic Portal's dispatch table (targetComponent + capability)
847
+ "register",
848
+ // runtime-callback handoff (targetComponent/targetMethod): reachability edge, never an invocation
801
849
  "branch",
802
850
  // if/else: condition + onTrueStep (default next) / onFalseStep
803
851
  "switch",
@@ -847,9 +895,9 @@ var init_specs = __esm({
847
895
  description: import_zod6.z.string(),
848
896
  type: NarrativeStepTypeSchema,
849
897
  targetComponent: import_zod6.z.string().optional(),
850
- // Required if type is 'call' or 'dispatch', references L2 Component id
898
+ // Required if type is 'call', 'register' or 'dispatch', references L2 Component id
851
899
  targetMethod: import_zod6.z.string().optional(),
852
- // Required if type is 'call', references Method name on target interface
900
+ // Required if type is 'call' or 'register', references Method name on target interface
853
901
  capability: import_zod6.z.string().optional(),
854
902
  // Required if type is 'dispatch': the capability routed through the target Portal's dispatch table
855
903
  /**
@@ -1163,7 +1211,7 @@ var init_defaults = __esm({
1163
1211
  copilot: ".github/prompts",
1164
1212
  codex: ".codex/agents"
1165
1213
  };
1166
- WAIRON_VERSION = "5.1.1-dev.2";
1214
+ WAIRON_VERSION = "5.1.1-dev.4";
1167
1215
  GITHUB_REPO = "SYW-Apps/Waffle-AIron";
1168
1216
  ARCHITECT_AGENT_ID = "agent-architect";
1169
1217
  ARCHITECT_TEMPLATE_ID = "architect";
@@ -1388,6 +1436,66 @@ var init_errors = __esm({
1388
1436
  }
1389
1437
  });
1390
1438
 
1439
+ // src/core/templates.ts
1440
+ function builtinTemplatesDir() {
1441
+ return path3.resolve(__dirname, "..", "templates");
1442
+ }
1443
+ function loadTemplate(id, globalOverride) {
1444
+ const dirs = templateSearchDirs(globalOverride);
1445
+ for (const dir of dirs) {
1446
+ const filePath = path3.join(dir, `${id}.yaml`);
1447
+ if (pathExists(filePath)) {
1448
+ const raw = readYamlFile(filePath);
1449
+ return { ...TemplateSchema.parse(raw), templateName: id };
1450
+ }
1451
+ }
1452
+ throw new TemplateNotFoundError(id);
1453
+ }
1454
+ function loadAgentOverride(agentId) {
1455
+ const filePath = path3.join(AI_PATHS.root(), "agents", `${agentId}.md`);
1456
+ return readFileOrNull(filePath);
1457
+ }
1458
+ function listTemplateIds(globalOverride) {
1459
+ const seen = /* @__PURE__ */ new Set();
1460
+ for (const dir of templateSearchDirs(globalOverride)) {
1461
+ for (const file of listFiles(dir, ".yaml")) {
1462
+ seen.add(path3.basename(file, ".yaml"));
1463
+ }
1464
+ }
1465
+ return Array.from(seen).sort();
1466
+ }
1467
+ function templateSearchDirs(globalOverride) {
1468
+ return [
1469
+ AI_PATHS.templatesDir(),
1470
+ // 1. project-local
1471
+ globalTemplatesDir(globalOverride),
1472
+ // 2. global user/org
1473
+ builtinTemplatesDir()
1474
+ // 3. built-in fallback
1475
+ ];
1476
+ }
1477
+ function renderTemplateInstructions(template, vars) {
1478
+ return template.instructions.replace(/\{\{(\w+)\}\}/g, (_match, key) => {
1479
+ return key in vars ? vars[key] : `{{${key}}}`;
1480
+ });
1481
+ }
1482
+ function parseTemplate(yamlContent) {
1483
+ return TemplateSchema.parse(parseYaml(yamlContent));
1484
+ }
1485
+ var path3;
1486
+ var init_templates = __esm({
1487
+ "src/core/templates.ts"() {
1488
+ "use strict";
1489
+ path3 = __toESM(require("path"));
1490
+ init_fs();
1491
+ init_yaml();
1492
+ init_errors();
1493
+ init_template();
1494
+ init_loader();
1495
+ init_defaults();
1496
+ }
1497
+ });
1498
+
1391
1499
  // src/utils/version.ts
1392
1500
  function isNewerVersion(current2, candidate) {
1393
1501
  const baseVersion = (v) => v.replace(/-.*$/, "");
@@ -1430,20 +1538,20 @@ function packFiles(dir, prefix = "") {
1430
1538
  for (const e of entries) {
1431
1539
  if (DIGEST_EXCLUDED.has(e.name)) continue;
1432
1540
  const rel2 = prefix ? `${prefix}/${e.name}` : e.name;
1433
- if (e.isDirectory()) out.push(...packFiles(path3.join(dir, e.name), rel2));
1541
+ if (e.isDirectory()) out.push(...packFiles(path4.join(dir, e.name), rel2));
1434
1542
  else if (e.isFile()) out.push(rel2);
1435
1543
  }
1436
1544
  return out.sort();
1437
1545
  }
1438
1546
  function computePackDigest(packDir) {
1439
1547
  const hash = crypto.createHash("sha256");
1440
- const abs = path3.resolve(packDir);
1548
+ const abs = path4.resolve(packDir);
1441
1549
  let isFile = false;
1442
1550
  try {
1443
1551
  isFile = fs2.statSync(abs).isFile();
1444
1552
  } catch {
1445
1553
  }
1446
- const entries = isFile ? [[path3.basename(abs), abs]] : packFiles(abs).map((rel2) => [rel2, path3.join(abs, rel2)]);
1554
+ const entries = isFile ? [[path4.basename(abs), abs]] : packFiles(abs).map((rel2) => [rel2, path4.join(abs, rel2)]);
1447
1555
  for (const [rel2, full] of entries) {
1448
1556
  hash.update(rel2);
1449
1557
  hash.update("\0");
@@ -1457,7 +1565,7 @@ function computePackDigest(packDir) {
1457
1565
  }
1458
1566
  function readInstallRecord(packPath) {
1459
1567
  try {
1460
- const raw = readYamlFile(path3.join(packPath, INSTALL_RECORD));
1568
+ const raw = readYamlFile(path4.join(packPath, INSTALL_RECORD));
1461
1569
  return raw && typeof raw === "object" ? raw : {};
1462
1570
  } catch {
1463
1571
  return {};
@@ -1494,7 +1602,7 @@ function versionedEntries(nameDir, fallbackName) {
1494
1602
  const out = [];
1495
1603
  for (const v of versions) {
1496
1604
  if (!v.isDirectory()) continue;
1497
- const versionDir = path3.join(nameDir, v.name);
1605
+ const versionDir = path4.join(nameDir, v.name);
1498
1606
  const entryFile = packDirEntry(versionDir);
1499
1607
  if (!entryFile) continue;
1500
1608
  out.push(installedFrom(versionDir, declaredName(entryFile) ?? fallbackName, v.name));
@@ -1502,7 +1610,7 @@ function versionedEntries(nameDir, fallbackName) {
1502
1610
  return out;
1503
1611
  }
1504
1612
  function storeEntryPacks(store, entry) {
1505
- const full = path3.join(store, entry.name);
1613
+ const full = path4.join(store, entry.name);
1506
1614
  if (entry.isFile()) {
1507
1615
  if (!PACK_FILE_RE.test(entry.name)) return [];
1508
1616
  const name = declaredName(full) ?? entry.name.replace(PACK_FILE_RE, "");
@@ -1534,16 +1642,16 @@ function resolveInstalledPack(name, version) {
1534
1642
  return candidates[0];
1535
1643
  }
1536
1644
  function installPackFromDirectory(sourceDir, origin) {
1537
- const abs = path3.resolve(sourceDir);
1645
+ const abs = path4.resolve(sourceDir);
1538
1646
  const entryFile = packDirEntry(abs);
1539
1647
  if (!entryFile) {
1540
1648
  throw new Error(`"${sourceDir}" is not a pack directory (no pack.yaml | pack.cjs | index.cjs | \u2026).`);
1541
1649
  }
1542
- const manifest = readManifest(entryFile, path3.dirname(entryFile));
1650
+ const manifest = readManifest(entryFile, path4.dirname(entryFile));
1543
1651
  const version = manifest.version && manifest.version.length > 0 ? manifest.version : UNVERSIONED;
1544
- const dest = path3.join(packStoreDir(), manifest.name, version);
1652
+ const dest = path4.join(packStoreDir(), manifest.name, version);
1545
1653
  fs2.rmSync(dest, { recursive: true, force: true });
1546
- fs2.mkdirSync(path3.dirname(dest), { recursive: true });
1654
+ fs2.mkdirSync(path4.dirname(dest), { recursive: true });
1547
1655
  fs2.cpSync(abs, dest, { recursive: true });
1548
1656
  const digest = computePackDigest(dest);
1549
1657
  const record = {
@@ -1552,7 +1660,7 @@ function installPackFromDirectory(sourceDir, origin) {
1552
1660
  waironVersion: WAIRON_VERSION,
1553
1661
  installedAt: (/* @__PURE__ */ new Date()).toISOString()
1554
1662
  };
1555
- writeYamlFile(path3.join(dest, INSTALL_RECORD), record);
1663
+ writeYamlFile(path4.join(dest, INSTALL_RECORD), record);
1556
1664
  return {
1557
1665
  name: manifest.name,
1558
1666
  version,
@@ -1568,8 +1676,8 @@ function uninstallPack(name, version) {
1568
1676
  if (targets.length === 0) return false;
1569
1677
  for (const target of targets) {
1570
1678
  fs2.rmSync(target.path, { recursive: true, force: true });
1571
- const parent = path3.dirname(target.path);
1572
- if (path3.resolve(parent) === path3.resolve(packStoreDir())) continue;
1679
+ const parent = path4.dirname(target.path);
1680
+ if (path4.resolve(parent) === path4.resolve(packStoreDir())) continue;
1573
1681
  try {
1574
1682
  if (fs2.readdirSync(parent).length === 0) fs2.rmdirSync(parent);
1575
1683
  } catch {
@@ -1577,13 +1685,13 @@ function uninstallPack(name, version) {
1577
1685
  }
1578
1686
  return true;
1579
1687
  }
1580
- var crypto, fs2, path3, UNVERSIONED, INSTALL_RECORD, DIGEST_EXCLUDED, PACK_FILE_RE;
1688
+ var crypto, fs2, path4, UNVERSIONED, INSTALL_RECORD, DIGEST_EXCLUDED, PACK_FILE_RE;
1581
1689
  var init_packstore = __esm({
1582
1690
  "src/core/packstore.ts"() {
1583
1691
  "use strict";
1584
1692
  crypto = __toESM(require("crypto"));
1585
1693
  fs2 = __toESM(require("fs"));
1586
- path3 = __toESM(require("path"));
1694
+ path4 = __toESM(require("path"));
1587
1695
  init_yaml();
1588
1696
  init_defaults();
1589
1697
  init_version();
@@ -1610,11 +1718,11 @@ function emptyExtensions() {
1610
1718
  return { packNames: [], packs: [], rules: [], profiles: {}, languages: {}, skills: [], patterns: [], guarantees: [], assertions: [], instructions: [], errors: [], selectionFailures: [] };
1611
1719
  }
1612
1720
  function globalPacksDir() {
1613
- return process.env.WAIRON_PACKS_DIR ?? path4.join(os2.homedir(), ".wairon", "packs");
1721
+ return process.env.WAIRON_PACKS_DIR ?? path5.join(os2.homedir(), ".wairon", "packs");
1614
1722
  }
1615
1723
  function packDirEntry(dir) {
1616
1724
  for (const name of PACK_DIR_ENTRIES) {
1617
- const p = path4.join(dir, name);
1725
+ const p = path5.join(dir, name);
1618
1726
  if (fs3.existsSync(p)) return p;
1619
1727
  }
1620
1728
  return null;
@@ -1629,7 +1737,7 @@ function latestVersionDir(nameDir) {
1629
1737
  let best = null;
1630
1738
  for (const v of versions) {
1631
1739
  if (!v.isDirectory()) continue;
1632
- const dir = path4.join(nameDir, v.name);
1740
+ const dir = path5.join(nameDir, v.name);
1633
1741
  if (!packDirEntry(dir)) continue;
1634
1742
  if (!best || isNewerVersion(best.version, v.name)) best = { version: v.name, dir };
1635
1743
  }
@@ -1644,7 +1752,7 @@ function discoverPacks(dir) {
1644
1752
  }
1645
1753
  const refs = [];
1646
1754
  for (const e of entries.sort((a, b) => a.name.localeCompare(b.name))) {
1647
- const full = path4.join(dir, e.name);
1755
+ const full = path5.join(dir, e.name);
1648
1756
  if (e.isDirectory()) {
1649
1757
  if (packDirEntry(full)) refs.push(full);
1650
1758
  else {
@@ -1674,16 +1782,16 @@ function mergePack(out, pack, ref, scope, packDir) {
1674
1782
  foreignBuiltins: [.../* @__PURE__ */ new Set([...existing.foreignBuiltins, ...def.foreignBuiltins])]
1675
1783
  } : def;
1676
1784
  }
1677
- for (const s of pack.skills) out.skills.push({ ...s, pack: pack.name, packVersion: pack.version, sourcePath: path4.resolve(packDir, s.source) });
1785
+ for (const s of pack.skills) out.skills.push({ ...s, pack: pack.name, packVersion: pack.version, sourcePath: path5.resolve(packDir, s.source) });
1678
1786
  for (const p of pack.patterns) out.patterns.push({ ...p, pack: pack.name });
1679
1787
  out.guarantees = [.../* @__PURE__ */ new Set([...out.guarantees, ...pack.guarantees])];
1680
1788
  for (const a of pack.assertions) out.assertions.push({ ...a, pack: pack.name, fullCode: assertionFullCode(pack.name, a.code) });
1681
1789
  for (const b of pack.instructions) out.instructions.push({ ...b, pack: pack.name });
1682
1790
  }
1683
1791
  function resolvePackRef(ref, projectRoot) {
1684
- const pathLike = ref.startsWith(".") || path4.isAbsolute(ref) || isYamlPath(ref);
1792
+ const pathLike = ref.startsWith(".") || path5.isAbsolute(ref) || isYamlPath(ref);
1685
1793
  if (!pathLike) return ref;
1686
- const resolved = path4.resolve(projectRoot, ref);
1794
+ const resolved = path5.resolve(projectRoot, ref);
1687
1795
  if (fs3.existsSync(resolved) && fs3.statSync(resolved).isDirectory()) {
1688
1796
  const entry = packDirEntry(resolved);
1689
1797
  if (!entry) throw new Error(`directory pack has no entry file (${PACK_DIR_ENTRIES.join(" | ")})`);
@@ -1697,7 +1805,7 @@ function readManifest(target, projectRoot) {
1697
1805
  if (raw == null) throw new Error("file not found or empty");
1698
1806
  return { ...DeclarativePackSchema.parse(raw), rules: [] };
1699
1807
  }
1700
- const req = (0, import_module.createRequire)(path4.join(projectRoot, "package.json"));
1808
+ const req = (0, import_module.createRequire)(path5.join(projectRoot, "package.json"));
1701
1809
  const modRaw = req(target);
1702
1810
  const mod = modRaw?.default ?? modRaw;
1703
1811
  const parsed = DeclarativePackSchema.parse({
@@ -1725,7 +1833,7 @@ function loadExtensionPacks(refs, projectRoot) {
1725
1833
  try {
1726
1834
  const target = resolvePackRef(ref, projectRoot);
1727
1835
  const manifest = readManifest(target, projectRoot);
1728
- mergePack(out, manifest, ref, scope, path4.dirname(target));
1836
+ mergePack(out, manifest, ref, scope, path5.dirname(target));
1729
1837
  for (const r of manifest.rules) out.rules.push(r);
1730
1838
  } catch (e) {
1731
1839
  out.errors.push(`Extension pack "${ref}" failed to load: ${e instanceof Error ? e.message : String(e)}`);
@@ -1778,7 +1886,7 @@ function defaultPackSelections() {
1778
1886
  const entry = packDirEntry(pack.path) ?? pack.path;
1779
1887
  let manifest;
1780
1888
  try {
1781
- manifest = readManifest(entry, path4.dirname(entry));
1889
+ manifest = readManifest(entry, path5.dirname(entry));
1782
1890
  } catch {
1783
1891
  continue;
1784
1892
  }
@@ -1816,7 +1924,7 @@ function diagnoseProjectPacks() {
1816
1924
  const globalsApplied = [];
1817
1925
  if (globalsOn) {
1818
1926
  for (const ref of discoverPacks(globalPacksDir())) {
1819
- const match = installed.find((p) => path4.resolve(p.path) === path4.resolve(ref));
1927
+ const match = installed.find((p) => path5.resolve(p.path) === path5.resolve(ref));
1820
1928
  if (match) globalsApplied.push({ name: match.name, version: match.version });
1821
1929
  }
1822
1930
  }
@@ -1897,7 +2005,7 @@ function verifyIntegrity(selection, packDir, where) {
1897
2005
  };
1898
2006
  }
1899
2007
  function detectBundleStoreDrift(selection, bundleDir) {
1900
- const bundledVersion = path4.basename(bundleDir);
2008
+ const bundledVersion = path5.basename(bundleDir);
1901
2009
  const installed = resolveInstalledPack(selection.name, bundledVersion);
1902
2010
  if (!installed) return void 0;
1903
2011
  const bundleDigest = computePackDigest(bundleDir);
@@ -1911,9 +2019,9 @@ function detectBundleStoreDrift(selection, bundleDir) {
1911
2019
  };
1912
2020
  }
1913
2021
  function findBundledPack(projectRoot, selection) {
1914
- const base = path4.join(projectRoot, ".wai", "packs", selection.name);
2022
+ const base = path5.join(projectRoot, ".wai", "packs", selection.name);
1915
2023
  if (selection.version) {
1916
- const pinned = path4.join(base, selection.version);
2024
+ const pinned = path5.join(base, selection.version);
1917
2025
  return packDirEntry(pinned) ? pinned : null;
1918
2026
  }
1919
2027
  if (packDirEntry(base)) return base;
@@ -1926,19 +2034,19 @@ function findBundledPack(projectRoot, selection) {
1926
2034
  let best = null;
1927
2035
  for (const v of versions) {
1928
2036
  if (!v.isDirectory()) continue;
1929
- const dir = path4.join(base, v.name);
2037
+ const dir = path5.join(base, v.name);
1930
2038
  if (!packDirEntry(dir)) continue;
1931
2039
  if (!best || isNewerVersion(best.version, v.name)) best = { version: v.name, dir };
1932
2040
  }
1933
2041
  return best?.dir ?? null;
1934
2042
  }
1935
- var fs3, os2, path4, import_module, import_zod7, ProfileDefSchema, LanguagePackDefSchema, PackSkillSchema, PackInstructionBlockSchema, PackInstructionsSchema, PatternDefSchema, AssertionSelectorSchema, assertionBase, PackAssertionSchema, DeclarativePackSchema, EXTENDABLE_BUILTIN_SKILLS, GLOBAL_PACKS_DEFAULT, PACK_DIR_ENTRIES, isYamlPath;
2043
+ var fs3, os2, path5, import_module, import_zod7, ProfileDefSchema, LanguagePackDefSchema, PackSkillSchema, PackInstructionBlockSchema, PackInstructionsSchema, PatternDefSchema, AssertionSelectorSchema, assertionBase, PackAssertionSchema, DeclarativePackSchema, EXTENDABLE_BUILTIN_SKILLS, GLOBAL_PACKS_DEFAULT, PACK_DIR_ENTRIES, isYamlPath;
1936
2044
  var init_extensions = __esm({
1937
2045
  "src/core/extensions.ts"() {
1938
2046
  "use strict";
1939
2047
  fs3 = __toESM(require("fs"));
1940
2048
  os2 = __toESM(require("os"));
1941
- path4 = __toESM(require("path"));
2049
+ path5 = __toESM(require("path"));
1942
2050
  import_module = require("module");
1943
2051
  import_zod7 = require("zod");
1944
2052
  init_yaml();
@@ -2081,7 +2189,7 @@ var init_extensions = __esm({
2081
2189
  */
2082
2190
  applyByDefault: import_zod7.z.boolean().default(false)
2083
2191
  });
2084
- EXTENDABLE_BUILTIN_SKILLS = ["sdd-architect", "sdd-narrative", "sdd-auditor", "sdd-implement"];
2192
+ EXTENDABLE_BUILTIN_SKILLS = ["sdd-architect", "sdd-narrative", "sdd-auditor", "sdd-implement", "sdd-delegate"];
2085
2193
  GLOBAL_PACKS_DEFAULT = false;
2086
2194
  PACK_DIR_ENTRIES = ["pack.yaml", "pack.yml", "pack.cjs", "pack.js", "index.cjs", "index.js"];
2087
2195
  isYamlPath = (p) => /\.ya?ml$/i.test(p);
@@ -2884,7 +2992,7 @@ var init_openapi = __esm({
2884
2992
 
2885
2993
  // src/core/surfaces.ts
2886
2994
  function surfacesDir(rootDir) {
2887
- return path5.join(rootDir, ".wai", SURFACES_DIRNAME);
2995
+ return path6.join(rootDir, ".wai", SURFACES_DIRNAME);
2888
2996
  }
2889
2997
  function audienceRank(audience) {
2890
2998
  const idx = SURFACE_AUDIENCES.indexOf(audience ?? "instance");
@@ -3047,7 +3155,7 @@ function listSnapshots(rootDir = getProjectRoot()) {
3047
3155
  for (const file of fs4.readdirSync(dir)) {
3048
3156
  if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue;
3049
3157
  try {
3050
- out.push(SurfaceSnapshotSchema.parse(readYamlFile(path5.join(dir, file))));
3158
+ out.push(SurfaceSnapshotSchema.parse(readYamlFile(path6.join(dir, file))));
3051
3159
  } catch {
3052
3160
  }
3053
3161
  }
@@ -3062,13 +3170,13 @@ function snapshotFilename(projectName) {
3062
3170
  function saveSnapshot(snapshot, rootDir = getProjectRoot()) {
3063
3171
  const dir = surfacesDir(rootDir);
3064
3172
  fs4.mkdirSync(dir, { recursive: true });
3065
- const p = path5.join(dir, snapshotFilename(snapshot.projectName));
3173
+ const p = path6.join(dir, snapshotFilename(snapshot.projectName));
3066
3174
  writeYamlFile(p, SurfaceSnapshotSchema.parse(snapshot));
3067
3175
  return p;
3068
3176
  }
3069
3177
  function removeSnapshot(projectName, rootDir = getProjectRoot()) {
3070
3178
  const dir = surfacesDir(rootDir);
3071
- const direct = path5.join(dir, snapshotFilename(projectName));
3179
+ const direct = path6.join(dir, snapshotFilename(projectName));
3072
3180
  if (fs4.existsSync(direct)) {
3073
3181
  fs4.unlinkSync(direct);
3074
3182
  return true;
@@ -3076,7 +3184,7 @@ function removeSnapshot(projectName, rootDir = getProjectRoot()) {
3076
3184
  if (!fs4.existsSync(dir)) return false;
3077
3185
  for (const file of fs4.readdirSync(dir)) {
3078
3186
  if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue;
3079
- const p = path5.join(dir, file);
3187
+ const p = path6.join(dir, file);
3080
3188
  try {
3081
3189
  const snap = SurfaceSnapshotSchema.parse(readYamlFile(p));
3082
3190
  if (snap.projectName === projectName) {
@@ -3100,13 +3208,13 @@ function selectPortalSpec(renderedSet, portalId) {
3100
3208
  return [hit];
3101
3209
  }
3102
3210
  function perPortalPath(resolvedOut, portalId) {
3103
- const ext = path5.extname(resolvedOut);
3211
+ const ext = path6.extname(resolvedOut);
3104
3212
  const stem = ext ? resolvedOut.slice(0, -ext.length) : resolvedOut;
3105
3213
  return `${stem}.${safeFilenamePart(portalId)}${ext}`;
3106
3214
  }
3107
3215
  function writeSurfaceFile(outPath, snapshot, renderedSet) {
3108
- const resolved = path5.resolve(outPath);
3109
- fs4.mkdirSync(path5.dirname(resolved), { recursive: true });
3216
+ const resolved = path6.resolve(outPath);
3217
+ fs4.mkdirSync(path6.dirname(resolved), { recursive: true });
3110
3218
  if (!renderedSet || renderedSet.length === 0) {
3111
3219
  writeYamlFile(resolved, snapshot);
3112
3220
  return [resolved];
@@ -3139,14 +3247,14 @@ function exportSurface(maxAudience, format, outPath, portalId) {
3139
3247
  return exportResult(snapshot, renderedSet, writtenPaths);
3140
3248
  }
3141
3249
  function importSurface(sourcePath, origin) {
3142
- const resolved = path5.resolve(sourcePath);
3250
+ const resolved = path6.resolve(sourcePath);
3143
3251
  if (!fs4.existsSync(resolved)) {
3144
3252
  throw new Error(`Surface document not found: ${resolved}`);
3145
3253
  }
3146
3254
  const body = fs4.readFileSync(resolved, "utf8");
3147
3255
  let snapshot;
3148
3256
  if (isOpenApiDocument(body)) {
3149
- const projectName = path5.basename(resolved).replace(/\.(json|ya?ml)$/i, "");
3257
+ const projectName = path6.basename(resolved).replace(/\.(json|ya?ml)$/i, "");
3150
3258
  snapshot = fromOpenApi(body, projectName);
3151
3259
  snapshot = { ...snapshot, origin };
3152
3260
  } else {
@@ -3172,7 +3280,7 @@ function generateChildSnapshots(rootDir = getProjectRoot()) {
3172
3280
  };
3173
3281
  const written = [];
3174
3282
  for (const child of children) {
3175
- const childDir = path5.resolve(rootDir, child.projectPath);
3283
+ const childDir = path6.resolve(rootDir, child.projectPath);
3176
3284
  if (!fs4.existsSync(childDir)) continue;
3177
3285
  written.push(saveSnapshot(familySnapshot, childDir));
3178
3286
  for (const sibling of topLevel) {
@@ -3217,7 +3325,7 @@ function checkChildSurfaceFreshness(rootDir = getProjectRoot()) {
3217
3325
  const current2 = surfaceContentKey(projectChildSurface());
3218
3326
  const issues = [];
3219
3327
  for (const child of children) {
3220
- const childDir = path5.resolve(rootDir, child.projectPath);
3328
+ const childDir = path6.resolve(rootDir, child.projectPath);
3221
3329
  const held = getSnapshot(system.name, childDir);
3222
3330
  if (!held || held.origin !== "generated") continue;
3223
3331
  if (surfaceContentKey(held) !== current2) {
@@ -3231,12 +3339,12 @@ function checkChildSurfaceFreshness(rootDir = getProjectRoot()) {
3231
3339
  }
3232
3340
  return issues;
3233
3341
  }
3234
- var fs4, path5, SURFACES_DIRNAME, CROSS_BOUNDARY_TARGETS;
3342
+ var fs4, path6, SURFACES_DIRNAME, CROSS_BOUNDARY_TARGETS;
3235
3343
  var init_surfaces = __esm({
3236
3344
  "src/core/surfaces.ts"() {
3237
3345
  "use strict";
3238
3346
  fs4 = __toESM(require("fs"));
3239
- path5 = __toESM(require("path"));
3347
+ path6 = __toESM(require("path"));
3240
3348
  init_fs();
3241
3349
  init_yaml();
3242
3350
  init_filenames();
@@ -3346,13 +3454,13 @@ var init_contracts = __esm({
3346
3454
  init_namespace();
3347
3455
  contractsRule = {
3348
3456
  name: "contract-symmetry-and-narratives",
3349
- description: "Implementations mirror their contract method-for-method. Narrative call steps must name an existing component and method, the caller must declare the dependency, and asserted semantic guarantees must be backed by the target contract.",
3457
+ description: "Implementations mirror their contract method-for-method. Narrative call steps (and register handoffs, which share the identical target shape) must name an existing component and method, the caller must declare the dependency, and asserted semantic guarantees must be backed by the target contract.",
3350
3458
  codes: [
3351
3459
  { code: "UNEXPECTED_IMPLEMENTATION_METHOD", defaultSeverity: "error", summary: "Implementation method not present on the contract" },
3352
3460
  { code: "MISSING_IMPLEMENTATION_METHOD", defaultSeverity: "error", summary: "Contract method missing from the implementation" },
3353
- { code: "MISSING_TARGET_COMPONENT", defaultSeverity: "error", summary: "Call step missing targetComponent" },
3354
- { code: "MISSING_TARGET_METHOD", defaultSeverity: "error", summary: "Call step missing targetMethod" },
3355
- { code: "INVALID_TARGET_COMPONENT_REFERENCE", defaultSeverity: "error", summary: "Call step targets a non-existent component" },
3461
+ { code: "MISSING_TARGET_COMPONENT", defaultSeverity: "error", summary: "Call/register step missing targetComponent" },
3462
+ { code: "MISSING_TARGET_METHOD", defaultSeverity: "error", summary: "Call/register step missing targetMethod" },
3463
+ { code: "INVALID_TARGET_COMPONENT_REFERENCE", defaultSeverity: "error", summary: "Call/register step targets a non-existent component" },
3356
3464
  { code: "CROSS_TREE_REF_UNRESOLVED", defaultSeverity: "warning", summary: "Cross-tree reference (super::/:: form) with no surface snapshot covering it \u2014 only the parent project can verify it" },
3357
3465
  { code: "SURFACE_REF_NOT_EXPOSED", defaultSeverity: "error", summary: "Cross-tree reference resolves to a surface snapshot that does not expose the called method/capability" },
3358
3466
  { code: "UNDECLARED_DEPENDENCY_CALL", defaultSeverity: "error", summary: "Call step targets a component the caller does not depend on or own" },
@@ -3390,7 +3498,7 @@ var init_contracts = __esm({
3390
3498
  }
3391
3499
  for (const implMethod of impl.methods) {
3392
3500
  for (const step of implMethod.narrative) {
3393
- if (step.type !== "call" && step.type !== "dispatch") continue;
3501
+ if (step.type !== "call" && step.type !== "dispatch" && step.type !== "register") continue;
3394
3502
  if (!step.targetComponent) {
3395
3503
  ctx.addIssue(
3396
3504
  "error",
@@ -3450,11 +3558,12 @@ var init_contracts = __esm({
3450
3558
  }
3451
3559
  continue;
3452
3560
  }
3561
+ const verb = step.type === "register" ? "registers callback" : "calls";
3453
3562
  if (!step.targetMethod) {
3454
3563
  ctx.addIssue(
3455
3564
  "error",
3456
3565
  "MISSING_TARGET_METHOD",
3457
- `Method "${implMethod.name}" in implementation "${impl.id}" has a call step (${step.stepNumber}) missing "targetMethod".`,
3566
+ `Method "${implMethod.name}" in implementation "${impl.id}" has a ${step.type} step (${step.stepNumber}) missing "targetMethod".`,
3458
3567
  impl.id,
3459
3568
  isDraftCtx
3460
3569
  );
@@ -3470,7 +3579,7 @@ var init_contracts = __esm({
3470
3579
  ctx.addIssue(
3471
3580
  "error",
3472
3581
  "SURFACE_REF_NOT_EXPOSED",
3473
- `Method "${implMethod.name}" in implementation "${impl.id}" calls "${step.targetMethod}" on cross-tree component "${step.targetComponent}" (step ${step.stepNumber}), but the surface snapshot of "${resolved.snapshot.projectName}" does not expose that method on "${resolved.entry.id}".`,
3582
+ `Method "${implMethod.name}" in implementation "${impl.id}" ${verb} "${step.targetMethod}" on cross-tree component "${step.targetComponent}" (step ${step.stepNumber}), but the surface snapshot of "${resolved.snapshot.projectName}" does not expose that method on "${resolved.entry.id}".`,
3474
3583
  impl.id,
3475
3584
  isDraftCtx,
3476
3585
  true
@@ -3495,7 +3604,7 @@ var init_contracts = __esm({
3495
3604
  ctx.addIssue(
3496
3605
  "warning",
3497
3606
  "CROSS_TREE_REF_UNRESOLVED",
3498
- `Method "${implMethod.name}" in implementation "${impl.id}" calls cross-tree component "${step.targetComponent}" (step ${step.stepNumber}), and no surface snapshot covers it \u2014 validate from the parent project, or import/generate the producing project's surface.`,
3607
+ `Method "${implMethod.name}" in implementation "${impl.id}" ${verb} cross-tree component "${step.targetComponent}" (step ${step.stepNumber}), and no surface snapshot covers it \u2014 validate from the parent project, or import/generate the producing project's surface.`,
3499
3608
  impl.id,
3500
3609
  isDraftCtx
3501
3610
  );
@@ -3503,7 +3612,7 @@ var init_contracts = __esm({
3503
3612
  ctx.addIssue(
3504
3613
  "error",
3505
3614
  "INVALID_TARGET_COMPONENT_REFERENCE",
3506
- `Method "${implMethod.name}" in implementation "${impl.id}" calls component "${step.targetComponent}" which does not exist (step ${step.stepNumber}).`,
3615
+ `Method "${implMethod.name}" in implementation "${impl.id}" ${verb} component "${step.targetComponent}" which does not exist (step ${step.stepNumber}).`,
3507
3616
  impl.id,
3508
3617
  isDraftCtx
3509
3618
  );
@@ -3516,7 +3625,7 @@ var init_contracts = __esm({
3516
3625
  ctx.addIssue(
3517
3626
  "error",
3518
3627
  "UNDECLARED_DEPENDENCY_CALL",
3519
- `Method "${implMethod.name}" in implementation "${impl.id}" (component "${callingComponent.id}") calls component "${step.targetComponent}" (step ${step.stepNumber}) but component "${callingComponent.id}" does not list "${step.targetComponent}" as a dependency.`,
3628
+ `Method "${implMethod.name}" in implementation "${impl.id}" (component "${callingComponent.id}") ${verb} component "${step.targetComponent}" (step ${step.stepNumber}) but component "${callingComponent.id}" does not list "${step.targetComponent}" as a dependency.`,
3520
3629
  impl.id,
3521
3630
  isDraftCtx || ctx.isComponentDraft(callingComponent.id)
3522
3631
  );
@@ -3535,7 +3644,7 @@ var init_contracts = __esm({
3535
3644
  ctx.addIssue(
3536
3645
  "error",
3537
3646
  "INVALID_TARGET_METHOD_REFERENCE",
3538
- `Method "${implMethod.name}" in implementation "${impl.id}" calls method "${step.targetMethod}" on component "${step.targetComponent}" which is not defined on any of its interfaces (step ${step.stepNumber}).`,
3647
+ `Method "${implMethod.name}" in implementation "${impl.id}" ${verb} method "${step.targetMethod}" on component "${step.targetComponent}" which is not defined on any of its interfaces (step ${step.stepNumber}).`,
3539
3648
  impl.id,
3540
3649
  isDraftCtx || ctx.isComponentDraft(step.targetComponent)
3541
3650
  );
@@ -3604,6 +3713,7 @@ function stepGraph(steps) {
3604
3713
  switch (s.type) {
3605
3714
  case "local":
3606
3715
  case "call":
3716
+ case "register":
3607
3717
  case "dispatch":
3608
3718
  succ.push(fallNext(n));
3609
3719
  break;
@@ -3699,6 +3809,7 @@ var init_narrative_flow = __esm({
3699
3809
  switch (s.type) {
3700
3810
  case "local":
3701
3811
  case "call":
3812
+ case "register":
3702
3813
  case "dispatch": {
3703
3814
  const extra = flowConfigOn(s);
3704
3815
  if (extra.length) malformed(`step ${s.stepNumber} (${s.type}) carries flow config (${extra.join(", ")}) \u2014 use a flow step type instead.`);
@@ -3853,7 +3964,7 @@ var init_narrative_flow = __esm({
3853
3964
  if (s.finallyStep !== void 0) handlerStarts.add(s.finallyStep);
3854
3965
  const last = byNum.get(s.endStep);
3855
3966
  const nxt = nextOf(s.endStep);
3856
- if (last && (last.type === "local" || last.type === "call" || last.type === "dispatch") && nxt !== void 0 && handlerStarts.has(nxt)) {
3967
+ if (last && (last.type === "local" || last.type === "call" || last.type === "register" || last.type === "dispatch") && nxt !== void 0 && handlerStarts.has(nxt)) {
3857
3968
  ctx.addIssue(
3858
3969
  "warning",
3859
3970
  "FALLTHROUGH_INTO_HANDLER",
@@ -3963,7 +4074,7 @@ function resolveTypeScript(projectRoot) {
3963
4074
  return cached.ts;
3964
4075
  }
3965
4076
  let ts = null;
3966
- const bases = [path6.join(projectRoot, "package.json"), __filename];
4077
+ const bases = [path7.join(projectRoot, "package.json"), __filename];
3967
4078
  for (const base of bases) {
3968
4079
  try {
3969
4080
  const req = (0, import_module2.createRequire)(base);
@@ -4119,7 +4230,7 @@ function walkExact(ts, sourceText, fileName) {
4119
4230
  }
4120
4231
  function resolveRelativeModule(fromFile, specifier) {
4121
4232
  if (!specifier.startsWith(".")) return null;
4122
- const base = path6.resolve(path6.dirname(fromFile), specifier);
4233
+ const base = path7.resolve(path7.dirname(fromFile), specifier);
4123
4234
  const candidates = [
4124
4235
  base,
4125
4236
  base.replace(/\.js$/, ".ts"),
@@ -4127,8 +4238,8 @@ function resolveRelativeModule(fromFile, specifier) {
4127
4238
  `${base}.ts`,
4128
4239
  `${base}.tsx`,
4129
4240
  `${base}.js`,
4130
- path6.join(base, "index.ts"),
4131
- path6.join(base, "index.js")
4241
+ path7.join(base, "index.ts"),
4242
+ path7.join(base, "index.js")
4132
4243
  ];
4133
4244
  for (const c of candidates) {
4134
4245
  try {
@@ -4142,7 +4253,7 @@ function chaseStarExports(ts, facts, filePath, projectRoot, visited, exactCache)
4142
4253
  for (const spec of facts.starExports) {
4143
4254
  const target = resolveRelativeModule(filePath, spec);
4144
4255
  if (!target || visited.has(target)) continue;
4145
- if (path6.relative(projectRoot, target).startsWith("..")) continue;
4256
+ if (path7.relative(projectRoot, target).startsWith("..")) continue;
4146
4257
  visited.add(target);
4147
4258
  let targetFacts = exactCache.get(target);
4148
4259
  if (targetFacts === void 0) {
@@ -4187,12 +4298,12 @@ function buildCodeModel(implementations, projectRoot) {
4187
4298
  if (seen.has(sourcePath)) continue;
4188
4299
  seen.add(sourcePath);
4189
4300
  const empty = { declaredNames: [], anchoredNames: [], exportedNames: [], imports: [], reexports: [] };
4190
- if (path6.isAbsolute(sourcePath) || path6.normalize(sourcePath).split(path6.sep)[0] === "..") {
4301
+ if (path7.isAbsolute(sourcePath) || path7.normalize(sourcePath).split(path7.sep)[0] === "..") {
4191
4302
  files.push({ path: sourcePath, status: "escaped", ...empty });
4192
4303
  continue;
4193
4304
  }
4194
- const absolute = path6.resolve(projectRoot, sourcePath);
4195
- if (path6.relative(projectRoot, absolute).startsWith("..")) {
4305
+ const absolute = path7.resolve(projectRoot, sourcePath);
4306
+ if (path7.relative(projectRoot, absolute).startsWith("..")) {
4196
4307
  files.push({ path: sourcePath, status: "escaped", ...empty });
4197
4308
  continue;
4198
4309
  }
@@ -4213,7 +4324,7 @@ function buildCodeModel(implementations, projectRoot) {
4213
4324
  continue;
4214
4325
  }
4215
4326
  const text = buffer.toString("utf8");
4216
- const language = EXTENSION_LANGUAGE[path6.extname(sourcePath).toLowerCase()];
4327
+ const language = EXTENSION_LANGUAGE[path7.extname(sourcePath).toLowerCase()];
4217
4328
  let analyzed;
4218
4329
  if (language === "typescript" || language === "javascript") {
4219
4330
  const ts = resolveTypeScript(projectRoot);
@@ -4247,12 +4358,12 @@ function buildCodeModel(implementations, projectRoot) {
4247
4358
  }
4248
4359
  return { files, projectRoot };
4249
4360
  }
4250
- var fs5, path6, import_module2, EXTENSION_LANGUAGE, C_FAMILY_COMMENTS, JS_PATTERNS, LANGUAGE_PATTERNS, PATTERN_ANALYSIS_MAX_BYTES, IDENTIFIER_RE, STRING_RE, tsResolutionCache, TS_RESOLUTION_RETRY_MS;
4361
+ var fs5, path7, import_module2, EXTENSION_LANGUAGE, C_FAMILY_COMMENTS, JS_PATTERNS, LANGUAGE_PATTERNS, PATTERN_ANALYSIS_MAX_BYTES, IDENTIFIER_RE, STRING_RE, tsResolutionCache, TS_RESOLUTION_RETRY_MS;
4251
4362
  var init_source_analysis = __esm({
4252
4363
  "src/core/source-analysis.ts"() {
4253
4364
  "use strict";
4254
4365
  fs5 = __toESM(require("fs"));
4255
- path6 = __toESM(require("path"));
4366
+ path7 = __toESM(require("path"));
4256
4367
  import_module2 = require("module");
4257
4368
  EXTENSION_LANGUAGE = {
4258
4369
  ".ts": "typescript",
@@ -5763,6 +5874,7 @@ var init_public_surface = __esm({
5763
5874
  // src/core/rules/graph.ts
5764
5875
  function walkNarrativeGraph(ctx, seeds, opts = {}) {
5765
5876
  const followDispatchTables = opts.followDispatchTables ?? true;
5877
+ const followRegisterEdges = opts.followRegisterEdges ?? true;
5766
5878
  const reachedComponents = /* @__PURE__ */ new Set();
5767
5879
  const reachedMethods = /* @__PURE__ */ new Set();
5768
5880
  const queue = [];
@@ -5821,6 +5933,10 @@ function walkNarrativeGraph(ctx, seeds, opts = {}) {
5821
5933
  reachComponent(step.targetComponent);
5822
5934
  enqueueMethod(step.targetComponent, step.targetMethod);
5823
5935
  }
5936
+ if (followRegisterEdges && step.type === "register" && step.targetComponent && step.targetMethod) {
5937
+ reachComponent(step.targetComponent);
5938
+ enqueueMethod(step.targetComponent, step.targetMethod);
5939
+ }
5824
5940
  if (step.type === "dispatch" && step.targetComponent) {
5825
5941
  reachComponent(step.targetComponent);
5826
5942
  const portal = ctx.componentMap.get(step.targetComponent);
@@ -5906,11 +6022,13 @@ var init_graph = __esm({
5906
6022
  methodKey = (compId, methodName) => `${compId}#${methodName}`;
5907
6023
  reachabilityRule = {
5908
6024
  name: "unused-detection",
5909
- description: "Walks the narrative execution graph (call steps, dispatch-table routing, lifecycle flows) from every entrypoint (Portal/Observer/published component/lifecycle entrypoint) and flags components and methods no execution chain reaches, plus types no field or signature references.",
6025
+ description: "Walks the narrative execution graph (call steps, register handoffs, dispatch-table routing, lifecycle flows) from every entrypoint (Portal/Observer/published component/lifecycle entrypoint/invokedBy-declared method) and flags components and methods no execution chain reaches, plus types no field or signature references. An interface method declaring invokedBy (a real caller outside the modeled graph) seeds the walk, so its narrative propagates reachability; the declaration itself is audited (thin caller prose, or a method the internal walk already reaches).",
5910
6026
  codes: [
5911
6027
  { code: "UNUSED_COMPONENT", defaultSeverity: "warning", summary: "Component never reached by any narrative call chain" },
5912
6028
  { code: "UNUSED_METHOD", defaultSeverity: "warning", summary: "Method never called by any narrative step" },
5913
- { code: "UNUSED_TYPE", defaultSeverity: "warning", summary: "Type never referenced by fields or signatures" }
6029
+ { code: "UNUSED_TYPE", defaultSeverity: "warning", summary: "Type never referenced by fields or signatures" },
6030
+ { code: "INVOKED_BY_UNDESCRIBED", defaultSeverity: "warning", summary: "invokedBy declaration whose caller prose is missing or placeholder-thin" },
6031
+ { code: "INVOKED_BY_REDUNDANT", defaultSeverity: "warning", summary: "invokedBy declaration on a method the internal narrative walk already reaches \u2014 stale, remove it" }
5914
6032
  ],
5915
6033
  check(ctx) {
5916
6034
  const seeds = [];
@@ -5929,7 +6047,37 @@ var init_graph = __esm({
5929
6047
  seeds.push({ compId: le.component, methodName: le.method });
5930
6048
  }
5931
6049
  }
5932
- const { reachedComponents, reachedMethods } = walkNarrativeGraph(ctx, seeds);
6050
+ const baseWalk = walkNarrativeGraph(ctx, seeds);
6051
+ const invokedBySeeds = [];
6052
+ for (const intf of ctx.interfaces) {
6053
+ if (!ctx.componentMap.has(intf.component)) continue;
6054
+ const comp = ctx.componentMap.get(intf.component);
6055
+ for (const m of intf.methods) {
6056
+ if (!m.invokedBy) continue;
6057
+ invokedBySeeds.push({ compId: intf.component, methodName: m.name });
6058
+ if (!ctx.isSpecInScope(intf.id)) continue;
6059
+ const isDraftCtx = comp.status === "draft" || comp.status === "design" || intf.status === "draft" || intf.status === "design";
6060
+ if (!passesIntentFloor(m.invokedBy.caller, m.name)) {
6061
+ ctx.addIssue(
6062
+ "warning",
6063
+ "INVOKED_BY_UNDESCRIBED",
6064
+ `Method "${m.name}" on component "${intf.component}" declares invokedBy (${m.invokedBy.kind}) but its "caller" prose is missing or placeholder-thin \u2014 state WHO invokes it and when, so the entrypoint claim stays reviewable.`,
6065
+ intf.id,
6066
+ isDraftCtx
6067
+ );
6068
+ }
6069
+ if (baseWalk.reachedMethods.has(methodKey(intf.component, m.name))) {
6070
+ ctx.addIssue(
6071
+ "warning",
6072
+ "INVOKED_BY_REDUNDANT",
6073
+ `Method "${m.name}" on component "${intf.component}" declares invokedBy (${m.invokedBy.kind}), but the internal narrative walk already reaches it \u2014 the declaration is stale; remove it.`,
6074
+ intf.id,
6075
+ isDraftCtx
6076
+ );
6077
+ }
6078
+ }
6079
+ }
6080
+ const { reachedComponents, reachedMethods } = invokedBySeeds.length ? walkNarrativeGraph(ctx, [...seeds, ...invokedBySeeds]) : baseWalk;
5933
6081
  for (const comp of ctx.components) {
5934
6082
  if (!ctx.isSpecInScope(comp.id)) continue;
5935
6083
  if (!reachedComponents.has(comp.id)) {
@@ -6264,7 +6412,7 @@ var init_semantic_edges = __esm({
6264
6412
  }
6265
6413
  }
6266
6414
  }
6267
- const initReach = initSeeds.length ? walkNarrativeGraph(ctx, initSeeds, { followDispatchTables: false }) : null;
6415
+ const initReach = initSeeds.length ? walkNarrativeGraph(ctx, initSeeds, { followDispatchTables: false, followRegisterEdges: false }) : null;
6268
6416
  for (const comp of ctx.components) {
6269
6417
  const isDraftCtx = ctx.isComponentDraft(comp.id);
6270
6418
  if (comp.componentType !== "Store") continue;
@@ -6662,6 +6810,7 @@ function isTerminal(step, nextOf) {
6662
6810
  switch (step.type) {
6663
6811
  case "local":
6664
6812
  case "call":
6813
+ case "register":
6665
6814
  case "dispatch":
6666
6815
  return nextOf(n) === void 0;
6667
6816
  case "branch":
@@ -6862,11 +7011,11 @@ var init_narrative_antipatterns = __esm({
6862
7011
  const memberEdges = keys.flatMap((k) => (adjacency.get(k) ?? []).filter((e) => inScc.has(e.toKey)));
6863
7012
  if (memberEdges.length === 0) continue;
6864
7013
  const anchor = [...memberEdges].sort((a, b) => a.fromKey.localeCompare(b.fromKey))[0];
6865
- const path23 = [...keys].sort().join(" \u2192 ");
7014
+ const path24 = [...keys].sort().join(" \u2192 ");
6866
7015
  ctx.addIssue(
6867
7016
  "warning",
6868
7017
  "UNCONDITIONAL_CALL_CYCLE",
6869
- `Call cycle with no guard: ${path23} \u2014 every call edge in this cycle is unavoidable on all paths of its narrative (e.g. step ${anchor.stepNumber} of "${anchor.methodName}" in "${anchor.impl.id}" always calls ${anchor.toLabel}). This recurses without a base case, by construction. Guard at least one edge with a branch/return before the call, or lint.allow with the termination argument.`,
7018
+ `Call cycle with no guard: ${path24} \u2014 every call edge in this cycle is unavoidable on all paths of its narrative (e.g. step ${anchor.stepNumber} of "${anchor.methodName}" in "${anchor.impl.id}" always calls ${anchor.toLabel}). This recurses without a base case, by construction. Guard at least one edge with a branch/return before the call, or lint.allow with the termination argument.`,
6870
7019
  anchor.impl.id,
6871
7020
  memberEdges.some((e) => ctx.isImplementationDraft(e.impl))
6872
7021
  );
@@ -7582,7 +7731,7 @@ var init_naming = __esm({
7582
7731
  // src/core/rules/integration-conformance.ts
7583
7732
  function resolveAgainst(mapped, fromFile, specifier) {
7584
7733
  if (!specifier.startsWith(".")) return null;
7585
- const joined = normalizePath(path7.posix.normalize(path7.posix.join(path7.posix.dirname(fromFile), specifier)));
7734
+ const joined = normalizePath(path8.posix.normalize(path8.posix.join(path8.posix.dirname(fromFile), specifier)));
7586
7735
  const candidates = [
7587
7736
  joined,
7588
7737
  joined.replace(/\.js$/, ".ts"),
@@ -7598,11 +7747,11 @@ function resolveAgainst(mapped, fromFile, specifier) {
7598
7747
  }
7599
7748
  return null;
7600
7749
  }
7601
- var path7, normalizePath, integrationConformanceRule;
7750
+ var path8, normalizePath, integrationConformanceRule;
7602
7751
  var init_integration_conformance = __esm({
7603
7752
  "src/core/rules/integration-conformance.ts"() {
7604
7753
  "use strict";
7605
- path7 = __toESM(require("path"));
7754
+ path8 = __toESM(require("path"));
7606
7755
  init_source_analysis();
7607
7756
  init_conformance();
7608
7757
  normalizePath = normalizeSourcePath;
@@ -7806,7 +7955,7 @@ var init_hidden_state = __esm({
7806
7955
  // src/core/rules/dependency-conformance.ts
7807
7956
  function resolveAgainst2(mapped, fromFile, specifier) {
7808
7957
  if (!specifier.startsWith(".")) return null;
7809
- const joined = normalizePath2(path8.posix.normalize(path8.posix.join(path8.posix.dirname(fromFile), specifier)));
7958
+ const joined = normalizePath2(path9.posix.normalize(path9.posix.join(path9.posix.dirname(fromFile), specifier)));
7810
7959
  const candidates = [
7811
7960
  joined,
7812
7961
  joined.replace(/\.js$/, ".ts"),
@@ -7822,11 +7971,11 @@ function resolveAgainst2(mapped, fromFile, specifier) {
7822
7971
  }
7823
7972
  return null;
7824
7973
  }
7825
- var path8, normalizePath2, dependencyConformanceRule;
7974
+ var path9, normalizePath2, dependencyConformanceRule;
7826
7975
  var init_dependency_conformance = __esm({
7827
7976
  "src/core/rules/dependency-conformance.ts"() {
7828
7977
  "use strict";
7829
- path8 = __toESM(require("path"));
7978
+ path9 = __toESM(require("path"));
7830
7979
  init_source_analysis();
7831
7980
  init_conformance();
7832
7981
  normalizePath2 = normalizeSourcePath;
@@ -8700,17 +8849,17 @@ function readLockRecord() {
8700
8849
  }
8701
8850
  function writeLockRecord(record) {
8702
8851
  const p = lockPath();
8703
- fs6.mkdirSync(path9.dirname(p), { recursive: true });
8852
+ fs6.mkdirSync(path10.dirname(p), { recursive: true });
8704
8853
  const tmp = `${p}.tmp`;
8705
8854
  fs6.writeFileSync(tmp, JSON.stringify(record, null, 2) + "\n");
8706
8855
  fs6.renameSync(tmp, p);
8707
8856
  }
8708
- var fs6, path9;
8857
+ var fs6, path10;
8709
8858
  var init_lockfile = __esm({
8710
8859
  "src/core/lockfile.ts"() {
8711
8860
  "use strict";
8712
8861
  fs6 = __toESM(require("fs"));
8713
- path9 = __toESM(require("path"));
8862
+ path10 = __toESM(require("path"));
8714
8863
  init_fs();
8715
8864
  }
8716
8865
  });
@@ -9242,6 +9391,9 @@ function buildCanvasModel(issues = []) {
9242
9391
  text: s.description,
9243
9392
  kind: s.type,
9244
9393
  ...s.type === "call" && s.targetComponent && s.targetMethod ? { call: { component: s.targetComponent, method: s.targetMethod } } : {},
9394
+ // Register (runtime-callback handoff) carries its target like a
9395
+ // call step — rendered as an edge, labeled by its own kind.
9396
+ ...s.type === "register" && s.targetComponent && s.targetMethod ? { call: { component: s.targetComponent, method: s.targetMethod } } : {},
9245
9397
  ...s.type === "dispatch" && s.targetComponent && s.capability ? { call: { component: s.targetComponent, method: `\u27E8${s.capability}\u27E9` } } : {},
9246
9398
  ...s.condition ? { cond: s.condition } : {},
9247
9399
  ...s.onTrueStep !== void 0 ? { onTrue: s.onTrueStep } : {},
@@ -9440,9 +9592,9 @@ function embedJson(value) {
9440
9592
  }
9441
9593
  function loadCytoscapeLib() {
9442
9594
  const candidates = [
9443
- path10.resolve(__dirname, "..", "templates", "canvas", "cytoscape.min.js"),
9595
+ path11.resolve(__dirname, "..", "templates", "canvas", "cytoscape.min.js"),
9444
9596
  // src/core & dist/cli
9445
- path10.resolve(__dirname, "templates", "canvas", "cytoscape.min.js")
9597
+ path11.resolve(__dirname, "templates", "canvas", "cytoscape.min.js")
9446
9598
  // dist (library entry)
9447
9599
  ];
9448
9600
  for (const p of candidates) {
@@ -9459,12 +9611,12 @@ function renderCanvasHtml(model) {
9459
9611
  function escapeHtml(s) {
9460
9612
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
9461
9613
  }
9462
- var fs7, path10, CANVAS_TEMPLATE;
9614
+ var fs7, path11, CANVAS_TEMPLATE;
9463
9615
  var init_canvas = __esm({
9464
9616
  "src/core/canvas.ts"() {
9465
9617
  "use strict";
9466
9618
  fs7 = __toESM(require("fs"));
9467
- path10 = __toESM(require("path"));
9619
+ path11 = __toESM(require("path"));
9468
9620
  init_specs2();
9469
9621
  init_type_analysis();
9470
9622
  init_diagram_export();
@@ -12848,6 +13000,7 @@ var MODEL = __MODEL_JSON__;
12848
13000
  case 'try': return s.n + '. \\u26E8 try \\u2014 ' + s.text;
12849
13001
  case 'parallel': return s.n + '. \\u2225 ' + s.text;
12850
13002
  case 'jump': return s.n + '. \\u21B7 ' + s.text;
13003
+ case 'register': return s.n + '. \\u27F2 register \\u2014 ' + s.text;
12851
13004
  case 'return': return s.n + '. \\u23CE return' + (s.outcome ? ' \\u2014 ' + s.outcome : '');
12852
13005
  case 'throw': return s.n + '. \\u26A1 throw' + (s.err ? ' ' + s.err : '');
12853
13006
  default: return s.n + '. ' + s.text;
@@ -12871,7 +13024,9 @@ var MODEL = __MODEL_JSON__;
12871
13024
  (graph.joins || []).forEach(function (j2) { joinByHeader[j2.header] = j2; });
12872
13025
  graph.steps.forEach(function (s, i) {
12873
13026
  var id = 'n' + s.n;
12874
- var isCall = (s.kind === 'call' || s.kind === 'dispatch') && !!s.call;
13027
+ // Register steps render like calls (target edge + label) \u2014 the label
13028
+ // itself says "register", keeping the handoff visually distinct.
13029
+ var isCall = (s.kind === 'call' || s.kind === 'dispatch' || s.kind === 'register') && !!s.call;
12875
13030
  // A detached call's target renders as a separate ghost node (below), so
12876
13031
  // the step node itself stays plain and undrillable.
12877
13032
  var isDetached = isCall && !!s.detach;
@@ -13126,7 +13281,7 @@ var MODEL = __MODEL_JSON__;
13126
13281
  comps.push({ id: 'start', name: flowTitle() + '()', subsystem: 'flow', componentType: 'Start', public: false, owns: [] });
13127
13282
  graph.steps.forEach(function (s) {
13128
13283
  var name = flowStepLabel(s) + (s.call && !s.detach ? ' \\u2192 ' + s.call.component + '.' + s.call.method + '()' : '');
13129
- comps.push({ id: 'n' + s.n, name: name, subsystem: 'flow', componentType: (s.kind === 'call' || s.kind === 'dispatch') ? 'Call' : 'Step', public: false, owns: [] });
13284
+ comps.push({ id: 'n' + s.n, name: name, subsystem: 'flow', componentType: (s.kind === 'call' || s.kind === 'dispatch' || s.kind === 'register') ? 'Call' : 'Step', public: false, owns: [] });
13130
13285
  });
13131
13286
  // Virtual flow nodes (join bars, detached-call ghosts) export as plain
13132
13287
  // steps so the editable diagrams keep the fan-out/join and detachment.
@@ -13636,7 +13791,7 @@ var init_repository = __esm({
13636
13791
 
13637
13792
  // src/core/variants.ts
13638
13793
  function globalVariantsDir() {
13639
- return process.env.WAIRON_VARIANTS_DIR ?? path11.join(os3.homedir(), ".wairon", "variants");
13794
+ return process.env.WAIRON_VARIANTS_DIR ?? path12.join(os3.homedir(), ".wairon", "variants");
13640
13795
  }
13641
13796
  function readVariantsDir(dir) {
13642
13797
  let entries;
@@ -13648,7 +13803,7 @@ function readVariantsDir(dir) {
13648
13803
  const out = [];
13649
13804
  for (const e of entries.sort((a, b) => a.name.localeCompare(b.name))) {
13650
13805
  if (!e.isFile() || !/\.ya?ml$/i.test(e.name)) continue;
13651
- const full = path11.join(dir, e.name);
13806
+ const full = path12.join(dir, e.name);
13652
13807
  try {
13653
13808
  const raw = readYamlFile(full);
13654
13809
  if (raw == null) continue;
@@ -13695,19 +13850,19 @@ function loadProjectVariants() {
13695
13850
  try {
13696
13851
  const byId = /* @__PURE__ */ new Map();
13697
13852
  for (const v of readVariantsDir(globalVariantsDir())) byId.set(v.id, v);
13698
- for (const v of readVariantsDir(path11.join(getProjectRoot(), ".wai", "variants"))) byId.set(v.id, v);
13853
+ for (const v of readVariantsDir(path12.join(getProjectRoot(), ".wai", "variants"))) byId.set(v.id, v);
13699
13854
  return [...byId.values()];
13700
13855
  } catch {
13701
13856
  return [];
13702
13857
  }
13703
13858
  }
13704
- var fs8, os3, path11, import_zod8, VariantDefSchema;
13859
+ var fs8, os3, path12, import_zod8, VariantDefSchema;
13705
13860
  var init_variants = __esm({
13706
13861
  "src/core/variants.ts"() {
13707
13862
  "use strict";
13708
13863
  fs8 = __toESM(require("fs"));
13709
13864
  os3 = __toESM(require("os"));
13710
- path11 = __toESM(require("path"));
13865
+ path12 = __toESM(require("path"));
13711
13866
  import_zod8 = require("zod");
13712
13867
  init_yaml();
13713
13868
  init_fs();
@@ -14393,6 +14548,17 @@ function generateSequenceDiagram(componentId, methodName, options) {
14393
14548
  }
14394
14549
  break;
14395
14550
  }
14551
+ case "register": {
14552
+ if (!step.targetComponent || !step.targetMethod) break;
14553
+ const regTarget = componentById.get(step.targetComponent);
14554
+ if (!regTarget) {
14555
+ lines.push(` Note over ${selfId}: ${escapeLabel(`registers callback on unknown "${step.targetComponent}"`)}`);
14556
+ break;
14557
+ }
14558
+ const regTargetId = declare(regTarget);
14559
+ lines.push(` ${selfId}--)${regTargetId}: ${escapeLabel(`register ${step.targetMethod}()`)}`);
14560
+ break;
14561
+ }
14396
14562
  case "call": {
14397
14563
  if (!step.targetComponent || !step.targetMethod) break;
14398
14564
  const target = componentById.get(step.targetComponent);
@@ -14600,16 +14766,16 @@ function relativizeId(id, prefix) {
14600
14766
  return `${"super::".repeat(prefixParts.length - common)}${idParts.slice(common).join("::")}`;
14601
14767
  }
14602
14768
  function isWithin(dir, file) {
14603
- const d = path12.resolve(dir);
14604
- const f = path12.resolve(file);
14605
- return f === d || f.startsWith(d + path12.sep);
14769
+ const d = path13.resolve(dir);
14770
+ const f = path13.resolve(file);
14771
+ return f === d || f.startsWith(d + path13.sep);
14606
14772
  }
14607
14773
  function projectPathEscapesRoot(projectRoot, projectPath, resolvedChildDir) {
14608
- return path12.isAbsolute(projectPath) || !isWithin(projectRoot, resolvedChildDir);
14774
+ return path13.isAbsolute(projectPath) || !isWithin(projectRoot, resolvedChildDir);
14609
14775
  }
14610
14776
  function assertContainedProjectPath(projectRoot, projectPath) {
14611
- const root = path12.resolve(projectRoot);
14612
- const resolved = path12.resolve(root, projectPath);
14777
+ const root = path13.resolve(projectRoot);
14778
+ const resolved = path13.resolve(root, projectPath);
14613
14779
  if (projectPathEscapesRoot(root, projectPath, resolved)) {
14614
14780
  throw new Error(
14615
14781
  `projectPath "${projectPath}" must resolve within the project root "${root}", but resolves to "${resolved}"; absolute paths and ../-escaping paths are rejected so a chained subproject is always contained by its parent.`
@@ -14620,11 +14786,11 @@ function assertContainedProjectPath(projectRoot, projectPath) {
14620
14786
  function findChainingParent(childRoot) {
14621
14787
  let childResolved;
14622
14788
  try {
14623
- childResolved = path12.resolve(childRoot);
14789
+ childResolved = path13.resolve(childRoot);
14624
14790
  } catch {
14625
14791
  return null;
14626
14792
  }
14627
- let dir = path12.dirname(childResolved);
14793
+ let dir = path13.dirname(childResolved);
14628
14794
  for (let hops = 0; hops < 32; hops++) {
14629
14795
  const specsDir = aiPathsAt(dir).specsDir();
14630
14796
  if (pathExists(specsDir)) {
@@ -14639,7 +14805,7 @@ function findChainingParent(childRoot) {
14639
14805
  const projectPath = raw.projectPath;
14640
14806
  if (typeof projectPath === "string" && projectPath.trim() !== "") {
14641
14807
  try {
14642
- if (path12.resolve(dir, projectPath) === childResolved) {
14808
+ if (path13.resolve(dir, projectPath) === childResolved) {
14643
14809
  const id = raw.id;
14644
14810
  return { parentRoot: dir, subsystemId: typeof id === "string" ? id : "?" };
14645
14811
  }
@@ -14649,7 +14815,7 @@ function findChainingParent(childRoot) {
14649
14815
  }
14650
14816
  }
14651
14817
  }
14652
- const up = path12.dirname(dir);
14818
+ const up = path13.dirname(dir);
14653
14819
  if (up === dir) break;
14654
14820
  dir = up;
14655
14821
  }
@@ -14754,18 +14920,18 @@ function findOwner(id, components) {
14754
14920
  }) ?? null;
14755
14921
  }
14756
14922
  function moveComponentFolder(fromDir, toDir) {
14757
- if (path12.normalize(fromDir) === path12.normalize(toDir)) return false;
14923
+ if (path13.normalize(fromDir) === path13.normalize(toDir)) return false;
14758
14924
  if (!fs9.existsSync(fromDir) || fs9.existsSync(toDir)) return false;
14759
- ensureDir(path12.dirname(toDir));
14925
+ ensureDir(path13.dirname(toDir));
14760
14926
  fs9.renameSync(fromDir, toDir);
14761
14927
  return true;
14762
14928
  }
14763
14929
  function cleanEmptyDirs(filePath, specsRoot) {
14764
- let dir = path12.dirname(filePath);
14930
+ let dir = path13.dirname(filePath);
14765
14931
  while (dir !== specsRoot && dir.startsWith(specsRoot)) {
14766
14932
  if (fs9.existsSync(dir) && fs9.readdirSync(dir).length === 0) {
14767
14933
  fs9.rmdirSync(dir);
14768
- dir = path12.dirname(dir);
14934
+ dir = path13.dirname(dir);
14769
14935
  } else {
14770
14936
  break;
14771
14937
  }
@@ -14800,7 +14966,7 @@ function computeSpecTreeSignature(dirs) {
14800
14966
  return parts.join("|");
14801
14967
  }
14802
14968
  function workspaceFor(rootDir) {
14803
- const key = path12.resolve(rootDir);
14969
+ const key = path13.resolve(rootDir);
14804
14970
  let ws = workspaces.get(key);
14805
14971
  if (!ws) {
14806
14972
  ws = new SpecWorkspace(key);
@@ -14939,7 +15105,7 @@ function readLockState() {
14939
15105
  return { state: stateIdEquals(record.stateId, current2) ? "locked" : "stale", record, current: current2 };
14940
15106
  }
14941
15107
  function computeStateIdAt(root) {
14942
- const resolved = path12.resolve(root);
15108
+ const resolved = path13.resolve(root);
14943
15109
  return runWithProjectRoot(resolved, () => {
14944
15110
  workspaceFor(resolved).invalidate();
14945
15111
  const system = loadSystemSpec();
@@ -14983,12 +15149,12 @@ function findLegacySpecFiles() {
14983
15149
  function updateSpec(kind, id, delta, hooks) {
14984
15150
  return current().updateSpec(kind, id, delta, hooks);
14985
15151
  }
14986
- var fs9, path12, SIGNATURE_TTL_MS, SpecWorkspace, workspaces;
15152
+ var fs9, path13, SIGNATURE_TTL_MS, SpecWorkspace, workspaces;
14987
15153
  var init_specs2 = __esm({
14988
15154
  "src/core/specs.ts"() {
14989
15155
  "use strict";
14990
15156
  fs9 = __toESM(require("fs"));
14991
- path12 = __toESM(require("path"));
15157
+ path13 = __toESM(require("path"));
14992
15158
  init_loader();
14993
15159
  init_fs();
14994
15160
  init_statehash();
@@ -15009,7 +15175,7 @@ var init_specs2 = __esm({
15009
15175
  this.rootSubsystems = /* @__PURE__ */ new Set();
15010
15176
  this.scanVisitedSpecDirs = [];
15011
15177
  this.loaderIssues = [];
15012
- this.rootDir = path12.resolve(rootDir);
15178
+ this.rootDir = path13.resolve(rootDir);
15013
15179
  this.paths = aiPathsAt(this.rootDir);
15014
15180
  }
15015
15181
  invalidate() {
@@ -15036,7 +15202,7 @@ var init_specs2 = __esm({
15036
15202
  this.rootSubsystems.clear();
15037
15203
  this.cachedRecursive = recursive;
15038
15204
  this.scanVisitedSpecDirs = [];
15039
- const visited = /* @__PURE__ */ new Set([path12.resolve(this.rootDir)]);
15205
+ const visited = /* @__PURE__ */ new Set([path13.resolve(this.rootDir)]);
15040
15206
  const maxDepth = typeof recursive === "number" ? recursive : recursive ? Infinity : 0;
15041
15207
  this.cachedIndex = this.scanSpecsForProject(this.rootDir, "", visited, maxDepth, 0);
15042
15208
  this.cachedSpecDirs = this.scanVisitedSpecDirs;
@@ -15051,10 +15217,10 @@ var init_specs2 = __esm({
15051
15217
  this.scanVisitedSpecDirs.push(specsDir);
15052
15218
  if (!pathExists(specsDir)) return index;
15053
15219
  const files = listFilesRecursive(specsDir, ".yaml");
15054
- const systemYaml = path12.normalize(projectPaths.specsSystem());
15220
+ const systemYaml = path13.normalize(projectPaths.specsSystem());
15055
15221
  const localSubprojects = [];
15056
15222
  for (const file of files) {
15057
- const normFile = path12.normalize(file);
15223
+ const normFile = path13.normalize(file);
15058
15224
  if (normFile === systemYaml) continue;
15059
15225
  let detectedType = "spec";
15060
15226
  try {
@@ -15064,7 +15230,7 @@ var init_specs2 = __esm({
15064
15230
  severity: "error",
15065
15231
  code: "INVALID_YAML",
15066
15232
  message: `Spec file "${file}" is not a valid YAML object or is empty.`,
15067
- specId: path12.basename(file, ".yaml")
15233
+ specId: path13.basename(file, ".yaml")
15068
15234
  });
15069
15235
  continue;
15070
15236
  }
@@ -15096,8 +15262,8 @@ var init_specs2 = __esm({
15096
15262
  detectedType = "implementation";
15097
15263
  const parsed = ImplementationSpecSchema.parse(raw);
15098
15264
  if (parsed.sourcePath) {
15099
- const absSourcePath = path12.resolve(projectDir, parsed.sourcePath);
15100
- parsed.sourcePath = path12.relative(projectDir, absSourcePath).replace(/\\/g, "/");
15265
+ const absSourcePath = path13.resolve(projectDir, parsed.sourcePath);
15266
+ parsed.sourcePath = path13.relative(projectDir, absSourcePath).replace(/\\/g, "/");
15101
15267
  }
15102
15268
  index.implementations.push(parsed);
15103
15269
  index.paths.implementation[parsed.id] = file;
@@ -15119,11 +15285,11 @@ var init_specs2 = __esm({
15119
15285
  severity: "error",
15120
15286
  code: "UNKNOWN_SPEC_TYPE",
15121
15287
  message: `Spec file "${file}" does not match any recognized L1-L4 schema structure.`,
15122
- specId: path12.basename(file, ".yaml")
15288
+ specId: path13.basename(file, ".yaml")
15123
15289
  });
15124
15290
  }
15125
15291
  } catch (e) {
15126
- const filename = path12.basename(file, ".yaml");
15292
+ const filename = path13.basename(file, ".yaml");
15127
15293
  this.loaderIssues.push({
15128
15294
  severity: "error",
15129
15295
  code: "SCHEMA_VALIDATION_ERROR",
@@ -15221,7 +15387,7 @@ var init_specs2 = __esm({
15221
15387
  }
15222
15388
  if (currentDepth < maxDepth) {
15223
15389
  for (const subproj of localSubprojects) {
15224
- const childDir = path12.resolve(projectDir, subproj.projectPath);
15390
+ const childDir = path13.resolve(projectDir, subproj.projectPath);
15225
15391
  if (projectPathEscapesRoot(this.rootDir, subproj.projectPath, childDir)) {
15226
15392
  this.loaderIssues.push({
15227
15393
  severity: "error",
@@ -15283,7 +15449,7 @@ var init_specs2 = __esm({
15283
15449
  const index = this.scanAll();
15284
15450
  const sub = index.subsystems.find((s) => s.id === currentPrefix);
15285
15451
  if (sub && sub.projectPath) {
15286
- const nextDir = path12.resolve(currentDir, sub.projectPath);
15452
+ const nextDir = path13.resolve(currentDir, sub.projectPath);
15287
15453
  if (projectPathEscapesRoot(this.rootDir, sub.projectPath, nextDir)) {
15288
15454
  this.loaderIssues.push({
15289
15455
  severity: "error",
@@ -15335,9 +15501,9 @@ var init_specs2 = __esm({
15335
15501
  return index.paths.subsystem[matches2[0]];
15336
15502
  }
15337
15503
  if (pathExists(this.paths.specsSubsystemsDir()) && listFiles(this.paths.specsSubsystemsDir(), ".yaml").length > 0) {
15338
- return path12.join(this.paths.specsSubsystemsDir(), `${id}.yaml`);
15504
+ return path13.join(this.paths.specsSubsystemsDir(), `${id}.yaml`);
15339
15505
  }
15340
- return path12.join(this.paths.specsDir(), id, ".index.yaml");
15506
+ return path13.join(this.paths.specsDir(), id, ".index.yaml");
15341
15507
  }
15342
15508
  getComponentPath(id, subsystemId) {
15343
15509
  const index = this.scanAll();
@@ -15357,21 +15523,21 @@ var init_specs2 = __esm({
15357
15523
  if (owner) {
15358
15524
  const ownerPath = index.paths.component[owner.id];
15359
15525
  if (ownerPath && ownerPath.endsWith(".index.yaml")) {
15360
- return path12.join(path12.dirname(ownerPath), id, ".index.yaml");
15526
+ return path13.join(path13.dirname(ownerPath), id, ".index.yaml");
15361
15527
  }
15362
15528
  }
15363
15529
  if (subsystemId) {
15364
15530
  const subPath = this.getSubsystemPath(subsystemId);
15365
- const subDir = path12.dirname(subPath);
15531
+ const subDir = path13.dirname(subPath);
15366
15532
  if (subPath.endsWith(".index.yaml")) {
15367
- return path12.join(subDir, id, ".index.yaml");
15533
+ return path13.join(subDir, id, ".index.yaml");
15368
15534
  }
15369
15535
  }
15370
15536
  if (pathExists(this.paths.specsComponentsDir()) && listFiles(this.paths.specsComponentsDir(), ".yaml").length > 0) {
15371
- return path12.join(this.paths.specsComponentsDir(), `${id}.yaml`);
15537
+ return path13.join(this.paths.specsComponentsDir(), `${id}.yaml`);
15372
15538
  }
15373
15539
  const targetSubsystem = subsystemId || "default";
15374
- return path12.join(this.paths.specsDir(), targetSubsystem, id, ".index.yaml");
15540
+ return path13.join(this.paths.specsDir(), targetSubsystem, id, ".index.yaml");
15375
15541
  }
15376
15542
  getInterfacePath(id, componentId) {
15377
15543
  const index = this.scanAll();
@@ -15397,16 +15563,16 @@ var init_specs2 = __esm({
15397
15563
  }
15398
15564
  if (componentId) {
15399
15565
  const compPath = this.getComponentPath(componentId);
15400
- const compDir = path12.dirname(compPath);
15566
+ const compDir = path13.dirname(compPath);
15401
15567
  if (compPath.endsWith(".index.yaml")) {
15402
- return path12.join(compDir, ".interface.yaml");
15568
+ return path13.join(compDir, ".interface.yaml");
15403
15569
  }
15404
15570
  }
15405
15571
  if (pathExists(this.paths.specsInterfacesDir()) && listFiles(this.paths.specsInterfacesDir(), ".yaml").length > 0) {
15406
- return path12.join(this.paths.specsInterfacesDir(), `${id}.yaml`);
15572
+ return path13.join(this.paths.specsInterfacesDir(), `${id}.yaml`);
15407
15573
  }
15408
15574
  const targetComponent = componentId || "default";
15409
- return path12.join(this.paths.specsDir(), "default", targetComponent, ".interface.yaml");
15575
+ return path13.join(this.paths.specsDir(), "default", targetComponent, ".interface.yaml");
15410
15576
  }
15411
15577
  getImplementationPath(id, contractId) {
15412
15578
  const index = this.scanAll();
@@ -15432,16 +15598,16 @@ var init_specs2 = __esm({
15432
15598
  }
15433
15599
  if (contractId) {
15434
15600
  const intfPath = this.getInterfacePath(contractId);
15435
- const intfDir = path12.dirname(intfPath);
15601
+ const intfDir = path13.dirname(intfPath);
15436
15602
  if (intfPath.endsWith(".interface.yaml")) {
15437
- return path12.join(intfDir, ".implementation.yaml");
15603
+ return path13.join(intfDir, ".implementation.yaml");
15438
15604
  }
15439
15605
  }
15440
15606
  if (pathExists(this.paths.specsImplementationsDir()) && listFiles(this.paths.specsImplementationsDir(), ".yaml").length > 0) {
15441
- return path12.join(this.paths.specsImplementationsDir(), `${id}.yaml`);
15607
+ return path13.join(this.paths.specsImplementationsDir(), `${id}.yaml`);
15442
15608
  }
15443
15609
  const targetContract = contractId ? contractId.replace(/^i/, "") : "default";
15444
- return path12.join(this.paths.specsDir(), "default", targetContract, ".implementation.yaml");
15610
+ return path13.join(this.paths.specsDir(), "default", targetContract, ".implementation.yaml");
15445
15611
  }
15446
15612
  getTypePath(id, subsystemId, group) {
15447
15613
  const index = this.scanAll();
@@ -15472,7 +15638,7 @@ var init_specs2 = __esm({
15472
15638
  const groupPath = index.paths.group[targetGroup] || index.paths.group[plainGroup];
15473
15639
  if (groupPath) {
15474
15640
  const localId2 = id.split("::").pop();
15475
- return path12.join(path12.dirname(groupPath), `${localId2}.yaml`);
15641
+ return path13.join(path13.dirname(groupPath), `${localId2}.yaml`);
15476
15642
  }
15477
15643
  }
15478
15644
  let localId = id;
@@ -15485,12 +15651,12 @@ var init_specs2 = __esm({
15485
15651
  }
15486
15652
  if (subsystemId) {
15487
15653
  const subPath = this.getSubsystemPath(subsystemId);
15488
- const subDir = path12.dirname(subPath);
15654
+ const subDir = path13.dirname(subPath);
15489
15655
  if (subPath.endsWith(".index.yaml")) {
15490
- return path12.join(subDir, "types", `${localId}.yaml`);
15656
+ return path13.join(subDir, "types", `${localId}.yaml`);
15491
15657
  }
15492
15658
  }
15493
- return path12.join(this.paths.specsTypesDir(), `${localId}.yaml`);
15659
+ return path13.join(this.paths.specsTypesDir(), `${localId}.yaml`);
15494
15660
  }
15495
15661
  getGroupPath(id, subsystemId) {
15496
15662
  const index = this.scanAll();
@@ -15524,12 +15690,12 @@ var init_specs2 = __esm({
15524
15690
  }
15525
15691
  if (subsystemId) {
15526
15692
  const subPath = this.getSubsystemPath(subsystemId);
15527
- const subDir = path12.dirname(subPath);
15693
+ const subDir = path13.dirname(subPath);
15528
15694
  if (subPath.endsWith(".index.yaml")) {
15529
- return path12.join(subDir, "types", localId, ".index.yaml");
15695
+ return path13.join(subDir, "types", localId, ".index.yaml");
15530
15696
  }
15531
15697
  }
15532
- return path12.join(this.paths.specsTypesDir(), localId, ".index.yaml");
15698
+ return path13.join(this.paths.specsTypesDir(), localId, ".index.yaml");
15533
15699
  }
15534
15700
  // -------------------------------------------------------------------------
15535
15701
  // Level 0: System
@@ -15552,7 +15718,7 @@ var init_specs2 = __esm({
15552
15718
  }
15553
15719
  saveSystemSpec(spec) {
15554
15720
  const p = this.paths.specsSystem();
15555
- ensureDir(path12.dirname(p));
15721
+ ensureDir(path13.dirname(p));
15556
15722
  writeYamlFile(p, parseOrThrow(SystemSpecSchema, spec, "system", spec.name));
15557
15723
  invalidateSpecCache();
15558
15724
  }
@@ -15670,7 +15836,7 @@ var init_specs2 = __esm({
15670
15836
  }
15671
15837
  saveSubsystemSpec(spec) {
15672
15838
  const p = this.getSubsystemPath(spec.id);
15673
- ensureDir(path12.dirname(p));
15839
+ ensureDir(path13.dirname(p));
15674
15840
  const { prefix } = splitNamespace(spec.id);
15675
15841
  if (!prefix && spec.projectPath && spec.projectPath.trim() !== "") {
15676
15842
  assertContainedProjectPath(this.rootDir, spec.projectPath);
@@ -15703,7 +15869,7 @@ var init_specs2 = __esm({
15703
15869
  const p = this.getSubsystemPath(id);
15704
15870
  if (!fs9.existsSync(p)) return false;
15705
15871
  fs9.unlinkSync(p);
15706
- cleanEmptyDirs(p, path12.resolve(this.paths.specsDir()));
15872
+ cleanEmptyDirs(p, path13.resolve(this.paths.specsDir()));
15707
15873
  invalidateSpecCache();
15708
15874
  return true;
15709
15875
  }
@@ -15736,7 +15902,7 @@ var init_specs2 = __esm({
15736
15902
  saveComponentSpec(spec, opts) {
15737
15903
  const notices = [];
15738
15904
  const p = this.getComponentPath(spec.id, spec.subsystem);
15739
- ensureDir(path12.dirname(p));
15905
+ ensureDir(path13.dirname(p));
15740
15906
  const specToWrite = this.prepareComponentForWrite(spec);
15741
15907
  const existing = this.loadComponentSpec(spec.id);
15742
15908
  if (existing) {
@@ -15753,7 +15919,7 @@ var init_specs2 = __esm({
15753
15919
  const subsystemChanged = existing && existing.subsystem !== spec.subsystem && splitNamespace(existing.subsystem).localId !== splitNamespace(spec.subsystem).localId;
15754
15920
  if (subsystemChanged && !p.endsWith(".index.yaml")) {
15755
15921
  notices.push(
15756
- `component "${spec.id}" already exists at ${path12.relative(this.rootDir, p)} \u2014 the flat layout re-saves in place and never relocates the file. The subsystem field is now "${spec.subsystem}" (was "${existing.subsystem}").`
15922
+ `component "${spec.id}" already exists at ${path13.relative(this.rootDir, p)} \u2014 the flat layout re-saves in place and never relocates the file. The subsystem field is now "${spec.subsystem}" (was "${existing.subsystem}").`
15757
15923
  );
15758
15924
  }
15759
15925
  specToWrite.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -15766,7 +15932,7 @@ var init_specs2 = __esm({
15766
15932
  const p = this.getComponentPath(id);
15767
15933
  if (!fs9.existsSync(p)) return false;
15768
15934
  fs9.unlinkSync(p);
15769
- cleanEmptyDirs(p, path12.resolve(this.paths.specsDir()));
15935
+ cleanEmptyDirs(p, path13.resolve(this.paths.specsDir()));
15770
15936
  invalidateSpecCache();
15771
15937
  return true;
15772
15938
  }
@@ -15779,12 +15945,12 @@ var init_specs2 = __esm({
15779
15945
  if (owner) {
15780
15946
  const ownerPath = index.paths.component[owner.id];
15781
15947
  if (ownerPath && ownerPath.endsWith(".index.yaml")) {
15782
- const ownerSubDir = path12.dirname(this.getSubsystemPath(owner.subsystem));
15783
- return path12.join(ownerSubDir, owner.id, comp.id);
15948
+ const ownerSubDir = path13.dirname(this.getSubsystemPath(owner.subsystem));
15949
+ return path13.join(ownerSubDir, owner.id, comp.id);
15784
15950
  }
15785
15951
  }
15786
- const subDir = path12.dirname(this.getSubsystemPath(comp.subsystem));
15787
- return path12.join(subDir, comp.id);
15952
+ const subDir = path13.dirname(this.getSubsystemPath(comp.subsystem));
15953
+ return path13.join(subDir, comp.id);
15788
15954
  }
15789
15955
  /**
15790
15956
  * Move component folders so the physical tree mirrors ownership: each owned
@@ -15800,7 +15966,7 @@ var init_specs2 = __esm({
15800
15966
  if (!currentPath) continue;
15801
15967
  const desiredDir = this.desiredComponentDir(comp, index);
15802
15968
  if (!desiredDir) continue;
15803
- if (moveComponentFolder(path12.dirname(currentPath), desiredDir)) moved.push(comp.id);
15969
+ if (moveComponentFolder(path13.dirname(currentPath), desiredDir)) moved.push(comp.id);
15804
15970
  }
15805
15971
  if (moved.length) invalidateSpecCache();
15806
15972
  return moved;
@@ -15834,12 +16000,12 @@ var init_specs2 = __esm({
15834
16000
  saveInterfaceSpec(spec, opts) {
15835
16001
  const notices = [];
15836
16002
  const p = this.getInterfacePath(spec.id, spec.component);
15837
- ensureDir(path12.dirname(p));
16003
+ ensureDir(path13.dirname(p));
15838
16004
  const specToWrite = this.prepareInterfaceForWrite(spec);
15839
16005
  const existing = this.loadInterfaceSpec(spec.id);
15840
16006
  if (existing && existing.component !== spec.component && splitNamespace(existing.component).localId !== splitNamespace(spec.component).localId) {
15841
16007
  notices.push(
15842
- `interface "${spec.id}" already exists at ${path12.relative(this.rootDir, p)} \u2014 re-saving updates the component binding field in place (now "${spec.component}", was "${existing.component}") and never moves the file.`
16008
+ `interface "${spec.id}" already exists at ${path13.relative(this.rootDir, p)} \u2014 re-saving updates the component binding field in place (now "${spec.component}", was "${existing.component}") and never moves the file.`
15843
16009
  );
15844
16010
  }
15845
16011
  if (existing) {
@@ -15864,7 +16030,7 @@ var init_specs2 = __esm({
15864
16030
  const p = this.getInterfacePath(id);
15865
16031
  if (!fs9.existsSync(p)) return false;
15866
16032
  fs9.unlinkSync(p);
15867
- cleanEmptyDirs(p, path12.resolve(this.paths.specsDir()));
16033
+ cleanEmptyDirs(p, path13.resolve(this.paths.specsDir()));
15868
16034
  invalidateSpecCache();
15869
16035
  return true;
15870
16036
  }
@@ -15897,12 +16063,12 @@ var init_specs2 = __esm({
15897
16063
  saveImplementationSpec(spec, opts) {
15898
16064
  const notices = [];
15899
16065
  const p = this.getImplementationPath(spec.id, spec.contract);
15900
- ensureDir(path12.dirname(p));
16066
+ ensureDir(path13.dirname(p));
15901
16067
  const specToWrite = this.prepareImplementationForWrite(spec);
15902
16068
  const existing = this.loadImplementationSpec(spec.id);
15903
16069
  if (existing && existing.contract !== spec.contract && splitNamespace(existing.contract).localId !== splitNamespace(spec.contract).localId) {
15904
16070
  notices.push(
15905
- `implementation "${spec.id}" already exists at ${path12.relative(this.rootDir, p)} \u2014 re-saving updates the contract binding field in place (now "${spec.contract}", was "${existing.contract}") and never moves the file.`
16071
+ `implementation "${spec.id}" already exists at ${path13.relative(this.rootDir, p)} \u2014 re-saving updates the contract binding field in place (now "${spec.contract}", was "${existing.contract}") and never moves the file.`
15906
16072
  );
15907
16073
  }
15908
16074
  if (existing) {
@@ -15920,7 +16086,7 @@ var init_specs2 = __esm({
15920
16086
  const p = this.getImplementationPath(id);
15921
16087
  if (!fs9.existsSync(p)) return false;
15922
16088
  fs9.unlinkSync(p);
15923
- cleanEmptyDirs(p, path12.resolve(this.paths.specsDir()));
16089
+ cleanEmptyDirs(p, path13.resolve(this.paths.specsDir()));
15924
16090
  invalidateSpecCache();
15925
16091
  return true;
15926
16092
  }
@@ -15945,11 +16111,11 @@ var init_specs2 = __esm({
15945
16111
  const existing = this.loadTypeSpec(spec.id);
15946
16112
  const group = spec.group || (existing ? existing.group : void 0);
15947
16113
  const p = this.getTypePath(spec.id, spec.subsystem, group);
15948
- ensureDir(path12.dirname(p));
16114
+ ensureDir(path13.dirname(p));
15949
16115
  const subsystemChanged = existing && (existing.subsystem ?? "") !== (spec.subsystem ?? "") && splitNamespace(existing.subsystem ?? "").localId !== splitNamespace(spec.subsystem ?? "").localId;
15950
16116
  if (subsystemChanged) {
15951
16117
  notices.push(
15952
- `type "${spec.id}" already exists at ${path12.relative(this.rootDir, p)} \u2014 re-saving updates fields in place and never relocates the file. The subsystem field is now "${spec.subsystem ?? "(none)"}" (was "${existing.subsystem ?? "(none)"}").`
16118
+ `type "${spec.id}" already exists at ${path13.relative(this.rootDir, p)} \u2014 re-saving updates fields in place and never relocates the file. The subsystem field is now "${spec.subsystem ?? "(none)"}" (was "${existing.subsystem ?? "(none)"}").`
15953
16119
  );
15954
16120
  }
15955
16121
  if (spec.subsystem && (!existing || subsystemChanged) && !this.getSubsystemPath(spec.subsystem).endsWith(".index.yaml")) {
@@ -15974,7 +16140,7 @@ var init_specs2 = __esm({
15974
16140
  const p = this.getTypePath(id, spec?.subsystem, spec?.group);
15975
16141
  if (!fs9.existsSync(p)) return false;
15976
16142
  fs9.unlinkSync(p);
15977
- cleanEmptyDirs(p, path12.resolve(this.paths.specsDir()));
16143
+ cleanEmptyDirs(p, path13.resolve(this.paths.specsDir()));
15978
16144
  invalidateSpecCache();
15979
16145
  return true;
15980
16146
  }
@@ -15989,7 +16155,7 @@ var init_specs2 = __esm({
15989
16155
  }
15990
16156
  saveGroupSpec(spec) {
15991
16157
  const p = this.getGroupPath(spec.id);
15992
- ensureDir(path12.dirname(p));
16158
+ ensureDir(path13.dirname(p));
15993
16159
  const specToWrite = this.prepareGroupForWrite(spec);
15994
16160
  const existing = this.loadGroupSpec(spec.id);
15995
16161
  if (existing) {
@@ -16003,7 +16169,7 @@ var init_specs2 = __esm({
16003
16169
  const p = this.getGroupPath(id);
16004
16170
  if (!fs9.existsSync(p)) return false;
16005
16171
  fs9.unlinkSync(p);
16006
- cleanEmptyDirs(p, path12.resolve(this.paths.specsDir()));
16172
+ cleanEmptyDirs(p, path13.resolve(this.paths.specsDir()));
16007
16173
  invalidateSpecCache();
16008
16174
  return true;
16009
16175
  }
@@ -16088,11 +16254,11 @@ var init_specs2 = __esm({
16088
16254
  const files = /* @__PURE__ */ new Set();
16089
16255
  const sysPath = this.paths.specsSystem();
16090
16256
  if (pathExists(sysPath)) {
16091
- files.add(path12.resolve(sysPath));
16257
+ files.add(path13.resolve(sysPath));
16092
16258
  }
16093
16259
  for (const group of Object.values(index.paths)) {
16094
16260
  for (const file of Object.values(group)) {
16095
- files.add(path12.resolve(file));
16261
+ files.add(path13.resolve(file));
16096
16262
  }
16097
16263
  }
16098
16264
  for (const file of files) {
@@ -16111,20 +16277,20 @@ var init_specs2 = __esm({
16111
16277
  const files = listFilesRecursive(specsDir, ".yaml");
16112
16278
  const legacy = [];
16113
16279
  for (const f of files) {
16114
- const base = path12.basename(f);
16115
- const dir = path12.dirname(f);
16280
+ const base = path13.basename(f);
16281
+ const dir = path13.dirname(f);
16116
16282
  if (base === "system.yaml") {
16117
- legacy.push({ path: f, expected: path12.join(dir, ".index.yaml") });
16283
+ legacy.push({ path: f, expected: path13.join(dir, ".index.yaml") });
16118
16284
  } else if (base === "subsystem.yaml") {
16119
- legacy.push({ path: f, expected: path12.join(dir, ".index.yaml") });
16285
+ legacy.push({ path: f, expected: path13.join(dir, ".index.yaml") });
16120
16286
  } else if (base === "component.yaml") {
16121
- legacy.push({ path: f, expected: path12.join(dir, ".index.yaml") });
16287
+ legacy.push({ path: f, expected: path13.join(dir, ".index.yaml") });
16122
16288
  } else if (base === "group.yaml") {
16123
- legacy.push({ path: f, expected: path12.join(dir, ".index.yaml") });
16289
+ legacy.push({ path: f, expected: path13.join(dir, ".index.yaml") });
16124
16290
  } else if (base === "interface.yaml") {
16125
- legacy.push({ path: f, expected: path12.join(dir, ".interface.yaml") });
16291
+ legacy.push({ path: f, expected: path13.join(dir, ".interface.yaml") });
16126
16292
  } else if (base === "implementation.yaml") {
16127
- legacy.push({ path: f, expected: path12.join(dir, ".implementation.yaml") });
16293
+ legacy.push({ path: f, expected: path13.join(dir, ".implementation.yaml") });
16128
16294
  }
16129
16295
  }
16130
16296
  return legacy;
@@ -16523,11 +16689,13 @@ var init_specs2 = __esm({
16523
16689
  // src/core/agent_resolver.ts
16524
16690
  var agent_resolver_exports = {};
16525
16691
  __export(agent_resolver_exports, {
16692
+ UnknownAgentError: () => UnknownAgentError,
16693
+ composeAgentBrief: () => composeAgentBrief,
16526
16694
  resolveAgentTopology: () => resolveAgentTopology
16527
16695
  });
16528
16696
  function listFilesRecursiveSafe(dirPath, ext) {
16529
16697
  if (!fs10.existsSync(dirPath)) return [];
16530
- const nameLower = path13.basename(dirPath).toLowerCase();
16698
+ const nameLower = path14.basename(dirPath).toLowerCase();
16531
16699
  const IGNORED_DIRS = /* @__PURE__ */ new Set([
16532
16700
  "node_modules",
16533
16701
  "target",
@@ -16545,7 +16713,7 @@ function listFilesRecursiveSafe(dirPath, ext) {
16545
16713
  const entries = fs10.readdirSync(dirPath, { withFileTypes: true });
16546
16714
  const files = [];
16547
16715
  for (const entry of entries) {
16548
- const fullPath = path13.join(dirPath, entry.name);
16716
+ const fullPath = path14.join(dirPath, entry.name);
16549
16717
  if (entry.isDirectory()) {
16550
16718
  files.push(...listFilesRecursiveSafe(fullPath, ext));
16551
16719
  } else if (entry.isFile() && entry.name.endsWith(ext)) {
@@ -16558,8 +16726,8 @@ function getProjectFiles(projectDir) {
16558
16726
  let files = projectFilesCache.get(projectDir);
16559
16727
  if (!files) {
16560
16728
  files = [];
16561
- const srcDir = path13.join(projectDir, "src");
16562
- const legacySrcDir = path13.join(projectDir, "legacy-src");
16729
+ const srcDir = path14.join(projectDir, "src");
16730
+ const legacySrcDir = path14.join(projectDir, "legacy-src");
16563
16731
  let searchDir = projectDir;
16564
16732
  if (pathExists(srcDir)) {
16565
16733
  searchDir = srcDir;
@@ -16574,7 +16742,7 @@ function getProjectFiles(projectDir) {
16574
16742
  files.push(...listFilesRecursiveSafe(searchDir, ext));
16575
16743
  }
16576
16744
  const rootDir = getProjectRoot();
16577
- files = files.map((f) => path13.relative(rootDir, f).replace(/\\/g, "/"));
16745
+ files = files.map((f) => path14.relative(rootDir, f).replace(/\\/g, "/"));
16578
16746
  projectFilesCache.set(projectDir, files);
16579
16747
  }
16580
16748
  return files;
@@ -16599,8 +16767,8 @@ function inferSourcePathForComponent(comp, subsystems) {
16599
16767
  let bestFile = null;
16600
16768
  let bestScore = -1;
16601
16769
  for (const f of files) {
16602
- const ext = path13.extname(f);
16603
- const base = path13.basename(f, ext).toLowerCase();
16770
+ const ext = path14.extname(f);
16771
+ const base = path14.basename(f, ext).toLowerCase();
16604
16772
  if (candidates.has(base)) {
16605
16773
  let score = 0;
16606
16774
  const normalizedPath = f.toLowerCase();
@@ -16696,7 +16864,7 @@ function resolveAgentTopology() {
16696
16864
  });
16697
16865
  for (const sub of subsystems) {
16698
16866
  if (sub.projectPath) {
16699
- const mountSpecPath = path13.relative(getProjectRoot(), getSubsystemPath(sub.id)).replace(/\\/g, "/");
16867
+ const mountSpecPath = path14.relative(getProjectRoot(), getSubsystemPath(sub.id)).replace(/\\/g, "/");
16700
16868
  agents.push({
16701
16869
  id: `${sub.id}-owner`,
16702
16870
  name: `${sub.name} (chained subproject)`,
@@ -16718,9 +16886,9 @@ function resolveAgentTopology() {
16718
16886
  }
16719
16887
  const subComponents = components.filter((c) => c.subsystem === sub.id);
16720
16888
  const ownedPaths = [];
16721
- ownedPaths.push(path13.relative(getProjectRoot(), getSubsystemPath(sub.id)).replace(/\\/g, "/"));
16889
+ ownedPaths.push(path14.relative(getProjectRoot(), getSubsystemPath(sub.id)).replace(/\\/g, "/"));
16722
16890
  for (const c of subComponents) {
16723
- ownedPaths.push(path13.relative(getProjectRoot(), getComponentPath(c.id, sub.id)).replace(/\\/g, "/"));
16891
+ ownedPaths.push(path14.relative(getProjectRoot(), getComponentPath(c.id, sub.id)).replace(/\\/g, "/"));
16724
16892
  }
16725
16893
  if (!config.rules.generateComponentImplementers) {
16726
16894
  for (const comp of subComponents) {
@@ -16793,10 +16961,10 @@ function resolveAgentTopology() {
16793
16961
  }
16794
16962
  const dependencies = comp.dependsOn.map((depId) => `${depId}-implementer`);
16795
16963
  const readPaths = [
16796
- path13.relative(getProjectRoot(), AI_PATHS.specsSystem()).replace(/\\/g, "/"),
16797
- path13.relative(getProjectRoot(), getComponentPath(comp.id, comp.subsystem)).replace(/\\/g, "/"),
16798
- ...compInterfaces.map((i) => path13.relative(getProjectRoot(), getInterfacePath(i.id, comp.id)).replace(/\\/g, "/")),
16799
- ...compImpls.map((impl) => path13.relative(getProjectRoot(), getImplementationPath(impl.id, impl.contract)).replace(/\\/g, "/"))
16964
+ path14.relative(getProjectRoot(), AI_PATHS.specsSystem()).replace(/\\/g, "/"),
16965
+ path14.relative(getProjectRoot(), getComponentPath(comp.id, comp.subsystem)).replace(/\\/g, "/"),
16966
+ ...compInterfaces.map((i) => path14.relative(getProjectRoot(), getInterfacePath(i.id, comp.id)).replace(/\\/g, "/")),
16967
+ ...compImpls.map((impl) => path14.relative(getProjectRoot(), getImplementationPath(impl.id, impl.contract)).replace(/\\/g, "/"))
16800
16968
  ];
16801
16969
  agents.push({
16802
16970
  id: `${comp.id}-implementer`,
@@ -16840,17 +17008,64 @@ function resolveAgentTopology() {
16840
17008
  }
16841
17009
  return agents;
16842
17010
  }
16843
- var path13, fs10, projectFilesCache;
17011
+ function composeAgentBrief(agentId) {
17012
+ const records = resolveAgentTopology();
17013
+ const record = records.find((r) => r.id === agentId);
17014
+ if (!record) {
17015
+ throw new UnknownAgentError(agentId, records.map((r) => r.id));
17016
+ }
17017
+ const template = loadTemplate(record.template, loadProjectConfig().globalTemplatesDir);
17018
+ let instructions = renderTemplateInstructions(template, {
17019
+ agentId: record.id,
17020
+ agentName: record.name,
17021
+ agentDescription: record.description,
17022
+ ownedPaths: record.ownedPaths.join("\n"),
17023
+ tags: record.tags.join(", "),
17024
+ renderContext: "root",
17025
+ contextNote: "",
17026
+ domainPath: ".",
17027
+ domainName: "",
17028
+ variantGuidance: record.variantGuidance ?? ""
17029
+ });
17030
+ const guidance = loadAgentOverride(agentId);
17031
+ if (guidance !== null) {
17032
+ instructions = `${instructions.trimEnd()}
17033
+
17034
+ ## Project guidance
17035
+
17036
+ ${guidance.trim()}
17037
+ `;
17038
+ }
17039
+ return {
17040
+ agentId: record.id,
17041
+ name: record.name,
17042
+ template: record.template,
17043
+ domainRoot: record.domainRoot,
17044
+ ownedPaths: record.ownedPaths,
17045
+ readPaths: record.readPaths,
17046
+ instructions,
17047
+ variantGuidance: record.variantGuidance || void 0
17048
+ };
17049
+ }
17050
+ var path14, fs10, projectFilesCache, UnknownAgentError;
16844
17051
  var init_agent_resolver = __esm({
16845
17052
  "src/core/agent_resolver.ts"() {
16846
17053
  "use strict";
16847
- path13 = __toESM(require("path"));
17054
+ path14 = __toESM(require("path"));
16848
17055
  fs10 = __toESM(require("fs"));
16849
17056
  init_loader();
16850
17057
  init_fs();
17058
+ init_errors();
17059
+ init_templates();
16851
17060
  init_specs2();
16852
17061
  init_variants();
16853
17062
  projectFilesCache = /* @__PURE__ */ new Map();
17063
+ UnknownAgentError = class extends WaironError {
17064
+ constructor(agentId, knownIds) {
17065
+ super(`Unknown agent id: "${agentId}". Known agent ids: ${knownIds.join(", ")}`);
17066
+ this.name = "UnknownAgentError";
17067
+ }
17068
+ };
16854
17069
  }
16855
17070
  });
16856
17071
 
@@ -16868,12 +17083,12 @@ __export(loader_exports, {
16868
17083
  saveTopologyConfig: () => saveTopologyConfig
16869
17084
  });
16870
17085
  function aiPathsAt(rootDir) {
16871
- const resolvedRoot = path14.resolve(rootDir);
17086
+ const resolvedRoot = path15.resolve(rootDir);
16872
17087
  const aiDirAt = (...segments) => {
16873
- const waiPath = path14.join(resolvedRoot, ".wai");
16874
- const waironPath = path14.join(resolvedRoot, ".wairon");
17088
+ const waiPath = path15.join(resolvedRoot, ".wai");
17089
+ const waironPath = path15.join(resolvedRoot, ".wairon");
16875
17090
  const base = !fs11.existsSync(waiPath) && fs11.existsSync(waironPath) ? waironPath : waiPath;
16876
- return path14.join(base, ...segments);
17091
+ return path15.join(base, ...segments);
16877
17092
  };
16878
17093
  const specsDir = () => {
16879
17094
  try {
@@ -16881,7 +17096,7 @@ function aiPathsAt(rootDir) {
16881
17096
  if (pathExists(projConfig)) {
16882
17097
  const raw = readYamlFile(projConfig);
16883
17098
  if (raw && raw.paths && raw.paths.specsDir) {
16884
- return path14.resolve(resolvedRoot, raw.paths.specsDir);
17099
+ return path15.resolve(resolvedRoot, raw.paths.specsDir);
16885
17100
  }
16886
17101
  }
16887
17102
  } catch {
@@ -16902,12 +17117,12 @@ function aiPathsAt(rootDir) {
16902
17117
  contextDomainsMd: () => aiDirAt("context", "domains.md"),
16903
17118
  contextWaironGuideMd: () => aiDirAt("context", "wairon-guide.md"),
16904
17119
  specsDir,
16905
- specsSystem: () => path14.join(specsDir(), ".index.yaml"),
16906
- specsSubsystemsDir: () => path14.join(specsDir(), "subsystems"),
16907
- specsComponentsDir: () => path14.join(specsDir(), "components"),
16908
- specsInterfacesDir: () => path14.join(specsDir(), "interfaces"),
16909
- specsImplementationsDir: () => path14.join(specsDir(), "implementations"),
16910
- specsTypesDir: () => path14.join(specsDir(), "types")
17120
+ specsSystem: () => path15.join(specsDir(), ".index.yaml"),
17121
+ specsSubsystemsDir: () => path15.join(specsDir(), "subsystems"),
17122
+ specsComponentsDir: () => path15.join(specsDir(), "components"),
17123
+ specsInterfacesDir: () => path15.join(specsDir(), "interfaces"),
17124
+ specsImplementationsDir: () => path15.join(specsDir(), "implementations"),
17125
+ specsTypesDir: () => path15.join(specsDir(), "types")
16911
17126
  };
16912
17127
  }
16913
17128
  function isProjectInitialized() {
@@ -16950,12 +17165,12 @@ function loadTopologyConfig() {
16950
17165
  function saveTopologyConfig(config) {
16951
17166
  writeYamlFile(AI_PATHS.topologyConfig(), config);
16952
17167
  }
16953
- var fs11, path14, AI_PATHS;
17168
+ var fs11, path15, AI_PATHS;
16954
17169
  var init_loader = __esm({
16955
17170
  "src/config/loader.ts"() {
16956
17171
  "use strict";
16957
17172
  fs11 = __toESM(require("fs"));
16958
- path14 = __toESM(require("path"));
17173
+ path15 = __toESM(require("path"));
16959
17174
  init_fs();
16960
17175
  init_yaml();
16961
17176
  init_errors();
@@ -16995,7 +17210,7 @@ __export(domains_exports, {
16995
17210
  resolveDomains: () => resolveDomains
16996
17211
  });
16997
17212
  function rel(p) {
16998
- return path16.relative(process.cwd(), p).replace(/\\/g, "/");
17213
+ return path17.relative(process.cwd(), p).replace(/\\/g, "/");
16999
17214
  }
17000
17215
  function deriveSubsystemDomains() {
17001
17216
  const subsystems = loadSubsystemSpecs();
@@ -17045,11 +17260,11 @@ function removeFreeStandingDomain(id) {
17045
17260
  config.domains.splice(idx, 1);
17046
17261
  saveTopologyConfig(config);
17047
17262
  }
17048
- var path16;
17263
+ var path17;
17049
17264
  var init_domains = __esm({
17050
17265
  "src/core/domains.ts"() {
17051
17266
  "use strict";
17052
- path16 = __toESM(require("path"));
17267
+ path17 = __toESM(require("path"));
17053
17268
  init_loader();
17054
17269
  init_specs2();
17055
17270
  init_errors();
@@ -17062,8 +17277,10 @@ __export(src_exports, {
17062
17277
  AI_PATHS: () => AI_PATHS,
17063
17278
  ARCHITECT_AGENT_ID: () => ARCHITECT_AGENT_ID,
17064
17279
  ARCHITECT_TEMPLATE_ID: () => ARCHITECT_TEMPLATE_ID,
17280
+ AgentBriefSchema: () => AgentBriefSchema,
17065
17281
  AgentRecordSchema: () => AgentRecordSchema,
17066
17282
  AgentStatusSchema: () => AgentStatusSchema,
17283
+ AgentTemplateSchema: () => AgentTemplateSchema,
17067
17284
  AssertionSelectorSchema: () => AssertionSelectorSchema,
17068
17285
  BACKEND_COMMANDS: () => BACKEND_COMMANDS,
17069
17286
  BUILTIN_PROFILES: () => BUILTIN_PROFILES,
@@ -17175,6 +17392,7 @@ __export(src_exports, {
17175
17392
  TypeMethodSchema: () => TypeMethodSchema,
17176
17393
  TypeSpecSchema: () => TypeSpecSchema,
17177
17394
  UNVERSIONED: () => UNVERSIONED,
17395
+ UnknownAgentError: () => UnknownAgentError,
17178
17396
  VariantDefSchema: () => VariantDefSchema,
17179
17397
  WAIRON_MANAGED_BANNER: () => WAIRON_MANAGED_BANNER,
17180
17398
  WAIRON_MANAGED_MARKER: () => WAIRON_MANAGED_MARKER,
@@ -17200,6 +17418,7 @@ __export(src_exports, {
17200
17418
  checkSkillFreshness: () => checkSkillFreshness,
17201
17419
  clearLoaderIssues: () => clearLoaderIssues,
17202
17420
  collectPromotableSpecs: () => collectPromotableSpecs,
17421
+ composeAgentBrief: () => composeAgentBrief,
17203
17422
  composeRuleSequence: () => composeRuleSequence,
17204
17423
  composeVariantGuidance: () => composeVariantGuidance,
17205
17424
  computeGateStateId: () => computeGateStateId,
@@ -17288,6 +17507,7 @@ __export(src_exports, {
17288
17507
  listSkillResources: () => listSkillResources,
17289
17508
  listSnapshots: () => listSnapshots,
17290
17509
  listTemplateIds: () => listTemplateIds,
17510
+ loadAgentOverride: () => loadAgentOverride,
17291
17511
  loadComponentSpec: () => loadComponentSpec,
17292
17512
  loadComponentSpecs: () => loadComponentSpecs,
17293
17513
  loadExtensionPacks: () => loadExtensionPacks,
@@ -17351,6 +17571,7 @@ __export(src_exports, {
17351
17571
  resolveAgentTopology: () => resolveAgentTopology,
17352
17572
  resolveChainingParent: () => resolveChainingParent,
17353
17573
  resolveDomains: () => resolveDomains,
17574
+ resolveExpectedOutputPaths: () => resolveExpectedOutputPaths,
17354
17575
  resolveInstalledPack: () => resolveInstalledPack,
17355
17576
  resolvePackRef: () => resolvePackRef,
17356
17577
  resolveSubprojectForNamespace: () => resolveSubprojectForNamespace,
@@ -17405,7 +17626,7 @@ init_loader();
17405
17626
 
17406
17627
  // src/core/detection.ts
17407
17628
  var fs12 = __toESM(require("fs"));
17408
- var path15 = __toESM(require("path"));
17629
+ var path16 = __toESM(require("path"));
17409
17630
  init_defaults();
17410
17631
  var PACKAGE_MARKERS = [
17411
17632
  "package.json",
@@ -17479,7 +17700,7 @@ function parseGitmodules(filePath) {
17479
17700
  return entries;
17480
17701
  }
17481
17702
  function detectGitSubmodules(projectRoot) {
17482
- const gitmodulesPath = path15.join(projectRoot, ".gitmodules");
17703
+ const gitmodulesPath = path16.join(projectRoot, ".gitmodules");
17483
17704
  if (!fs12.existsSync(gitmodulesPath)) return [];
17484
17705
  return parseGitmodules(gitmodulesPath).map((entry) => ({
17485
17706
  suggestedId: pathToId(entry.path),
@@ -17505,10 +17726,10 @@ function walkForGit(projectRoot, currentDir, depth, results) {
17505
17726
  for (const entry of entries) {
17506
17727
  if (!entry.isDirectory()) continue;
17507
17728
  if (SCAN_EXCLUDE_DIRS.has(entry.name)) continue;
17508
- const fullPath = path15.join(currentDir, entry.name);
17509
- const relPath = normalizePath3(path15.relative(projectRoot, fullPath));
17729
+ const fullPath = path16.join(currentDir, entry.name);
17730
+ const relPath = normalizePath3(path16.relative(projectRoot, fullPath));
17510
17731
  if (relPath === "" || relPath === ".") continue;
17511
- const gitPath = path15.join(fullPath, ".git");
17732
+ const gitPath = path16.join(fullPath, ".git");
17512
17733
  if (fs12.existsSync(gitPath)) {
17513
17734
  results.push({
17514
17735
  suggestedId: pathToId(relPath),
@@ -17538,10 +17759,10 @@ function walkForPackages(projectRoot, currentDir, depth, results) {
17538
17759
  for (const entry of entries) {
17539
17760
  if (!entry.isDirectory()) continue;
17540
17761
  if (SCAN_EXCLUDE_DIRS.has(entry.name)) continue;
17541
- const fullPath = path15.join(currentDir, entry.name);
17542
- const relPath = normalizePath3(path15.relative(projectRoot, fullPath));
17762
+ const fullPath = path16.join(currentDir, entry.name);
17763
+ const relPath = normalizePath3(path16.relative(projectRoot, fullPath));
17543
17764
  if (relPath === "" || relPath === ".") continue;
17544
- const hasMarker = PACKAGE_MARKERS.some((m) => fs12.existsSync(path15.join(fullPath, m)));
17765
+ const hasMarker = PACKAGE_MARKERS.some((m) => fs12.existsSync(path16.join(fullPath, m)));
17545
17766
  if (hasMarker) {
17546
17767
  results.push({
17547
17768
  suggestedId: pathToId(relPath),
@@ -17555,7 +17776,7 @@ function walkForPackages(projectRoot, currentDir, depth, results) {
17555
17776
  }
17556
17777
  }
17557
17778
  function pathToId(relPath) {
17558
- const basename9 = path15.basename(relPath);
17779
+ const basename9 = path16.basename(relPath);
17559
17780
  return basename9.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
17560
17781
  }
17561
17782
  function pathToName(relPath) {
@@ -17568,58 +17789,7 @@ function normalizePath3(p) {
17568
17789
 
17569
17790
  // src/core/index.ts
17570
17791
  init_domains();
17571
-
17572
- // src/core/templates.ts
17573
- var path17 = __toESM(require("path"));
17574
- init_fs();
17575
- init_yaml();
17576
- init_errors();
17577
- init_template();
17578
- init_loader();
17579
- init_defaults();
17580
- function builtinTemplatesDir() {
17581
- return path17.resolve(__dirname, "..", "templates");
17582
- }
17583
- function loadTemplate(id, globalOverride) {
17584
- const dirs = templateSearchDirs(globalOverride);
17585
- for (const dir of dirs) {
17586
- const filePath = path17.join(dir, `${id}.yaml`);
17587
- if (pathExists(filePath)) {
17588
- const raw = readYamlFile(filePath);
17589
- return TemplateSchema.parse(raw);
17590
- }
17591
- }
17592
- throw new TemplateNotFoundError(id);
17593
- }
17594
- function listTemplateIds(globalOverride) {
17595
- const seen = /* @__PURE__ */ new Set();
17596
- for (const dir of templateSearchDirs(globalOverride)) {
17597
- for (const file of listFiles(dir, ".yaml")) {
17598
- seen.add(path17.basename(file, ".yaml"));
17599
- }
17600
- }
17601
- return Array.from(seen).sort();
17602
- }
17603
- function templateSearchDirs(globalOverride) {
17604
- return [
17605
- AI_PATHS.templatesDir(),
17606
- // 1. project-local
17607
- globalTemplatesDir(globalOverride),
17608
- // 2. global user/org
17609
- builtinTemplatesDir()
17610
- // 3. built-in fallback
17611
- ];
17612
- }
17613
- function renderTemplateInstructions(template, vars) {
17614
- return template.instructions.replace(/\{\{(\w+)\}\}/g, (_match, key) => {
17615
- return key in vars ? vars[key] : `{{${key}}}`;
17616
- });
17617
- }
17618
- function parseTemplate(yamlContent) {
17619
- return TemplateSchema.parse(parseYaml(yamlContent));
17620
- }
17621
-
17622
- // src/core/index.ts
17792
+ init_templates();
17623
17793
  init_validation();
17624
17794
  init_extensions();
17625
17795
  init_variants();
@@ -17649,6 +17819,9 @@ function defaultProjectConfig(name, now) {
17649
17819
  // a large tree/subproject with per-component implementers emits thousands
17650
17820
  // of agents that every session then loads. Opt in with `true` on small trees.
17651
17821
  generateComponentImplementers: false,
17822
+ // Files are the opt-in materialized view of the live briefs — off means
17823
+ // `generate` reconciles to zero agent files.
17824
+ materializeAgentFiles: false,
17652
17825
  sddRuleSeverity: {}
17653
17826
  },
17654
17827
  paths: { specsDir: ".wai/specs" },
@@ -18118,7 +18291,17 @@ before you design anything**, and the others when their turn comes \u2014 they c
18118
18291
  architecture standard, the narrative step reference, and the review checklist that
18119
18292
  this briefing only points at:
18120
18293
 
18121
- ${skillPointers(skills)}`;
18294
+ ${skillPointers(skills)}
18295
+
18296
+ ## Delegating implementation
18297
+
18298
+ Delegate component work from a LIVE agent brief, never a generated file: discover
18299
+ agents via \`listAgents\` (or the \`wairon-agent://\` resources), fetch the target's
18300
+ brief with \`sdd_get_agent_brief\`, and spawn a scoped subagent from it \u2014 its
18301
+ \`instructions\` as prompt, its \`ownedPaths\` as write fence. Briefs are composed
18302
+ from the current spec tree on every call, so a re-lock never requires a session
18303
+ restart \u2014 fetch fresh per delegation. \`wairon-skill://sdd-delegate\` carries the
18304
+ full flow.`;
18122
18305
  }
18123
18306
  function buildServerInstructions() {
18124
18307
  const profile = governingProfile();
@@ -18144,7 +18327,7 @@ ${block.text.trim()}`);
18144
18327
  }
18145
18328
 
18146
18329
  // src/core/skills.ts
18147
- var SKILL_NAMES = ["sdd-architect", "sdd-narrative", "sdd-auditor", "sdd-implement"];
18330
+ var SKILL_NAMES = ["sdd-architect", "sdd-narrative", "sdd-auditor", "sdd-implement", "sdd-delegate"];
18148
18331
  function loadProjectExtensions2() {
18149
18332
  return loadProjectExtensions();
18150
18333
  }
@@ -18345,7 +18528,7 @@ If \`.wai/specs/\` exists, the wairon SDD workflow is active; otherwise ignore i
18345
18528
  1. **Skills**: Use \`sdd-architect\` to design (and \`sdd-implement\`, \`sdd-narrative\`, \`sdd-auditor\`). Refer to project's local guide file for detailed constraints.
18346
18529
  2. **MCP Tools Only**: Author/validate specs *only* via \`sdd_*\` tools (e.g. \`sdd_initialize_system\`, \`sdd_validate_tree\`).
18347
18530
  3. **No CLI Exec**: Do not run the \`wairon\` CLI (human tool). Use MCP tools \`sdd_validate_tree\` and \`sdd_get_status\` instead.
18348
- 4. **Subagents**: Spawn generated \`<component>-implementer\` subagents for coding.
18531
+ 4. **Delegation**: Delegate implementation via the \`sdd-delegate\` skill \u2014 live agent briefs (\`sdd_get_agent_brief\` MCP tool / \`wairon-agent://\` resource) are composed per call and always current; no session restart. Generated agent files are an optional materialized view of the same topology. User-owned per-agent guidance may live in \`.wai/agents/<agent-id>.md\` (folded into every brief; scaffold via \`wairon agent customize <id>\`).
18349
18532
  5. **Design First**: Complete spec and pass \`sdd_validate_tree\` before writing code.
18350
18533
  6. **Consistency**: Code must match L3 interfaces and L5 narratives exactly. If the spec is wrong, stop and update the spec.
18351
18534
  7. **Subprojects & Namespacing**: If a subsystem uses \`projectPath\` delegation, target its specs using namespaced IDs (e.g. \`subsystem::component\`). Use leading \`::\` to target root (e.g. \`::shared::type\`) and \`super::\` to go up a level (e.g. \`super::sibling\`). wairon automatically resolves the path and strips the prefix on writes.`;
@@ -18492,6 +18675,7 @@ init_surfaces();
18492
18675
  init_openapi();
18493
18676
  init_packstore();
18494
18677
  init_extensions();
18678
+ init_agent_resolver();
18495
18679
 
18496
18680
  // src/exporters/base.ts
18497
18681
  var WAIRON_MANAGED_MARKER = "wairon:managed";
@@ -18596,6 +18780,7 @@ function yamlString(value) {
18596
18780
  }
18597
18781
 
18598
18782
  // src/exporters/generate.ts
18783
+ var path23 = __toESM(require("path"));
18599
18784
  init_fs();
18600
18785
 
18601
18786
  // src/exporters/registry.ts
@@ -18626,7 +18811,7 @@ function generateAgent(agent, projectConfig, options = {}) {
18626
18811
  const projectRoot = options.projectRoot ?? getProjectRoot();
18627
18812
  const template = loadTemplate(agent.template, projectConfig.globalTemplatesDir);
18628
18813
  const rendered = `${WAIRON_MANAGED_BANNER}
18629
- ${renderTemplateInstructions(template, buildVars(agent))}`;
18814
+ ${composeAgentBrief(agent.id).instructions}`;
18630
18815
  const results = [];
18631
18816
  for (const agentTarget of agent.targets) {
18632
18817
  const targetConfig = resolveTargetConfig(agentTarget, projectConfig);
@@ -18655,19 +18840,17 @@ function generateAll(agents, projectConfig, options = {}) {
18655
18840
  }
18656
18841
  return pool.map((agent) => generateAgent(agent, projectConfig, options));
18657
18842
  }
18658
- function buildVars(agent) {
18659
- return {
18660
- agentId: agent.id,
18661
- agentName: agent.name,
18662
- agentDescription: agent.description,
18663
- ownedPaths: agent.ownedPaths.join("\n"),
18664
- tags: agent.tags.join(", "),
18665
- renderContext: "root",
18666
- contextNote: "",
18667
- domainPath: ".",
18668
- domainName: "",
18669
- variantGuidance: agent.variantGuidance ?? ""
18670
- };
18843
+ function resolveExpectedOutputPaths(agents, projectConfig, projectRoot = getProjectRoot()) {
18844
+ const expected = /* @__PURE__ */ new Set();
18845
+ for (const agent of agents) {
18846
+ for (const agentTarget of agent.targets) {
18847
+ const targetConfig = resolveTargetConfig(agentTarget, projectConfig);
18848
+ if (!targetConfig) continue;
18849
+ const ctx = { agent, projectRoot, target: targetConfig };
18850
+ expected.add(path23.resolve(getExporter(targetConfig).outputPath(ctx)));
18851
+ }
18852
+ }
18853
+ return expected;
18671
18854
  }
18672
18855
  function resolveTargetConfig(agentTarget, projectConfig) {
18673
18856
  const targetType = typeof agentTarget === "string" ? agentTarget : agentTarget.type;
@@ -18741,8 +18924,10 @@ init_yaml();
18741
18924
  AI_PATHS,
18742
18925
  ARCHITECT_AGENT_ID,
18743
18926
  ARCHITECT_TEMPLATE_ID,
18927
+ AgentBriefSchema,
18744
18928
  AgentRecordSchema,
18745
18929
  AgentStatusSchema,
18930
+ AgentTemplateSchema,
18746
18931
  AssertionSelectorSchema,
18747
18932
  BACKEND_COMMANDS,
18748
18933
  BUILTIN_PROFILES,
@@ -18854,6 +19039,7 @@ init_yaml();
18854
19039
  TypeMethodSchema,
18855
19040
  TypeSpecSchema,
18856
19041
  UNVERSIONED,
19042
+ UnknownAgentError,
18857
19043
  VariantDefSchema,
18858
19044
  WAIRON_MANAGED_BANNER,
18859
19045
  WAIRON_MANAGED_MARKER,
@@ -18879,6 +19065,7 @@ init_yaml();
18879
19065
  checkSkillFreshness,
18880
19066
  clearLoaderIssues,
18881
19067
  collectPromotableSpecs,
19068
+ composeAgentBrief,
18882
19069
  composeRuleSequence,
18883
19070
  composeVariantGuidance,
18884
19071
  computeGateStateId,
@@ -18967,6 +19154,7 @@ init_yaml();
18967
19154
  listSkillResources,
18968
19155
  listSnapshots,
18969
19156
  listTemplateIds,
19157
+ loadAgentOverride,
18970
19158
  loadComponentSpec,
18971
19159
  loadComponentSpecs,
18972
19160
  loadExtensionPacks,
@@ -19030,6 +19218,7 @@ init_yaml();
19030
19218
  resolveAgentTopology,
19031
19219
  resolveChainingParent,
19032
19220
  resolveDomains,
19221
+ resolveExpectedOutputPaths,
19033
19222
  resolveInstalledPack,
19034
19223
  resolvePackRef,
19035
19224
  resolveSubprojectForNamespace,