forgecraft-mcp 1.2.0 → 1.4.0

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 (185) hide show
  1. package/README.md +525 -525
  2. package/dist/artifacts/commit-hooks.d.ts +1 -1
  3. package/dist/artifacts/commit-hooks.d.ts.map +1 -1
  4. package/dist/artifacts/commit-hooks.js +2 -0
  5. package/dist/artifacts/commit-hooks.js.map +1 -1
  6. package/dist/cli/commands.d.ts +35 -1
  7. package/dist/cli/commands.d.ts.map +1 -1
  8. package/dist/cli/commands.js +109 -2
  9. package/dist/cli/commands.js.map +1 -1
  10. package/dist/cli/help.d.ts.map +1 -1
  11. package/dist/cli/help.js +51 -44
  12. package/dist/cli/help.js.map +1 -1
  13. package/dist/cli.d.ts.map +1 -1
  14. package/dist/cli.js +10 -1
  15. package/dist/cli.js.map +1 -1
  16. package/dist/registry/renderer-skeletons.js +92 -92
  17. package/dist/shared/gs-score-logger.js +6 -6
  18. package/dist/shared/result-utils.d.ts +27 -0
  19. package/dist/shared/result-utils.d.ts.map +1 -0
  20. package/dist/shared/result-utils.js +41 -0
  21. package/dist/shared/result-utils.js.map +1 -0
  22. package/dist/tools/add-module.js +123 -123
  23. package/dist/tools/advice-registry.js +18 -18
  24. package/dist/tools/check-cascade-report.js +64 -64
  25. package/dist/tools/close-cycle-helpers.d.ts +21 -2
  26. package/dist/tools/close-cycle-helpers.d.ts.map +1 -1
  27. package/dist/tools/close-cycle-helpers.js +66 -10
  28. package/dist/tools/close-cycle-helpers.js.map +1 -1
  29. package/dist/tools/close-cycle.d.ts +2 -2
  30. package/dist/tools/close-cycle.d.ts.map +1 -1
  31. package/dist/tools/close-cycle.js +1 -1
  32. package/dist/tools/close-cycle.js.map +1 -1
  33. package/dist/tools/configure-mcp.d.ts +3 -0
  34. package/dist/tools/configure-mcp.d.ts.map +1 -1
  35. package/dist/tools/configure-mcp.js +10 -0
  36. package/dist/tools/configure-mcp.js.map +1 -1
  37. package/dist/tools/consolidate-status.d.ts +81 -0
  38. package/dist/tools/consolidate-status.d.ts.map +1 -0
  39. package/dist/tools/consolidate-status.js +251 -0
  40. package/dist/tools/consolidate-status.js.map +1 -0
  41. package/dist/tools/forgecraft-dispatch.d.ts.map +1 -1
  42. package/dist/tools/forgecraft-dispatch.js +13 -0
  43. package/dist/tools/forgecraft-dispatch.js.map +1 -1
  44. package/dist/tools/forgecraft-router.d.ts +8 -0
  45. package/dist/tools/forgecraft-router.d.ts.map +1 -1
  46. package/dist/tools/forgecraft-router.js +21 -1
  47. package/dist/tools/forgecraft-router.js.map +1 -1
  48. package/dist/tools/forgecraft-schema-params.d.ts +13 -4
  49. package/dist/tools/forgecraft-schema-params.d.ts.map +1 -1
  50. package/dist/tools/forgecraft-schema-params.js +21 -0
  51. package/dist/tools/forgecraft-schema-params.js.map +1 -1
  52. package/dist/tools/forgecraft-schema.d.ts +14 -5
  53. package/dist/tools/forgecraft-schema.d.ts.map +1 -1
  54. package/dist/tools/forgecraft-schema.js +3 -0
  55. package/dist/tools/forgecraft-schema.js.map +1 -1
  56. package/dist/tools/gate-violations.d.ts +59 -0
  57. package/dist/tools/gate-violations.d.ts.map +1 -0
  58. package/dist/tools/gate-violations.js +152 -0
  59. package/dist/tools/gate-violations.js.map +1 -0
  60. package/dist/tools/generate-session-prompt.d.ts +3 -3
  61. package/dist/tools/generate-session-prompt.d.ts.map +1 -1
  62. package/dist/tools/generate-session-prompt.js +57 -15
  63. package/dist/tools/generate-session-prompt.js.map +1 -1
  64. package/dist/tools/refresh-output.js +14 -14
  65. package/dist/tools/roadmap-builder.d.ts.map +1 -1
  66. package/dist/tools/roadmap-builder.js +19 -9
  67. package/dist/tools/roadmap-builder.js.map +1 -1
  68. package/dist/tools/scaffold-spec-stubs.js +115 -115
  69. package/dist/tools/scaffold-templates.js +62 -62
  70. package/dist/tools/session-prompt-builders.d.ts.map +1 -1
  71. package/dist/tools/session-prompt-builders.js +34 -10
  72. package/dist/tools/session-prompt-builders.js.map +1 -1
  73. package/dist/tools/setup-artifact-writers.d.ts +30 -0
  74. package/dist/tools/setup-artifact-writers.d.ts.map +1 -1
  75. package/dist/tools/setup-artifact-writers.js +120 -8
  76. package/dist/tools/setup-artifact-writers.js.map +1 -1
  77. package/dist/tools/setup-phase1.d.ts +3 -0
  78. package/dist/tools/setup-phase1.d.ts.map +1 -1
  79. package/dist/tools/setup-phase1.js +79 -35
  80. package/dist/tools/setup-phase1.js.map +1 -1
  81. package/dist/tools/setup-phase2.d.ts +2 -0
  82. package/dist/tools/setup-phase2.d.ts.map +1 -1
  83. package/dist/tools/setup-phase2.js +10 -1
  84. package/dist/tools/setup-phase2.js.map +1 -1
  85. package/dist/tools/setup-project.d.ts +18 -0
  86. package/dist/tools/setup-project.d.ts.map +1 -1
  87. package/dist/tools/setup-project.js +77 -1
  88. package/dist/tools/setup-project.js.map +1 -1
  89. package/dist/tools/spec-parser-tags.d.ts +9 -0
  90. package/dist/tools/spec-parser-tags.d.ts.map +1 -1
  91. package/dist/tools/spec-parser-tags.js +92 -0
  92. package/dist/tools/spec-parser-tags.js.map +1 -1
  93. package/package.json +89 -86
  94. package/templates/analytics/instructions.yaml +37 -37
  95. package/templates/analytics/mcp-servers.yaml +11 -11
  96. package/templates/analytics/structure.yaml +25 -25
  97. package/templates/api/instructions.yaml +231 -231
  98. package/templates/api/mcp-servers.yaml +22 -13
  99. package/templates/api/nfr.yaml +23 -23
  100. package/templates/api/review.yaml +103 -103
  101. package/templates/api/structure.yaml +34 -34
  102. package/templates/api/verification.yaml +132 -132
  103. package/templates/cli/instructions.yaml +31 -31
  104. package/templates/cli/mcp-servers.yaml +11 -11
  105. package/templates/cli/review.yaml +53 -53
  106. package/templates/cli/structure.yaml +16 -16
  107. package/templates/data-lineage/instructions.yaml +28 -28
  108. package/templates/data-lineage/mcp-servers.yaml +22 -22
  109. package/templates/data-pipeline/instructions.yaml +84 -84
  110. package/templates/data-pipeline/mcp-servers.yaml +13 -13
  111. package/templates/data-pipeline/nfr.yaml +39 -39
  112. package/templates/data-pipeline/structure.yaml +23 -23
  113. package/templates/fintech/hooks.yaml +55 -55
  114. package/templates/fintech/instructions.yaml +112 -112
  115. package/templates/fintech/mcp-servers.yaml +13 -13
  116. package/templates/fintech/nfr.yaml +46 -46
  117. package/templates/fintech/playbook.yaml +210 -210
  118. package/templates/fintech/verification.yaml +239 -239
  119. package/templates/game/instructions.yaml +289 -289
  120. package/templates/game/mcp-servers.yaml +38 -38
  121. package/templates/game/nfr.yaml +64 -64
  122. package/templates/game/playbook.yaml +214 -214
  123. package/templates/game/review.yaml +97 -97
  124. package/templates/game/structure.yaml +67 -67
  125. package/templates/game/verification.yaml +174 -174
  126. package/templates/healthcare/instructions.yaml +42 -42
  127. package/templates/healthcare/mcp-servers.yaml +13 -13
  128. package/templates/healthcare/nfr.yaml +47 -47
  129. package/templates/hipaa/instructions.yaml +41 -41
  130. package/templates/hipaa/mcp-servers.yaml +13 -13
  131. package/templates/infra/instructions.yaml +104 -104
  132. package/templates/infra/mcp-servers.yaml +20 -20
  133. package/templates/infra/nfr.yaml +46 -46
  134. package/templates/infra/review.yaml +65 -65
  135. package/templates/infra/structure.yaml +25 -25
  136. package/templates/library/instructions.yaml +36 -36
  137. package/templates/library/mcp-servers.yaml +20 -20
  138. package/templates/library/review.yaml +56 -56
  139. package/templates/library/structure.yaml +19 -19
  140. package/templates/medallion-architecture/instructions.yaml +41 -41
  141. package/templates/medallion-architecture/mcp-servers.yaml +22 -22
  142. package/templates/ml/instructions.yaml +85 -85
  143. package/templates/ml/mcp-servers.yaml +11 -11
  144. package/templates/ml/nfr.yaml +39 -39
  145. package/templates/ml/structure.yaml +25 -25
  146. package/templates/ml/verification.yaml +156 -156
  147. package/templates/mobile/instructions.yaml +44 -44
  148. package/templates/mobile/mcp-servers.yaml +11 -11
  149. package/templates/mobile/nfr.yaml +49 -49
  150. package/templates/mobile/structure.yaml +27 -27
  151. package/templates/mobile/verification.yaml +121 -121
  152. package/templates/observability-xray/instructions.yaml +40 -40
  153. package/templates/observability-xray/mcp-servers.yaml +15 -15
  154. package/templates/realtime/instructions.yaml +42 -42
  155. package/templates/realtime/mcp-servers.yaml +13 -13
  156. package/templates/soc2/instructions.yaml +41 -41
  157. package/templates/soc2/mcp-servers.yaml +24 -24
  158. package/templates/social/instructions.yaml +43 -43
  159. package/templates/social/mcp-servers.yaml +24 -24
  160. package/templates/state-machine/instructions.yaml +42 -42
  161. package/templates/state-machine/mcp-servers.yaml +11 -11
  162. package/templates/tools-registry.yaml +164 -164
  163. package/templates/universal/hooks.yaml +723 -531
  164. package/templates/universal/instructions.yaml +1692 -1692
  165. package/templates/universal/mcp-servers.yaml +50 -50
  166. package/templates/universal/nfr.yaml +197 -197
  167. package/templates/universal/reference.yaml +326 -326
  168. package/templates/universal/review.yaml +204 -204
  169. package/templates/universal/skills.yaml +262 -262
  170. package/templates/universal/structure.yaml +67 -67
  171. package/templates/universal/verification.yaml +416 -416
  172. package/templates/web-react/hooks.yaml +44 -44
  173. package/templates/web-react/instructions.yaml +207 -207
  174. package/templates/web-react/mcp-servers.yaml +20 -20
  175. package/templates/web-react/nfr.yaml +27 -27
  176. package/templates/web-react/review.yaml +94 -94
  177. package/templates/web-react/structure.yaml +46 -46
  178. package/templates/web-react/verification.yaml +126 -126
  179. package/templates/web-static/instructions.yaml +115 -115
  180. package/templates/web-static/mcp-servers.yaml +20 -20
  181. package/templates/web3/instructions.yaml +44 -44
  182. package/templates/web3/mcp-servers.yaml +11 -11
  183. package/templates/web3/verification.yaml +159 -159
  184. package/templates/zero-trust/instructions.yaml +41 -41
  185. package/templates/zero-trust/mcp-servers.yaml +15 -15
