guardian-framework 0.1.132 → 0.1.134

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -3078,7 +3078,11 @@ function categorizeFile(relativePath) {
3078
3078
  "agent/AGENTS.md",
3079
3079
  "domain/",
3080
3080
  "architecture/CHANGELOG.md",
3081
- "architecture/implementation-roadmap.md"
3081
+ "architecture/implementation-roadmap.md",
3082
+ "architecture/diagrams/",
3083
+ "architecture/modules/",
3084
+ "architecture/decisions/",
3085
+ "architecture/contracts/"
3082
3086
  ];
3083
3087
  if (userEditable.some((p3) => relativePath.includes(p3))) {
3084
3088
  return "user";
@@ -3202,7 +3206,7 @@ __export(exports_package, {
3202
3206
  bin: () => bin,
3203
3207
  author: () => author
3204
3208
  });
3205
- var name = "guardian-framework", version = "0.1.132", description = "Token-optimized agentic framework scaffolder with pi-first architecture", type = "module", main = "dist/exports.js", exports, types = "dist/exports.d.ts", bin, files, engines, scripts, publishConfig, pi, repository, homepage = "https://github.com/arman-jalili/guardian-framework#readme", bugs, dependencies, devDependencies, keywords, author = "Arman Wolkensteiner-Jalili", license = "MIT", package_default;
3209
+ var name = "guardian-framework", version = "0.1.134", description = "Token-optimized agentic framework scaffolder with pi-first architecture", type = "module", main = "dist/exports.js", exports, types = "dist/exports.d.ts", bin, files, engines, scripts, publishConfig, pi, repository, homepage = "https://github.com/arman-jalili/guardian-framework#readme", bugs, dependencies, devDependencies, keywords, author = "Arman Wolkensteiner-Jalili", license = "MIT", package_default;
3206
3210
  var init_package = __esm(() => {
3207
3211
  exports = {
3208
3212
  ".": {
@@ -11085,6 +11089,12 @@ async function runUpdate(targetDir, options) {
11085
11089
  outro(`Error: ${error instanceof Error ? error.message : "Unknown error"}`);
11086
11090
  }
11087
11091
  }
11092
+ function isUserOwnedPiPath(manifestPath) {
11093
+ const p3 = manifestPath.replace(/^\.pi\//, "").toLowerCase();
11094
+ if (p3.includes("template"))
11095
+ return false;
11096
+ return p3.startsWith("architecture/diagrams/") || p3.startsWith("architecture/modules/") || p3.startsWith("architecture/decisions/") || p3.startsWith("architecture/contracts/") || p3.startsWith("architecture/architecture-overview.md") || p3.startsWith("domain/exploration.md") || p3.startsWith("domain/exploration/") || p3.startsWith("domain/ubiquitous-language.md");
11097
+ }
11088
11098
  function analyzeChanges(targetDir, manifest, templateFiles, context, options) {
11089
11099
  const changes = [];
11090
11100
  const templatePaths = new Set(templateFiles);
@@ -11092,6 +11102,14 @@ function analyzeChanges(targetDir, manifest, templateFiles, context, options) {
11092
11102
  if (!filePath.startsWith(".pi/"))
11093
11103
  continue;
11094
11104
  const fullPath = path9.join(targetDir, filePath);
11105
+ if (isUserOwnedPiPath(filePath)) {
11106
+ changes.push({
11107
+ path: filePath,
11108
+ action: "preserve",
11109
+ reason: "Project-owned architecture content \u2014 never overwritten by update"
11110
+ });
11111
+ continue;
11112
+ }
11095
11113
  if (!templatePaths.has(filePath.replace(".pi/", ""))) {
11096
11114
  changes.push({
11097
11115
  path: filePath,
@@ -11148,6 +11166,15 @@ function analyzeChanges(targetDir, manifest, templateFiles, context, options) {
11148
11166
  for (const relativePath of templateFiles) {
11149
11167
  const manifestPath = `.pi/${relativePath}`;
11150
11168
  if (!manifest.files[manifestPath]) {
11169
+ const existing = path9.join(targetDir, manifestPath);
11170
+ if (fs10.existsSync(existing) && isUserOwnedPiPath(manifestPath)) {
11171
+ changes.push({
11172
+ path: manifestPath,
11173
+ action: "preserve",
11174
+ reason: "Project-owned content already exists"
11175
+ });
11176
+ continue;
11177
+ }
11151
11178
  changes.push({ path: manifestPath, action: "add", reason: "New template file" });
11152
11179
  }
11153
11180
  }
@@ -12838,6 +12865,27 @@ ${bc.description}
12838
12865
  }
12839
12866
  content += `
12840
12867
  `;
12868
+ content += `## Application Services (from exploration use-cases)
12869
+ `;
12870
+ content += `
12871
+ `;
12872
+ const ctxServices = (sessionResult.applicationServices ?? []).filter((svc) => svc.context === bc.name);
12873
+ if (ctxServices.length === 0) {
12874
+ content += `None captured in exploration yet (run the use-cases pass).
12875
+
12876
+ `;
12877
+ } else {
12878
+ content += `| Service | Use case | Maps to FR |
12879
+ `;
12880
+ content += `|---------|----------|-----------|
12881
+ `;
12882
+ for (const svc of ctxServices) {
12883
+ content += `| \`${svc.name}\` | ${svc.useCase ?? "\u2014"} | ${svc.mapsToFr ?? "\u2014"} |
12884
+ `;
12885
+ }
12886
+ content += `
12887
+ `;
12888
+ }
12841
12889
  content += `## Ubiquitous Language
12842
12890
  `;
12843
12891
  content += `
package/dist/exports.js CHANGED
@@ -1898,7 +1898,11 @@ function categorizeFile(relativePath) {
1898
1898
  "agent/AGENTS.md",
1899
1899
  "domain/",
1900
1900
  "architecture/CHANGELOG.md",
1901
- "architecture/implementation-roadmap.md"
1901
+ "architecture/implementation-roadmap.md",
1902
+ "architecture/diagrams/",
1903
+ "architecture/modules/",
1904
+ "architecture/decisions/",
1905
+ "architecture/contracts/"
1902
1906
  ];
1903
1907
  if (userEditable.some((p2) => relativePath.includes(p2))) {
1904
1908
  return "user";
@@ -1987,7 +1991,7 @@ __export(exports_package, {
1987
1991
  bin: () => bin,
1988
1992
  author: () => author
1989
1993
  });
1990
- var name = "guardian-framework", version = "0.1.132", description = "Token-optimized agentic framework scaffolder with pi-first architecture", type = "module", main = "dist/exports.js", exports, types = "dist/exports.d.ts", bin, files, engines, scripts, publishConfig, pi, repository, homepage = "https://github.com/arman-jalili/guardian-framework#readme", bugs, dependencies, devDependencies, keywords, author = "Arman Wolkensteiner-Jalili", license = "MIT", package_default;
1994
+ var name = "guardian-framework", version = "0.1.134", description = "Token-optimized agentic framework scaffolder with pi-first architecture", type = "module", main = "dist/exports.js", exports, types = "dist/exports.d.ts", bin, files, engines, scripts, publishConfig, pi, repository, homepage = "https://github.com/arman-jalili/guardian-framework#readme", bugs, dependencies, devDependencies, keywords, author = "Arman Wolkensteiner-Jalili", license = "MIT", package_default;
1991
1995
  var init_package = __esm(() => {
1992
1996
  exports = {
1993
1997
  ".": {
@@ -10209,6 +10213,12 @@ async function runUpdate(targetDir, options) {
10209
10213
  outro(`Error: ${error instanceof Error ? error.message : "Unknown error"}`);
10210
10214
  }
10211
10215
  }
10216
+ function isUserOwnedPiPath(manifestPath) {
10217
+ const p2 = manifestPath.replace(/^\.pi\//, "").toLowerCase();
10218
+ if (p2.includes("template"))
10219
+ return false;
10220
+ return p2.startsWith("architecture/diagrams/") || p2.startsWith("architecture/modules/") || p2.startsWith("architecture/decisions/") || p2.startsWith("architecture/contracts/") || p2.startsWith("architecture/architecture-overview.md") || p2.startsWith("domain/exploration.md") || p2.startsWith("domain/exploration/") || p2.startsWith("domain/ubiquitous-language.md");
10221
+ }
10212
10222
  function analyzeChanges(targetDir, manifest, templateFiles, context, options) {
10213
10223
  const changes = [];
10214
10224
  const templatePaths = new Set(templateFiles);
@@ -10216,6 +10226,14 @@ function analyzeChanges(targetDir, manifest, templateFiles, context, options) {
10216
10226
  if (!filePath.startsWith(".pi/"))
10217
10227
  continue;
10218
10228
  const fullPath = path5.join(targetDir, filePath);
10229
+ if (isUserOwnedPiPath(filePath)) {
10230
+ changes.push({
10231
+ path: filePath,
10232
+ action: "preserve",
10233
+ reason: "Project-owned architecture content — never overwritten by update"
10234
+ });
10235
+ continue;
10236
+ }
10219
10237
  if (!templatePaths.has(filePath.replace(".pi/", ""))) {
10220
10238
  changes.push({
10221
10239
  path: filePath,
@@ -10272,6 +10290,15 @@ function analyzeChanges(targetDir, manifest, templateFiles, context, options) {
10272
10290
  for (const relativePath of templateFiles) {
10273
10291
  const manifestPath = `.pi/${relativePath}`;
10274
10292
  if (!manifest.files[manifestPath]) {
10293
+ const existing = path5.join(targetDir, manifestPath);
10294
+ if (fs6.existsSync(existing) && isUserOwnedPiPath(manifestPath)) {
10295
+ changes.push({
10296
+ path: manifestPath,
10297
+ action: "preserve",
10298
+ reason: "Project-owned content already exists"
10299
+ });
10300
+ continue;
10301
+ }
10275
10302
  changes.push({ path: manifestPath, action: "add", reason: "New template file" });
10276
10303
  }
10277
10304
  }
@@ -13162,6 +13189,27 @@ ${bc.description}
13162
13189
  }
13163
13190
  content += `
13164
13191
  `;
13192
+ content += `## Application Services (from exploration use-cases)
13193
+ `;
13194
+ content += `
13195
+ `;
13196
+ const ctxServices = (sessionResult.applicationServices ?? []).filter((svc) => svc.context === bc.name);
13197
+ if (ctxServices.length === 0) {
13198
+ content += `None captured in exploration yet (run the use-cases pass).
13199
+
13200
+ `;
13201
+ } else {
13202
+ content += `| Service | Use case | Maps to FR |
13203
+ `;
13204
+ content += `|---------|----------|-----------|
13205
+ `;
13206
+ for (const svc of ctxServices) {
13207
+ content += `| \`${svc.name}\` | ${svc.useCase ?? "—"} | ${svc.mapsToFr ?? "—"} |
13208
+ `;
13209
+ }
13210
+ content += `
13211
+ `;
13212
+ }
13165
13213
  content += `## Ubiquitous Language
13166
13214
  `;
13167
13215
  content += `
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "guardian-framework",
3
- "version": "0.1.132",
3
+ "version": "0.1.134",
4
4
  "description": "Token-optimized agentic framework scaffolder with pi-first architecture",
5
5
  "type": "module",
6
6
  "main": "dist/exports.js",
@@ -1550,12 +1550,46 @@ export default function (pi: ExtensionAPI) {
1550
1550
  ctx.ui.notify("Enriching " + moduleFiles.length + " module docs from session " + sessionId, "info");
1551
1551
  const lang = readLanguage(ctx.cwd);
1552
1552
 
1553
+ let servicesCatalog = "(no catalog available)";
1554
+ try {
1555
+ const svcRaw = JSON.parse(fs.readFileSync(sRawPath, "utf-8")) as Record<string, unknown>;
1556
+ const svcAll = Array.isArray(svcRaw.applicationServices) ? (svcRaw.applicationServices as Record<string, unknown>[]) : [];
1557
+ const svcBcs = Array.isArray(svcRaw.boundedContexts) ? (svcRaw.boundedContexts as Record<string, unknown>[]) : [];
1558
+ const ctxFor = (file: string): string => {
1559
+ const wanted = norm(file.replace(/\.md$/, ""));
1560
+ const bc = svcBcs.find((b) => norm(String(b.name ?? "")) === wanted);
1561
+ return bc ? String(bc.name ?? "") : "";
1562
+ };
1563
+ const chunks = moduleFiles.map((f) => {
1564
+ const ctx = ctxFor(f);
1565
+ const svcs = svcAll.filter((sv) => String(sv.context ?? "") === ctx);
1566
+ if (!ctx || svcs.length === 0) return "";
1567
+ const lines = svcs.map((sv) => {
1568
+ const extra = [String(sv.useCase ?? ""), sv.mapsToFr ? "mapsToFr: " + String(sv.mapsToFr) : ""]
1569
+ .filter(Boolean).join(" — ");
1570
+ return `- \u0060${String(sv.name ?? "")}\u0060 : ${extra}`;
1571
+ });
1572
+ return "### " + ctx + " (module doc: " + f + ")\n" + lines.join("\n");
1573
+ }).filter(Boolean);
1574
+ if (chunks.length > 0) servicesCatalog = chunks.join("\n\n");
1575
+ } catch { /* leave fallback text */ }
1576
+
1553
1577
  const enrichPrompt = [
1554
1578
  "## Task: Complete Architecture Package",
1555
1579
  "",
1556
1580
  "The scaffold generated basic stubs. Your task is to produce a **complete, interconnected architecture package**",
1557
1581
  "that an implementation agent can build from.",
1558
1582
  "",
1583
+ "### Application-services catalog (AUTHORITATIVE — from the exploration use-cases pass)",
1584
+ "",
1585
+ "The Application Layer section of EVERY module doc you enrich must list exactly these",
1586
+ "application services for that module's bounded context — EXACT names, use-case, and",
1587
+ "FR mapping. Do NOT rename, drop, or substitute services, and do not invent services",
1588
+ "that replace them. Extra controllers/adapters/query helpers may be added BELOW the",
1589
+ "catalog, but every catalog entry must appear verbatim:",
1590
+ "",
1591
+ servicesCatalog,
1592
+ "",
1559
1593
  "**YOU MUST FOLLOW THESE 3 STEPS IN ORDER. Do not skip steps or reorder them.**",
1560
1594
  "",
1561
1595
  "### Source Data",
@@ -1711,6 +1745,8 @@ export default function (pi: ExtensionAPI) {
1711
1745
 
1712
1746
  const explorationDir = path.join(ctx.cwd, ".pi", "domain", "exploration");
1713
1747
  const sessionPath = path.join(explorationDir, sessionId + ".md");
1748
+ const modulesDir = path.join(ctx.cwd, ".pi", "architecture", "modules");
1749
+ const norm = (n: string) => n.toLowerCase().replace(/[^a-z0-9]/g, "");
1714
1750
  const checks: string[] = [];
1715
1751
  let allPassed = true;
1716
1752
 
@@ -1725,6 +1761,105 @@ export default function (pi: ExtensionAPI) {
1725
1761
  checks.push(content.includes("## Ubiquitous Language") ? " PASS Ubiquitous language section" : " FAIL Missing ubiquitous language section");
1726
1762
  }
1727
1763
 
1764
+ // Application-services drift gate (root cause: use-cases stopped at the
1765
+ // exploration layer). Every catalog service must be present in its module
1766
+ // doc's Application Layer catalog block; Implemented rows must resolve to a
1767
+ // real seam class in src; Planned/Seam rows must carry a roadmap/phase
1768
+ // pointer. Catches doc gaps (e.g. evidence-export had no catalog block) and
1769
+ // paper claims (doc says Implemented, code has no such seam).
1770
+ const rawVPath = sessionPath.replace(/\.md$/, ".raw.json");
1771
+ if (fs.existsSync(rawVPath)) {
1772
+ try {
1773
+ const rawV = JSON.parse(fs.readFileSync(rawVPath, "utf-8")) as Record<string, unknown>;
1774
+ const svcV = Array.isArray(rawV.applicationServices) ? (rawV.applicationServices as Record<string, unknown>[]) : [];
1775
+ if (svcV.length > 0) {
1776
+ const vModules = fs.readdirSync(modulesDir).filter((f) => f.endsWith(".md") && f !== "module-template.md");
1777
+ const typeExists = (typeName: string): boolean => {
1778
+ const srcBase = path.join(ctx.cwd, "src");
1779
+ if (!fs.existsSync(srcBase)) return false;
1780
+ const target = typeName.replace(/[^A-Za-z0-9_]/g, "");
1781
+ let found = false;
1782
+ const walk = (dir: string, dep: number): void => {
1783
+ if (found || dep > 9) return;
1784
+ let entries;
1785
+ try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }
1786
+ for (const e of entries) {
1787
+ if (e.name === "node_modules" || e.name === "target" || e.name === ".git" || e.name === "dist") continue;
1788
+ const full = path.join(dir, e.name);
1789
+ if (e.isFile() && (e.name === target + ".java" || e.name === target + ".kt" || e.name === target + ".ts")) { found = true; return; }
1790
+ if (e.isDirectory()) walk(full, dep + 1);
1791
+ }
1792
+ };
1793
+ walk(srcBase, 0);
1794
+ return found;
1795
+ };
1796
+ const ctxNames = new Map<string, string>(); // norm(ctx) -> ctx
1797
+ const svcByCtx = new Map<string, string[]>();
1798
+ for (const sv of svcV) {
1799
+ const ctx = String(sv.context ?? ""); const nm = String(sv.name ?? "");
1800
+ if (!ctx || !nm) continue;
1801
+ ctxNames.set(norm(ctx), ctx);
1802
+ const arr = svcByCtx.get(ctx) ?? [];
1803
+ arr.push(nm); svcByCtx.set(ctx, arr);
1804
+ }
1805
+ let issues = 0;
1806
+ for (const [normCtx, ctx] of ctxNames) {
1807
+ const docFile = vModules.find((f) => norm(f.replace(/\.md$/, "")) === normCtx) ?? "";
1808
+ if (!docFile) {
1809
+ checks.push(" FAIL Module doc not found for context " + ctx + " (has " + svcByCtx.get(ctx)!.length + " catalog services)");
1810
+ issues++; continue;
1811
+ }
1812
+ const docText = fs.readFileSync(path.join(modulesDir, docFile), "utf-8");
1813
+ const catNames = svcByCtx.get(ctx)!;
1814
+ let miss = 0;
1815
+ for (const nm of catNames) if (!docText.includes(nm)) miss++;
1816
+ if (miss > 0) { checks.push(" FAIL " + docFile + " missing " + miss + " catalog service name(s): " + catNames.filter((n) => !docText.includes(n)).join(", ")); issues += miss; }
1817
+ if (!docText.includes("Service (canonical)")) {
1818
+ checks.push(" FAIL " + docFile + " has no Application Layer catalog block (header 'Service (canonical)') for " + catNames.length + " catalog services");
1819
+ issues++;
1820
+ }
1821
+ // Parse catalog table rows: | `Service` | use case | fr | Status | Delivered by |
1822
+ const block = docText.slice(docText.indexOf("### Application Layer") >= 0 ? docText.indexOf("### Application Layer") : 0);
1823
+ for (const line of block.split("\n")) {
1824
+ if (!line.trim().startsWith("|")) continue;
1825
+ const cells = line.split("|").map((c) => c.trim());
1826
+ if (cells.length < 6) continue;
1827
+ const svcName = cells[1].replace(/^`|`$/g, "");
1828
+ if (!catNames.includes(svcName)) continue; // catalog row only
1829
+ const statusCell = cells[4] + " " + cells[5];
1830
+ const seamCell = cells[5];
1831
+ if (/implemented/i.test(statusCell) && !/planned|seam/i.test(statusCell)) {
1832
+ const seamTokens = Array.from(seamCell.matchAll(/`([A-Za-z0-9_]+)`/g)).map((m) => m[1]);
1833
+ if (seamTokens.length === 0 && !/[A-Z][A-Za-z0-9_]+/.test(seamCell)) {
1834
+ checks.push(" FAIL " + docFile + ": Implemented catalog service " + svcName + " has no seam class named in the doc");
1835
+ issues++;
1836
+ } else {
1837
+ for (const tk of seamTokens.length > 0 ? seamTokens : seamCell.match(/[A-Z][A-Za-z0-9_]+/g) ?? []) {
1838
+ if (!typeExists(tk)) {
1839
+ checks.push(" FAIL " + docFile + ": Implemented service " + svcName + " names seam " + tk + " but no such type exists in src");
1840
+ issues++;
1841
+ }
1842
+ }
1843
+ }
1844
+ } else if (/planned|seam/i.test(statusCell)) {
1845
+ if (!/phase|roadmap|later|projection|pending|seam|intake|console|partial|deterministic/i.test(statusCell)) {
1846
+ checks.push(" FAIL " + docFile + ": catalog service " + svcName + " is Planned/Seam without a roadmap/phase pointer");
1847
+ issues++;
1848
+ }
1849
+ }
1850
+ }
1851
+ }
1852
+ checks.push(issues === 0
1853
+ ? " PASS Catalog blocks + seams verified for all " + svcV.length + " application services"
1854
+ : " FAIL " + issues + " catalog/seam issue(s)");
1855
+ if (issues > 0) allPassed = false;
1856
+ } else {
1857
+ checks.push(" PASS No application services in session (use-cases pass not run)");
1858
+ }
1859
+ } catch { /* ignore */ }
1860
+ }
1861
+
1862
+
1728
1863
  const header = allPassed ? "Domain Validation - All Checks Passed" : "Domain Validation - Some Checks Failed";
1729
1864
  ctx.ui.notify(header, allPassed ? "success" : "error");
1730
1865
 
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2026-09-06T15:49:30Z",
2
+ "timestamp": "2026-09-07T07:52:39Z",
3
3
  "mode": "all",
4
4
  "stages_run": [],
5
5
  "summary": {