@boyingliu01/xp-gate 0.18.5 → 0.19.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 (254) hide show
  1. package/adapter-common.sh +27 -0
  2. package/adapters/gate-3.sh +0 -0
  3. package/adapters/gate-4.sh +0 -0
  4. package/adapters/gate-7.sh +0 -0
  5. package/adapters/gate-8.sh +0 -0
  6. package/adapters/gate-9.sh +0 -0
  7. package/adapters/powershell.sh +85 -33
  8. package/adapters/typescript.sh +8 -8
  9. package/build-integrity/__tests__/import-resolver.test.ts +22 -0
  10. package/build-integrity/__tests__/orchestrator.test.ts +1 -2
  11. package/build-integrity/gate-10.ts +7 -0
  12. package/gate-12-file-hygiene.sh +230 -0
  13. package/hooks/adapter-common.sh +27 -0
  14. package/hooks/gate-10.sh +105 -0
  15. package/hooks/gate-12-file-hygiene.sh +0 -0
  16. package/hooks/lib/validate-code-walkthrough.cjs +125 -0
  17. package/hooks/pre-commit +130 -33
  18. package/hooks/pre-push +15 -91
  19. package/lib/__tests__/check-version.test.js +67 -46
  20. package/lib/__tests__/doctor.test.js +7 -6
  21. package/lib/__tests__/gate-runner.test.js +267 -0
  22. package/lib/__tests__/init.test.js +32 -0
  23. package/lib/__tests__/npm-package.test.js +13 -0
  24. package/lib/__tests__/phase-transition.test.js +604 -12
  25. package/lib/__tests__/sprint-discovery.test.ts +0 -1
  26. package/lib/__tests__/sprint-status-rework.test.js +100 -1
  27. package/lib/__tests__/update-hooks.test.js +143 -10
  28. package/lib/__tests__/upgrade-exec.test.js +73 -45
  29. package/lib/__tests__/upgrade-skill-sync.test.js +1 -1
  30. package/lib/__tests__/upgrade.test.js +12 -11
  31. package/lib/doctor.js +2 -1
  32. package/lib/gate-runner.js +68 -23
  33. package/lib/init.js +34 -5
  34. package/lib/install-skill.js +1 -0
  35. package/lib/mattpocock-license-verdict.json +1 -1
  36. package/lib/phase-transition.js +203 -23
  37. package/lib/shared-paths.js +2 -0
  38. package/lib/sprint-status.js +15 -4
  39. package/lib/test-alignment.ts +3 -13
  40. package/lib/update-hooks.js +129 -15
  41. package/mock-policy/AGENTS.md +5 -5
  42. package/mock-policy/__tests__/gate-m3.test.ts +0 -5
  43. package/mock-policy/__tests__/scope-scanner.test.ts +8 -2
  44. package/mutation/AGENTS.md +4 -4
  45. package/mutation/__tests__/mutmut-runner.test.ts +443 -2
  46. package/mutation/__tests__/update-baseline.test.ts +0 -2
  47. package/mutation/runners/mutmut-runner.ts +67 -17
  48. package/package.json +9 -3
  49. package/plugins/claude-code/.claude-plugin/plugin.json +1 -1
  50. package/plugins/claude-code/skills/clipboard-vision/SKILL.md +47 -0
  51. package/plugins/claude-code/skills/clipboard-vision/__tests__/clipboard-vision-distribution.test.cjs +65 -0
  52. package/plugins/claude-code/skills/clipboard-vision/__tests__/clipboard-vision-security.test.cjs +185 -0
  53. package/plugins/claude-code/skills/clipboard-vision/__tests__/clipboard-vision.Tests.ps1 +138 -0
  54. package/plugins/claude-code/skills/clipboard-vision/__tests__/clipboard-vision.test.cjs +273 -0
  55. package/plugins/claude-code/skills/clipboard-vision/describe-clipboard.ps1 +115 -0
  56. package/plugins/claude-code/skills/clipboard-vision/describe-clipboard.sh +161 -0
  57. package/plugins/claude-code/skills/clipboard-vision/scripts/clipboard-vision.ps1 +86 -0
  58. package/plugins/claude-code/skills/clipboard-vision/scripts/clipboard-vision.sh +137 -0
  59. package/plugins/claude-code/skills/delphi-review/.delphi-config.json.example +24 -27
  60. package/plugins/claude-code/skills/delphi-review/AGENTS.md +13 -12
  61. package/plugins/claude-code/skills/delphi-review/INSTALL.md +15 -17
  62. package/plugins/claude-code/skills/delphi-review/SKILL.md +30 -29
  63. package/plugins/claude-code/skills/delphi-review/opencode.json.delphi.example +6 -10
  64. package/plugins/claude-code/skills/delphi-review/references/code-walkthrough.md +33 -49
  65. package/plugins/claude-code/skills/delphi-review/references/requirements.md +66 -54
  66. package/plugins/claude-code/skills/delphi-review/references/round-templates.md +7 -7
  67. package/plugins/claude-code/skills/sprint-flow/AGENTS.md +5 -5
  68. package/plugins/claude-code/skills/sprint-flow/SKILL.md +4 -4
  69. package/plugins/claude-code/skills/sprint-flow/references/components/skill-invocations.md +2 -2
  70. package/plugins/claude-code/skills/sprint-flow/references/force-levels.md +37 -35
  71. package/plugins/claude-code/skills/sprint-flow/references/orchestration-rules.md +1 -1
  72. package/plugins/claude-code/skills/sprint-flow/references/phase-1-prep.md +1 -1
  73. package/plugins/claude-code/skills/sprint-flow/references/phase-2-design.md +24 -14
  74. package/plugins/claude-code/skills/sprint-flow/references/phase-4-verify.md +6 -6
  75. package/plugins/claude-code/skills/sprint-flow/references/phase-overview.md +2 -2
  76. package/plugins/claude-code/skills/test-specification-alignment/AGENTS.md +4 -4
  77. package/plugins/dsh/README.md +25 -0
  78. package/plugins/dsh/cordis.patch.yml +7 -0
  79. package/plugins/dsh/package.json +70 -0
  80. package/plugins/dsh/scripts/prepack.cjs +82 -0
  81. package/plugins/dsh/skills/admin-template-guidelines/SKILL.md +113 -0
  82. package/plugins/dsh/skills/admin-template-guidelines/references/rule-1.md +91 -0
  83. package/plugins/dsh/skills/admin-template-guidelines/references/rule-2.md +155 -0
  84. package/plugins/dsh/skills/admin-template-guidelines/references/rule-3.md +70 -0
  85. package/plugins/dsh/skills/admin-template-guidelines/references/rule-4.md +154 -0
  86. package/plugins/dsh/skills/admin-template-guidelines/references/rule-5.md +126 -0
  87. package/plugins/dsh/skills/admin-template-guidelines/references/rule-6.md +180 -0
  88. package/plugins/dsh/skills/batch-grill-me/SKILL.md +15 -0
  89. package/plugins/dsh/skills/clipboard-vision/SKILL.md +47 -0
  90. package/plugins/dsh/skills/clipboard-vision/__tests__/clipboard-vision-distribution.test.cjs +65 -0
  91. package/plugins/dsh/skills/clipboard-vision/__tests__/clipboard-vision-security.test.cjs +185 -0
  92. package/plugins/dsh/skills/clipboard-vision/__tests__/clipboard-vision.Tests.ps1 +138 -0
  93. package/plugins/dsh/skills/clipboard-vision/__tests__/clipboard-vision.test.cjs +273 -0
  94. package/plugins/dsh/skills/clipboard-vision/describe-clipboard.ps1 +115 -0
  95. package/plugins/dsh/skills/clipboard-vision/describe-clipboard.sh +161 -0
  96. package/plugins/dsh/skills/clipboard-vision/scripts/clipboard-vision.ps1 +86 -0
  97. package/plugins/dsh/skills/clipboard-vision/scripts/clipboard-vision.sh +137 -0
  98. package/plugins/dsh/skills/delphi-review/.delphi-config.json.example +70 -0
  99. package/plugins/dsh/skills/delphi-review/AGENTS.md +67 -0
  100. package/plugins/dsh/skills/delphi-review/INSTALL.md +150 -0
  101. package/plugins/dsh/skills/delphi-review/SKILL.md +559 -0
  102. package/plugins/dsh/skills/delphi-review/hooks.md +19 -0
  103. package/plugins/dsh/skills/delphi-review/opencode.json.delphi.example +52 -0
  104. package/plugins/dsh/skills/delphi-review/references/code-walkthrough.md +470 -0
  105. package/plugins/dsh/skills/delphi-review/references/orchestrator-dispatch.md +64 -0
  106. package/plugins/dsh/skills/delphi-review/references/requirements.md +402 -0
  107. package/plugins/dsh/skills/delphi-review/references/round-templates.md +134 -0
  108. package/plugins/dsh/skills/delphi-review/scripts/verify-consensus.sh +43 -0
  109. package/plugins/dsh/skills/delphi-review/tools.md +29 -0
  110. package/plugins/dsh/skills/domain-modeling/ADR-FORMAT.md +64 -0
  111. package/plugins/dsh/skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
  112. package/plugins/dsh/skills/domain-modeling/SKILL.md +74 -0
  113. package/plugins/dsh/skills/grill-with-docs/SKILL.md +7 -0
  114. package/plugins/dsh/skills/grilling/SKILL.md +12 -0
  115. package/plugins/dsh/skills/improve-codebase-architecture/SKILL.md +156 -0
  116. package/plugins/dsh/skills/ralph-loop/SKILL.md +198 -0
  117. package/plugins/dsh/skills/ralph-loop/references/components.md +113 -0
  118. package/plugins/dsh/skills/ralph-loop/references/phase-2-build-ralph.md +89 -0
  119. package/plugins/dsh/skills/ralph-loop/references/workflow-details.md +99 -0
  120. package/plugins/dsh/skills/ralph-loop/templates/progress-log.md +36 -0
  121. package/plugins/dsh/skills/sprint-flow/AGENTS.md +103 -0
  122. package/plugins/dsh/skills/sprint-flow/SKILL.md +411 -0
  123. package/plugins/dsh/skills/sprint-flow/__tests__/sprint-flow.test.cjs +457 -0
  124. package/plugins/dsh/skills/sprint-flow/hooks.md +18 -0
  125. package/plugins/dsh/skills/sprint-flow/references/components/memory.md +87 -0
  126. package/plugins/dsh/skills/sprint-flow/references/components/middleware.md +75 -0
  127. package/plugins/dsh/skills/sprint-flow/references/components/skill-invocations.md +105 -0
  128. package/plugins/dsh/skills/sprint-flow/references/components/system-prompt.md +27 -0
  129. package/plugins/dsh/skills/sprint-flow/references/components/tool-descriptions.md +95 -0
  130. package/plugins/dsh/skills/sprint-flow/references/force-levels.md +204 -0
  131. package/plugins/dsh/skills/sprint-flow/references/orchestration-rules.md +236 -0
  132. package/plugins/dsh/skills/sprint-flow/references/phase-1-prep.md +294 -0
  133. package/plugins/dsh/skills/sprint-flow/references/phase-2-design.md +273 -0
  134. package/plugins/dsh/skills/sprint-flow/references/phase-3-build.md +348 -0
  135. package/plugins/dsh/skills/sprint-flow/references/phase-4-verify.md +225 -0
  136. package/plugins/dsh/skills/sprint-flow/references/phase-5-ship.md +222 -0
  137. package/plugins/dsh/skills/sprint-flow/references/phase-6-close.md +266 -0
  138. package/plugins/dsh/skills/sprint-flow/references/phase-overview.md +486 -0
  139. package/plugins/dsh/skills/sprint-flow/scripts/verify-sprint-state.sh +38 -0
  140. package/plugins/dsh/skills/sprint-flow/templates/auto-estimate-learning-log.md +136 -0
  141. package/plugins/dsh/skills/sprint-flow/templates/auto-estimate-output-template.md +110 -0
  142. package/plugins/dsh/skills/sprint-flow/templates/emergent-issues-template.md +120 -0
  143. package/plugins/dsh/skills/sprint-flow/templates/pain-document-template.md +115 -0
  144. package/plugins/dsh/skills/sprint-flow/templates/sprint-progress-template.md +140 -0
  145. package/plugins/dsh/skills/sprint-flow/templates/sprint-summary-template.md +121 -0
  146. package/plugins/dsh/skills/sprint-flow/tools.md +29 -0
  147. package/plugins/dsh/skills/test-driven-development/SKILL.md +371 -0
  148. package/plugins/dsh/skills/test-driven-development/testing-anti-patterns.md +299 -0
  149. package/plugins/dsh/skills/test-specification-alignment/AGENTS.md +56 -0
  150. package/plugins/dsh/skills/test-specification-alignment/SKILL.md +205 -0
  151. package/plugins/dsh/skills/test-specification-alignment/references/alignment-verification-algorithm.md +493 -0
  152. package/plugins/dsh/skills/test-specification-alignment/references/phase2-constraint-enforcement.md +431 -0
  153. package/plugins/dsh/skills/test-specification-alignment/references/specification-format.md +348 -0
  154. package/plugins/dsh/skills/to-issues/SKILL.md +277 -0
  155. package/plugins/dsh/src/command.test.ts +102 -0
  156. package/plugins/dsh/src/command.ts +75 -0
  157. package/plugins/dsh/src/contract.test.ts +62 -0
  158. package/plugins/dsh/src/gate-runner.test.ts +100 -0
  159. package/plugins/dsh/src/gate-runner.ts +58 -0
  160. package/plugins/dsh/src/index.test.ts +97 -0
  161. package/plugins/dsh/src/index.ts +94 -0
  162. package/plugins/dsh/src/skills.test.ts +58 -0
  163. package/plugins/dsh/tsconfig.build.json +13 -0
  164. package/plugins/dsh/tsconfig.json +19 -0
  165. package/plugins/dsh/vitest.config.ts +8 -0
  166. package/plugins/opencode/package.json +1 -1
  167. package/plugins/opencode/scripts/prepack.cjs +1 -0
  168. package/plugins/opencode/skills/clipboard-vision/SKILL.md +47 -0
  169. package/plugins/opencode/skills/clipboard-vision/__tests__/clipboard-vision-distribution.test.cjs +65 -0
  170. package/plugins/opencode/skills/clipboard-vision/__tests__/clipboard-vision-security.test.cjs +185 -0
  171. package/plugins/opencode/skills/clipboard-vision/__tests__/clipboard-vision.Tests.ps1 +138 -0
  172. package/plugins/opencode/skills/clipboard-vision/__tests__/clipboard-vision.test.cjs +273 -0
  173. package/plugins/opencode/skills/clipboard-vision/describe-clipboard.ps1 +115 -0
  174. package/plugins/opencode/skills/clipboard-vision/describe-clipboard.sh +161 -0
  175. package/plugins/opencode/skills/clipboard-vision/scripts/clipboard-vision.ps1 +86 -0
  176. package/plugins/opencode/skills/clipboard-vision/scripts/clipboard-vision.sh +137 -0
  177. package/plugins/opencode/skills/delphi-review/.delphi-config.json.example +24 -27
  178. package/plugins/opencode/skills/delphi-review/AGENTS.md +13 -12
  179. package/plugins/opencode/skills/delphi-review/INSTALL.md +15 -17
  180. package/plugins/opencode/skills/delphi-review/SKILL.md +30 -29
  181. package/plugins/opencode/skills/delphi-review/opencode.json.delphi.example +6 -10
  182. package/plugins/opencode/skills/delphi-review/references/code-walkthrough.md +33 -49
  183. package/plugins/opencode/skills/delphi-review/references/requirements.md +66 -54
  184. package/plugins/opencode/skills/delphi-review/references/round-templates.md +7 -7
  185. package/plugins/opencode/skills/sprint-flow/AGENTS.md +5 -5
  186. package/plugins/opencode/skills/sprint-flow/SKILL.md +4 -4
  187. package/plugins/opencode/skills/sprint-flow/references/components/skill-invocations.md +2 -2
  188. package/plugins/opencode/skills/sprint-flow/references/force-levels.md +37 -35
  189. package/plugins/opencode/skills/sprint-flow/references/orchestration-rules.md +1 -1
  190. package/plugins/opencode/skills/sprint-flow/references/phase-1-prep.md +1 -1
  191. package/plugins/opencode/skills/sprint-flow/references/phase-2-design.md +24 -14
  192. package/plugins/opencode/skills/sprint-flow/references/phase-4-verify.md +6 -6
  193. package/plugins/opencode/skills/sprint-flow/references/phase-overview.md +2 -2
  194. package/plugins/opencode/skills/test-specification-alignment/AGENTS.md +4 -4
  195. package/plugins/qoder/plugin.json +1 -1
  196. package/plugins/qoder/skills/clipboard-vision/SKILL.md +47 -0
  197. package/plugins/qoder/skills/clipboard-vision/__tests__/clipboard-vision-distribution.test.cjs +65 -0
  198. package/plugins/qoder/skills/clipboard-vision/__tests__/clipboard-vision-security.test.cjs +185 -0
  199. package/plugins/qoder/skills/clipboard-vision/__tests__/clipboard-vision.Tests.ps1 +138 -0
  200. package/plugins/qoder/skills/clipboard-vision/__tests__/clipboard-vision.test.cjs +273 -0
  201. package/plugins/qoder/skills/clipboard-vision/clipboard-vision/SKILL.md +47 -0
  202. package/plugins/qoder/skills/clipboard-vision/clipboard-vision/__tests__/clipboard-vision-distribution.test.cjs +65 -0
  203. package/plugins/qoder/skills/clipboard-vision/clipboard-vision/__tests__/clipboard-vision-security.test.cjs +185 -0
  204. package/plugins/qoder/skills/clipboard-vision/clipboard-vision/__tests__/clipboard-vision.Tests.ps1 +138 -0
  205. package/plugins/qoder/skills/clipboard-vision/clipboard-vision/__tests__/clipboard-vision.test.cjs +273 -0
  206. package/plugins/qoder/skills/clipboard-vision/clipboard-vision/scripts/clipboard-vision.ps1 +86 -0
  207. package/plugins/qoder/skills/clipboard-vision/clipboard-vision/scripts/clipboard-vision.sh +137 -0
  208. package/plugins/qoder/skills/clipboard-vision/scripts/clipboard-vision.ps1 +86 -0
  209. package/plugins/qoder/skills/clipboard-vision/scripts/clipboard-vision.sh +137 -0
  210. package/plugins/qoder/skills/delphi-review/.delphi-config.json.example +3 -11
  211. package/plugins/qoder/skills/delphi-review/AGENTS.md +15 -17
  212. package/plugins/qoder/skills/delphi-review/INSTALL.md +12 -12
  213. package/plugins/qoder/skills/delphi-review/SKILL.md +58 -25
  214. package/plugins/qoder/skills/delphi-review/opencode.json.delphi.example +1 -1
  215. package/plugins/qoder/skills/delphi-review/references/code-walkthrough.md +33 -49
  216. package/plugins/qoder/skills/sprint-flow/AGENTS.md +5 -5
  217. package/plugins/qoder/skills/sprint-flow/SKILL.md +2 -2
  218. package/plugins/qoder/skills/sprint-flow/references/force-levels.md +38 -35
  219. package/plugins/qoder/skills/sprint-flow/references/phase-1-prep.md +1 -1
  220. package/plugins/qoder/skills/sprint-flow/references/phase-2-design.md +48 -6
  221. package/plugins/qoder/skills/sprint-flow/references/phase-4-verify.md +5 -6
  222. package/plugins/qoder/skills/test-specification-alignment/AGENTS.md +4 -4
  223. package/principles/AGENTS.md +4 -4
  224. package/scripts/__tests__/sync-package-content.test.js +30 -0
  225. package/scripts/delphi-external-review.cjs +194 -63
  226. package/scripts/sync-package-content.js +9 -2
  227. package/skills/clipboard-vision/SKILL.md +47 -0
  228. package/skills/clipboard-vision/__tests__/clipboard-vision-distribution.test.cjs +65 -0
  229. package/skills/clipboard-vision/__tests__/clipboard-vision-security.test.cjs +185 -0
  230. package/skills/clipboard-vision/__tests__/clipboard-vision.Tests.ps1 +138 -0
  231. package/skills/clipboard-vision/__tests__/clipboard-vision.test.cjs +273 -0
  232. package/skills/clipboard-vision/describe-clipboard.ps1 +115 -0
  233. package/skills/clipboard-vision/describe-clipboard.sh +161 -0
  234. package/skills/clipboard-vision/scripts/clipboard-vision.ps1 +86 -0
  235. package/skills/clipboard-vision/scripts/clipboard-vision.sh +137 -0
  236. package/skills/delphi-review/.delphi-config.json.example +24 -27
  237. package/skills/delphi-review/AGENTS.md +13 -12
  238. package/skills/delphi-review/INSTALL.md +15 -17
  239. package/skills/delphi-review/SKILL.md +30 -29
  240. package/skills/delphi-review/opencode.json.delphi.example +6 -10
  241. package/skills/delphi-review/references/code-walkthrough.md +33 -49
  242. package/skills/delphi-review/references/requirements.md +66 -54
  243. package/skills/delphi-review/references/round-templates.md +7 -7
  244. package/skills/sprint-flow/AGENTS.md +5 -5
  245. package/skills/sprint-flow/SKILL.md +4 -4
  246. package/skills/sprint-flow/references/components/skill-invocations.md +2 -2
  247. package/skills/sprint-flow/references/force-levels.md +37 -35
  248. package/skills/sprint-flow/references/orchestration-rules.md +1 -1
  249. package/skills/sprint-flow/references/phase-1-prep.md +1 -1
  250. package/skills/sprint-flow/references/phase-2-design.md +24 -14
  251. package/skills/sprint-flow/references/phase-4-verify.md +6 -6
  252. package/skills/sprint-flow/references/phase-overview.md +2 -2
  253. package/skills/test-specification-alignment/AGENTS.md +4 -4
  254. package/sprint-gate.sh +291 -0