@@ -11,42 +11,42 @@
11
11
  * @returns Status.md content ready to write
12
12
  */
13
13
  export function renderStatusMd(context) {
14
- return `# Status.md
15
-
16
- ## Last Updated: ${new Date().toISOString().split("T")[0]}
17
- ## Session Summary
18
- Project initialized with ForgeCraft. Tags: ${context.tags.join(", ")}.
19
-
20
- ## Project Structure
21
- \`\`\`
22
- [Run 'tree -L 3 --dirsfirst' to populate]
23
- \`\`\`
24
-
25
- ## Feature Tracker
26
- | Feature | Status | Branch | Notes |
27
- |---------|--------|--------|-------|
28
- | | ⬚ Not Started | | |
29
-
30
- ## Known Bugs
31
- | ID | Description | Severity | Status |
32
- |----|-------------|----------|--------|
33
- | | | | |
34
-
35
- ## Technical Debt
36
- | Item | Impact | Effort | Priority |
37
- |------|--------|--------|----------|
38
- | | | | |
39
-
40
- ## Current Context
41
- - Working on:
42
- - Blocked by:
43
- - Decisions pending:
44
- - Next steps:
45
-
46
- ## Architecture Decision Log
47
- | Date | Decision | Rationale | Status |
48
- |------|----------|-----------|--------|
49
- | | | | |
14
+ return `# Status.md
15
+
16
+ ## Last Updated: ${new Date().toISOString().split("T")[0]}
17
+ ## Session Summary
18
+ Project initialized with ForgeCraft. Tags: ${context.tags.join(", ")}.
19
+
20
+ ## Project Structure
21
+ \`\`\`
22
+ [Run 'tree -L 3 --dirsfirst' to populate]
23
+ \`\`\`
24
+
25
+ ## Feature Tracker
26
+ | Feature | Status | Branch | Notes |
27
+ |---------|--------|--------|-------|
28
+ | | ⬚ Not Started | | |
29
+
30
+ ## Known Bugs
31
+ | ID | Description | Severity | Status |
32
+ |----|-------------|----------|--------|
33
+ | | | | |
34
+
35
+ ## Technical Debt
36
+ | Item | Impact | Effort | Priority |
37
+ |------|--------|--------|----------|
38
+ | | | | |
39
+
40
+ ## Current Context
41
+ - Working on:
42
+ - Blocked by:
43
+ - Decisions pending:
44
+ - Next steps:
45
+
46
+ ## Architecture Decision Log
47
+ | Date | Decision | Rationale | Status |
48
+ |------|----------|-----------|--------|
49
+ | | | | |
50
50
  `;
51
51
  }
