guardian-framework 0.1.143 → 0.1.144

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
@@ -3206,7 +3206,7 @@ __export(exports_package, {
3206
3206
  bin: () => bin,
3207
3207
  author: () => author
3208
3208
  });
3209
- var name = "guardian-framework", version = "0.1.143", 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.144", 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;
3210
3210
  var init_package = __esm(() => {
3211
3211
  exports = {
3212
3212
  ".": {
@@ -11625,6 +11625,117 @@ import * as path3 from "path";
11625
11625
  import * as crypto from "crypto";
11626
11626
  import * as fs from "fs";
11627
11627
  import * as path2 from "path";
11628
+
11629
+ // src/lib/language-stubs.ts
11630
+ var FENCE = {
11631
+ typescript: "typescript",
11632
+ nextjs: "typescript",
11633
+ angular: "typescript",
11634
+ rust: "rust",
11635
+ python: "python",
11636
+ go: "go",
11637
+ java: "java"
11638
+ };
11639
+ function normalizeStubLanguage(language) {
11640
+ const l2 = (language ?? "").trim().toLowerCase();
11641
+ if (l2 === "nextjs" || l2 === "angular" || l2 === "typescript")
11642
+ return "typescript";
11643
+ if (l2 === "rust" || l2 === "python" || l2 === "go" || l2 === "java")
11644
+ return l2;
11645
+ return "neutral";
11646
+ }
11647
+ function renderRepositoryInterface(language, aggregateName) {
11648
+ const lang = normalizeStubLanguage(language);
11649
+ const fence = FENCE[lang] ?? "text";
11650
+ const id = `${aggregateName}Id`;
11651
+ if (lang === "rust") {
11652
+ return [
11653
+ `\`\`\`${fence}`,
11654
+ `pub trait ${aggregateName}Repository: Send + Sync {`,
11655
+ ` async fn find_by_id(&self, id: &${id}) -> Result<Option<${aggregateName}>, DomainError>;`,
11656
+ ` async fn save(&self, ${lowerFirst(aggregateName)}: &${aggregateName}) -> Result<(), DomainError>;`,
11657
+ ` async fn delete(&self, id: &${id}) -> Result<(), DomainError>;`,
11658
+ "}",
11659
+ "```"
11660
+ ].join(`
11661
+ `);
11662
+ }
11663
+ if (lang === "python") {
11664
+ return [
11665
+ `\`\`\`${fence}`,
11666
+ "from abc import ABC, abstractmethod",
11667
+ "",
11668
+ "",
11669
+ `class ${aggregateName}Repository(ABC):`,
11670
+ ` """Persistence port for the ${aggregateName} aggregate (implemented in infrastructure)."""`,
11671
+ "",
11672
+ " @abstractmethod",
11673
+ ` async def find_by_id(self, id_: ${id}) -> ${aggregateName} | None: ...`,
11674
+ "",
11675
+ " @abstractmethod",
11676
+ ` async def save(self, ${snake(aggregateName)}: ${aggregateName}) -> None: ...`,
11677
+ "",
11678
+ " @abstractmethod",
11679
+ ` async def delete(self, id_: ${id}) -> None: ...`,
11680
+ "```"
11681
+ ].join(`
11682
+ `);
11683
+ }
11684
+ if (lang === "java") {
11685
+ return [
11686
+ `\`\`\`${fence}`,
11687
+ `public interface ${aggregateName}Repository {`,
11688
+ ` Optional<${aggregateName}> findById(${id} id);`,
11689
+ ` void save(${aggregateName} ${lowerFirst(aggregateName)});`,
11690
+ ` void delete(${id} id);`,
11691
+ "}",
11692
+ "```"
11693
+ ].join(`
11694
+ `);
11695
+ }
11696
+ if (lang === "go") {
11697
+ return [
11698
+ `\`\`\`${fence}`,
11699
+ `// ${aggregateName}Repository is the persistence port for the ${aggregateName} aggregate.`,
11700
+ `type ${aggregateName}Repository interface {`,
11701
+ ` FindByID(ctx context.Context, id ${id}) (*${aggregateName}, error)`,
11702
+ ` Save(ctx context.Context, ${lowerFirst(aggregateName)} *${aggregateName}) error`,
11703
+ ` Delete(ctx context.Context, id ${id}) error`,
11704
+ "}",
11705
+ "```"
11706
+ ].join(`
11707
+ `);
11708
+ }
11709
+ if (lang === "typescript") {
11710
+ return [
11711
+ `\`\`\`${fence}`,
11712
+ `export interface ${aggregateName}Repository {`,
11713
+ ` findById(id: ${id}): Promise<${aggregateName} | null>;`,
11714
+ ` save(${lowerFirst(aggregateName)}: ${aggregateName}): Promise<void>;`,
11715
+ ` delete(id: ${id}): Promise<void>;`,
11716
+ "}",
11717
+ "```"
11718
+ ].join(`
11719
+ `);
11720
+ }
11721
+ return [
11722
+ `\`\`\`${fence}`,
11723
+ `${aggregateName}Repository (persistence port)`,
11724
+ ` findById(id: ${id}) -> ${aggregateName} | null`,
11725
+ ` save(${aggregateName}) -> void`,
11726
+ ` delete(id: ${id}) -> void`,
11727
+ "```"
11728
+ ].join(`
11729
+ `);
11730
+ }
11731
+ function lowerFirst(s) {
11732
+ return s.length > 0 ? s.charAt(0).toLowerCase() + s.slice(1) : s;
11733
+ }
11734
+ function snake(s) {
11735
+ return s.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[\s-]+/g, "_").toLowerCase();
11736
+ }
11737
+
11738
+ // src/lib/domain-explorer.ts
11628
11739
  var __dirname = "/Users/arman/project/guardian-framework/src/lib", __filename = "/Users/arman/project/guardian-framework/src/lib/domain-explorer.ts";
11629
11740
  var MAX_BUSINESS_CONTEXT_LENGTH = 5000;
11630
11741
  function sanitizeBusinessContext(context) {
@@ -12793,23 +12904,11 @@ ${bc.description}
12793
12904
  content += `
12794
12905
  `;
12795
12906
  }
12796
- const arVarName = ar.name.charAt(0).toLowerCase() + ar.name.slice(1);
12797
12907
  content += `**Repository Interface:**
12798
12908
  `;
12799
12909
  content += `
12800
12910
  `;
12801
- content += "```rust\n";
12802
- content += `pub trait ${ar.name}Repository: Send + Sync {
12803
- `;
12804
- content += ` async fn find_by_id(&self, id: &${ar.name}Id) -> Result<Option<${ar.name}>, DomainError>;
12805
- `;
12806
- content += ` async fn save(&self, ${arVarName}: &${ar.name}) -> Result<(), DomainError>;
12807
- `;
12808
- content += ` async fn delete(&self, id: &${ar.name}Id) -> Result<(), DomainError>;
12809
- `;
12810
- content += `}
12811
- `;
12812
- content += "```";
12911
+ content += renderRepositoryInterface(lang, ar.name);
12813
12912
  content += `
12814
12913
  `;
12815
12914
  if (ownedEntities.length > 0 || ownedVOs.length > 0 || invariants.length > 0) {
package/dist/exports.js CHANGED
@@ -1991,7 +1991,7 @@ __export(exports_package, {
1991
1991
  bin: () => bin,
1992
1992
  author: () => author
1993
1993
  });
1994
- var name = "guardian-framework", version = "0.1.143", 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.144", 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;
1995
1995
  var init_package = __esm(() => {
1996
1996
  exports = {
1997
1997
  ".": {
@@ -11948,6 +11948,117 @@ import * as path12 from "node:path";
11948
11948
  import * as crypto4 from "node:crypto";
11949
11949
  import * as fs12 from "node:fs";
11950
11950
  import * as path11 from "node:path";
11951
+
11952
+ // src/lib/language-stubs.ts
11953
+ var FENCE = {
11954
+ typescript: "typescript",
11955
+ nextjs: "typescript",
11956
+ angular: "typescript",
11957
+ rust: "rust",
11958
+ python: "python",
11959
+ go: "go",
11960
+ java: "java"
11961
+ };
11962
+ function normalizeStubLanguage(language) {
11963
+ const l2 = (language ?? "").trim().toLowerCase();
11964
+ if (l2 === "nextjs" || l2 === "angular" || l2 === "typescript")
11965
+ return "typescript";
11966
+ if (l2 === "rust" || l2 === "python" || l2 === "go" || l2 === "java")
11967
+ return l2;
11968
+ return "neutral";
11969
+ }
11970
+ function renderRepositoryInterface(language, aggregateName) {
11971
+ const lang = normalizeStubLanguage(language);
11972
+ const fence = FENCE[lang] ?? "text";
11973
+ const id = `${aggregateName}Id`;
11974
+ if (lang === "rust") {
11975
+ return [
11976
+ `\`\`\`${fence}`,
11977
+ `pub trait ${aggregateName}Repository: Send + Sync {`,
11978
+ ` async fn find_by_id(&self, id: &${id}) -> Result<Option<${aggregateName}>, DomainError>;`,
11979
+ ` async fn save(&self, ${lowerFirst(aggregateName)}: &${aggregateName}) -> Result<(), DomainError>;`,
11980
+ ` async fn delete(&self, id: &${id}) -> Result<(), DomainError>;`,
11981
+ "}",
11982
+ "```"
11983
+ ].join(`
11984
+ `);
11985
+ }
11986
+ if (lang === "python") {
11987
+ return [
11988
+ `\`\`\`${fence}`,
11989
+ "from abc import ABC, abstractmethod",
11990
+ "",
11991
+ "",
11992
+ `class ${aggregateName}Repository(ABC):`,
11993
+ ` """Persistence port for the ${aggregateName} aggregate (implemented in infrastructure)."""`,
11994
+ "",
11995
+ " @abstractmethod",
11996
+ ` async def find_by_id(self, id_: ${id}) -> ${aggregateName} | None: ...`,
11997
+ "",
11998
+ " @abstractmethod",
11999
+ ` async def save(self, ${snake(aggregateName)}: ${aggregateName}) -> None: ...`,
12000
+ "",
12001
+ " @abstractmethod",
12002
+ ` async def delete(self, id_: ${id}) -> None: ...`,
12003
+ "```"
12004
+ ].join(`
12005
+ `);
12006
+ }
12007
+ if (lang === "java") {
12008
+ return [
12009
+ `\`\`\`${fence}`,
12010
+ `public interface ${aggregateName}Repository {`,
12011
+ ` Optional<${aggregateName}> findById(${id} id);`,
12012
+ ` void save(${aggregateName} ${lowerFirst(aggregateName)});`,
12013
+ ` void delete(${id} id);`,
12014
+ "}",
12015
+ "```"
12016
+ ].join(`
12017
+ `);
12018
+ }
12019
+ if (lang === "go") {
12020
+ return [
12021
+ `\`\`\`${fence}`,
12022
+ `// ${aggregateName}Repository is the persistence port for the ${aggregateName} aggregate.`,
12023
+ `type ${aggregateName}Repository interface {`,
12024
+ ` FindByID(ctx context.Context, id ${id}) (*${aggregateName}, error)`,
12025
+ ` Save(ctx context.Context, ${lowerFirst(aggregateName)} *${aggregateName}) error`,
12026
+ ` Delete(ctx context.Context, id ${id}) error`,
12027
+ "}",
12028
+ "```"
12029
+ ].join(`
12030
+ `);
12031
+ }
12032
+ if (lang === "typescript") {
12033
+ return [
12034
+ `\`\`\`${fence}`,
12035
+ `export interface ${aggregateName}Repository {`,
12036
+ ` findById(id: ${id}): Promise<${aggregateName} | null>;`,
12037
+ ` save(${lowerFirst(aggregateName)}: ${aggregateName}): Promise<void>;`,
12038
+ ` delete(id: ${id}): Promise<void>;`,
12039
+ "}",
12040
+ "```"
12041
+ ].join(`
12042
+ `);
12043
+ }
12044
+ return [
12045
+ `\`\`\`${fence}`,
12046
+ `${aggregateName}Repository (persistence port)`,
12047
+ ` findById(id: ${id}) -> ${aggregateName} | null`,
12048
+ ` save(${aggregateName}) -> void`,
12049
+ ` delete(id: ${id}) -> void`,
12050
+ "```"
12051
+ ].join(`
12052
+ `);
12053
+ }
12054
+ function lowerFirst(s) {
12055
+ return s.length > 0 ? s.charAt(0).toLowerCase() + s.slice(1) : s;
12056
+ }
12057
+ function snake(s) {
12058
+ return s.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[\s-]+/g, "_").toLowerCase();
12059
+ }
12060
+
12061
+ // src/lib/domain-explorer.ts
11951
12062
  var __dirname = "/Users/arman/project/guardian-framework/src/lib", __filename = "/Users/arman/project/guardian-framework/src/lib/domain-explorer.ts";
11952
12063
  var MAX_BUSINESS_CONTEXT_LENGTH = 5000;
11953
12064
  function sanitizeBusinessContext(context) {
@@ -13116,23 +13227,11 @@ ${bc.description}
13116
13227
  content += `
13117
13228
  `;
13118
13229
  }
13119
- const arVarName = ar.name.charAt(0).toLowerCase() + ar.name.slice(1);
13120
13230
  content += `**Repository Interface:**
13121
13231
  `;
13122
13232
  content += `
13123
13233
  `;
13124
- content += "```rust\n";
13125
- content += `pub trait ${ar.name}Repository: Send + Sync {
13126
- `;
13127
- content += ` async fn find_by_id(&self, id: &${ar.name}Id) -> Result<Option<${ar.name}>, DomainError>;
13128
- `;
13129
- content += ` async fn save(&self, ${arVarName}: &${ar.name}) -> Result<(), DomainError>;
13130
- `;
13131
- content += ` async fn delete(&self, id: &${ar.name}Id) -> Result<(), DomainError>;
13132
- `;
13133
- content += `}
13134
- `;
13135
- content += "```";
13234
+ content += renderRepositoryInterface(lang, ar.name);
13136
13235
  content += `
13137
13236
  `;
13138
13237
  if (ownedEntities.length > 0 || ownedVOs.length > 0 || invariants.length > 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "guardian-framework",
3
- "version": "0.1.143",
3
+ "version": "0.1.144",
4
4
  "description": "Token-optimized agentic framework scaffolder with pi-first architecture",
5
5
  "type": "module",
6
6
  "main": "dist/exports.js",
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2026-09-25T19:59:49Z",
2
+ "timestamp": "2026-11-07T13:11:23Z",
3
3
  "mode": "all",
4
4
  "stages_run": [],
5
5
  "summary": {
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env bash
2
+ # ============================================================================
3
+ # check_language_consistency.sh — architecture docs must use the project language
4
+ # ============================================================================
5
+ # Catches two failure modes:
6
+ # 1. Scaffold emitting stubs in the wrong language (historically Rust in every
7
+ # project, regardless of manifest language).
8
+ # 2. An enrichment/codegen agent copying a foreign-language sample.
9
+ #
10
+ # Fences for "infrastructure" languages that are legitimately language-agnostic
11
+ # (json, yaml, toml, bash, sql, mermaid, text, dockerfile, http, diff, ini) are
12
+ # always allowed; markdown is allowed too.
13
+ #
14
+ # Usage: bash .pi/scripts/check_language_consistency.sh [--strict]
15
+ # --strict also treat other framework languages (angular/nextjs) as foreign
16
+ # ============================================================================
17
+ set -uo pipefail
18
+
19
+ RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
20
+ PASS=0; FAIL=0; WARN=0
21
+ pass() { echo -e "${GREEN}✅ PASS${NC} $1"; PASS=$((PASS+1)); }
22
+ fail() { echo -e "${RED}❌ FAIL${NC} $1"; FAIL=$((FAIL+1)); }
23
+ warn() { echo -e "${YELLOW}⚠️ WARN${NC} $1"; WARN=$((WARN+1)); }
24
+
25
+ STRICT=0
26
+ [ "${1:-}" = "--strict" ] && STRICT=1
27
+
28
+ echo "============================================"
29
+ echo " Language Consistency (architecture docs)"
30
+ echo "============================================"
31
+
32
+ # ── Resolve project language ────────────────────────────────────────────────
33
+ LANG_NAME=""
34
+ if [ -f "guardian-manifest.json" ]; then
35
+ LANG_NAME=$(python3 -c "import json;print(json.load(open('guardian-manifest.json')).get('language',''))" 2>/dev/null || true)
36
+ fi
37
+ if [ -z "$LANG_NAME" ] && [ -f ".pi/guardian-manifest.json" ]; then
38
+ LANG_NAME=$(python3 -c "import json;print(json.load(open('.pi/guardian-manifest.json')).get('language',''))" 2>/dev/null || true)
39
+ fi
40
+ if [ -z "$LANG_NAME" ]; then
41
+ echo "no manifest language — skipping"
42
+ exit 0
43
+ fi
44
+ echo "Project language: $LANG_NAME"
45
+ echo ""
46
+
47
+ case "$LANG_NAME" in
48
+ typescript|nextjs|angular) EXPECTED="typescript|tsx|ts|javascript|jsx|js" ;;
49
+ python) EXPECTED="python|py" ;;
50
+ rust) EXPECTED="rust" ;;
51
+ go) EXPECTED="go" ;;
52
+ java) EXPECTED="java" ;;
53
+ *) EXPECTED="" ;;
54
+ esac
55
+
56
+ if [ -z "$EXPECTED" ]; then
57
+ echo "unsupported language '$LANG_NAME' — skipping"
58
+ exit 0
59
+ fi
60
+
61
+ ALL_FENCES="typescript|tsx|ts|javascript|jsx|js|python|py|rust|go|java|kotlin|kt|csharp|cs|ruby|rb|php|swift|cpp|c\+\+|c|scala|elixir|dart"
62
+ ALLOWED_NEUTRAL="json|jsonc|yaml|yml|toml|bash|sh|shell|zsh|sql|mermaid|text|txt|plaintext|dockerfile|docker|http|diff|ini|properties|xml|html|css|scss|makefile|cmake|gradle|protobuf|proto|csv|regex|"
63
+
64
+ is_expected() {
65
+ local f="$1"
66
+ [ -z "$f" ] && return 1 # bare ``` with no language
67
+ case "$EXPECTED" in
68
+ *"|$f|"*|"$f|"*) return 0 ;;
69
+ esac
70
+ # substring match for multi-alias lists
71
+ echo "$EXPECTED" | tr '|' '\n' | grep -qx "$f" && return 0
72
+ return 1
73
+ }
74
+
75
+ is_neutral() {
76
+ local f="$1"
77
+ [ -z "$f" ] && return 0
78
+ echo "$ALLOWED_NEUTRAL" | tr '|' '\n' | grep -qx "$f"
79
+ }
80
+
81
+ ROOT=".pi/architecture"
82
+ [ -d "$ROOT" ] || { echo "no $ROOT — nothing to check"; exit 0; }
83
+
84
+ FILES=$(find "$ROOT" -name "*.md" -type f 2>/dev/null | grep -v "/modules/module-template.md$")
85
+ MISMATCHES=0
86
+ CHECKED=0
87
+ for doc in $FILES; do
88
+ CHECKED=$((CHECKED+1))
89
+ # Collect fenced block languages
90
+ fences=$(grep -oE '^```[a-zA-Z0-9_+-]*' "$doc" 2>/dev/null | sed 's/^```//' | sort -u)
91
+ [ -z "$fences" ] && continue
92
+ bad=""
93
+ for f in $fences; do
94
+ lower=$(echo "$f" | tr '[:upper:]' '[:lower:]')
95
+ if is_neutral "$lower"; then continue; fi
96
+ if is_expected "$lower"; then continue; fi
97
+ # A fence that is a known programming language but not this project's
98
+ if echo "$lower" | grep -qE "^($ALL_FENCES)$"; then
99
+ bad="$bad $lower"
100
+ elif [ "$STRICT" = "1" ]; then
101
+ bad="$bad $lower"
102
+ fi
103
+ done
104
+ if [ -n "$bad" ]; then
105
+ fail "$doc uses foreign code fence(s):$(echo "$bad" | tr ' ' '\n' | sed '/^$/d' | sort -u | sed 's/^/ /' | tr '\n' ',' | sed 's/,$//') (project: $LANG_NAME)"
106
+ MISMATCHES=$((MISMATCHES+1))
107
+ fi
108
+ done
109
+
110
+ if [ "$MISMATCHES" -eq 0 ]; then
111
+ pass "$CHECKED architecture doc(s) use $LANG_NAME (no foreign code fences)"
112
+ else
113
+ fail "$MISMATCHES of $CHECKED architecture doc(s) contain foreign-language code samples"
114
+ fi
115
+
116
+ echo ""
117
+ echo "============================================"
118
+ echo " Summary"
119
+ echo "============================================"
120
+ echo " Passed: $PASS Failed: $FAIL Warnings: $WARN"
121
+ [ "$FAIL" -eq 0 ] && exit 0
122
+ exit 1
@@ -13,10 +13,28 @@ detect_language() {
13
13
 
14
14
  LANG=$(detect_language)
15
15
  LANG_SCRIPT="${SCRIPT_DIR}/languages/${LANG}/validate-architecture.sh"
16
+ CONSISTENCY_SCRIPT="${SCRIPT_DIR}/check_language_consistency.sh"
17
+
18
+ # Language consistency runs for EVERY language (architecture docs must use the
19
+ # project language — catches scaffold stubs emitted in the wrong language).
20
+ run_consistency() {
21
+ if [ -f "$CONSISTENCY_SCRIPT" ]; then
22
+ bash "$CONSISTENCY_SCRIPT" || CONSISTENCY_RC=1
23
+ echo ""
24
+ fi
25
+ }
16
26
 
17
27
  if [ -f "$LANG_SCRIPT" ]; then
18
- exec bash "$LANG_SCRIPT" "$@"
28
+ bash "$LANG_SCRIPT" "$@"
29
+ LANG_RC=$?
30
+ CONSISTENCY_RC=0
31
+ run_consistency
32
+ [ "$LANG_RC" -ne 0 ] && exit "$LANG_RC"
33
+ [ "${CONSISTENCY_RC:-0}" -ne 0 ] && exit 1
34
+ exit 0
19
35
  else
20
36
  echo "No architecture validator for language: $LANG"
21
- exit 0
37
+ CONSISTENCY_RC=0
38
+ run_consistency
39
+ exit "${CONSISTENCY_RC:-0}"
22
40
  fi