guardian-framework 0.1.105 → 0.1.109

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.
Files changed (69) hide show
  1. package/README.md +11 -2
  2. package/dist/cli.js +232 -16
  3. package/dist/exports.js +232 -16
  4. package/package.json +1 -1
  5. package/templates/languages/rust-patterns.md +5 -2
  6. package/templates/pi/context/checklists.md +15 -1
  7. package/templates/pi/domain/exploration.md +9 -0
  8. package/templates/pi/domain/ubiquitous-language.md +12 -0
  9. package/templates/pi/extensions/architect-lib/generators.ts +158 -7
  10. package/templates/pi/extensions/architect-lib/helpers.ts +49 -0
  11. package/templates/pi/extensions/architect-lib/types.ts +44 -2
  12. package/templates/pi/extensions/architect.ts +102 -42
  13. package/templates/pi/extensions/ask-user-question.ts +2 -2
  14. package/templates/pi/extensions/bash-guard.ts +2 -2
  15. package/templates/pi/extensions/config-reload.ts +12 -5
  16. package/templates/pi/extensions/coordinator.ts +2 -2
  17. package/templates/pi/extensions/curator.ts +1 -1
  18. package/templates/pi/extensions/domain-explorer.ts +50 -3
  19. package/templates/pi/extensions/filechanges.ts +2 -2
  20. package/templates/pi/extensions/goal-loop.ts +3 -3
  21. package/templates/pi/extensions/hooks.ts +1 -1
  22. package/templates/pi/extensions/pi-env.d.ts +96 -0
  23. package/templates/pi/extensions/pipeline.ts +1 -1
  24. package/templates/pi/extensions/project-scaffolder.ts +1 -1
  25. package/templates/pi/extensions/read-only-mode.ts +5 -1
  26. package/templates/pi/extensions/tsconfig.json +9 -2
  27. package/templates/pi/preflight_report.json +1 -1
  28. package/templates/pi/prompts/ci-blueprint.md +2 -2
  29. package/templates/pi/scripts/check_model_judgment.sh +28 -0
  30. package/templates/pi/scripts/ci/check_judgment_contracts.sh +93 -0
  31. package/templates/pi/scripts/ci/run_preflight.sh +3 -3
  32. package/templates/pi/scripts/ci/run_stage.sh +1 -1
  33. package/templates/pi/scripts/ci/stage_lint.sh +1 -1
  34. package/templates/pi/scripts/coverage.sh +58 -0
  35. package/templates/pi/scripts/install_coverage_tools.sh +43 -0
  36. package/templates/pi/scripts/languages/go/check_model_judgment.sh +70 -0
  37. package/templates/pi/scripts/languages/go/check_runtime_reachability.sh +34 -0
  38. package/templates/pi/scripts/languages/go/coverage.sh +78 -0
  39. package/templates/pi/scripts/languages/go/install_coverage_tools.sh +17 -0
  40. package/templates/pi/scripts/languages/java/check_model_judgment.sh +142 -0
  41. package/templates/pi/scripts/languages/java/check_runtime_reachability.sh +31 -0
  42. package/templates/pi/scripts/languages/java/coverage.sh +103 -0
  43. package/templates/pi/scripts/languages/java/install_coverage_tools.sh +40 -0
  44. package/templates/pi/scripts/languages/java/validate-architecture.sh +20 -0
  45. package/templates/pi/scripts/languages/python/check_model_judgment.sh +67 -0
  46. package/templates/pi/scripts/languages/python/check_runtime_reachability.sh +34 -0
  47. package/templates/pi/scripts/languages/python/coverage.sh +88 -0
  48. package/templates/pi/scripts/languages/python/install_coverage_tools.sh +22 -0
  49. package/templates/pi/scripts/languages/rust/check_model_judgment.sh +61 -0
  50. package/templates/pi/scripts/languages/rust/check_runtime_reachability.sh +40 -0
  51. package/templates/pi/scripts/languages/rust/coverage.sh +79 -0
  52. package/templates/pi/scripts/languages/rust/install_coverage_tools.sh +20 -0
  53. package/templates/pi/scripts/languages/rust/validate-tests.sh +9 -6
  54. package/templates/pi/scripts/languages/typescript/check_model_judgment.sh +81 -0
  55. package/templates/pi/scripts/languages/typescript/check_runtime_reachability.sh +41 -0
  56. package/templates/pi/scripts/languages/typescript/coverage.sh +154 -0
  57. package/templates/pi/scripts/languages/typescript/install_coverage_tools.sh +41 -0
  58. package/templates/pi/scripts/languages/typescript/validate-canonical.sh +6 -2
  59. package/templates/pi/scripts/languages/typescript/validate-ci.sh +2 -2
  60. package/templates/pi/scripts/validate-architecture-readiness.sh +29 -0
  61. package/templates/pi/scripts/validate-exploration-depth.sh +112 -0
  62. package/templates/pi/scripts/validate-runtime-wiring.sh +35 -0
  63. package/templates/pi/skills/agents/architecture-validator.md +28 -0
  64. package/templates/pi/skills/agents/test-validator.md +1 -1
  65. package/templates/pi/skills/go-enterprise-codegen.md +46 -0
  66. package/templates/pi/skills/java-spring-enterprise-codegen.md +50 -0
  67. package/templates/pi/skills/python-enterprise-codegen.md +46 -0
  68. package/templates/pi/skills/rust-enterprise-codegen.md +46 -0
  69. package/templates/pi/skills/typescript-enterprise-codegen.md +46 -0
