@pigcloud/skills 1.0.11 → 1.1.2

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 (298) hide show
  1. package/CHANGELOG.md +25 -20
  2. package/README.en.md +41 -75
  3. package/README.md +26 -39
  4. package/bin/cli.js +260 -151
  5. package/bin/rules-loader.js +271 -484
  6. package/codex-commands/README.md +25 -23
  7. package/codex-commands/commands/analyze.md +21 -22
  8. package/codex-commands/commands/build.md +22 -22
  9. package/codex-commands/commands/design.md +21 -22
  10. package/codex-commands/commands/distill.md +21 -21
  11. package/codex-commands/commands/doc.md +21 -22
  12. package/codex-commands/commands/infra.md +21 -21
  13. package/codex-commands/commands/init.md +20 -20
  14. package/codex-commands/commands/kb.md +21 -20
  15. package/codex-commands/commands/perf.md +21 -21
  16. package/codex-commands/commands/prd.md +21 -22
  17. package/codex-commands/commands/review.md +21 -22
  18. package/codex-commands/commands/security.md +21 -22
  19. package/codex-commands/commands/test.md +21 -21
  20. package/codex-commands/commands/workflow.md +21 -20
  21. package/package.json +5 -2
  22. package/rules/core/index.md +26 -41
  23. package/rules/delivery/index.md +25 -0
  24. package/rules/design/index.md +25 -0
  25. package/rules/discovery/index.md +25 -0
  26. package/rules/implementation/index.md +25 -0
  27. package/rules/index.md +24 -39
  28. package/rules/overlays/index.md +19 -19
  29. package/rules/overlays/pig-cloud.md +20 -45
  30. package/rules/shared/index.md +25 -0
  31. package/rules/skill-stage-map.json +26 -0
  32. package/rules/stages.json +48 -0
  33. package/rules/validation/index.md +25 -0
  34. package/scripts/add-skill-reference-nav.js +3 -0
  35. package/scripts/bootstrap-skill-specs.js +96 -0
  36. package/scripts/ci-validator.sh +51 -114
  37. package/scripts/generate-skill-prompt-library.js +3 -0
  38. package/scripts/golden-prompt-suite.current.js +211 -0
  39. package/scripts/migrate-skill-packages.js +309 -0
  40. package/scripts/run-golden-replays.js +110 -79
  41. package/scripts/validate-rules.js +128 -125
  42. package/scripts/validate-skill-replay-signals.js +45 -57
  43. package/scripts/validate-skill-shapes.js +153 -127
  44. package/scripts/validate-skill-stop-rules.js +54 -46
  45. package/skills/01-discovery/ambiguity-detection/SKILL.md +30 -0
  46. package/skills/01-discovery/ambiguity-detection/assets/golden-prompt-suite.current.js +22 -0
  47. package/skills/01-discovery/ambiguity-detection/references/README.md +17 -0
  48. package/skills/01-discovery/ambiguity-detection/references/cases.md +26 -0
  49. package/skills/01-discovery/ambiguity-detection/references/prompt-template.md +18 -0
  50. package/skills/01-discovery/ambiguity-detection/skill-spec.json +26 -0
  51. package/skills/01-discovery/business-analysis/SKILL.md +30 -0
  52. package/skills/01-discovery/business-analysis/assets/golden-prompt-suite.current.js +22 -0
  53. package/skills/01-discovery/business-analysis/references/README.md +17 -0
  54. package/skills/01-discovery/business-analysis/references/cases.md +26 -0
  55. package/skills/01-discovery/business-analysis/references/prompt-template.md +18 -0
  56. package/skills/01-discovery/business-analysis/skill-spec.json +26 -0
  57. package/skills/01-discovery/impact-analysis/SKILL.md +30 -0
  58. package/skills/01-discovery/impact-analysis/assets/golden-prompt-suite.current.js +22 -0
  59. package/skills/01-discovery/impact-analysis/references/README.md +17 -0
  60. package/skills/01-discovery/impact-analysis/references/cases.md +26 -0
  61. package/skills/01-discovery/impact-analysis/references/prompt-template.md +18 -0
  62. package/skills/01-discovery/impact-analysis/skill-spec.json +26 -0
  63. package/skills/01-discovery/requirement-discovery/SKILL.md +30 -0
  64. package/skills/01-discovery/requirement-discovery/assets/golden-prompt-suite.current.js +24 -0
  65. package/skills/01-discovery/requirement-discovery/references/README.md +17 -0
  66. package/skills/01-discovery/requirement-discovery/references/cases.md +28 -0
  67. package/skills/01-discovery/requirement-discovery/references/prompt-template.md +18 -0
  68. package/skills/01-discovery/requirement-discovery/skill-spec.json +26 -0
  69. package/skills/02-design/api-design/SKILL.md +29 -0
  70. package/skills/02-design/api-design/assets/golden-prompt-suite.current.js +22 -0
  71. package/skills/02-design/api-design/references/README.md +17 -0
  72. package/skills/02-design/api-design/references/cases.md +26 -0
  73. package/skills/02-design/api-design/references/prompt-template.md +18 -0
  74. package/skills/02-design/api-design/skill-spec.json +25 -0
  75. package/skills/02-design/architecture-design/SKILL.md +29 -0
  76. package/skills/02-design/architecture-design/assets/golden-prompt-suite.current.js +22 -0
  77. package/skills/02-design/architecture-design/references/README.md +17 -0
  78. package/skills/02-design/architecture-design/references/cases.md +26 -0
  79. package/skills/02-design/architecture-design/references/prompt-template.md +18 -0
  80. package/skills/02-design/architecture-design/skill-spec.json +25 -0
  81. package/skills/02-design/database-design/SKILL.md +29 -0
  82. package/skills/02-design/database-design/assets/golden-prompt-suite.current.js +22 -0
  83. package/skills/02-design/database-design/references/README.md +17 -0
  84. package/skills/02-design/database-design/references/cases.md +26 -0
  85. package/skills/02-design/database-design/references/prompt-template.md +18 -0
  86. package/skills/02-design/database-design/skill-spec.json +25 -0
  87. package/skills/02-design/task-breakdown/SKILL.md +29 -0
  88. package/skills/02-design/task-breakdown/assets/golden-prompt-suite.current.js +22 -0
  89. package/skills/02-design/task-breakdown/references/README.md +17 -0
  90. package/skills/02-design/task-breakdown/references/cases.md +26 -0
  91. package/skills/02-design/task-breakdown/references/prompt-template.md +18 -0
  92. package/skills/02-design/task-breakdown/skill-spec.json +25 -0
  93. package/skills/03-implementation/backend-development/SKILL.md +29 -0
  94. package/skills/03-implementation/backend-development/assets/golden-prompt-suite.current.js +22 -0
  95. package/skills/03-implementation/backend-development/references/README.md +17 -0
  96. package/skills/03-implementation/backend-development/references/cases.md +26 -0
  97. package/skills/03-implementation/backend-development/references/prompt-template.md +18 -0
  98. package/skills/03-implementation/backend-development/skill-spec.json +25 -0
  99. package/skills/03-implementation/bug-fix/SKILL.md +29 -0
  100. package/skills/03-implementation/bug-fix/assets/golden-prompt-suite.current.js +22 -0
  101. package/skills/03-implementation/bug-fix/references/README.md +17 -0
  102. package/skills/03-implementation/bug-fix/references/cases.md +26 -0
  103. package/skills/03-implementation/bug-fix/references/prompt-template.md +18 -0
  104. package/skills/03-implementation/bug-fix/skill-spec.json +25 -0
  105. package/skills/03-implementation/database-change/SKILL.md +29 -0
  106. package/skills/03-implementation/database-change/assets/golden-prompt-suite.current.js +22 -0
  107. package/skills/03-implementation/database-change/references/README.md +17 -0
  108. package/skills/03-implementation/database-change/references/cases.md +26 -0
  109. package/skills/03-implementation/database-change/references/prompt-template.md +18 -0
  110. package/skills/03-implementation/database-change/skill-spec.json +25 -0
  111. package/skills/03-implementation/frontend-development/SKILL.md +29 -0
  112. package/skills/03-implementation/frontend-development/assets/golden-prompt-suite.current.js +22 -0
  113. package/skills/03-implementation/frontend-development/references/README.md +17 -0
  114. package/skills/03-implementation/frontend-development/references/cases.md +26 -0
  115. package/skills/03-implementation/frontend-development/references/prompt-template.md +18 -0
  116. package/skills/03-implementation/frontend-development/skill-spec.json +25 -0
  117. package/skills/04-validation/code-review/SKILL.md +29 -0
  118. package/skills/04-validation/code-review/assets/golden-prompt-suite.current.js +22 -0
  119. package/skills/04-validation/code-review/references/README.md +17 -0
  120. package/skills/04-validation/code-review/references/cases.md +26 -0
  121. package/skills/04-validation/code-review/references/prompt-template.md +18 -0
  122. package/skills/04-validation/code-review/skill-spec.json +25 -0
  123. package/skills/04-validation/performance-review/SKILL.md +29 -0
  124. package/skills/04-validation/performance-review/assets/golden-prompt-suite.current.js +22 -0
  125. package/skills/04-validation/performance-review/references/README.md +17 -0
  126. package/skills/04-validation/performance-review/references/cases.md +26 -0
  127. package/skills/04-validation/performance-review/references/prompt-template.md +18 -0
  128. package/skills/04-validation/performance-review/skill-spec.json +25 -0
  129. package/skills/04-validation/regression-check/SKILL.md +29 -0
  130. package/skills/04-validation/regression-check/assets/golden-prompt-suite.current.js +22 -0
  131. package/skills/04-validation/regression-check/references/README.md +17 -0
  132. package/skills/04-validation/regression-check/references/cases.md +26 -0
  133. package/skills/04-validation/regression-check/references/prompt-template.md +18 -0
  134. package/skills/04-validation/regression-check/skill-spec.json +25 -0
  135. package/skills/04-validation/security-review/SKILL.md +29 -0
  136. package/skills/04-validation/security-review/assets/golden-prompt-suite.current.js +22 -0
  137. package/skills/04-validation/security-review/references/README.md +17 -0
  138. package/skills/04-validation/security-review/references/cases.md +26 -0
  139. package/skills/04-validation/security-review/references/prompt-template.md +18 -0
  140. package/skills/04-validation/security-review/skill-spec.json +25 -0
  141. package/skills/04-validation/unit-test/SKILL.md +29 -0
  142. package/skills/04-validation/unit-test/assets/golden-prompt-suite.current.js +22 -0
  143. package/skills/04-validation/unit-test/references/README.md +17 -0
  144. package/skills/04-validation/unit-test/references/cases.md +26 -0
  145. package/skills/04-validation/unit-test/references/prompt-template.md +18 -0
  146. package/skills/04-validation/unit-test/skill-spec.json +25 -0
  147. package/skills/05-delivery/change-log/SKILL.md +29 -0
  148. package/skills/05-delivery/change-log/assets/golden-prompt-suite.current.js +22 -0
  149. package/skills/05-delivery/change-log/references/README.md +17 -0
  150. package/skills/05-delivery/change-log/references/cases.md +26 -0
  151. package/skills/05-delivery/change-log/references/prompt-template.md +18 -0
  152. package/skills/05-delivery/change-log/skill-spec.json +25 -0
  153. package/skills/05-delivery/deployment-guide/SKILL.md +29 -0
  154. package/skills/05-delivery/deployment-guide/assets/golden-prompt-suite.current.js +22 -0
  155. package/skills/05-delivery/deployment-guide/references/README.md +17 -0
  156. package/skills/05-delivery/deployment-guide/references/cases.md +26 -0
  157. package/skills/05-delivery/deployment-guide/references/prompt-template.md +18 -0
  158. package/skills/05-delivery/deployment-guide/skill-spec.json +25 -0
  159. package/skills/05-delivery/release-check/SKILL.md +29 -0
  160. package/skills/05-delivery/release-check/assets/golden-prompt-suite.current.js +22 -0
  161. package/skills/05-delivery/release-check/references/README.md +17 -0
  162. package/skills/05-delivery/release-check/references/cases.md +26 -0
  163. package/skills/05-delivery/release-check/references/prompt-template.md +18 -0
  164. package/skills/05-delivery/release-check/skill-spec.json +25 -0
  165. package/skills/05-delivery/release-validation/SKILL.md +29 -0
  166. package/skills/05-delivery/release-validation/assets/golden-prompt-suite.current.js +22 -0
  167. package/skills/05-delivery/release-validation/references/README.md +17 -0
  168. package/skills/05-delivery/release-validation/references/cases.md +26 -0
  169. package/skills/05-delivery/release-validation/references/prompt-template.md +18 -0
  170. package/skills/05-delivery/release-validation/skill-spec.json +25 -0
  171. package/skills/shared/codebase-learning/SKILL.md +29 -0
  172. package/skills/shared/codebase-learning/assets/golden-prompt-suite.current.js +22 -0
  173. package/skills/shared/codebase-learning/references/README.md +17 -0
  174. package/skills/shared/codebase-learning/references/cases.md +26 -0
  175. package/skills/shared/codebase-learning/references/prompt-template.md +18 -0
  176. package/skills/shared/codebase-learning/skill-spec.json +25 -0
  177. package/skills/shared/evidence-collector/SKILL.md +29 -0
  178. package/skills/shared/evidence-collector/assets/golden-prompt-suite.current.js +22 -0
  179. package/skills/shared/evidence-collector/references/README.md +17 -0
  180. package/skills/shared/evidence-collector/references/cases.md +26 -0
  181. package/skills/shared/evidence-collector/references/prompt-template.md +18 -0
  182. package/skills/shared/evidence-collector/skill-spec.json +25 -0
  183. package/skills/shared/framework-guide/SKILL.md +28 -0
  184. package/skills/shared/framework-guide/assets/golden-prompt-suite.current.js +22 -0
  185. package/skills/shared/framework-guide/references/README.md +17 -0
  186. package/skills/shared/framework-guide/references/cases.md +26 -0
  187. package/skills/shared/framework-guide/references/prompt-template.md +18 -0
  188. package/skills/shared/framework-guide/skill-spec.json +24 -0
  189. package/rules/bundles.json +0 -358
  190. package/rules/coding/analysis.md +0 -27
  191. package/rules/coding/backend/cache-invalidation.md +0 -30
  192. package/rules/coding/backend/cache-keying.md +0 -30
  193. package/rules/coding/backend/cache.md +0 -37
  194. package/rules/coding/backend/database.md +0 -32
  195. package/rules/coding/backend/feign.md +0 -30
  196. package/rules/coding/backend/index.md +0 -42
  197. package/rules/coding/backend/query.md +0 -32
  198. package/rules/coding/backend/remote.md +0 -33
  199. package/rules/coding/backend/transaction-boundary.md +0 -30
  200. package/rules/coding/backend/transaction-rollback.md +0 -30
  201. package/rules/coding/backend/transaction.md +0 -38
  202. package/rules/coding/boundary.md +0 -25
  203. package/rules/coding/implementation.md +0 -26
  204. package/rules/coding/index.md +0 -38
  205. package/rules/coding/scaffold.md +0 -28
  206. package/rules/coding/testing.md +0 -29
  207. package/rules/coding/validation.md +0 -29
  208. package/rules/core/code-quality.md +0 -30
  209. package/rules/core/evidence.md +0 -26
  210. package/rules/core/interface.md +0 -26
  211. package/rules/core/iteration.md +0 -26
  212. package/rules/core/layer-boundary.md +0 -25
  213. package/rules/core/logging.md +0 -26
  214. package/rules/core/security.md +0 -26
  215. package/rules/core/task-boundary.md +0 -27
  216. package/rules/docs/api.md +0 -34
  217. package/rules/docs/capture-summary.md +0 -29
  218. package/rules/docs/capture.md +0 -34
  219. package/rules/docs/contract.md +0 -30
  220. package/rules/docs/decision-log.md +0 -32
  221. package/rules/docs/examples.md +0 -28
  222. package/rules/docs/index.md +0 -49
  223. package/rules/docs/reference.md +0 -32
  224. package/rules/overlays/pig-cloud/controller.md +0 -33
  225. package/rules/overlays/pig-cloud/dto-vo.md +0 -33
  226. package/rules/overlays/pig-cloud/entity.md +0 -32
  227. package/rules/overlays/pig-cloud/exception.md +0 -32
  228. package/rules/overlays/pig-cloud/layering.md +0 -31
  229. package/rules/overlays/pig-cloud/mapper.md +0 -32
  230. package/rules/overlays/pig-cloud/query-style.md +0 -32
  231. package/rules/overlays/pig-cloud/rest-response.md +0 -33
  232. package/rules/overlays/pig-cloud/service.md +0 -33
  233. package/rules/overlays/pig-cloud/transactions.md +0 -32
  234. package/rules/overlays/pig-cloud/validation.md +0 -33
  235. package/rules/product/acceptance.md +0 -25
  236. package/rules/product/briefing.md +0 -27
  237. package/rules/product/index.md +0 -36
  238. package/rules/product/intake.md +0 -27
  239. package/rules/product/modeling.md +0 -25
  240. package/rules/product/project-context.md +0 -29
  241. package/rules/review/code.md +0 -35
  242. package/rules/review/evidence.md +0 -31
  243. package/rules/review/index.md +0 -50
  244. package/rules/review/java.md +0 -42
  245. package/rules/review/performance.md +0 -38
  246. package/rules/review/rubric.md +0 -28
  247. package/rules/review/security.md +0 -38
  248. package/rules/review/ts.md +0 -33
  249. package/rules/review/vue.md +0 -33
  250. package/rules/skill-profile-map.json +0 -59
  251. package/rules/skill-profile-map.md +0 -29
  252. package/rules/workflow/handoff.md +0 -25
  253. package/rules/workflow/index.md +0 -37
  254. package/rules/workflow/refinement.md +0 -29
  255. package/rules/workflow/router.md +0 -25
  256. package/rules/workflow/selection.md +0 -25
  257. package/rules/workflow/stop.md +0 -25
  258. package/skills/api-contract-docs/SKILL.md +0 -77
  259. package/skills/business-fact-extraction/SKILL.md +0 -337
  260. package/skills/business-fact-extraction/scripts/write-knowledge-base.js +0 -228
  261. package/skills/code-review/SKILL.md +0 -136
  262. package/skills/code-review/references/findings-template.md +0 -51
  263. package/skills/code-review/references/performance-checklist.md +0 -213
  264. package/skills/code-review/references/rubric.md +0 -232
  265. package/skills/code-review/references/rules.md +0 -32
  266. package/skills/code-review/references/security-checklist.md +0 -178
  267. package/skills/code-review/references/stack-notes.md +0 -25
  268. package/skills/code-review/references/template-review.md +0 -39
  269. package/skills/code-review/scripts/lint-code-review.mjs +0 -431
  270. package/skills/domain-modeling/SKILL.md +0 -81
  271. package/skills/domain-modeling/references/README.md +0 -134
  272. package/skills/domain-modeling/references/distillation-checklist.md +0 -44
  273. package/skills/domain-modeling/references/test-cases-template.md +0 -128
  274. package/skills/environment-deploy/SKILL.md +0 -81
  275. package/skills/feature-build/SKILL.md +0 -122
  276. package/skills/feature-build/references/coding-checklist.md +0 -97
  277. package/skills/feature-build/references/comment-specification.md +0 -89
  278. package/skills/knowledge-capture/SKILL.md +0 -93
  279. package/skills/performance-audit/SKILL.md +0 -118
  280. package/skills/project-bootstrap/SKILL.md +0 -81
  281. package/skills/references/anti-rationalization.md +0 -144
  282. package/skills/references/business-fact-extraction.md +0 -415
  283. package/skills/references/engineering-delivery-method.md +0 -64
  284. package/skills/references/engineering-delivery-template.md +0 -81
  285. package/skills/references/golden-prompt-suite.js +0 -436
  286. package/skills/references/golden-prompt-suite.md +0 -33
  287. package/skills/references/project-requirement-alignment.md +0 -42
  288. package/skills/references/rule-loading-map.md +0 -117
  289. package/skills/references/skill-authoring-standard.md +0 -74
  290. package/skills/references/skill-boundary-template.md +0 -71
  291. package/skills/references/skill-enhanced-template.md +0 -103
  292. package/skills/references/skill-reference-matrix.md +0 -62
  293. package/skills/security-audit/SKILL.md +0 -119
  294. package/skills/spec-refinement/SKILL.md +0 -149
  295. package/skills/technical-design/SKILL.md +0 -106
  296. package/skills/technical-design/references/solid-checklist.md +0 -199
  297. package/skills/test-design/SKILL.md +0 -92
  298. package/skills/workflow-router/SKILL.md +0 -86