@@ -198,16 +198,6 @@ export function parseSpecification(specPath: string): SpecificationMap {
198
198
  // Step 2: parseTestFiles()
199
199
  // ============================================================================
200
200
 
201
- const REQ_ID_PATTERN = /REQ-[A-Z0-9]+-[A-Z0-9]+/;
202
-
203
- function extractTag(text: string, tag: string): string | null {
204
- // Match @tag value (single line extraction, stops at newline or */)
205
- const regex = new RegExp('@' + tag.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '\\s+(.+?)(?:\\n|\\*\\/)', 's');
206
- const match = text.match(regex);
207
- if (!match) return null;
208
- return match[1]!.trim();
209
- }
210
-
211
201
  function extractAllTags(text: string, tag: string): string[] {
212
202
  const escapedTag = tag.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
213
203
  const regex = new RegExp('@' + escapedTag + '\\s+(.+?)(?:\\n|\\*\\/)', 'gs');
@@ -396,7 +386,7 @@ export function verifyAlignment(
396
386
  // Collect all requirement IDs and acceptance criteria IDs from spec
397
387
  const allReqIds = new Set<string>();
398
388
  const allAcIds = new Set<string>();
399
- let totalEdgeCases = 0;
389
+ const totalEdgeCases = 0;
400
390
 
401
391
  for (const req of specMap.requirements) {
402
392
  allReqIds.add(req.id);
@@ -583,7 +573,7 @@ export function runFullAlignment(options: AlignmentOptions): TestAlignmentReport
583
573
  let spec: SpecificationMap;
584
574
  try {
585
575
  spec = parseSpecification(specPath);
586
- } catch (e: any) {
576
+ } catch (e) {
587
577
  return {
588
578
  alignment_status: 'BLOCKED',
589
579
  phase: 0,
@@ -593,7 +583,7 @@ export function runFullAlignment(options: AlignmentOptions): TestAlignmentReport
593
583
  timestamp: new Date().toISOString(),
594
584
  misaligned_tests: [],
595
585
  anti_pattern_detected: false,
596
- errors: [`Failed to parse specification: ${e.message}`],
586
+ errors: [`Failed to parse specification: ${e instanceof Error ? e.message : String(e)}`],
597
587
  };
598
588
  }
599
589
 
@@ -3,9 +3,9 @@
3
3
  * @intent Sync latest hook versions from xp-gate package to project or global directory
4
4
  * @covers AC-265-01, AC-265-02, AC-265-03, AC-265-04
5
5
  */
6
- const fs = require('fs');
7
- const path = require('path');
8
- const { GLOBAL_HOOKS_DIR, GLOBAL_ADAPTERS_DIR } = require('./shared-paths.js');
6
+ const fs = require('node:fs');
7
+ const path = require('node:path');
8
+ const { GLOBAL_HOOKS_DIR, GLOBAL_ADAPTERS_DIR, GLOBAL_MODULES_DIR, CONFIG_DIR } = require('./shared-paths.js');
9
9
 
10
10
  /**
11
11
  * Get the xp-gate package root directory (src/npm-package/).
@@ -97,6 +97,17 @@ function detectLocalModifications(srcDir, hooksDestDir, adaptersDestDir) {
97
97
  });
98
98
  }
99
99
 
100
+ // Check sprint-gate.sh in the hooks directory (Gate MS resolves it there)
101
+ const sprintGateSrc = path.join(srcDir, 'sprint-gate.sh');
102
+ const sprintGateDest = path.join(hooksDestDir, 'sprint-gate.sh');
103
+ if (fs.existsSync(sprintGateDest) && fs.existsSync(sprintGateSrc)) {
104
+ const srcContent = fs.readFileSync(sprintGateSrc, 'utf8');
105
+ const destContent = fs.readFileSync(sprintGateDest, 'utf8');
106
+ if (srcContent !== destContent) {
107
+ modified.push('sprint-gate.sh');
108
+ }
109
+ }
110
+
100
111
  return modified;
101
112
  }
102
113
 
@@ -152,6 +163,21 @@ function copyHooks(srcDir, destDir, dryRun, noBackup) {
152
163
  const dest = path.join(destDir, hook);
153
164
  atomicCopyFile(src, dest, dryRun, noBackup, hook);
154
165
  });
166
+ const libSrcDir = path.join(hooksSrcDir, 'lib');
167
+ if (fs.existsSync(libSrcDir)) {
168
+ fs.readdirSync(libSrcDir, { withFileTypes: true })
169
+ .filter(entry => entry.isFile())
170
+ .forEach(entry => {
171
+ const label = `lib/${entry.name}`;
172
+ atomicCopyFile(
173
+ path.join(libSrcDir, entry.name),
174
+ path.join(destDir, label),
175
+ dryRun,
176
+ noBackup,
177
+ label
178
+ );
179
+ });
180
+ }
155
181
  }
156
182
 
157
183
  /**
@@ -190,7 +216,7 @@ function copyAdapters(srcDir, destDir, dryRun, noBackup) {
190
216
  function copyGateScripts(srcDir, destDir, dryRun, noBackup) {
191
217
  if (!fs.existsSync(srcDir)) return;
192
218
  fs.readdirSync(srcDir).forEach(f => {
193
- if ((f.startsWith('gate-') || f === 'sprint-gate.sh') && f.endsWith('.sh')) {
219
+ if (f.startsWith('gate-') && f.endsWith('.sh')) {
194
220
  const src = path.join(srcDir, f);
195
221
  const dest = path.join(destDir, f);
196
222
  atomicCopyFile(src, dest, dryRun, noBackup, f);
@@ -198,31 +224,92 @@ function copyGateScripts(srcDir, destDir, dryRun, noBackup) {
198
224
  });
199
225
  }
200
226
 
227
+ /**
228
+ * Copy sprint-gate.sh from package root to the hooks directory.
229
+ * The pre-push Gate MS resolves it at $(dirname "$0")/sprint-gate.sh, i.e.
230
+ * alongside pre-commit/pre-push — NOT the adapters directory.
231
+ * @param {string} srcDir - Package root directory
232
+ * @param {string} hooksDestDir - Destination hooks directory
233
+ * @param {boolean} dryRun
234
+ * @param {boolean} noBackup
235
+ */
236
+ function copySprintGate(srcDir, hooksDestDir, dryRun, noBackup) {
237
+ const src = path.join(srcDir, 'sprint-gate.sh');
238
+ if (!fs.existsSync(src)) return;
239
+ atomicCopyFile(src, path.join(hooksDestDir, 'sprint-gate.sh'), dryRun, noBackup, 'sprint-gate.sh');
240
+ }
241
+
242
+ /**
243
+ * Copy quality gate modules (principles, mutation, mock-policy, build-integrity)
244
+ * into the modules directory. These ship in the npm package but were never
245
+ * installed by an already-initialized global setup, so update-hooks must
246
+ * re-deploy them to repair Gate 9/10 (build-integrity) on existing installs.
247
+ * @param {string} srcDir - Package root directory
248
+ * @param {string} modulesDestDir - Destination modules directory
249
+ * @param {boolean} dryRun
250
+ * @param {boolean} noBackup
251
+ */
252
+ const MODULES = ['principles', 'mutation', 'mock-policy', 'build-integrity'];
253
+ function copyModules(srcDir, modulesDestDir, dryRun, noBackup) {
254
+ MODULES.forEach(module => {
255
+ const srcDirPath = path.join(srcDir, module);
256
+ if (!fs.existsSync(srcDirPath)) return;
257
+ const destDirPath = path.join(modulesDestDir, module);
258
+ fs.mkdirSync(destDirPath, { recursive: true });
259
+ fs.readdirSync(srcDirPath).forEach(entry => {
260
+ const srcEntry = path.join(srcDirPath, entry);
261
+ const destEntry = path.join(destDirPath, entry);
262
+ const stats = fs.statSync(srcEntry);
263
+ if (stats.isDirectory()) {
264
+ copyRecursiveDir(srcEntry, destEntry, dryRun, noBackup, module);
265
+ } else if (!dryRun) {
266
+ atomicCopyFile(srcEntry, destEntry, dryRun, noBackup, `${module}/${entry}`);
267
+ }
268
+ });
269
+ if (!dryRun) console.log(` ${module}/ -> ${modulesDestDir}/${module}/`);
270
+ });
271
+ }
272
+
273
+ function copyRecursiveDir(src, dest, dryRun, noBackup, label) {
274
+ fs.mkdirSync(dest, { recursive: true });
275
+ fs.readdirSync(src).forEach(entry => {
276
+ const srcEntry = path.join(src, entry);
277
+ const destEntry = path.join(dest, entry);
278
+ if (fs.statSync(srcEntry).isDirectory()) {
279
+ copyRecursiveDir(srcEntry, destEntry, dryRun, noBackup, label);
280
+ } else {
281
+ atomicCopyFile(srcEntry, destEntry, dryRun, noBackup, `${label}/${entry}`);
282
+ }
283
+ });
284
+ }
285
+
201
286
  function resolveSrcDir() {
202
- return (module.exports && module.exports.getPackageRoot)
287
+ return module.exports?.getPackageRoot
203
288
  ? module.exports.getPackageRoot()
204
289
  : getPackageRoot();
205
290
  }
206
291
 
207
292
  function resolveDirs(global) {
208
- if (global) return { hooksDestDir: GLOBAL_HOOKS_DIR, adaptersDestDir: GLOBAL_ADAPTERS_DIR };
209
- return { hooksDestDir: getProjectHooksDir(), adaptersDestDir: path.join(process.cwd(), 'githooks') };
293
+ if (global) return { hooksDestDir: GLOBAL_HOOKS_DIR, adaptersDestDir: GLOBAL_ADAPTERS_DIR, modulesDestDir: GLOBAL_MODULES_DIR };
294
+ return { hooksDestDir: getProjectHooksDir(), adaptersDestDir: path.join(process.cwd(), 'githooks'), modulesDestDir: path.join(process.cwd(), '.xp-gate', 'modules') };
210
295
  }
211
296
 
212
- function ensureDirsExist(adaptersDestDir, hooksDestDir) {
297
+ function ensureDirsExist(adaptersDestDir, hooksDestDir, modulesDestDir) {
213
298
  fs.mkdirSync(hooksDestDir, { recursive: true });
214
299
  fs.mkdirSync(adaptersDestDir, { recursive: true });
215
300
  fs.mkdirSync(path.join(adaptersDestDir, 'adapters'), { recursive: true });
301
+ if (modulesDestDir) fs.mkdirSync(modulesDestDir, { recursive: true });
216
302
  }
217
303
 
218
304
  function printUpdateHeader(opts) {
219
- const { global, srcDir, hooksDestDir, adaptersDestDir, scope, dryRun } = opts;
305
+ const { global, srcDir, hooksDestDir, adaptersDestDir, modulesDestDir, scope, dryRun } = opts;
220
306
  console.log(`XP-Gate Update Hooks`);
221
307
  console.log(`====================`);
222
308
  console.log(`Mode: ${global ? 'Global' : 'Local'}`);
223
309
  console.log(`Source: ${srcDir}`);
224
310
  console.log(`Hooks destination: ${hooksDestDir}`);
225
311
  console.log(`Adapters destination: ${adaptersDestDir}`);
312
+ if (modulesDestDir) console.log(`Modules destination: ${modulesDestDir}`);
226
313
  console.log(`Scope: ${scope}`);
227
314
  if (dryRun) console.log(`Dry run: yes (no files will be modified)`);
228
315
  console.log('');
@@ -233,13 +320,15 @@ function checkLocalModifications(srcDir, hooksDestDir, adaptersDestDir, force, d
233
320
  const localMods = detectLocalModifications(srcDir, hooksDestDir, adaptersDestDir);
234
321
  if (localMods.length === 0) return 0;
235
322
  console.warn(`[WARN] Detected ${localMods.length} locally modified file(s):`);
236
- localMods.forEach(f => console.warn(` - ${f}`));
323
+ localMods.forEach(f => {
324
+ console.warn(` - ${f}`);
325
+ });
237
326
  console.warn('Use --force to overwrite, or manually backup first.');
238
327
  return 1;
239
328
  }
240
329
 
241
330
  function copyByScope(opts) {
242
- const { scope, srcDir, hooksDestDir, adaptersDestDir, dryRun, noBackup } = opts;
331
+ const { scope, srcDir, hooksDestDir, adaptersDestDir, modulesDestDir, dryRun, noBackup } = opts;
243
332
  if (scope === 'all' || scope === 'hooks') {
244
333
  printInfo('hooks');
245
334
  copyHooks(srcDir, hooksDestDir, dryRun, noBackup);
@@ -251,6 +340,27 @@ function copyByScope(opts) {
251
340
  if (scope === 'all') {
252
341
  printInfo('gate scripts');
253
342
  copyGateScripts(srcDir, adaptersDestDir, dryRun, noBackup);
343
+ if (modulesDestDir) {
344
+ printInfo('modules');
345
+ copyModules(srcDir, modulesDestDir, dryRun, noBackup);
346
+ }
347
+ }
348
+ if (scope === 'all' || scope === 'hooks') {
349
+ copySprintGate(srcDir, hooksDestDir, dryRun, noBackup);
350
+ }
351
+ }
352
+
353
+ function warnMissingModuleDeps(global, dryRun) {
354
+ if (!global || dryRun) return;
355
+ // Copied gate modules (e.g. mock-policy) import js-yaml/zod installed into
356
+ // <CONFIG_DIR>/node_modules by setup-global. If absent (e.g. an install made
357
+ // before that step existed), Gate ML would crash at push — guide the user to
358
+ // re-run setup-global rather than silently failing.
359
+ const depsDir = path.join(CONFIG_DIR, 'node_modules', 'js-yaml');
360
+ if (!fs.existsSync(depsDir)) {
361
+ console.warn('\n[warn] Global quality-gate module runtime deps not found.');
362
+ console.warn(` Expected: ${path.join(CONFIG_DIR, 'node_modules')}`);
363
+ console.warn(' Run `xp-gate setup-global` once to install them (Gate ML needs js-yaml/zod).');
254
364
  }
255
365
  }
256
366
 
@@ -262,15 +372,16 @@ function printInfo(label) { console.log(`Updating ${label}...`); }
262
372
  function updateHooks(options = {}) {
263
373
  const { global = false, force = false, dryRun = false, noBackup = false, scope = 'all' } = options;
264
374
  const srcDir = resolveSrcDir();
265
- const { hooksDestDir, adaptersDestDir } = resolveDirs(global);
375
+ const { hooksDestDir, adaptersDestDir, modulesDestDir } = resolveDirs(global);
266
376
 
267
- ensureDirsExist(adaptersDestDir, hooksDestDir);
268
- printUpdateHeader({ global, srcDir, hooksDestDir, adaptersDestDir, scope, dryRun });
377
+ ensureDirsExist(adaptersDestDir, hooksDestDir, modulesDestDir);
378
+ printUpdateHeader({ global, srcDir, hooksDestDir, adaptersDestDir, modulesDestDir, scope, dryRun });
269
379
 
270
380
  const modCheck = checkLocalModifications(srcDir, hooksDestDir, adaptersDestDir, force, dryRun);
271
381
  if (modCheck !== 0) return modCheck;
272
382
 
273
- copyByScope({ scope, srcDir, hooksDestDir, adaptersDestDir, dryRun, noBackup });
383
+ copyByScope({ scope, srcDir, hooksDestDir, adaptersDestDir, modulesDestDir, dryRun, noBackup });
384
+ warnMissingModuleDeps(global, dryRun);
274
385
 
275
386
  if (!dryRun) console.log('\nUpdate complete!');
276
387
  return 0;
@@ -282,6 +393,9 @@ module.exports = {
282
393
  copyHooks,
283
394
  copyAdapters,
284
395
  copyGateScripts,
396
+ copySprintGate,
397
+ copyModules,
398
+ warnMissingModuleDeps,
285
399
  atomicCopyFile,
286
400
  getPackageRoot,
287
401
  getProjectHooksDir,
@@ -1,9 +1,9 @@
1
1
  # SRC/MOCK-POLICY KNOWLEDGE BASE
2
2
 
3
- **Generated:** 2026-07-29
4
- **Commit:** 05d23ae
5
- **Branch:** main
6
- **Version:** 0.18.5.0
3
+ **Generated:** 2026-08-24
4
+ **Commit:** a1a4683
5
+ **Branch:** dsh-plugin
6
+ **Version:** 0.19.0.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Mock layering policy enforcement — Gate M3 of pre-push hook. Ensures integration tests use real implementations for internal dependencies, mock external dependencies, and annotate pending mocks with removal plans. Combines project scope scanning, mock decision engine, and per-file validation into a single pipeline.
@@ -88,7 +88,7 @@ npx vitest run src/mock-policy/__tests__/integration.test.ts
88
88
 
89
89
  ## NOTES
90
90
  - Gate M3 is invoked by pre-push hook after Gate M (mutation) and Gate M2 (AI test detection)
91
- - push limits: max 20 files or 500 LOC per push — Gate M3 respects this via the changed files input
91
+ - code walkthrough scope: no hard file-count or LOC threshold; large diffs require complete review or user-directed splitting, never a size-based bypass
92
92
  - Coverage exclude: src/mock-policy/ controlled by vitest config
93
93
  - The integration test creates real temporary directories under os.tmpdir()
94
94
  - Dependencies on: `src/mutation/detect-ai-test.ts` (detectTestLayer)
@@ -271,9 +271,7 @@ describe('runGateM3', () => {
271
271
  // ---------------------------------------------------------------------------
272
272
  describe('main', () => {
273
273
  let tmpDir: string;
274
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
275
274
  let consoleErrorSpy: any;
276
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
277
275
  let consoleLogSpy: any;
278
276
 
279
277
  beforeEach(() => {
@@ -335,7 +333,6 @@ describe('main', () => {
335
333
  const exitCode = await main([testFile]);
336
334
 
337
335
  const logCalls: string[] = consoleLogSpy.mock.calls.map(
338
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
339
336
  (c: any[]) => String(c[0]),
340
337
  );
341
338
  expect(logCalls.some((msg) => msg.includes('Gate M3'))).toBe(true);
@@ -357,7 +354,6 @@ describe('main', () => {
357
354
  await main([testFile]);
358
355
 
359
356
  const logCalls: string[] = consoleLogSpy.mock.calls.map(
360
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
361
357
  (c: any[]) => String(c[0]),
362
358
  );
363
359
  const hasPassLabel = logCalls.some(
@@ -373,7 +369,6 @@ describe('main', () => {
373
369
  await main([testFile]);
374
370
 
375
371
  const logCalls: string[] = consoleLogSpy.mock.calls.map(
376
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
377
372
  (c: any[]) => String(c[0]),
378
373
  );
379
374
  const hasFileCount = logCalls.some(
@@ -196,9 +196,12 @@ describe('resolveToRealPath', () => {
196
196
  // ---------------------------------------------------------------------------
197
197
  describe('loadExternalDependencies', () => {
198
198
  let tmpDir: string;
199
+ let tmpCounter = 0;
199
200
 
200
201
  beforeEach(() => {
201
- tmpDir = join(tmpdir(), `scope-scanner-test-${Date.now()}`);
202
+ // Monotonic counter avoids Date.now() collisions when tests run fast
203
+ tmpCounter += 1;
204
+ tmpDir = join(tmpdir(), `scope-scanner-test-${process.pid}-${tmpCounter}`);
202
205
  mkdirSync(tmpDir, { recursive: true });
203
206
  });
204
207
 
@@ -361,9 +364,12 @@ describe('classifyDependency', () => {
361
364
  // ---------------------------------------------------------------------------
362
365
  describe('scanProjectScope', () => {
363
366
  let tmpDir: string;
367
+ let tmpCounter = 0;
364
368
 
365
369
  beforeEach(() => {
366
- tmpDir = join(tmpdir(), `scope-scanner-integration-${Date.now()}`);
370
+ // Monotonic counter avoids Date.now() collisions when tests run fast
371
+ tmpCounter += 1;
372
+ tmpDir = join(tmpdir(), `scope-scanner-integration-${process.pid}-${tmpCounter}`);
367
373
  mkdirSync(tmpDir, { recursive: true });
368
374
 
369
375
  // Create a real project structure
@@ -1,9 +1,9 @@
1
1
  # SRC/MUTATION KNOWLEDGE BASE
2
2
 
3
- **Generated:** 2026-07-29
4
- **Commit:** 05d23ae
5
- **Branch:** main
6
- **Version:** 0.18.5.0
3
+ **Generated:** 2026-08-24
4
+ **Commit:** a1a4683
5
+ **Branch:** dsh-plugin
6
+ **Version:** 0.19.0.0
7
7
 
8
8
  ## OVERVIEW
9
9
  **Gate M** (incremental mutation testing) + **Gate M2** helpers (test-layer detection used by `src/mock-policy/`). Pre-push quality gate. TypeScript-only; uses Stryker.