@@ -182,7 +182,7 @@ async function askSingleChoice(
182
182
  { id: "other", label: otherLabel, value: "__other__", isOther: true },
183
183
  ];
184
184
 
185
- return ctx.ui.custom<AskAnswer | null>(
185
+ return (ctx.ui as any).custom(
186
186
  (tui: any, theme: any, _kb: any, done: (r: AskAnswer | null) => void) => {
187
187
  let optionIndex = 0;
188
188
  let editMode = false;
@@ -306,7 +306,7 @@ async function askMultiChoice(
306
306
  { id: "submit", label: "Submit", value: "__submit__", isSubmit: true },
307
307
  ];
308
308
 
309
- return ctx.ui.custom<AskAnswer[] | null>(
309
+ return (ctx.ui as any).custom(
310
310
  (tui: any, theme: any, _kb: any, done: (r: AskAnswer[] | null) => void) => {
311
311
  let optionIndex = 0;
312
312
  let editMode = false;
@@ -65,7 +65,7 @@ function tokenizeCommand(cmd: string): { parts: string[]; ops: string[] } {
65
65
  }
66
66
 
67
67
  // Operators: |, ||, &&, ;, >, >>, <
68
- if (ch === "|" || ch === ";" || ch === "<" || ch === ">") {
68
+ if (ch === "|" || ch === ";" || ch === "<" || ch === ">" || ch === "&") {
69
69
  if (current.trim()) parts.push(current.trim());
70
70
  current = "";
71
71
 
@@ -304,7 +304,7 @@ async function promptRunOrAbort(ctx: any, command: string, risk: Risk): Promise<
304
304
  { value: "abort", label: "Abort", description: "Block this command" },
305
305
  ];
306
306
 
307
- const choice = await ctx.ui.custom<"run" | "abort">(
307
+ const choice = await (ctx.ui as any).custom(
308
308
  (tui, theme, _kb, done) => {
309
309
  const container = new Container();
310
310
  container.addChild(
@@ -14,12 +14,12 @@ import * as fs from "node:fs";
14
14
  import * as path from "node:path";
15
15
 
16
16
  type ExtensionAPI = {
17
- on(event: string, handler: (event: unknown, ctx: unknown) => void | Promise<void>): void;
17
+ on(event: string, handler: (event: unknown, ctx: ReloadCtx) => void | Promise<void>): void;
18
18
  registerCommand(
19
19
  name: string,
20
20
  options: {
21
21
  description: string;
22
- handler(args: string[], ctx: unknown): unknown | Promise<unknown>;
22
+ handler(args: string[], ctx: ReloadCtx): unknown | Promise<unknown>;
23
23
  },
24
24
  ): void;
25
25
  };
@@ -35,11 +35,18 @@ function parseFrontMatter(text: string): string {
35
35
  return text.slice(4, end);
36
36
  }
37
37
 
38
+ type ReloadUi = {
39
+ notify(message: string, level?: string): void;
40
+ setStatus(key: string, message: string | null): void;
41
+ theme?: { fg(role: string, text: string): string };
42
+ };
43
+ type ReloadCtx = { ui?: ReloadUi };
44
+
38
45
  let lastKnownConfig = "";
39
46
  let watcher: fs.FSWatcher | undefined;
40
47
  let reloadCount = 0;
41
48
 
42
- function startWatching(ctx: unknown): void {
49
+ function startWatching(ctx: ReloadCtx): void {
43
50
  if (!fs.existsSync(CONFIG_FILE)) return;
44
51
 
45
52
  lastKnownConfig = fs.readFileSync(CONFIG_FILE, "utf-8");
@@ -82,7 +89,7 @@ function stopWatching(): void {
82
89
  }
83
90
 
84
91
  export default function (pi: ExtensionAPI) {
85
- pi.on("session_start", async (_event: unknown, ctx: unknown) => {
92
+ pi.on("session_start", async (_event: unknown, ctx: ReloadCtx) => {
86
93
  stopWatching();
87
94
  startWatching(ctx);
88
95
  });
@@ -93,7 +100,7 @@ export default function (pi: ExtensionAPI) {
93
100
 
94
101
  pi.registerCommand("reload-config", {
95
102
  description: "Manually reload workflow config from AGENTS.md",
96
- handler: async (_args: string[], ctx: unknown) => {
103
+ handler: async (_args: string[], ctx: ReloadCtx) => {
97
104
  if (!fs.existsSync(CONFIG_FILE)) {
98
105
  ctx?.ui?.notify("No .pi/agent/AGENTS.md found.", "warning");
99
106
  return;
@@ -24,7 +24,7 @@ type ExtensionContext = {
24
24
  type ToolCallEvent = { toolName: string; toolCallId: string; input: { command: string } };
25
25
 
26
26
  type ExtensionAPI = {
27
- on(event: string, handler: (event: unknown, ctx: ExtensionContext) => void | Promise<void>): void;
27
+ on(event: string, handler: (event: unknown, ctx: ExtensionContext) => unknown | Promise<unknown>): void;
28
28
  registerTool(options: {
29
29
  name: string;
30
30
  label: string;
@@ -34,7 +34,7 @@ type ExtensionAPI = {
34
34
  toolCallId: string,
35
35
  params: Record<string, unknown>,
36
36
  signal: AbortSignal,
37
- onUpdate: (update: { type: string; message: string }) => void,
37
+ onUpdate: (update: { type?: string; message?: string; content?: unknown }) => void,
38
38
  ctx: ExtensionContext,
39
39
  ): unknown | Promise<unknown>;
40
40
  }): void;
@@ -252,7 +252,7 @@ class Curator {
252
252
  : new Date(skill.createdAt).getTime();
253
253
  const age = now - lastActivity;
254
254
 
255
- if (age > archiveThreshold && skill.state !== "archived") {
255
+ if (age > archiveThreshold) {
256
256
  if (!dryRun) {
257
257
  this.archiveSkill(name);
258
258
  }
@@ -464,6 +464,26 @@ export default function (pi: ExtensionAPI) {
464
464
  addCheck("Glossary file", false, "Not found");
465
465
  }
466
466
 
467
+ // 4b. ADR-008 modeling-depth rules (deterministic, over raw session JSON)
468
+ const depthRawPath = sessionPath.replace(/\.md$/, "") + ".raw.json";
469
+ const depthScript = path.join(ctx.cwd, ".pi", "scripts", "validate-exploration-depth.sh");
470
+ if (fs.existsSync(depthRawPath) && fs.existsSync(depthScript)) {
471
+ try {
472
+ const depthResult = await shellExec(ctx, "bash " + depthScript + " " + depthRawPath);
473
+ const lines = depthResult.stdout.trim().split("\n").filter((l) => l.trim() !== "");
474
+ const violations = lines.filter((l) => l.includes("[") && l.includes("] error:"));
475
+ addCheck(
476
+ "Modeling depth rules (ADR-008)",
477
+ depthResult.exitCode === 0,
478
+ violations.length > 0 ? violations.join(" | ") : lines.slice(-1)[0] || "",
479
+ );
480
+ } catch (err) {
481
+ addCheck("Modeling depth rules (ADR-008)", false, "Error: " + String(err));
482
+ }
483
+ } else {
484
+ addCheck("Modeling depth rules (ADR-008) - skipped", true, "no session raw.json");
485
+ }
486
+
467
487
  // 4. Source code drift
468
488
  const scriptPath = path.join(ctx.cwd, ".pi", "scripts", "validate-ubiquitous-language.sh");
469
489
  if (fs.existsSync(scriptPath)) {
@@ -988,8 +1008,35 @@ export default function (pi: ExtensionAPI) {
988
1008
  "- Current ADR-001: `.pi/architecture/decisions/ADR-001-architecture-pattern.md`",
989
1009
  "- System diagram: `.pi/architecture/diagrams/system-context.md`",
990
1010
  "- Module stubs: `.pi/architecture/modules/` (" + moduleFiles.length + " files)",
1011
+ "- ADR-008 modeling depth: `.pi/architecture/decisions/ADR-008-proportional-modeling-depth.md`",
1012
+ "- Structured session JSON (depth fields): `.pi/domain/exploration/" + sessionId + ".raw.json`",
991
1013
  "",
992
- "### STEP 1: Generate All ADRs",
1014
+ "### STEP 0: ADR-008 Modeling Depth (read first, applies everywhere)",
1015
+ "",
1016
+ "Read the `**Modeling Depth:**` header of EVERY module doc plus the structured",
1017
+ "session JSON (`.raw.json`). Enrich PROPORTIONALLY — never rewrite the depth header,",
1018
+ "never delete an existing `Modeling Depth Note (ADR-008)` section, and never invent",
1019
+ "modeling the exploration did not capture:",
1020
+ "",
1021
+ "- **tactical** (core subdomain): full DDD enrichment — aggregates as consistency",
1022
+ " boundaries with the exploration invariants (`rule` + illegalStatePrevented),",
1023
+ " behavior methods not setters, repository interface owned by the domain layer,",
1024
+ " value objects with entity-vs-VO justification, triaged domain events with payloads,",
1025
+ " and explicit domain / application / infrastructure service classification.",
1026
+ "- **service** (supporting subdomain): enrich to a Service + Persistence Contract.",
1027
+ " Do NOT expand aggregates, value objects, domain events, or API surfaces beyond",
1028
+ " what the exploration captured.",
1029
+ "- **adapter** (generic subdomain): enrich to an Interface + Anti-Corruption Layer —",
1030
+ " the narrow interface the domain consumes, the vendor/OSS choice, the ACL",
1031
+ " translation and its context-map edge. NO domain entities or aggregates.",
1032
+ "",
1033
+ "Language judgment: for Java/Spring modules apply the decision tables in the",
1034
+ "`java-spring-enterprise-codegen` skill section 10 (entity-vs-VO, service classifier,",
1035
+ "event triage, transaction placement — `@Transactional` only in application services).",
1036
+ "Diagrams and section breadth follow each module's depth (full module-level diagram",
1037
+ "set only for tactical; service = data-flow + sequence; adapter = ACL/integration).",
1038
+ "",
1039
+ "### STEP 1: Generate All ADRs",
993
1040
  "",
994
1041
  "**Do this first, before touching any module docs.** Module enrichment needs ADR references.",
995
1042
  "",
@@ -1035,8 +1082,8 @@ export default function (pi: ExtensionAPI) {
1035
1082
  "1. **## Related ADRs** — Links to ADR files with descriptions of relevance",
1036
1083
  "2. **## Diagrams** — Embed the 4 mermaid diagrams from Step 2",
1037
1084
  "3. **## Acceptance Criteria** — Add a table row for each component: | # | Component | Criterion | Verify In | with specific, testable acceptance criteria",
1038
- "5. **## Components** — Expand each aggregate with " + lang + " stubs, methods, invariants keep `status:` and `depends:` markers",
1039
- "6. **Domain Events** — Table: Event, Description, Trigger, Payload, Published By",
1085
+ "5. **## Components** — depth-aware: for tactical modules expand aggregates with " + lang + " stubs, methods, exploration invariants, VO justifications and a domain/-owned repository interface; for service/adapter modules keep only what the Modeling Depth Note permits (no invented aggregates/VOs). Always keep `status:` and `depends:` markers",
1086
+ "6. **Domain Events** (tactical modules only) — Table: Event, Description, Trigger, Payload, Published By; include ADR-008 triage flags (domain expert cares / crosses boundary / audit trail)",
1040
1087
  "7. **API Endpoints** — Table: Method, Path, Handler, Input, Output, Auth",
1041
1088
  "8. **Ubiquitous Language** — Terms for this context from `.pi/domain/ubiquitous-language.md`",
1042
1089
  "9. **Dependencies** — Depends On + Used By",
@@ -493,7 +493,7 @@ export default function (pi: ExtensionAPI) {
493
493
  })),
494
494
  ];
495
495
 
496
- const picked = await ctx.ui.custom<string | null>(
496
+ const picked = await (ctx.ui as any).custom(
497
497
  (tui, theme, _kb, done) => {
498
498
  const container = new Container();
499
499
  container.addChild(new DynamicBorder((s) => theme.fg("accent", s)));
@@ -546,7 +546,7 @@ export default function (pi: ExtensionAPI) {
546
546
  }
547
547
 
548
548
  const md = `\`\`\`diff\n${t.diff.trimEnd() || "(no diff)"}\n\`\`\``;
549
- await ctx.ui.custom<void>(
549
+ await (ctx.ui as any).custom(
550
550
  (tui, theme, _kb, done) => {
551
551
  const container = new Container();
552
552
  container.addChild(new DynamicBorder((s) => theme.fg("accent", s)));
@@ -285,9 +285,9 @@ class GoalManager {
285
285
 
286
286
  clear(): void {
287
287
  if (!this.state) return;
288
- this.state.status = "cleared";
289
- saveGoalState(this.cwd, this.state);
290
- this.state = null;
288
+ this._state.status = "cleared";
289
+ saveGoalState(this.cwd, this._state);
290
+ this._state = null;
291
291
  }
292
292
 
293
293
  addSubgoal(textIn: string): string {
@@ -52,7 +52,7 @@ type ExtensionContext = {
52
52
  };
53
53
 
54
54
  type ExtensionAPI = {
55
- on(event: string, handler: (event: unknown, ctx: ExtensionContext) => void | Promise<void>): void;
55
+ on(event: string, handler: (event: unknown, ctx: ExtensionContext) => unknown | Promise<unknown>): void;
56
56
  registerTool(options: {
57
57
  name: string;
58
58
  label: string;
@@ -0,0 +1,96 @@
1
+ // Ambient declarations for the pi runtime SDK. The host provides these at
2
+ // runtime with real types; not vendored here. Auto-generated names from
3
+ // actual imports across the extension sources so tsc type-checks cleanly.
4
+
5
+ declare module "@mariozechner/pi-coding-agent" {
6
+ export const DynamicBorder: any;
7
+ export type DynamicBorder = any;
8
+ export const ExtensionAPI: any;
9
+ export type ExtensionAPI = any;
10
+ export const ExtensionCommandContext: any;
11
+ export type ExtensionCommandContext = any;
12
+ export const ExtensionContext: any;
13
+ export type ExtensionContext = any;
14
+ export const createFindTool: any;
15
+ export type createFindTool = any;
16
+ export const createGrepTool: any;
17
+ export type createGrepTool = any;
18
+ export const createLsTool: any;
19
+ export type createLsTool = any;
20
+ export const createReadTool: any;
21
+ export type createReadTool = any;
22
+ export const getMarkdownTheme: any;
23
+ export type getMarkdownTheme = any;
24
+ export const isEditToolResult: any;
25
+ export type isEditToolResult = any;
26
+ export const isToolCallEventType: any;
27
+ export type isToolCallEventType = any;
28
+ export const isWriteToolResult: any;
29
+ export type isWriteToolResult = any;
30
+ }
31
+
32
+ declare module "@mariozechner/pi-tui" {
33
+ export const Container: any;
34
+ export type Container = any;
35
+ export const Editor: any;
36
+ export type Editor = any;
37
+ export const EditorTheme: any;
38
+ export type EditorTheme = any;
39
+ export const Key: any;
40
+ export type Key = any;
41
+ export const Markdown: any;
42
+ export type Markdown = any;
43
+ export const SelectItem: any;
44
+ export type SelectItem = any;
45
+ export const SelectList: any;
46
+ export type SelectList = any;
47
+ export const Text: any;
48
+ export type Text = any;
49
+ export const matchesKey: any;
50
+ export type matchesKey = any;
51
+ export const truncateToWidth: any;
52
+ export type truncateToWidth = any;
53
+ export const wrapTextWithAnsi: any;
54
+ export type wrapTextWithAnsi = any;
55
+ }
56
+
57
+ declare module "@earendil-works/pi-coding-agent" {
58
+ export const ExecResult: any;
59
+ export type ExecResult = any;
60
+ export const ExtensionAPI: any;
61
+ export type ExtensionAPI = any;
62
+ export const ExtensionContext: any;
63
+ export type ExtensionContext = any;
64
+ }
65
+
66
+ declare module "typebox" {
67
+ export const Type: any;
68
+ export type Type = any;
69
+ export const Static: any;
70
+ export type Static = any;
71
+ export const TObject: any;
72
+ export type TObject = any;
73
+ export const TSchema: any;
74
+ export type TSchema = any;
75
+ export const TProperties: any;
76
+ export type TProperties = any;
77
+ export const TString: any;
78
+ export type TString = any;
79
+ export const TArray: any;
80
+ export type TArray = any;
81
+ export const TOptional: any;
82
+ export type TOptional = any;
83
+ export const TBoolean: any;
84
+ export type TBoolean = any;
85
+ export const TNumber: any;
86
+ export type TNumber = any;
87
+ export const TUnion: any;
88
+ export type TUnion = any;
89
+ export const TLiteral: any;
90
+ export type TLiteral = any;
91
+ export const TRecord: any;
92
+ export type TRecord = any;
93
+ export const TAny: any;
94
+ export type TAny = any;
95
+ }
96
+ declare module "@sinclair/typebox" { export const Type: any; export type Static = any; }
@@ -256,7 +256,7 @@ class PipelineManager {
256
256
  * Reload pipeline state from disk, discarding any cached in-memory state.
257
257
  * Use this when another extension (e.g., architect) may have written state directly.
258
258
  */
259
- private reloadFromDisk(): void {
259
+ reloadFromDisk(): void {
260
260
  this.state = loadPipelineState(this.cwd);
261
261
  }
262
262
 
@@ -227,7 +227,7 @@ export default function (pi: ExtensionAPI) {
227
227
  dryRun ? "Mode: **Dry Run** (no files written)" : "Mode: **Live**",
228
228
  "",
229
229
  "```",
230
- result.trim(),
230
+ String(result).trim(),
231
231
  "```",
232
232
  "",
233
233
  dryRun
@@ -25,6 +25,8 @@ import {
25
25
  const COMMAND_NAME = "read-only";
26
26
  const STATUS_KEY = "read-only-mode";
27
27
  const WIDGET_KEY = "read-only-mode";
28
+ let readOnlyActive = false;
29
+
28
30
  const READ_ONLY_TOOL_NAMES = ["read", "grep", "find", "ls"] as const;
29
31
 
30
32
  function getReadOnlyToolNames(pi: ExtensionAPI): string[] {
@@ -95,6 +97,7 @@ export default function (pi: ExtensionAPI) {
95
97
  });
96
98
 
97
99
  function enable(ctx: ExtensionContext): void {
100
+ readOnlyActive = true;
98
101
  if (enabled) {
99
102
  updateUi(pi, ctx, enabled);
100
103
  ctx.ui.notify("Read-only mode is already enabled.", "info");
@@ -111,6 +114,7 @@ export default function (pi: ExtensionAPI) {
111
114
  }
112
115
 
113
116
  function disable(ctx: ExtensionContext): void {
117
+ readOnlyActive = false;
114
118
  if (!enabled) {
115
119
  updateUi(pi, ctx, enabled);
116
120
  ctx.ui.notify("Read-only mode is already disabled.", "info");
@@ -130,7 +134,7 @@ export default function (pi: ExtensionAPI) {
130
134
  switch (action) {
131
135
  case "":
132
136
  case "toggle":
133
- toggle(ctx);
137
+ if (readOnlyActive) disable(ctx); else enable(ctx);
134
138
  return;
135
139
  case "on":
136
140
  case "enable":
@@ -1,7 +1,11 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "types": ["bun-types"],
3
+ "types": [
4
+ "bun-types"
5
+ ],
4
6
  "strict": true,
7
+ "noImplicitAny": false,
8
+ "strictNullChecks": false,
5
9
  "target": "ES2022",
6
10
  "module": "ESNext",
7
11
  "moduleResolution": "bundler",
@@ -11,5 +15,8 @@
11
15
  "isolatedModules": true,
12
16
  "allowImportingTsExtensions": true
13
17
  },
14
- "include": ["**/*.ts"]
18
+ "include": [
19
+ "**/*.ts",
20
+ "**/*.d.ts"
21
+ ]
15
22
  }
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2026-07-20T16:02:31Z",
2
+ "timestamp": "2026-09-04T13:00:27Z",
3
3
  "mode": "all",
4
4
  "stages_run": [],
5
5
  "summary": {
@@ -72,7 +72,7 @@ Language-specific linting.
72
72
  | `unit_application` | `pytest tests/unit/application` | No |
73
73
  | `unit_contract` | `pytest tests/contract` | No |
74
74
  | `unit_verification` | `pytest tests/verification` | No |
75
- | `coverage_threshold_check` | `.pi/scripts/ci/check_coverage_thresholds.py` | No |
75
+ | `coverage_gate` | `bash .pi/scripts/install_coverage_tools.sh && bash .pi/scripts/coverage.sh --gate --lcov` | No |
76
76
 
77
77
  ## Stage 6: Integration
78
78
 
@@ -119,7 +119,7 @@ Language-specific linting.
119
119
  | Rule | Jobs Using It |
120
120
  |------|---------------|
121
121
  | `rules_default` (MRs or main branch) | Most jobs |
122
- | `rules_sonar` (requires `$SONAR_TOKEN` + `$SONAR_HOST_URL`) | coverage_report, sonar_quality_gate |
122
+ | `rules_sonar` (requires `$SONAR_TOKEN` + `$SONAR_HOST_URL`) | coverage_gate (uploads lcov artifact), sonar_quality_gate |
123
123
  | `rules_main_only` | `package_build` |
124
124
  | `rules_migration_changes` (migration file changes only) | `migration_verify` stage |
125
125
 
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env bash
2
+ # ============================================================================
3
+ # check_model_judgment.sh — ADR-008/009 dispatcher
4
+ # Runs the language-scoped model-judgment hard gates (dip-domain,
5
+ # interface-ownership, adapter-purity, transaction placement per language).
6
+ # Usage: bash .pi/scripts/check_model_judgment.sh [--root <dir>]
7
+ # ============================================================================
8
+ set -uo pipefail
9
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
10
+ ROOT="$(pwd)"
11
+ if [ "${1:-}" = "--root" ] && [ -n "${2:-}" ]; then ROOT="$2"; fi
12
+ cd "$ROOT" || exit 1
13
+
14
+ detect_language() {
15
+ if [ -f "Cargo.lock" ] || [ -f "Cargo.toml" ]; then echo "rust"
16
+ elif [ -f "package.json" ]; then echo "typescript"
17
+ elif [ -f "go.mod" ]; then echo "go"
18
+ elif [ -f "pyproject.toml" ] || [ -f "requirements.txt" ]; then echo "python"
19
+ elif [ -f "pom.xml" ] || [ -f "build.gradle" ]; then echo "java"
20
+ else echo "unknown"; fi
21
+ }
22
+ LANG="$(detect_language)"
23
+ SCRIPT="${SCRIPT_DIR}/languages/${LANG}/check_model_judgment.sh"
24
+ if [ -f "$SCRIPT" ]; then
25
+ exec bash "$SCRIPT" --root "$ROOT"
26
+ fi
27
+ echo "model-judgment: no gate script for language '${LANG}'"
28
+ exit 0
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env bash
2
+ # ============================================================================
3
+ # check_judgment_contracts.sh — proofing for ADR-008 P1 (judgment-aware
4
+ # modeling). Deterministic proof that each frozen contract (§1–§7 of
5
+ # .pi/architecture/contracts/judgment-aware-modeling-p1.md) is implemented
6
+ # in the framework sources.
7
+ #
8
+ # Checks:
9
+ # 1. exploration prompt emits ADR-008 schema markers (src)
10
+ # 2. validate-exploration-depth.sh exists + executable
11
+ # 3. java model-judgment gate exists + executable
12
+ # 4. module-doc scaffold emits 'Modeling Depth' header (src)
13
+ # 5. java-spring codegen skill carries 'Judgment Tables (ADR-008)'
14
+ # 6. architecture-validator skill carries Model Judgment Review R1-R4
15
+ # 7. modeling contracts: ModuleComponent type carries the ADR-008 fields
16
+ # 8. exploration.md template carries the Modeling Judgment section
17
+ #
18
+ # Exit 0 = all contracts proven; 1 = at least one missing.
19
+ # ============================================================================
20
+ set -uo pipefail
21
+
22
+ ROOT="$(pwd)"
23
+ if [ "${1:-}" = "--root" ] && [ -n "${2:-}" ]; then ROOT="$2"; fi
24
+ cd "$ROOT" || exit 1
25
+
26
+ FAILED=0
27
+ PASSED=0
28
+
29
+ check() { # label, file-or-dir, grep pattern
30
+ local label="$1" path="$2" pattern="$3"
31
+ if [ -n "$path" ] && [ -e "$path" ] && grep -qE "$pattern" "$path" 2>/dev/null; then
32
+ echo " PASS: $label"
33
+ PASSED=$((PASSED + 1))
34
+ else
35
+ echo " FAIL: $label (missing: $path / $pattern)" >&2
36
+ FAILED=$((FAILED + 1))
37
+ fi
38
+ }
39
+
40
+ check_file() { # label file
41
+ if [ -f "$2" ] && [ -x "$2" ]; then
42
+ echo " PASS: $1"
43
+ PASSED=$((PASSED + 1))
44
+ else
45
+ echo " FAIL: $1 (not found/executable: $2)" >&2
46
+ FAILED=$((FAILED + 1))
47
+ fi
48
+ }
49
+
50
+ echo "Judgment contracts proofing (ADR-008 P1)"
51
+ echo "----------------------------------------"
52
+
53
+ # 1. exploration prompt schema markers
54
+ check "exploration prompt: subdomainType/invariants/triage/contextMap/conflicts" \
55
+ "src/lib/domain-explorer.ts" 'subdomainType|"invariants"|"triage"|"contextMap"|"conflicts"'
56
+
57
+ # 2. depth validator present + executable
58
+ check_file "validate-exploration-depth.sh executable" ".pi/scripts/validate-exploration-depth.sh"
59
+ check_file "validate-exploration-depth.sh (templates copy)" "templates/pi/scripts/validate-exploration-depth.sh"
60
+
61
+ # 3. java model-judgment gate present + executable
62
+ check_file "java model-judgment gate" ".pi/scripts/languages/java/check_model_judgment.sh"
63
+ check_file "java model-judgment gate (templates copy)" "templates/pi/scripts/languages/java/check_model_judgment.sh"
64
+
65
+ # 4. scaffold emits Modeling Depth header + invariants + depth note
66
+ check "scaffold: Modeling Depth header" "src/lib/domain-explorer.ts" 'Modeling Depth'
67
+ check "scaffold: depth note for service/adapter" "src/lib/domain-explorer.ts" 'Modeling Depth Note \(ADR-008\)'
68
+
69
+ # 5. java-spring codegen skill: judgment tables
70
+ check "java-spring skill: Judgment Tables (ADR-008)" \
71
+ ".pi/skills/java-spring-enterprise-codegen.md" 'Judgment Tables \(ADR-008\)'
72
+
73
+ # 6. architecture-validator skill: R1-R4 review questions
74
+ check "architecture-validator skill: Model Judgment Review" \
75
+ ".pi/skills/agents/architecture-validator.md" 'Model Judgment Review'
76
+
77
+ # 7. ModuleComponent modeling-contract fields
78
+ check "architect-lib types: modelingDepth/aggregateRoot/invariants/events" \
79
+ ".pi/extensions/architect-lib/types.ts" 'modelingDepth|aggregateRoot|invariants|publishes'
80
+ check "generators: Modeling Contract emission" \
81
+ ".pi/extensions/architect-lib/generators.ts" 'Modeling Contract \(ADR-008\)'
82
+
83
+ # 8. exploration.md template: Modeling Judgment section
84
+ check "exploration.md template: Modeling Judgment section" \
85
+ "templates/pi/domain/exploration.md" 'Modeling Judgment \(ADR-008\)'
86
+
87
+ echo ""
88
+ echo " Passed: $PASSED Failed: $FAILED"
89
+ if [ "$FAILED" -gt 0 ]; then
90
+ exit 1
91
+ fi
92
+ echo "All judgment contracts proven."
93
+ exit 0
@@ -255,10 +255,10 @@ run_stage_lint() {
255
255
  log_fail "biome check" "lint errors found" "$(( $(date +%s) - t ))"
256
256
  fi
257
257
  t=$(date +%s)
258
- if biome format --check . >/dev/null 2>&1; then
259
- log_pass "biome format --check" "$(( $(date +%s) - t ))"
258
+ if biome ci . >/dev/null 2>&1; then
259
+ log_pass "biome ci" "$(( $(date +%s) - t ))"
260
260
  else
261
- log_fail "biome format --check" "format errors found" "$(( $(date +%s) - t ))"
261
+ log_fail "biome ci" "format errors found" "$(( $(date +%s) - t ))"
262
262
  fi
263
263
  else
264
264
  log_skip "biome" "not installed"
@@ -76,7 +76,7 @@ case "$STAGE" in
76
76
  ruff check . && ruff format --check .
77
77
  elif [[ -f "package.json" ]]; then
78
78
  echo "TypeScript project detected"
79
- biome check . && biome format --check .
79
+ biome check . && biome ci .
80
80
  elif [[ -f "Cargo.toml" ]]; then
81
81
  echo "Rust project detected"
82
82
  cargo clippy -- -D warnings && cargo fmt --check
@@ -72,7 +72,7 @@ case "$LANG" in
72
72
  else
73
73
  log_fail "biome lint" "Lint errors found"
74
74
  fi
75
- if biome format . --check 2>/dev/null; then
75
+ if biome ci . 2>/dev/null; then
76
76
  log_pass "biome format check"
77
77
  else
78
78
  log_fail "biome format check" "Format errors found"
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env bash
2
+ # ============================================================================
3
+ # coverage.sh — Real project coverage measurement + gate (dispatcher)
4
+ #
5
+ # Runs the project's REAL coverage tool for the detected language and reports
6
+ # line coverage. This is the honest replacement for the old per-module
7
+ # heuristic `*_coverage.sh` checks (coverage-theater — they counted test
8
+ # functions via grep, never a real percentage).
9
+ #
10
+ # Delegates to languages/<lang>/coverage.sh. Real coverage tool per language:
11
+ # rust — cargo llvm-cov (workspace line coverage, lcov artifact)
12
+ # python — coverage.py (pytest/unittest)
13
+ # typescript — vitest / jest / bun test --coverage (istanbul text)
14
+ # go — go test -coverprofile + go tool cover
15
+ # java — JaCoCo (maven/gradle)
16
+ #
17
+ # Usage:
18
+ # bash .pi/scripts/coverage.sh # measure + print summary
19
+ # bash .pi/scripts/coverage.sh --gate # exit 1 if lines < COVERAGE_THRESHOLD
20
+ # bash .pi/scripts/coverage.sh --lcov # also emit the tool's report artifact
21
+ #
22
+ # Env:
23
+ # COVERAGE_THRESHOLD minimum line-coverage % (default: 60 — a conservative
24
+ # floor; set it to the threshold your CI actually enforces)
25
+ #
26
+ # Exit codes:
27
+ # 0 — measured and (with --gate) meets threshold, or language not applicable
28
+ # 1 — coverage tool missing / below threshold / could not measure (honest
29
+ # fail — never fake-pass)
30
+ # 2 — unknown argument
31
+ # ============================================================================
32
+ set -uo pipefail
33
+
34
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
35
+
36
+ detect_language() {
37
+ if [ -f "Cargo.lock" ] || [ -f "Cargo.toml" ]; then echo "rust"
38
+ elif [ -f "poetry.lock" ] || [ -f "pyproject.toml" ] || [ -f "requirements.txt" ]; then echo "python"
39
+ elif [ -f "go.mod" ]; then echo "go"
40
+ elif [ -f "package.json" ]; then echo "typescript"
41
+ elif [ -f "pom.xml" ] || [ -f "build.gradle" ] || [ -f "build.gradle.kts" ]; then echo "java"
42
+ else echo "unknown"; fi
43
+ }
44
+
45
+ LANG="$(detect_language)"
46
+
47
+ if [ "$LANG" = "unknown" ]; then
48
+ echo "⚠️ No project language detected — no real coverage gate applies." >&2
49
+ exit 0
50
+ fi
51
+
52
+ LANG_SCRIPT="${SCRIPT_DIR}/languages/${LANG}/coverage.sh"
53
+ if [ ! -f "$LANG_SCRIPT" ]; then
54
+ echo "⚠️ No coverage gate script for '${LANG}' yet (${LANG_SCRIPT})." >&2
55
+ exit 0
56
+ fi
57
+
58
+ exec bash "$LANG_SCRIPT" "$@"