@@ -4,18 +4,45 @@ const fs = require('fs');
4
4
  const https = require('https');
5
5
  const path = require('path');
6
6
 
7
- const suite = require('../skills/references/golden-prompt-suite.js');
8
-
9
- const repoRoot = path.join(__dirname, '..');
10
- const skillsRoot = path.join(repoRoot, 'skills');
11
-
12
- function parseArgs(argv) {
13
- const options = {
14
- provider: process.env.PIG_SKILLS_REPLAY_PROVIDER || 'openai',
15
- model: process.env.OPENAI_MODEL || 'gpt-4.1-mini',
16
- limit: 0,
17
- out: null,
18
- };
7
+ const repoRoot = path.join(__dirname, '..');
8
+ const skillsRoot = path.join(repoRoot, 'skills');
9
+
10
+ function readSkillDirectories() {
11
+ if (!fs.existsSync(skillsRoot)) {
12
+ return [];
13
+ }
14
+
15
+ const results = [];
16
+
17
+ function walk(dir) {
18
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
19
+ if (entry.name === 'references') {
20
+ continue;
21
+ }
22
+
23
+ const fullPath = path.join(dir, entry.name);
24
+ if (entry.isDirectory()) {
25
+ const skillFile = path.join(fullPath, 'SKILL.md');
26
+ if (fs.existsSync(skillFile)) {
27
+ results.push(fullPath);
28
+ }
29
+ walk(fullPath);
30
+ }
31
+ }
32
+ }
33
+
34
+ walk(skillsRoot);
35
+ return results.sort();
36
+ }
37
+
38
+ function parseArgs(argv) {
39
+ const options = {
40
+ provider: process.env.PIG_SKILLS_REPLAY_PROVIDER || 'openai',
41
+ model: process.env.OPENAI_MODEL || 'gpt-4.1-mini',
42
+ suite: process.env.PIG_SKILLS_REPLAY_SUITE || 'current',
43
+ limit: 0,
44
+ out: null,
45
+ };
19
46
 
20
47
  for (let index = 0; index < argv.length; index += 1) {
21
48
  const token = argv[index];
@@ -27,17 +54,25 @@ function parseArgs(argv) {
27
54
  options.provider = token.slice('--provider='.length);
28
55
  continue;
29
56
  }
30
- if (token === '--model') {
31
- options.model = argv[++index];
32
- continue;
33
- }
34
- if (token.startsWith('--model=')) {
35
- options.model = token.slice('--model='.length);
36
- continue;
37
- }
38
- if (token === '--limit') {
39
- options.limit = Number(argv[++index]) || 0;
40
- continue;
57
+ if (token === '--model') {
58
+ options.model = argv[++index];
59
+ continue;
60
+ }
61
+ if (token.startsWith('--model=')) {
62
+ options.model = token.slice('--model='.length);
63
+ continue;
64
+ }
65
+ if (token === '--suite') {
66
+ options.suite = argv[++index];
67
+ continue;
68
+ }
69
+ if (token.startsWith('--suite=')) {
70
+ options.suite = token.slice('--suite='.length);
71
+ continue;
72
+ }
73
+ if (token === '--limit') {
74
+ options.limit = Number(argv[++index]) || 0;
75
+ continue;
41
76
  }
42
77
  if (token.startsWith('--limit=')) {
43
78
  options.limit = Number(token.slice('--limit='.length)) || 0;
@@ -53,55 +88,49 @@ function parseArgs(argv) {
53
88
  }
54
89
  }
55
90
 
56
- return options;
57
- }
58
-
59
- function readSkillCatalog() {
60
- return fs.readdirSync(skillsRoot, { withFileTypes: true })
61
- .filter((entry) => entry.isDirectory() && entry.name !== 'references')
62
- .map((entry) => {
63
- const skillFile = path.join(skillsRoot, entry.name, 'SKILL.md');
64
- const content = fs.readFileSync(skillFile, 'utf8');
65
- const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
66
- const frontmatter = frontmatterMatch ? frontmatterMatch[1] : '';
67
- const name = (frontmatter.match(/^name:\s*(.+)$/m) || [])[1]?.trim() || entry.name;
68
- const description = (frontmatter.match(/^description:\s*(.+)$/m) || [])[1]?.trim() || '';
69
- const lifecycleStage = (frontmatter.match(/^lifecycle_stage:\s*(.+)$/m) || [])[1]?.trim() || '';
70
- const outputSection = (content.match(/## Output\s+([\s\S]*?)(?:\n## |\n---|$)/) || [])[1] || '';
71
- const gatesSection = (content.match(/## Stop Rules\s+([\s\S]*?)(?:\n## |\n---|$)/) || [])[1] || '';
72
-
73
- return {
74
- name,
75
- description,
76
- lifecycleStage,
77
- outputs: outputSection
78
- .split(/\r?\n/)
79
- .map((line) => line.trim().replace(/^-+\s*/, ''))
80
- .filter(Boolean)
81
- .map((line) => line.replace(/^[*-]\s*/, '')),
82
- stopRules: gatesSection
83
- .split(/\r?\n/)
84
- .map((line) => line.trim().replace(/^-+\s*/, ''))
85
- .filter(Boolean),
86
- };
87
- });
88
- }
91
+ return options;
92
+ }
93
+
94
+ function loadSuite(suiteName) {
95
+ const currentSuitePath = path.join(repoRoot, 'scripts', 'golden-prompt-suite.current.js');
96
+ if (fs.existsSync(currentSuitePath)) {
97
+ return require(currentSuitePath);
98
+ }
99
+ throw new Error(`Missing replay suite: ${currentSuitePath}`);
100
+ }
101
+
102
+ function readSkillCatalog() {
103
+ return readSkillDirectories()
104
+ .map((skillDir) => {
105
+ const skillFile = path.join(skillDir, 'SKILL.md');
106
+ const content = fs.readFileSync(skillFile, 'utf8');
107
+ const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
108
+ const frontmatter = frontmatterMatch ? frontmatterMatch[1] : '';
109
+ const name = (frontmatter.match(/^name:\s*(.+)$/m) || [])[1]?.trim() || path.basename(skillDir);
110
+ const description = (frontmatter.match(/^description:\s*(.+)$/m) || [])[1]?.trim() || '';
111
+
112
+ return {
113
+ name,
114
+ description,
115
+ };
116
+ });
117
+ }
89
118
 
90
119
  function buildSystemPrompt(catalog) {
91
- const lines = [
92
- 'You are evaluating the pig-skills workflow replay suite.',
93
- 'Choose the first skill that should handle the prompt.',
94
- 'Return ONLY valid JSON with these keys:',
95
- '{"firstSkill":"...","artifact":"...","stopRule":"...","handoff":"...","notes":"..."}',
96
- 'Use exact canonical skill names.',
97
- 'Artifact should be short and reflect the expected work product.',
98
- 'Do not explain your reasoning outside the JSON object.',
99
- '',
100
- 'Available skills:',
101
- ...catalog.map((skill) => `- ${skill.name} | ${skill.description} | outputs: ${skill.outputs.join('; ')} | stop: ${skill.stopRules.join(' | ')}`),
102
- ];
103
- return lines.join('\n');
104
- }
120
+ const lines = [
121
+ 'You are evaluating the pig-skills workflow replay suite.',
122
+ 'Choose the first skill that should handle the prompt.',
123
+ 'Return ONLY valid JSON with these keys:',
124
+ '{"firstSkill":"...","artifact":"...","stopRule":"...","handoff":"...","notes":"..."}',
125
+ 'Use exact canonical skill names.',
126
+ 'Artifact should be short and reflect the expected work product.',
127
+ 'Do not explain your reasoning outside the JSON object.',
128
+ '',
129
+ 'Available skills:',
130
+ ...catalog.map((skill) => `- ${skill.name} | ${skill.description}`),
131
+ ];
132
+ return lines.join('\n');
133
+ }
105
134
 
106
135
  function normalizeText(value) {
107
136
  return String(value || '')
@@ -255,11 +284,12 @@ async function evaluateCase(testCase, context) {
255
284
  };
256
285
  }
257
286
 
258
- async function main() {
259
- const options = parseArgs(process.argv.slice(2));
260
- const catalog = readSkillCatalog();
261
- const systemPrompt = buildSystemPrompt(catalog);
262
- const cases = options.limit > 0 ? suite.cases.slice(0, options.limit) : suite.cases;
287
+ async function main() {
288
+ const options = parseArgs(process.argv.slice(2));
289
+ const suite = loadSuite(options.suite);
290
+ const catalog = readSkillCatalog();
291
+ const systemPrompt = buildSystemPrompt(catalog);
292
+ const cases = options.limit > 0 ? suite.cases.slice(0, options.limit) : suite.cases;
263
293
 
264
294
  const context = {
265
295
  provider: options.provider,
@@ -267,10 +297,11 @@ async function main() {
267
297
  systemPrompt,
268
298
  };
269
299
 
270
- console.log(`# Golden replay run`);
271
- console.log(`provider: ${context.provider}`);
272
- console.log(`model: ${context.model}`);
273
- console.log(`cases: ${cases.length}`);
300
+ console.log(`# Golden replay run`);
301
+ console.log(`suite: ${options.suite}`);
302
+ console.log(`provider: ${context.provider}`);
303
+ console.log(`model: ${context.model}`);
304
+ console.log(`cases: ${cases.length}`);
274
305
 
275
306
  const results = [];
276
307
  for (const testCase of cases) {
@@ -1,125 +1,128 @@
1
- #!/usr/bin/env node
2
-
3
- const fs = require('fs');
4
- const path = require('path');
5
-
6
- const repoRoot = path.join(__dirname, '..');
7
- const rulesRoot = path.join(repoRoot, 'rules');
8
- const bundlesPath = path.join(rulesRoot, 'bundles.json');
9
- const skillProfileMapPath = path.join(rulesRoot, 'skill-profile-map.json');
10
- const skillsRoot = path.join(repoRoot, 'skills');
11
- const expectedBundles = ['core', 'workflow', 'product', 'coding', 'docs', 'review', 'overlays'];
12
- const requiredSections = [
13
- '## 默认做法',
14
- '## 禁区',
15
- '## 检查',
16
- '## 回放信号',
17
- '## References',
18
- ];
19
-
20
- function readJson(filePath) {
21
- return JSON.parse(fs.readFileSync(filePath, 'utf8'));
22
- }
23
-
24
- function readText(filePath) {
25
- return fs.readFileSync(filePath, 'utf8');
26
- }
27
-
28
- function assert(condition, message) {
29
- if (!condition) {
30
- throw new Error(message);
31
- }
32
- }
33
-
34
- function readSkillDirectories() {
35
- return fs.readdirSync(skillsRoot, { withFileTypes: true })
36
- .filter((entry) => entry.isDirectory() && entry.name !== 'references')
37
- .map((entry) => entry.name)
38
- .sort();
39
- }
40
-
41
- function readSkillProfile(skillName) {
42
- const skillFile = path.join(skillsRoot, skillName, 'SKILL.md');
43
- const content = readText(skillFile);
44
- const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
45
- if (!match) return null;
46
- const profileMatch = match[1].match(/^rule_profile:\s*(.+)$/m);
47
- return profileMatch ? profileMatch[1].trim() : null;
48
- }
49
-
50
- function verifyBundleFiles(bundleName, bundleConfig) {
51
- assert(bundleConfig && typeof bundleConfig === 'object', `${bundleName}: missing bundle config`);
52
- assert(typeof bundleConfig.entry === 'string' && bundleConfig.entry.length > 0, `${bundleName}: missing entry`);
53
- assert(Array.isArray(bundleConfig.files) && bundleConfig.files.length > 0, `${bundleName}: missing files`);
54
-
55
- const files = new Set(bundleConfig.files);
56
- files.add(bundleConfig.entry);
57
-
58
- for (const relativePath of files) {
59
- assert(relativePath.startsWith(`${bundleName}/`) || relativePath === `${bundleName}/index.md`, `${bundleName}: file escapes bundle namespace: ${relativePath}`);
60
- const filePath = path.join(rulesRoot, relativePath);
61
- assert(fs.existsSync(filePath), `${bundleName}: missing file ${relativePath}`);
62
- const content = readText(filePath);
63
- for (const section of requiredSections) {
64
- assert(content.includes(section), `${relativePath}: missing section ${section}`);
65
- }
66
- }
67
-
68
- if (bundleConfig.profiles) {
69
- for (const [profileName, profileConfig] of Object.entries(bundleConfig.profiles)) {
70
- assert(typeof profileConfig.entry === 'string' && profileConfig.entry.length > 0, `${bundleName}/${profileName}: missing entry`);
71
- assert(Array.isArray(profileConfig.files) && profileConfig.files.length > 0, `${bundleName}/${profileName}: missing files`);
72
- const profileFiles = new Set(profileConfig.files);
73
- profileFiles.add(profileConfig.entry);
74
- for (const relativePath of profileFiles) {
75
- assert(relativePath.startsWith(`${bundleName}/`) || relativePath === `${bundleName}/index.md`, `${bundleName}/${profileName}: file escapes bundle namespace: ${relativePath}`);
76
- const filePath = path.join(rulesRoot, relativePath);
77
- assert(fs.existsSync(filePath), `${bundleName}/${profileName}: missing file ${relativePath}`);
78
- }
79
- }
80
- }
81
- }
82
-
83
- function main() {
84
- const bundles = readJson(bundlesPath);
85
- const skillProfileMap = readJson(skillProfileMapPath);
86
- const skillDirs = readSkillDirectories();
87
-
88
- for (const bundleName of expectedBundles) {
89
- assert(Object.prototype.hasOwnProperty.call(bundles, bundleName), `bundles.json missing ${bundleName} bundle`);
90
- }
91
-
92
- for (const [bundleName, bundleConfig] of Object.entries(bundles)) {
93
- verifyBundleFiles(bundleName, bundleConfig);
94
- }
95
-
96
- for (const skillName of skillDirs) {
97
- const declaredProfile = readSkillProfile(skillName);
98
- assert(declaredProfile, `${skillName}: missing rule_profile`);
99
- const mapped = skillProfileMap[skillName];
100
- assert(mapped, `${skillName}: missing skill-profile mapping`);
101
- assert(mapped.profile === declaredProfile, `${skillName}: profile mismatch (${mapped.profile} != ${declaredProfile})`);
102
- assert(expectedBundles.includes(mapped.bundle), `${skillName}: unknown bundle ${mapped.bundle}`);
103
- assert(bundles[mapped.bundle].profiles && bundles[mapped.bundle].profiles[mapped.profile], `${skillName}: unknown profile ${mapped.bundle}/${mapped.profile}`);
104
- }
105
-
106
- const indexContent = readText(path.join(rulesRoot, 'index.md'));
107
- for (const bundleName of expectedBundles) {
108
- assert(indexContent.includes(bundleName), `rules/index.md should mention ${bundleName}`);
109
- }
110
- assert(indexContent.includes('skill-profile-map.json'), 'rules/index.md should mention skill-profile-map.json');
111
-
112
- const loaderContent = readText(path.join(repoRoot, 'bin', 'rules-loader.js'));
113
- assert(loaderContent.includes("const CORE_BUNDLE_NAME = 'core'"), 'rules-loader.js should define core bundle');
114
- assert(loaderContent.includes("const CORE_PROFILE_NAME = 'core'"), 'rules-loader.js should define core profile');
115
- assert(loaderContent.includes("hasCodingSignals"), 'rules-loader.js should define coding detection');
116
-
117
- console.log(`=== Rules validation complete for ${skillDirs.length} skills and ${Object.keys(bundles).length} bundles ===`);
118
- }
119
-
120
- try {
121
- main();
122
- } catch (error) {
123
- console.error(error.message);
124
- process.exitCode = 1;
125
- }
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ const repoRoot = path.join(__dirname, '..');
7
+ const rulesRoot = path.join(repoRoot, 'rules');
8
+ const stagesPath = path.join(rulesRoot, 'stages.json');
9
+ const skillStageMapPath = path.join(rulesRoot, 'skill-stage-map.json');
10
+ const skillsRoot = path.join(repoRoot, 'skills');
11
+ const expectedStages = ['core', 'discovery', 'design', 'implementation', 'validation', 'delivery', 'shared', 'overlays'];
12
+
13
+ function readJson(filePath) {
14
+ return JSON.parse(fs.readFileSync(filePath, 'utf8'));
15
+ }
16
+
17
+ function assert(condition, message) {
18
+ if (!condition) {
19
+ throw new Error(message);
20
+ }
21
+ }
22
+
23
+ function readSkillDirectories() {
24
+ const results = [];
25
+
26
+ function walk(dir) {
27
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
28
+ if (entry.name === 'references') {
29
+ continue;
30
+ }
31
+
32
+ const fullPath = path.join(dir, entry.name);
33
+ if (entry.isDirectory()) {
34
+ const skillFile = path.join(fullPath, 'SKILL.md');
35
+ if (fs.existsSync(skillFile)) {
36
+ results.push(skillFile);
37
+ }
38
+ walk(fullPath);
39
+ }
40
+ }
41
+ }
42
+
43
+ walk(skillsRoot);
44
+ return results.sort();
45
+ }
46
+
47
+ function readSkillName(skillFile) {
48
+ const content = fs.readFileSync(skillFile, 'utf8');
49
+ const match = content.match(/^name:\s*(.+)$/m);
50
+ return match ? match[1].trim() : '';
51
+ }
52
+
53
+ function verifyStageFiles(stageName, stageConfig) {
54
+ assert(stageConfig && typeof stageConfig === 'object', `${stageName}: missing stage config`);
55
+ assert(typeof stageConfig.entry === 'string' && stageConfig.entry.length > 0, `${stageName}: missing entry`);
56
+ assert(Array.isArray(stageConfig.files) && stageConfig.files.length > 0, `${stageName}: missing files`);
57
+
58
+ const files = new Set(stageConfig.files);
59
+ files.add(stageConfig.entry);
60
+
61
+ for (const relativePath of files) {
62
+ assert(relativePath.startsWith(`${stageName}/`) || stageName === 'overlays' || relativePath === 'core/index.md', `${stageName}: file escapes stage namespace: ${relativePath}`);
63
+ const filePath = path.join(rulesRoot, relativePath);
64
+ assert(fs.existsSync(filePath), `${stageName}: missing file ${relativePath}`);
65
+ }
66
+
67
+ if (stageConfig.variants) {
68
+ for (const [variantName, variantConfig] of Object.entries(stageConfig.variants)) {
69
+ assert(typeof variantConfig.entry === 'string' && variantConfig.entry.length > 0, `${stageName}/${variantName}: missing entry`);
70
+ assert(Array.isArray(variantConfig.files) && variantConfig.files.length > 0, `${stageName}/${variantName}: missing files`);
71
+
72
+ const variantFiles = new Set(variantConfig.files);
73
+ variantFiles.add(variantConfig.entry);
74
+
75
+ for (const relativePath of variantFiles) {
76
+ assert(relativePath.startsWith(`${stageName}/`) || relativePath === 'core/index.md' || relativePath === 'overlays/index.md' || relativePath === 'overlays/pig-cloud.md', `${stageName}/${variantName}: file escapes stage namespace: ${relativePath}`);
77
+ const filePath = path.join(rulesRoot, relativePath);
78
+ assert(fs.existsSync(filePath), `${stageName}/${variantName}: missing file ${relativePath}`);
79
+ }
80
+ }
81
+ }
82
+ }
83
+
84
+ function main() {
85
+ assert(!fs.existsSync(path.join(rulesRoot, 'bundles.json')), 'legacy bundles.json should not exist');
86
+ assert(!fs.existsSync(path.join(rulesRoot, 'skill-profile-map.json')), 'legacy skill-profile-map.json should not exist');
87
+
88
+ const stages = readJson(stagesPath);
89
+ const skillStageMap = readJson(skillStageMapPath);
90
+ const skillFiles = readSkillDirectories();
91
+
92
+ for (const stageName of expectedStages) {
93
+ assert(Object.prototype.hasOwnProperty.call(stages, stageName), `stages.json missing ${stageName} stage`);
94
+ }
95
+
96
+ for (const [stageName, stageConfig] of Object.entries(stages)) {
97
+ verifyStageFiles(stageName, stageConfig);
98
+ }
99
+
100
+ for (const skillFile of skillFiles) {
101
+ const skillName = readSkillName(skillFile);
102
+ assert(skillName, `${path.relative(repoRoot, skillFile)}: missing skill name`);
103
+ const mapped = skillStageMap[skillName];
104
+ assert(mapped, `${skillName}: missing skill-stage mapping`);
105
+ assert(expectedStages.includes(mapped.stage), `${skillName}: unknown stage ${mapped.stage}`);
106
+ assert(stages[mapped.stage], `${skillName}: unknown stage config ${mapped.stage}`);
107
+ }
108
+
109
+ const indexContent = fs.readFileSync(path.join(rulesRoot, 'index.md'), 'utf8');
110
+ for (const stageName of expectedStages) {
111
+ assert(indexContent.includes(stageName), `rules/index.md should mention ${stageName}`);
112
+ }
113
+ assert(indexContent.includes('skill-stage-map.json'), 'rules/index.md should mention skill-stage-map.json');
114
+
115
+ const loaderContent = fs.readFileSync(path.join(repoRoot, 'bin', 'rules-loader.js'), 'utf8');
116
+ assert(loaderContent.includes('detectRulesStage'), 'rules-loader.js should define detectRulesStage');
117
+ assert(!loaderContent.includes('hasCodingSignals'), 'rules-loader.js should not use workspace coding detection');
118
+ assert(!loaderContent.includes('detectRulesBundle'), 'rules-loader.js should not expose bundle-based routing');
119
+
120
+ console.log(`=== Rules validation complete for ${skillFiles.length} skills and ${Object.keys(stages).length} stages ===`);
121
+ }
122
+
123
+ try {
124
+ main();
125
+ } catch (error) {
126
+ console.error(error.message);
127
+ process.exitCode = 1;
128
+ }
@@ -6,63 +6,51 @@ const path = require('path');
6
6
  const repoRoot = path.join(__dirname, '..');
7
7
  const skillsRoot = path.join(repoRoot, 'skills');
8
8
 
9
- function readSkillDirectories() {
10
- return fs.readdirSync(skillsRoot, { withFileTypes: true })
11
- .filter((entry) => entry.isDirectory() && entry.name !== 'references')
12
- .map((entry) => entry.name)
13
- .sort();
14
- }
15
-
16
- function readSkillFile(skillName) {
17
- const skillFile = path.join(skillsRoot, skillName, 'SKILL.md');
18
- return fs.readFileSync(skillFile, 'utf8');
19
- }
20
-
21
- function validateSkill(skillName) {
22
- const content = readSkillFile(skillName);
23
- const lines = content.split(/\r?\n/);
24
- const sectionLines = [];
25
- let inReplaySection = false;
26
-
27
- for (const rawLine of lines) {
28
- const line = rawLine.trim();
29
- if (!inReplaySection) {
30
- if (line === '## Replay Signals') {
31
- inReplaySection = true;
32
- }
33
- continue;
34
- }
35
-
36
- if (line.startsWith('## ')) {
37
- break;
38
- }
39
-
40
- if (line.length > 0) {
41
- sectionLines.push(line.replace(/^[-*]\s*/, ''));
42
- }
43
- }
44
-
45
- if (sectionLines.length === 0) {
46
- throw new Error(`${skillName}: missing Replay Signals section`);
47
- }
48
-
49
- const requiredPrefixes = [
50
- 'Input signal:',
51
- 'Output to verify:',
52
- 'Stop signal:',
53
- 'Handoff signal:',
54
- ];
55
-
56
- const missing = requiredPrefixes.filter((prefix) => !sectionLines.some((line) => line.startsWith(prefix)));
57
- if (missing.length > 0) {
58
- throw new Error(`${skillName}: Replay Signals missing lines: ${missing.join(' | ')}`);
59
- }
60
- }
61
-
62
- function main() {
63
- for (const skillName of readSkillDirectories()) {
64
- validateSkill(skillName);
65
- }
9
+ function readSkillDirectories() {
10
+ const results = [];
11
+
12
+ function walk(dir) {
13
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
14
+ if (entry.name === 'references') {
15
+ continue;
16
+ }
17
+
18
+ const fullPath = path.join(dir, entry.name);
19
+ if (entry.isDirectory()) {
20
+ const skillFile = path.join(fullPath, 'SKILL.md');
21
+ if (fs.existsSync(skillFile)) {
22
+ results.push(fullPath);
23
+ }
24
+ walk(fullPath);
25
+ }
26
+ }
27
+ }
28
+
29
+ walk(skillsRoot);
30
+ return results.sort();
31
+ }
32
+
33
+ function readSkillFile(skillDir) {
34
+ const skillFile = path.join(skillDir, 'SKILL.md');
35
+ return fs.readFileSync(skillFile, 'utf8');
36
+ }
37
+
38
+ function validateSkill(skillDir) {
39
+ const skillName = path.basename(skillDir);
40
+ const content = readSkillFile(skillDir);
41
+ const body = content.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, '');
42
+ if (!/##\s+Purpose/.test(body)) {
43
+ throw new Error(`${skillName}: missing Purpose section`);
44
+ }
45
+ if (!/##\s+When to Use/.test(body)) {
46
+ throw new Error(`${skillName}: missing When to Use section`);
47
+ }
48
+ }
49
+
50
+ function main() {
51
+ for (const skillDir of readSkillDirectories()) {
52
+ validateSkill(skillDir);
53
+ }
66
54
 
67
55
  console.log('=== Replay signal validation complete ===');
68
56
  }