52
52
  /**
@@ -56,33 +56,33 @@ Project initialized with ForgeCraft. Tags: ${context.tags.join(", ")}.
56
56
  * @returns PRD.md content ready to write
57
57
  */
58
58
  export function renderPrdSkeleton(context) {
59
- return `# PRD: ${context.projectName}
60
-
61
- ## Background & Context
62
- [Why this project exists, what problem it solves]
63
-
64
- ## Stakeholders
65
- [Who owns it, who uses it, who's affected]
66
-
67
- ## User Stories
68
- [Organized by feature area]
69
- - US-001: As a [type], I want [action] so that [benefit]
70
-
71
- ## Requirements
72
- ### Functional Requirements
73
- - FR-001: [requirement]
74
-
75
- ### Non-Functional Requirements
76
- [Generated from active tags: ${context.tags.join(", ")}]
77
-
78
- ## Out of Scope
79
- [Explicitly list what this project does NOT do]
80
-
81
- ## Success Metrics
82
- [How do we know this project succeeded?]
83
-
84
- ## Open Questions
85
- [Unresolved decisions]
59
+ return `# PRD: ${context.projectName}
60
+
61
+ ## Background & Context
62
+ [Why this project exists, what problem it solves]
63
+
64
+ ## Stakeholders
65
+ [Who owns it, who uses it, who's affected]
66
+
67
+ ## User Stories
68
+ [Organized by feature area]
69
+ - US-001: As a [type], I want [action] so that [benefit]
70
+
71
+ ## Requirements
72
+ ### Functional Requirements
73
+ - FR-001: [requirement]
74
+
75
+ ### Non-Functional Requirements
76
+ [Generated from active tags: ${context.tags.join(", ")}]
77
+
78
+ ## Out of Scope
79
+ [Explicitly list what this project does NOT do]
80
+
81
+ ## Success Metrics
82
+ [How do we know this project succeeded?]
83
+
84
+ ## Open Questions
85
+ [Unresolved decisions]
86
86
  `;
87
87
  }
88
88
  /**
@@ -92,35 +92,35 @@ export function renderPrdSkeleton(context) {
92
92
  * @returns TechSpec.md content ready to write
93
93
  */
94
94
  export function renderTechSpecSkeleton(context) {
95
- return `# Tech Spec: ${context.projectName}
96
-
97
- ## Overview
98
- [One paragraph translating PRD to technical approach]
99
-
100
- ## Architecture
101
- ### System Diagram
102
- [Mermaid diagram or description of components]
103
-
104
- ### Tech Stack
105
- - Runtime: ${context.language}
106
- - Framework: ${context.framework ?? "[TBD]"}
107
-
108
- ### Data Flow
109
- [How data moves through the system]
110
-
111
- ## API Contracts
112
- [Key endpoints, request/response shapes]
113
-
114
- ## Security & Compliance
115
- [Auth approach, encryption, audit logging]
116
-
117
- ## Dependencies
118
- [External services, APIs, libraries with version pins]
119
-
120
- ## Risks & Mitigations
121
- | Risk | Likelihood | Impact | Mitigation |
122
- |------|-----------|--------|------------|
123
- | | H/M/L | H/M/L | |
95
+ return `# Tech Spec: ${context.projectName}
96
+
97
+ ## Overview
98
+ [One paragraph translating PRD to technical approach]
99
+
100
+ ## Architecture
101
+ ### System Diagram
102
+ [Mermaid diagram or description of components]
103
+
104
+ ### Tech Stack
105
+ - Runtime: ${context.language}
106
+ - Framework: ${context.framework ?? "[TBD]"}
107
+
108
+ ### Data Flow
109
+ [How data moves through the system]
110
+
111
+ ## API Contracts
112
+ [Key endpoints, request/response shapes]
113
+
114
+ ## Security & Compliance
115
+ [Auth approach, encryption, audit logging]
116
+
117
+ ## Dependencies
118
+ [External services, APIs, libraries with version pins]
119
+
120
+ ## Risks & Mitigations
121
+ | Risk | Likelihood | Impact | Mitigation |
122
+ |------|-----------|--------|------------|
123
+ | | H/M/L | H/M/L | |
124
124
  `;
125
125
  }
126
126
  //# sourceMappingURL=renderer-skeletons.js.map
@@ -11,12 +11,12 @@ import { appendFileSync, existsSync, mkdirSync, writeFileSync } from "fs";
11
11
  import { join } from "path";
12
12
  // ── Constants ────────────────────────────────────────────────────────
13
13
  const GS_SCORE_FILE = "docs/gs-score.md";
14
- const GS_SCORE_HEADER = `# GS Score Log
15
-
16
- Tracks S_realized and GS property scores per loop.
17
-
18
- | date | loop | roadmap_item | s_realized | self-describing | bounded | verifiable | defended | auditable | composable | executable |
19
- |------|------|--------------|------------|-----------------|---------|-----------|----------|-----------|-----------|-----------|
14
+ const GS_SCORE_HEADER = `# GS Score Log
15
+
16
+ Tracks S_realized and GS property scores per loop.
17
+
18
+ | date | loop | roadmap_item | s_realized | self-describing | bounded | verifiable | defended | auditable | composable | executable |
19
+ |------|------|--------------|------------|-----------------|---------|-----------|----------|-----------|-----------|-----------|
20
20
  `;
21
21
  const GS_PROPERTY_ORDER = [
22
22
  "self-describing",
@@ -0,0 +1,27 @@
1
+ /**
2
+ * MCP tool result size utilities.
3
+ *
4
+ * Prevents silent schema truncation at the MCP transport layer by:
5
+ * - Annotating large results with their size (chars + lines)
6
+ * - Truncating results that exceed the limit with an explicit marker
7
+ * so the caller knows to refine their query rather than acting on
8
+ * incomplete data.
9
+ */
10
+ /** Maximum characters returned in a single tool result. */
11
+ export declare const MAX_TOOL_RESULT_CHARS = 50000;
12
+ /**
13
+ * Annotate a tool result text with its size and truncate if necessary.
14
+ *
15
+ * - Under `maxChars` and over `SIZE_ANNOTATION_THRESHOLD`: appends a compact
16
+ * footer showing char/line count.
17
+ * - Over `maxChars`: truncates to `maxChars` and appends a `[TRUNCATED]`
18
+ * footer so the caller knows the response is incomplete.
19
+ * - Under `SIZE_ANNOTATION_THRESHOLD`: returned as-is (no footer noise for
20
+ * short replies like "No violations recorded.").
21
+ *
22
+ * @param text - Raw tool result text
23
+ * @param maxChars - Truncation limit (default: MAX_TOOL_RESULT_CHARS)
24
+ * @returns Annotated (and possibly truncated) text
25
+ */
26
+ export declare function annotateResult(text: string, maxChars?: number): string;
27
+ //# sourceMappingURL=result-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result-utils.d.ts","sourceRoot":"","sources":["../../src/shared/result-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,2DAA2D;AAC3D,eAAO,MAAM,qBAAqB,QAAS,CAAC;AAK5C;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,QAAQ,GAAE,MAA8B,GACvC,MAAM,CAgBR"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * MCP tool result size utilities.
3
+ *
4
+ * Prevents silent schema truncation at the MCP transport layer by:
5
+ * - Annotating large results with their size (chars + lines)
6
+ * - Truncating results that exceed the limit with an explicit marker
7
+ * so the caller knows to refine their query rather than acting on
8
+ * incomplete data.
9
+ */
10
+ /** Maximum characters returned in a single tool result. */
11
+ export const MAX_TOOL_RESULT_CHARS = 50_000;
12
+ /** Minimum size (chars) before a size annotation is appended. */
13
+ const SIZE_ANNOTATION_THRESHOLD = 1_000;
14
+ /**
15
+ * Annotate a tool result text with its size and truncate if necessary.
16
+ *
17
+ * - Under `maxChars` and over `SIZE_ANNOTATION_THRESHOLD`: appends a compact
18
+ * footer showing char/line count.
19
+ * - Over `maxChars`: truncates to `maxChars` and appends a `[TRUNCATED]`
20
+ * footer so the caller knows the response is incomplete.
21
+ * - Under `SIZE_ANNOTATION_THRESHOLD`: returned as-is (no footer noise for
22
+ * short replies like "No violations recorded.").
23
+ *
24
+ * @param text - Raw tool result text
25
+ * @param maxChars - Truncation limit (default: MAX_TOOL_RESULT_CHARS)
26
+ * @returns Annotated (and possibly truncated) text
27
+ */
28
+ export function annotateResult(text, maxChars = MAX_TOOL_RESULT_CHARS) {
29
+ const total = text.length;
30
+ if (total <= SIZE_ANNOTATION_THRESHOLD)
31
+ return text;
32
+ if (total <= maxChars) {
33
+ const lines = text.split("\n").length;
34
+ return `${text}\n\n---\n_↩ ${total.toLocaleString()} chars · ${lines.toLocaleString()} lines_`;
35
+ }
36
+ const truncated = text.slice(0, maxChars);
37
+ return (`${truncated}\n\n---\n` +
38
+ `_[TRUNCATED: showing first ${maxChars.toLocaleString()} of ${total.toLocaleString()} chars — ` +
39
+ `use a more specific query or smaller scope to see the rest]_`);
40
+ }
41
+ //# sourceMappingURL=result-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result-utils.js","sourceRoot":"","sources":["../../src/shared/result-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,2DAA2D;AAC3D,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAE5C,iEAAiE;AACjE,MAAM,yBAAyB,GAAG,KAAK,CAAC;AAExC;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,cAAc,CAC5B,IAAY,EACZ,WAAmB,qBAAqB;IAExC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC;IAE1B,IAAI,KAAK,IAAI,yBAAyB;QAAE,OAAO,IAAI,CAAC;IAEpD,IAAI,KAAK,IAAI,QAAQ,EAAE,CAAC;QACtB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;QACtC,OAAO,GAAG,IAAI,eAAe,KAAK,CAAC,cAAc,EAAE,YAAY,KAAK,CAAC,cAAc,EAAE,SAAS,CAAC;IACjG,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAC1C,OAAO,CACL,GAAG,SAAS,WAAW;QACvB,8BAA8B,QAAQ,CAAC,cAAc,EAAE,OAAO,KAAK,CAAC,cAAc,EAAE,WAAW;QAC/F,8DAA8D,CAC/D,CAAC;AACJ,CAAC"}
@@ -60,97 +60,97 @@ function generateTypeScriptModule(moduleDir, moduleName, className, tags) {
60
60
  const files = [];
61
61
  const relBase = `src/modules/${moduleName}`;
62
62
  // Types
63
- const typesContent = `/**
64
- * ${className} module types.
65
- */
66
-
67
- export interface ${className} {
68
- readonly id: string;
69
- // TODO: Define ${className} properties
70
- }
71
-
72
- export interface Create${className}Input {
73
- // TODO: Define creation input
74
- }
75
-
76
- export interface Update${className}Input {
77
- readonly id: string;
78
- // TODO: Define update input
79
- }
63
+ const typesContent = `/**
64
+ * ${className} module types.
65
+ */
66
+
67
+ export interface ${className} {
68
+ readonly id: string;
69
+ // TODO: Define ${className} properties
70
+ }
71
+
72
+ export interface Create${className}Input {
73
+ // TODO: Define creation input
74
+ }
75
+
76
+ export interface Update${className}Input {
77
+ readonly id: string;
78
+ // TODO: Define update input
79
+ }
80
80
  `;
81
81
  writeFileSync(join(moduleDir, "types.ts"), typesContent);
82
82
  files.push(`${relBase}/types.ts`);
83
83
  // Interface
84
- const interfaceContent = `/**
85
- * ${className} service interface.
86
- *
87
- * Defines the contract — implementations are swappable.
88
- */
89
-
90
- import type { ${className}, Create${className}Input, Update${className}Input } from "./types.js";
91
-
92
- export interface I${className}Service {
93
- create(input: Create${className}Input): Promise<${className}>;
94
- findById(id: string): Promise<${className} | null>;
95
- update(input: Update${className}Input): Promise<${className}>;
96
- delete(id: string): Promise<void>;
97
- }
84
+ const interfaceContent = `/**
85
+ * ${className} service interface.
86
+ *
87
+ * Defines the contract — implementations are swappable.
88
+ */
89
+
90
+ import type { ${className}, Create${className}Input, Update${className}Input } from "./types.js";
91
+
92
+ export interface I${className}Service {
93
+ create(input: Create${className}Input): Promise<${className}>;
94
+ findById(id: string): Promise<${className} | null>;
95
+ update(input: Update${className}Input): Promise<${className}>;
96
+ delete(id: string): Promise<void>;
97
+ }
98
98
  `;
99
99
  writeFileSync(join(moduleDir, "interface.ts"), interfaceContent);
100
100
  files.push(`${relBase}/interface.ts`);
101
101
  // Service implementation
102
- const serviceContent = `/**
103
- * ${className} service implementation.
104
- */
105
-
106
- import type { ${className}, Create${className}Input, Update${className}Input } from "./types.js";
107
- import type { I${className}Service } from "./interface.js";
108
-
109
- export class ${className}Service implements I${className}Service {
110
- async create(input: Create${className}Input): Promise<${className}> {
111
- // TODO: Implement creation logic
112
- throw new Error("Not implemented");
113
- }
114
-
115
- async findById(id: string): Promise<${className} | null> {
116
- // TODO: Implement find logic
117
- throw new Error("Not implemented");
118
- }
119
-
120
- async update(input: Update${className}Input): Promise<${className}> {
121
- // TODO: Implement update logic
122
- throw new Error("Not implemented");
123
- }
124
-
125
- async delete(id: string): Promise<void> {
126
- // TODO: Implement delete logic
127
- throw new Error("Not implemented");
128
- }
129
- }
102
+ const serviceContent = `/**
103
+ * ${className} service implementation.
104
+ */
105
+
106
+ import type { ${className}, Create${className}Input, Update${className}Input } from "./types.js";
107
+ import type { I${className}Service } from "./interface.js";
108
+
109
+ export class ${className}Service implements I${className}Service {
110
+ async create(input: Create${className}Input): Promise<${className}> {
111
+ // TODO: Implement creation logic
112
+ throw new Error("Not implemented");
113
+ }
114
+
115
+ async findById(id: string): Promise<${className} | null> {
116
+ // TODO: Implement find logic
117
+ throw new Error("Not implemented");
118
+ }
119
+
120
+ async update(input: Update${className}Input): Promise<${className}> {
121
+ // TODO: Implement update logic
122
+ throw new Error("Not implemented");
123
+ }
124
+
125
+ async delete(id: string): Promise<void> {
126
+ // TODO: Implement delete logic
127
+ throw new Error("Not implemented");
128
+ }
129
+ }
130
130
  `;
131
131
  writeFileSync(join(moduleDir, "service.ts"), serviceContent);
132
132
  files.push(`${relBase}/service.ts`);
133
133
  // Index barrel
134
- const indexContent = `export type { ${className}, Create${className}Input, Update${className}Input } from "./types.js";
135
- export type { I${className}Service } from "./interface.js";
136
- export { ${className}Service } from "./service.js";
134
+ const indexContent = `export type { ${className}, Create${className}Input, Update${className}Input } from "./types.js";
135
+ export type { I${className}Service } from "./interface.js";
136
+ export { ${className}Service } from "./service.js";
137
137
  `;
138
138
  writeFileSync(join(moduleDir, "index.ts"), indexContent);
139
139
  files.push(`${relBase}/index.ts`);
140
140
  // API routes if API tag present
141
141
  if (tags.includes("API")) {
142
- const routesContent = `/**
143
- * ${className} API routes.
144
- */
145
-
146
- // TODO: Register routes with your HTTP framework
147
- // Example:
148
- // router.post("/${moduleName}", create${className}Handler);
149
- // router.get("/${moduleName}/:id", get${className}Handler);
150
- // router.put("/${moduleName}/:id", update${className}Handler);
151
- // router.delete("/${moduleName}/:id", delete${className}Handler);
152
-
153
- export {};
142
+ const routesContent = `/**
143
+ * ${className} API routes.
144
+ */
145
+
146
+ // TODO: Register routes with your HTTP framework
147
+ // Example:
148
+ // router.post("/${moduleName}", create${className}Handler);
149
+ // router.get("/${moduleName}/:id", get${className}Handler);
150
+ // router.put("/${moduleName}/:id", update${className}Handler);
151
+ // router.delete("/${moduleName}/:id", delete${className}Handler);
152
+
153
+ export {};
154
154
  `;
155
155
  writeFileSync(join(moduleDir, "routes.ts"), routesContent);
156
156
  files.push(`${relBase}/routes.ts`);
@@ -158,17 +158,17 @@ export {};
158
158
  // Test file
159
159
  const testDir = join(moduleDir, "__tests__");
160
160
  mkdirSync(testDir, { recursive: true });
161
- const testContent = `import { describe, it, expect } from "vitest";
162
- import { ${className}Service } from "../service.js";
163
-
164
- describe("${className}Service", () => {
165
- it("should be defined", () => {
166
- const service = new ${className}Service();
167
- expect(service).toBeDefined();
168
- });
169
-
170
- // TODO: Add comprehensive tests
171
- });
161
+ const testContent = `import { describe, it, expect } from "vitest";
162
+ import { ${className}Service } from "../service.js";
163
+
164
+ describe("${className}Service", () => {
165
+ it("should be defined", () => {
166
+ const service = new ${className}Service();
167
+ expect(service).toBeDefined();
168
+ });
169
+
170
+ // TODO: Add comprehensive tests
171
+ });
172
172
  `;
173
173
  writeFileSync(join(testDir, `${moduleName}.test.ts`), testContent);
174
174
  files.push(`${relBase}/__tests__/${moduleName}.test.ts`);
@@ -185,48 +185,48 @@ function generatePythonModule(moduleDir, moduleName, className, _tags) {
185
185
  writeFileSync(join(moduleDir, "__init__.py"), `"""${className} module."""\n`);
186
186
  files.push(`${relBase}/__init__.py`);
187
187
  // models.py
188
- const modelsContent = `"""${className} data models."""
189
-
190
- from dataclasses import dataclass
191
-
192
-
193
- @dataclass
194
- class ${className}:
195
- id: str
196
- # TODO: Define ${className} fields
197
-
198
-
199
- @dataclass
200
- class Create${className}Input:
201
- # TODO: Define creation input
202
- pass
203
-
204
-
205
- @dataclass
206
- class Update${className}Input:
207
- id: str
208
- # TODO: Define update input
188
+ const modelsContent = `"""${className} data models."""
189
+
190
+ from dataclasses import dataclass
191
+
192
+
193
+ @dataclass
194
+ class ${className}:
195
+ id: str
196
+ # TODO: Define ${className} fields
197
+
198
+
199
+ @dataclass
200
+ class Create${className}Input:
201
+ # TODO: Define creation input
202
+ pass
203
+
204
+
205
+ @dataclass
206
+ class Update${className}Input:
207
+ id: str
208
+ # TODO: Define update input
209
209
  `;
210
210
  writeFileSync(join(moduleDir, "models.py"), modelsContent);
211
211
  files.push(`${relBase}/models.py`);
212
212
  // service.py
213
- const serviceContent = `"""${className} service."""
214
-
215
- from .models import ${className}, Create${className}Input, Update${className}Input
216
-
217
-
218
- class ${className}Service:
219
- async def create(self, input: Create${className}Input) -> ${className}:
220
- raise NotImplementedError
221
-
222
- async def find_by_id(self, id: str) -> ${className} | None:
223
- raise NotImplementedError
224
-
225
- async def update(self, input: Update${className}Input) -> ${className}:
226
- raise NotImplementedError
227
-
228
- async def delete(self, id: str) -> None:
229
- raise NotImplementedError
213
+ const serviceContent = `"""${className} service."""
214
+
215
+ from .models import ${className}, Create${className}Input, Update${className}Input
216
+
217
+
218
+ class ${className}Service:
219
+ async def create(self, input: Create${className}Input) -> ${className}:
220
+ raise NotImplementedError
221
+
222
+ async def find_by_id(self, id: str) -> ${className} | None:
223
+ raise NotImplementedError
224
+
225
+ async def update(self, input: Update${className}Input) -> ${className}:
226
+ raise NotImplementedError
227
+
228
+ async def delete(self, id: str) -> None:
229
+ raise NotImplementedError
230
230
  `;
231
231
  writeFileSync(join(moduleDir, "service.py"), serviceContent);
232
232
  files.push(`${relBase}/service.py`);
@@ -189,24 +189,24 @@ export function smokeConfigExample(tags) {
189
189
  if (hasApi) {
190
190
  projects.push(" // API smoke uses APIRequestContext — no browser project needed");
191
191
  }
192
- return `
193
- ## Example: playwright.smoke.config.ts
194
-
195
- \`\`\`typescript
196
- import { defineConfig${hasBrowser ? ", devices" : ""} } from '@playwright/test';
197
-
198
- export default defineConfig({
199
- testMatch: '**/*.smoke.ts',
200
- retries: 1, // one retry — smoke fail = broken deploy
201
- timeout: 15_000,
202
- use: {
203
- baseURL: process.env['PLAYWRIGHT_BASE_URL'] ?? 'http://localhost:3000',
204
- // Never run smoke against localhost in CI — use staging URL
205
- },${hasBrowser ? `\n projects: [\n${projects.join(",\n")}\n ],` : ""}
206
- });
207
- \`\`\`
208
-
209
- Run with: \`npx playwright test --config playwright.smoke.config.ts\`
192
+ return `
193
+ ## Example: playwright.smoke.config.ts
194
+
195
+ \`\`\`typescript
196
+ import { defineConfig${hasBrowser ? ", devices" : ""} } from '@playwright/test';
197
+
198
+ export default defineConfig({
199
+ testMatch: '**/*.smoke.ts',
200
+ retries: 1, // one retry — smoke fail = broken deploy
201
+ timeout: 15_000,
202
+ use: {
203
+ baseURL: process.env['PLAYWRIGHT_BASE_URL'] ?? 'http://localhost:3000',
204
+ // Never run smoke against localhost in CI — use staging URL
205
+ },${hasBrowser ? `\n projects: [\n${projects.join(",\n")}\n ],` : ""}
206
+ });
207
+ \`\`\`
208
+
209
+ Run with: \`npx playwright test --config playwright.smoke.config.ts\`
210
210
  `;
211
211
  }
212
212
  //# sourceMappingURL=advice-registry.js.map