cc-devflow 1.0.1

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 (277) hide show
  1. package/.claude/CLAUDE.md +83 -0
  2. package/.claude/agents/architecture-designer.md +443 -0
  3. package/.claude/agents/bug-analyzer.md +382 -0
  4. package/.claude/agents/checklist-agent.md +175 -0
  5. package/.claude/agents/clarify-analyst.md +50 -0
  6. package/.claude/agents/code-reviewer.md +71 -0
  7. package/.claude/agents/codex-analyzer.md +39 -0
  8. package/.claude/agents/compatibility-checker.md +580 -0
  9. package/.claude/agents/consistency-checker.md +532 -0
  10. package/.claude/agents/impact-analyzer.md +441 -0
  11. package/.claude/agents/planner.md +230 -0
  12. package/.claude/agents/prd-writer.md +320 -0
  13. package/.claude/agents/project-guidelines-generator.md +1329 -0
  14. package/.claude/agents/qa-tester.md +313 -0
  15. package/.claude/agents/release-manager.md +295 -0
  16. package/.claude/agents/security-reviewer.md +314 -0
  17. package/.claude/agents/style-guide-generator.md +458 -0
  18. package/.claude/agents/tech-architect.md +516 -0
  19. package/.claude/agents/ui-designer.md +485 -0
  20. package/.claude/commands/code-review-high.md +58 -0
  21. package/.claude/commands/core-architecture.md +429 -0
  22. package/.claude/commands/core-guidelines.md +486 -0
  23. package/.claude/commands/core-roadmap.md +439 -0
  24. package/.claude/commands/core-style.md +293 -0
  25. package/.claude/commands/flow-archive.md +245 -0
  26. package/.claude/commands/flow-checklist.md +260 -0
  27. package/.claude/commands/flow-clarify.md +136 -0
  28. package/.claude/commands/flow-constitution.md +82 -0
  29. package/.claude/commands/flow-dev.md +134 -0
  30. package/.claude/commands/flow-epic.md +150 -0
  31. package/.claude/commands/flow-fix.md +104 -0
  32. package/.claude/commands/flow-ideate.md +214 -0
  33. package/.claude/commands/flow-init.md +313 -0
  34. package/.claude/commands/flow-new.md +394 -0
  35. package/.claude/commands/flow-prd.md +131 -0
  36. package/.claude/commands/flow-qa.md +93 -0
  37. package/.claude/commands/flow-release.md +92 -0
  38. package/.claude/commands/flow-restart.md +98 -0
  39. package/.claude/commands/flow-status.md +64 -0
  40. package/.claude/commands/flow-tech.md +142 -0
  41. package/.claude/commands/flow-ui.md +189 -0
  42. package/.claude/commands/flow-update.md +111 -0
  43. package/.claude/commands/flow-upgrade.md +115 -0
  44. package/.claude/commands/flow-verify.md +96 -0
  45. package/.claude/commands/problem-analyzer.md +60 -0
  46. package/.claude/config/quality-rules.yml +161 -0
  47. package/.claude/docs/SPEC_KIT_CONSTITUTION_ANALYSIS.md +426 -0
  48. package/.claude/docs/design/consistency-conflict-detection-algorithms.md +658 -0
  49. package/.claude/docs/design/intent-driven-input-design.md +380 -0
  50. package/.claude/docs/design/prd-version-management-design.md +437 -0
  51. package/.claude/docs/guides/INIT_TROUBLESHOOTING.md +117 -0
  52. package/.claude/docs/guides/NEW_TROUBLESHOOTING.md +151 -0
  53. package/.claude/docs/guides/ROADMAP_TROUBLESHOOTING.md +188 -0
  54. package/.claude/docs/guides/TASK_COMPLETION_MARKING.md +338 -0
  55. package/.claude/docs/templates/ARCHITECTURE_TEMPLATE.md +633 -0
  56. package/.claude/docs/templates/BACKLOG_TEMPLATE.md +261 -0
  57. package/.claude/docs/templates/CHECKLIST_TEMPLATE.md +52 -0
  58. package/.claude/docs/templates/CLARIFICATION_REPORT_TEMPLATE.md +206 -0
  59. package/.claude/docs/templates/CODE_REVIEW_TEMPLATE.md +71 -0
  60. package/.claude/docs/templates/EPIC_TEMPLATE.md +805 -0
  61. package/.claude/docs/templates/INIT_FLOW_TEMPLATE.md +213 -0
  62. package/.claude/docs/templates/INTENT_CLARIFICATION_TEMPLATE.md +57 -0
  63. package/.claude/docs/templates/NEW_ORCHESTRATION_TEMPLATE.md +148 -0
  64. package/.claude/docs/templates/PRD_TEMPLATE.md +562 -0
  65. package/.claude/docs/templates/RESEARCH_TEMPLATE.md +276 -0
  66. package/.claude/docs/templates/REVIEW-HIGH.md +57 -0
  67. package/.claude/docs/templates/ROADMAP_DIALOGUE_TEMPLATE.md +198 -0
  68. package/.claude/docs/templates/ROADMAP_TEMPLATE.md +310 -0
  69. package/.claude/docs/templates/STYLE_TEMPLATE.md +1266 -0
  70. package/.claude/docs/templates/TASKS_TEMPLATE.md +523 -0
  71. package/.claude/docs/templates/TECH_DESIGN_TEMPLATE.md +1019 -0
  72. package/.claude/docs/templates/UI_PROTOTYPE_TEMPLATE.md +1436 -0
  73. package/.claude/guides/agent-guides/agent-coordination-guide.md +459 -0
  74. package/.claude/guides/project-guidelines-system.md +463 -0
  75. package/.claude/guides/technical-guides/datetime-handling-guide.md +563 -0
  76. package/.claude/guides/technical-guides/git-github-guide.md +642 -0
  77. package/.claude/guides/technical-guides/test-execution-guide.md +618 -0
  78. package/.claude/guides/workflow-guides/bug-fix-orchestrator.md +217 -0
  79. package/.claude/guides/workflow-guides/flow-orchestrator.md +282 -0
  80. package/.claude/hooks/checklist-gate.js +397 -0
  81. package/.claude/hooks/error-handling-reminder.sh +12 -0
  82. package/.claude/hooks/error-handling-reminder.ts +459 -0
  83. package/.claude/hooks/post-tool-use-tracker.sh +280 -0
  84. package/.claude/hooks/pre-tool-use-guardrail.sh +36 -0
  85. package/.claude/hooks/pre-tool-use-guardrail.ts +342 -0
  86. package/.claude/hooks/skill-activation-prompt.sh +36 -0
  87. package/.claude/hooks/skill-activation-prompt.ts +214 -0
  88. package/.claude/hooks/state/skills-used-test-guard.json +3 -0
  89. package/.claude/rules/devflow-conventions.md +305 -0
  90. package/.claude/rules/project-constitution.md +748 -0
  91. package/.claude/schemas/constitution.schema.json +43 -0
  92. package/.claude/scripts/analyze-upgrade-impact.sh +200 -0
  93. package/.claude/scripts/archive-requirement.sh +351 -0
  94. package/.claude/scripts/calculate-checklist-completion.sh +243 -0
  95. package/.claude/scripts/calculate-quarter.sh +206 -0
  96. package/.claude/scripts/check-dependencies.sh +409 -0
  97. package/.claude/scripts/check-prerequisites.sh +232 -0
  98. package/.claude/scripts/check-task-status.sh +264 -0
  99. package/.claude/scripts/checklist-errors.sh +131 -0
  100. package/.claude/scripts/common.sh +570 -0
  101. package/.claude/scripts/consolidate-research.sh +182 -0
  102. package/.claude/scripts/create-requirement.sh +426 -0
  103. package/.claude/scripts/export-contracts.sh +117 -0
  104. package/.claude/scripts/extract-data-model.sh +78 -0
  105. package/.claude/scripts/generate-clarification-questions.sh +377 -0
  106. package/.claude/scripts/generate-clarification-report.sh +463 -0
  107. package/.claude/scripts/generate-quickstart.sh +146 -0
  108. package/.claude/scripts/generate-research-tasks.sh +157 -0
  109. package/.claude/scripts/generate-status-report.sh +523 -0
  110. package/.claude/scripts/generate-tech-analysis.sh +46 -0
  111. package/.claude/scripts/locate-requirement-in-roadmap.sh +233 -0
  112. package/.claude/scripts/manage-constitution.sh +602 -0
  113. package/.claude/scripts/mark-task-complete.sh +198 -0
  114. package/.claude/scripts/populate-research-tasks.sh +259 -0
  115. package/.claude/scripts/recover-workflow.sh +460 -0
  116. package/.claude/scripts/run-clarify-scan.sh +601 -0
  117. package/.claude/scripts/run-high-review.sh +62 -0
  118. package/.claude/scripts/run-problem-analysis.sh +68 -0
  119. package/.claude/scripts/setup-epic.sh +173 -0
  120. package/.claude/scripts/sync-roadmap-progress.sh +300 -0
  121. package/.claude/scripts/sync-task-marks.sh +199 -0
  122. package/.claude/scripts/test-clarify-scan.sh +515 -0
  123. package/.claude/scripts/update-agent-context.sh +806 -0
  124. package/.claude/scripts/validate-constitution.sh +567 -0
  125. package/.claude/scripts/validate-hooks.sh +487 -0
  126. package/.claude/scripts/validate-research.sh +332 -0
  127. package/.claude/scripts/validate-scope-boundary.sh +493 -0
  128. package/.claude/scripts/verify-setup.sh +37 -0
  129. package/.claude/settings.json +76 -0
  130. package/.claude/skills/_reference-implementations/README.md +96 -0
  131. package/.claude/skills/_reference-implementations/backend-express-prisma/SKILL.md +302 -0
  132. package/.claude/skills/_reference-implementations/backend-express-prisma/resources/architecture-overview.md +451 -0
  133. package/.claude/skills/_reference-implementations/backend-express-prisma/resources/async-and-errors.md +307 -0
  134. package/.claude/skills/_reference-implementations/backend-express-prisma/resources/complete-examples.md +638 -0
  135. package/.claude/skills/_reference-implementations/backend-express-prisma/resources/configuration.md +275 -0
  136. package/.claude/skills/_reference-implementations/backend-express-prisma/resources/database-patterns.md +224 -0
  137. package/.claude/skills/_reference-implementations/backend-express-prisma/resources/middleware-guide.md +213 -0
  138. package/.claude/skills/_reference-implementations/backend-express-prisma/resources/routing-and-controllers.md +756 -0
  139. package/.claude/skills/_reference-implementations/backend-express-prisma/resources/sentry-and-monitoring.md +336 -0
  140. package/.claude/skills/_reference-implementations/backend-express-prisma/resources/services-and-repositories.md +789 -0
  141. package/.claude/skills/_reference-implementations/backend-express-prisma/resources/testing-guide.md +235 -0
  142. package/.claude/skills/_reference-implementations/backend-express-prisma/resources/validation-patterns.md +754 -0
  143. package/.claude/skills/_reference-implementations/frontend-react-mui/SKILL.md +399 -0
  144. package/.claude/skills/_reference-implementations/frontend-react-mui/resources/common-patterns.md +331 -0
  145. package/.claude/skills/_reference-implementations/frontend-react-mui/resources/complete-examples.md +872 -0
  146. package/.claude/skills/_reference-implementations/frontend-react-mui/resources/component-patterns.md +502 -0
  147. package/.claude/skills/_reference-implementations/frontend-react-mui/resources/data-fetching.md +767 -0
  148. package/.claude/skills/_reference-implementations/frontend-react-mui/resources/file-organization.md +502 -0
  149. package/.claude/skills/_reference-implementations/frontend-react-mui/resources/loading-and-error-states.md +501 -0
  150. package/.claude/skills/_reference-implementations/frontend-react-mui/resources/performance.md +406 -0
  151. package/.claude/skills/_reference-implementations/frontend-react-mui/resources/routing-guide.md +364 -0
  152. package/.claude/skills/_reference-implementations/frontend-react-mui/resources/styling-guide.md +428 -0
  153. package/.claude/skills/_reference-implementations/frontend-react-mui/resources/typescript-standards.md +418 -0
  154. package/.claude/skills/cc-devflow-orchestrator/SKILL.md +229 -0
  155. package/.claude/skills/constitution-guardian/SKILL.md +306 -0
  156. package/.claude/skills/devflow-constitution-quick-ref/SKILL.md +374 -0
  157. package/.claude/skills/devflow-file-standards/SKILL.md +353 -0
  158. package/.claude/skills/devflow-tdd-enforcer/SKILL.md +192 -0
  159. package/.claude/skills/skill-developer/ADVANCED.md +197 -0
  160. package/.claude/skills/skill-developer/HOOK_MECHANISMS.md +306 -0
  161. package/.claude/skills/skill-developer/PATTERNS_LIBRARY.md +152 -0
  162. package/.claude/skills/skill-developer/SKILL.md +426 -0
  163. package/.claude/skills/skill-developer/SKILL_RULES_REFERENCE.md +315 -0
  164. package/.claude/skills/skill-developer/TRIGGER_TYPES.md +305 -0
  165. package/.claude/skills/skill-developer/TROUBLESHOOTING.md +514 -0
  166. package/.claude/skills/skill-rules.json +213 -0
  167. package/.claude/tests/README.md +300 -0
  168. package/.claude/tests/TODO.md +69 -0
  169. package/.claude/tests/__pycache__/test_analyze_upgrade_impact.cpython-311-pytest-7.2.2.pyc +0 -0
  170. package/.claude/tests/__pycache__/test_consolidate_research.cpython-311-pytest-7.2.2.pyc +0 -0
  171. package/.claude/tests/__pycache__/test_export_contracts.cpython-311-pytest-7.2.2.pyc +0 -0
  172. package/.claude/tests/__pycache__/test_extract_data_model.cpython-311-pytest-7.2.2.pyc +0 -0
  173. package/.claude/tests/__pycache__/test_generate_quickstart.cpython-311-pytest-7.2.2.pyc +0 -0
  174. package/.claude/tests/__pycache__/test_generate_research_tasks.cpython-311-pytest-7.2.2.pyc +0 -0
  175. package/.claude/tests/constitution/run_all_constitution_tests.sh +111 -0
  176. package/.claude/tests/constitution/test_agent_assignment.sh +207 -0
  177. package/.claude/tests/constitution/test_article_coverage.sh +201 -0
  178. package/.claude/tests/constitution/test_template_completeness.sh +150 -0
  179. package/.claude/tests/constitution/test_version_consistency.sh +120 -0
  180. package/.claude/tests/fixtures/spec_delta_full.md +16 -0
  181. package/.claude/tests/fixtures/tasks_progress_sample.md +5 -0
  182. package/.claude/tests/run-all-tests.sh +229 -0
  183. package/.claude/tests/scripts/run.sh +30 -0
  184. package/.claude/tests/scripts/test-framework.sh +128 -0
  185. package/.claude/tests/scripts/test_check_prerequisites.sh +511 -0
  186. package/.claude/tests/scripts/test_check_prerequisites.sh.bak +504 -0
  187. package/.claude/tests/scripts/test_check_prerequisites.sh.bak2 +505 -0
  188. package/.claude/tests/scripts/test_check_prerequisites.sh.bak3 +506 -0
  189. package/.claude/tests/scripts/test_check_prerequisites.sh.bak4 +507 -0
  190. package/.claude/tests/scripts/test_check_prerequisites.sh.bak5 +508 -0
  191. package/.claude/tests/scripts/test_check_task_status.sh +499 -0
  192. package/.claude/tests/scripts/test_common.sh +244 -0
  193. package/.claude/tests/scripts/test_generate_status_report.sh +71 -0
  194. package/.claude/tests/scripts/test_mark_task_complete.sh +441 -0
  195. package/.claude/tests/scripts/test_mark_task_complete.sh.backup +410 -0
  196. package/.claude/tests/scripts/test_recover_workflow.sh +304 -0
  197. package/.claude/tests/scripts/test_setup_epic.sh +437 -0
  198. package/.claude/tests/scripts/test_sync_task_marks.sh +196 -0
  199. package/.claude/tests/scripts/test_validate_constitution.sh +74 -0
  200. package/.claude/tests/scripts/test_validate_research.sh +462 -0
  201. package/.claude/tests/slugify.bats +82 -0
  202. package/.claude/tests/test-framework.sh +732 -0
  203. package/.claude/tests/test_analyze_upgrade_impact.py +34 -0
  204. package/.claude/tests/test_consolidate_research.py +48 -0
  205. package/.claude/tests/test_export_contracts.py +43 -0
  206. package/.claude/tests/test_extract_data_model.py +33 -0
  207. package/.claude/tests/test_generate_quickstart.py +50 -0
  208. package/.claude/tests/test_generate_research_tasks.py +52 -0
  209. package/.claude/tsc-cache/6e64f818-6398-49ca-8623-581a9af85c44/edited-files.log +1 -0
  210. package/.claude/tsc-cache/795ba6e3-b98a-423b-bab2-51aa62812569/affected-repos.txt +1 -0
  211. package/.claude/tsc-cache/795ba6e3-b98a-423b-bab2-51aa62812569/edited-files.log +1 -0
  212. package/.claude/tsc-cache/ae335694-be5a-4ba4-a1a0-b676c09a7906/affected-repos.txt +1 -0
  213. package/.claude/tsc-cache/ae335694-be5a-4ba4-a1a0-b676c09a7906/edited-files.log +1 -0
  214. package/CHANGELOG.md +507 -0
  215. package/LICENSE +21 -0
  216. package/README.md +534 -0
  217. package/README.zh-CN.md +530 -0
  218. package/bin/adapt.js +240 -0
  219. package/bin/cc-devflow-cli.js +185 -0
  220. package/bin/cc-devflow.js +78 -0
  221. package/config/adapters.yml +5 -0
  222. package/config/schema/adapters.schema.json +44 -0
  223. package/docs/CLAUDE.md +26 -0
  224. package/docs/commands/README.md +61 -0
  225. package/docs/commands/README.zh-CN.md +55 -0
  226. package/docs/commands/core-roadmap.md +106 -0
  227. package/docs/commands/core-roadmap.zh-CN.md +102 -0
  228. package/docs/commands/core-style.md +405 -0
  229. package/docs/commands/core-style.zh-CN.md +405 -0
  230. package/docs/commands/flow-init.md +134 -0
  231. package/docs/commands/flow-init.zh-CN.md +163 -0
  232. package/docs/commands/flow-new.md +274 -0
  233. package/docs/commands/flow-new.zh-CN.md +270 -0
  234. package/docs/guides/getting-started.md +204 -0
  235. package/docs/guides/getting-started.zh-CN.md +152 -0
  236. package/lib/adapters/adapter-interface.js +57 -0
  237. package/lib/adapters/claude-adapter.js +74 -0
  238. package/lib/adapters/codex-adapter.js +40 -0
  239. package/lib/adapters/config-validator.js +68 -0
  240. package/lib/adapters/logger.js +42 -0
  241. package/lib/adapters/registry.js +153 -0
  242. package/lib/compiler/CLAUDE.md +92 -0
  243. package/lib/compiler/__tests__/drift.test.js +215 -0
  244. package/lib/compiler/__tests__/errors.test.js +184 -0
  245. package/lib/compiler/__tests__/incremental.test.js +174 -0
  246. package/lib/compiler/__tests__/integration.test.js +174 -0
  247. package/lib/compiler/__tests__/manifest.test.js +233 -0
  248. package/lib/compiler/__tests__/parser.test.js +456 -0
  249. package/lib/compiler/__tests__/schemas.test.js +301 -0
  250. package/lib/compiler/__tests__/skills-registry.test.js +125 -0
  251. package/lib/compiler/__tests__/transformer.test.js +286 -0
  252. package/lib/compiler/emitters/antigravity-emitter.js +171 -0
  253. package/lib/compiler/emitters/base-emitter.js +73 -0
  254. package/lib/compiler/emitters/codex-emitter.js +52 -0
  255. package/lib/compiler/emitters/cursor-emitter.js +31 -0
  256. package/lib/compiler/emitters/index.js +50 -0
  257. package/lib/compiler/emitters/qwen-emitter.js +39 -0
  258. package/lib/compiler/errors.js +119 -0
  259. package/lib/compiler/index.js +256 -0
  260. package/lib/compiler/manifest.js +242 -0
  261. package/lib/compiler/parser.js +258 -0
  262. package/lib/compiler/platforms.js +113 -0
  263. package/lib/compiler/resource-copier.js +320 -0
  264. package/lib/compiler/rules-emitters/__tests__/antigravity-rules-emitter.test.js +191 -0
  265. package/lib/compiler/rules-emitters/__tests__/codex-rules-emitter.test.js +109 -0
  266. package/lib/compiler/rules-emitters/__tests__/cursor-rules-emitter.test.js +123 -0
  267. package/lib/compiler/rules-emitters/__tests__/qwen-rules-emitter.test.js +123 -0
  268. package/lib/compiler/rules-emitters/antigravity-rules-emitter.js +253 -0
  269. package/lib/compiler/rules-emitters/base-rules-emitter.js +83 -0
  270. package/lib/compiler/rules-emitters/codex-rules-emitter.js +116 -0
  271. package/lib/compiler/rules-emitters/cursor-rules-emitter.js +98 -0
  272. package/lib/compiler/rules-emitters/index.js +71 -0
  273. package/lib/compiler/rules-emitters/qwen-rules-emitter.js +70 -0
  274. package/lib/compiler/schemas.js +144 -0
  275. package/lib/compiler/skills-registry.js +225 -0
  276. package/lib/compiler/transformer.js +236 -0
  277. package/package.json +50 -0
@@ -0,0 +1,191 @@
1
+ /**
2
+ * T008: Antigravity Rules Emitter Tests
3
+ *
4
+ * 测试 AntigravityRulesEmitter 12K 字符限制:
5
+ * 1. 内容 < 12000 字符时输出单个文件
6
+ * 2. 内容 > 12000 字符时分割为多个 Part 文件
7
+ * 3. 每个 part <= 12000 字符
8
+ * 4. Part 文件正确命名 (rules-part1.md, rules-part2.md)
9
+ * 5. Part 文件之间使用 @ 引用链接
10
+ *
11
+ * Reference: research.md#D06 - 12K limit confirmed
12
+ */
13
+
14
+ const matter = require('gray-matter');
15
+
16
+ const MAX_FILE_CHARS = 12000;
17
+
18
+ describe('AntigravityRulesEmitter', () => {
19
+ describe('format()', () => {
20
+ test('should output valid Markdown with YAML frontmatter', async () => {
21
+ const { AntigravityRulesEmitter } = require('../../rules-emitters/antigravity-rules-emitter');
22
+
23
+ const emitter = new AntigravityRulesEmitter();
24
+ const registry = {
25
+ version: '1.0',
26
+ skills: [
27
+ { name: 'test-skill', description: 'Test', type: 'domain' }
28
+ ]
29
+ };
30
+
31
+ const content = emitter.format(registry, []);
32
+
33
+ // 解析 frontmatter
34
+ const parsed = matter(content);
35
+
36
+ // 验证 frontmatter
37
+ expect(parsed.data).toHaveProperty('description');
38
+ });
39
+
40
+ test('should include skills and commands content', async () => {
41
+ const { AntigravityRulesEmitter } = require('../../rules-emitters/antigravity-rules-emitter');
42
+
43
+ const emitter = new AntigravityRulesEmitter();
44
+ const registry = {
45
+ version: '1.0',
46
+ skills: [
47
+ { name: 'cc-devflow-orchestrator', description: 'Router', type: 'domain' }
48
+ ]
49
+ };
50
+ const commands = [
51
+ { name: 'flow-init', description: 'Initialize' }
52
+ ];
53
+
54
+ const content = emitter.format(registry, commands);
55
+
56
+ expect(content).toContain('cc-devflow-orchestrator');
57
+ expect(content).toContain('flow-init');
58
+ });
59
+ });
60
+
61
+ describe('emit() - Single file (< 12K)', () => {
62
+ test('should output single file when content < 12000 chars', async () => {
63
+ const { AntigravityRulesEmitter } = require('../../rules-emitters/antigravity-rules-emitter');
64
+
65
+ const emitter = new AntigravityRulesEmitter();
66
+ const registry = {
67
+ version: '1.0',
68
+ skills: [{ name: 'test', description: 'Test', type: 'domain' }]
69
+ };
70
+
71
+ const results = await emitter.emit(registry, []);
72
+
73
+ // 应返回单个文件结果
74
+ expect(Array.isArray(results) ? results.length : 1).toBe(1);
75
+
76
+ const result = Array.isArray(results) ? results[0] : results;
77
+ expect(result.path).toBe('.agent/rules/rules.md');
78
+ });
79
+
80
+ test('should output to .agent/rules/rules.md', async () => {
81
+ const { AntigravityRulesEmitter } = require('../../rules-emitters/antigravity-rules-emitter');
82
+
83
+ const emitter = new AntigravityRulesEmitter();
84
+
85
+ expect(emitter.outputPath).toBe('.agent/rules/rules.md');
86
+ });
87
+ });
88
+
89
+ describe('emit() - Multi-file split (> 12K)', () => {
90
+ test('should split into Part files when content > 12000 chars', async () => {
91
+ const { AntigravityRulesEmitter } = require('../../rules-emitters/antigravity-rules-emitter');
92
+
93
+ const emitter = new AntigravityRulesEmitter();
94
+
95
+ // 创建超过 12K 的内容
96
+ const largeSkills = [];
97
+ for (let i = 0; i < 100; i++) {
98
+ largeSkills.push({
99
+ name: `skill-${i}`,
100
+ description: 'A'.repeat(200), // 200 chars per skill
101
+ type: 'domain'
102
+ });
103
+ }
104
+
105
+ const registry = { version: '1.0', skills: largeSkills };
106
+ const results = await emitter.emit(registry, []);
107
+
108
+ // 应返回多个文件结果
109
+ if (Array.isArray(results)) {
110
+ expect(results.length).toBeGreaterThan(1);
111
+
112
+ // 验证 Part 文件命名
113
+ expect(results[0].path).toMatch(/rules-part1\.md$/);
114
+ expect(results[1].path).toMatch(/rules-part2\.md$/);
115
+ }
116
+ });
117
+
118
+ test('should ensure each part <= 12000 chars', async () => {
119
+ const { AntigravityRulesEmitter } = require('../../rules-emitters/antigravity-rules-emitter');
120
+
121
+ const emitter = new AntigravityRulesEmitter();
122
+
123
+ // 创建超大内容
124
+ const largeSkills = [];
125
+ for (let i = 0; i < 100; i++) {
126
+ largeSkills.push({
127
+ name: `skill-${i}`,
128
+ description: 'B'.repeat(200),
129
+ type: 'domain'
130
+ });
131
+ }
132
+
133
+ const registry = { version: '1.0', skills: largeSkills };
134
+ const results = await emitter.emit(registry, []);
135
+
136
+ if (Array.isArray(results)) {
137
+ for (const result of results) {
138
+ // 每个 part 的内容长度应 <= 12000
139
+ // 注意:这里需要实际读取文件验证
140
+ expect(result.size || result.chars).toBeLessThanOrEqual(MAX_FILE_CHARS);
141
+ }
142
+ }
143
+ });
144
+
145
+ test('should add @ reference links between parts', async () => {
146
+ const { AntigravityRulesEmitter } = require('../../rules-emitters/antigravity-rules-emitter');
147
+
148
+ const emitter = new AntigravityRulesEmitter();
149
+
150
+ // 创建足够大的内容触发分割
151
+ const largeSkills = [];
152
+ for (let i = 0; i < 100; i++) {
153
+ largeSkills.push({
154
+ name: `skill-${i}`,
155
+ description: 'C'.repeat(200),
156
+ type: 'domain'
157
+ });
158
+ }
159
+
160
+ const registry = { version: '1.0', skills: largeSkills };
161
+ const results = await emitter.emit(registry, []);
162
+
163
+ if (Array.isArray(results) && results.length > 1) {
164
+ // 第一个 part 应包含指向下一个 part 的引用
165
+ // 如 @rules-part2.md
166
+ expect(results[0].content || '').toMatch(/@rules-part2|See also|Continued in/i);
167
+ }
168
+ });
169
+ });
170
+
171
+ describe('smartChunk()', () => {
172
+ test('should split by ## headers', async () => {
173
+ const { AntigravityRulesEmitter } = require('../../rules-emitters/antigravity-rules-emitter');
174
+
175
+ const emitter = new AntigravityRulesEmitter();
176
+
177
+ // 测试 smartChunk 内部逻辑
178
+ if (typeof emitter.smartChunk === 'function') {
179
+ const content = `## Section 1\n${'a'.repeat(6000)}\n## Section 2\n${'b'.repeat(6000)}\n## Section 3\n${'c'.repeat(6000)}`;
180
+
181
+ const chunks = emitter.smartChunk(content, MAX_FILE_CHARS);
182
+
183
+ expect(chunks.length).toBeGreaterThan(1);
184
+
185
+ for (const chunk of chunks) {
186
+ expect(chunk.length).toBeLessThanOrEqual(MAX_FILE_CHARS);
187
+ }
188
+ }
189
+ });
190
+ });
191
+ });
@@ -0,0 +1,109 @@
1
+ /**
2
+ * T006: Codex Rules Emitter Tests
3
+ *
4
+ * 测试 CodexRulesEmitter SKILL.md 格式输出:
5
+ * 1. 输出包含 YAML frontmatter (name, description, type)
6
+ * 2. 输出路径为 .codex/skills/cc-devflow/SKILL.md
7
+ * 3. Skills 和 Commands 部分存在
8
+ *
9
+ * Reference: contracts/cli-spec.yaml#codex
10
+ */
11
+
12
+ const matter = require('gray-matter');
13
+
14
+ describe('CodexRulesEmitter', () => {
15
+ describe('format()', () => {
16
+ test('should output YAML frontmatter with name, description, type', async () => {
17
+ const { CodexRulesEmitter } = require('../../rules-emitters/codex-rules-emitter');
18
+
19
+ const emitter = new CodexRulesEmitter();
20
+ const registry = {
21
+ version: '1.0',
22
+ skills: [
23
+ { name: 'test-skill', description: 'Test', type: 'domain' }
24
+ ]
25
+ };
26
+
27
+ const content = emitter.format(registry, []);
28
+
29
+ // 解析 frontmatter
30
+ const parsed = matter(content);
31
+
32
+ // 验证必需的 frontmatter 字段
33
+ expect(parsed.data).toHaveProperty('name');
34
+ expect(parsed.data).toHaveProperty('description');
35
+ expect(parsed.data).toHaveProperty('type');
36
+
37
+ expect(parsed.data.name).toBe('cc-devflow');
38
+ expect(parsed.data.type).toBe('domain');
39
+ });
40
+
41
+ test('should include Skills section', async () => {
42
+ const { CodexRulesEmitter } = require('../../rules-emitters/codex-rules-emitter');
43
+
44
+ const emitter = new CodexRulesEmitter();
45
+ const registry = {
46
+ version: '1.0',
47
+ skills: [
48
+ { name: 'cc-devflow-orchestrator', description: 'Router', type: 'domain', enforcement: 'suggest' },
49
+ { name: 'devflow-tdd-enforcer', description: 'TDD', type: 'guardrail', enforcement: 'block' }
50
+ ]
51
+ };
52
+
53
+ const content = emitter.format(registry, []);
54
+ const parsed = matter(content);
55
+
56
+ // 验证 Skills 部分
57
+ expect(parsed.content).toMatch(/## Skills/i);
58
+ expect(parsed.content).toContain('cc-devflow-orchestrator');
59
+ expect(parsed.content).toContain('devflow-tdd-enforcer');
60
+
61
+ // 验证包含 Triggers 和 Enforcement 信息
62
+ expect(parsed.content).toMatch(/Triggers|Enforcement/i);
63
+ });
64
+
65
+ test('should include Commands section', async () => {
66
+ const { CodexRulesEmitter } = require('../../rules-emitters/codex-rules-emitter');
67
+
68
+ const emitter = new CodexRulesEmitter();
69
+ const commands = [
70
+ { name: 'flow-init', description: 'Initialize' },
71
+ { name: 'flow-prd', description: 'Generate PRD' }
72
+ ];
73
+
74
+ const content = emitter.format({ skills: [] }, commands);
75
+ const parsed = matter(content);
76
+
77
+ // 验证 Commands 部分
78
+ expect(parsed.content).toMatch(/## Commands/i);
79
+ expect(parsed.content).toContain('flow-init');
80
+ expect(parsed.content).toContain('flow-prd');
81
+ });
82
+ });
83
+
84
+ describe('emit()', () => {
85
+ test('should output to .codex/skills/cc-devflow/SKILL.md', async () => {
86
+ const { CodexRulesEmitter } = require('../../rules-emitters/codex-rules-emitter');
87
+
88
+ const emitter = new CodexRulesEmitter();
89
+
90
+ expect(emitter.outputPath).toBe('.codex/skills/cc-devflow/SKILL.md');
91
+ });
92
+
93
+ test('should write file with correct content', async () => {
94
+ const { CodexRulesEmitter } = require('../../rules-emitters/codex-rules-emitter');
95
+
96
+ const emitter = new CodexRulesEmitter();
97
+ const registry = { version: '1.0', skills: [] };
98
+
99
+ const result = await emitter.emit(registry, []);
100
+
101
+ expect(result).toHaveProperty('path');
102
+ expect(result).toHaveProperty('hash');
103
+ expect(result).toHaveProperty('timestamp');
104
+
105
+ expect(result.path).toBe('.codex/skills/cc-devflow/SKILL.md');
106
+ expect(result.hash).toMatch(/^[a-f0-9]{64}$/);
107
+ });
108
+ });
109
+ });
@@ -0,0 +1,123 @@
1
+ /**
2
+ * T005: Cursor Rules Emitter Tests
3
+ *
4
+ * 测试 CursorRulesEmitter MDC 格式输出:
5
+ * 1. 输出包含 YAML frontmatter (description, globs, alwaysApply)
6
+ * 2. 输出路径为 .cursor/rules/devflow.mdc
7
+ * 3. MDC 格式验证 (--- 分隔符)
8
+ *
9
+ * Reference: contracts/cli-spec.yaml#cursor
10
+ */
11
+
12
+ const path = require('path');
13
+ const fs = require('fs');
14
+ const matter = require('gray-matter');
15
+
16
+ describe('CursorRulesEmitter', () => {
17
+ describe('format()', () => {
18
+ test('should output valid MDC format with YAML frontmatter', async () => {
19
+ const { CursorRulesEmitter } = require('../../rules-emitters/cursor-rules-emitter');
20
+
21
+ const emitter = new CursorRulesEmitter();
22
+ const registry = {
23
+ version: '1.0',
24
+ skills: [
25
+ { name: 'test-skill', description: 'Test', type: 'domain' }
26
+ ]
27
+ };
28
+ const commands = [
29
+ { name: 'test-cmd', description: 'Test command' }
30
+ ];
31
+
32
+ const content = emitter.format(registry, commands);
33
+
34
+ // 验证 MDC 格式 (YAML frontmatter + Markdown)
35
+ expect(content).toMatch(/^---\n/);
36
+ expect(content).toMatch(/\n---\n/);
37
+
38
+ // 解析 frontmatter
39
+ const parsed = matter(content);
40
+
41
+ // 验证必需的 frontmatter 字段
42
+ expect(parsed.data).toHaveProperty('description');
43
+ expect(parsed.data).toHaveProperty('globs');
44
+ expect(parsed.data).toHaveProperty('alwaysApply');
45
+
46
+ // globs 应该是数组
47
+ expect(Array.isArray(parsed.data.globs)).toBe(true);
48
+ expect(parsed.data.globs).toContain('devflow/**/*');
49
+ expect(parsed.data.globs).toContain('.claude/**/*');
50
+
51
+ // alwaysApply 应该是 boolean
52
+ expect(typeof parsed.data.alwaysApply).toBe('boolean');
53
+ });
54
+
55
+ test('should include Skills section with skill list', async () => {
56
+ const { CursorRulesEmitter } = require('../../rules-emitters/cursor-rules-emitter');
57
+
58
+ const emitter = new CursorRulesEmitter();
59
+ const registry = {
60
+ version: '1.0',
61
+ skills: [
62
+ { name: 'cc-devflow-orchestrator', description: 'Workflow router', type: 'domain' },
63
+ { name: 'devflow-tdd-enforcer', description: 'TDD enforcement', type: 'guardrail' }
64
+ ]
65
+ };
66
+
67
+ const content = emitter.format(registry, []);
68
+ const parsed = matter(content);
69
+
70
+ // Markdown body 应包含 Skills 部分
71
+ expect(parsed.content).toMatch(/## Available Skills/i);
72
+ expect(parsed.content).toContain('cc-devflow-orchestrator');
73
+ expect(parsed.content).toContain('devflow-tdd-enforcer');
74
+ });
75
+
76
+ test('should include Commands section with command list', async () => {
77
+ const { CursorRulesEmitter } = require('../../rules-emitters/cursor-rules-emitter');
78
+
79
+ const emitter = new CursorRulesEmitter();
80
+ const commands = [
81
+ { name: 'flow-init', description: 'Initialize requirement' },
82
+ { name: 'flow-prd', description: 'Generate PRD' }
83
+ ];
84
+
85
+ const content = emitter.format({ skills: [] }, commands);
86
+ const parsed = matter(content);
87
+
88
+ // Markdown body 应包含 Commands 部分
89
+ expect(parsed.content).toMatch(/## Key Commands|## Commands/i);
90
+ expect(parsed.content).toContain('flow-init');
91
+ expect(parsed.content).toContain('flow-prd');
92
+ });
93
+ });
94
+
95
+ describe('emit()', () => {
96
+ test('should output to .cursor/rules/devflow.mdc', async () => {
97
+ const { CursorRulesEmitter } = require('../../rules-emitters/cursor-rules-emitter');
98
+
99
+ const emitter = new CursorRulesEmitter();
100
+
101
+ // 验证输出路径
102
+ expect(emitter.outputPath).toBe('.cursor/rules/devflow.mdc');
103
+ });
104
+
105
+ test('should write file with correct content', async () => {
106
+ const { CursorRulesEmitter } = require('../../rules-emitters/cursor-rules-emitter');
107
+
108
+ const emitter = new CursorRulesEmitter();
109
+ const registry = { version: '1.0', skills: [] };
110
+ const commands = [];
111
+
112
+ const result = await emitter.emit(registry, commands);
113
+
114
+ // 验证返回结果
115
+ expect(result).toHaveProperty('path');
116
+ expect(result).toHaveProperty('hash');
117
+ expect(result).toHaveProperty('timestamp');
118
+
119
+ expect(result.path).toBe('.cursor/rules/devflow.mdc');
120
+ expect(result.hash).toMatch(/^[a-f0-9]{64}$/);
121
+ });
122
+ });
123
+ });
@@ -0,0 +1,123 @@
1
+ /**
2
+ * T007: Qwen Rules Emitter Tests
3
+ *
4
+ * 测试 QwenRulesEmitter TOML 格式输出:
5
+ * 1. 输出为有效 TOML (可被 @iarna/toml 解析)
6
+ * 2. 包含 [skill] 和 [commands] 段
7
+ * 3. 输出路径为 .qwen/commands/devflow.toml
8
+ *
9
+ * Reference: contracts/cli-spec.yaml#qwen
10
+ */
11
+
12
+ const TOML = require('@iarna/toml');
13
+
14
+ describe('QwenRulesEmitter', () => {
15
+ describe('format()', () => {
16
+ test('should output valid TOML parseable by @iarna/toml', async () => {
17
+ const { QwenRulesEmitter } = require('../../rules-emitters/qwen-rules-emitter');
18
+
19
+ const emitter = new QwenRulesEmitter();
20
+ const registry = {
21
+ version: '1.0',
22
+ skills: [
23
+ { name: 'test-skill', description: 'Test', type: 'domain' }
24
+ ]
25
+ };
26
+
27
+ const content = emitter.format(registry, []);
28
+
29
+ // 验证 TOML 格式有效
30
+ expect(() => TOML.parse(content)).not.toThrow();
31
+
32
+ const parsed = TOML.parse(content);
33
+ expect(parsed).toBeDefined();
34
+ });
35
+
36
+ test('should contain [skill] section', async () => {
37
+ const { QwenRulesEmitter } = require('../../rules-emitters/qwen-rules-emitter');
38
+
39
+ const emitter = new QwenRulesEmitter();
40
+ const registry = { version: '1.0', skills: [] };
41
+
42
+ const content = emitter.format(registry, []);
43
+ const parsed = TOML.parse(content);
44
+
45
+ // 验证 [skill] 段存在
46
+ expect(parsed).toHaveProperty('skill');
47
+ expect(parsed.skill).toHaveProperty('name');
48
+ expect(parsed.skill).toHaveProperty('description');
49
+ expect(parsed.skill.name).toBe('cc-devflow');
50
+ });
51
+
52
+ test('should contain [skills.*] sections for each skill', async () => {
53
+ const { QwenRulesEmitter } = require('../../rules-emitters/qwen-rules-emitter');
54
+
55
+ const emitter = new QwenRulesEmitter();
56
+ const registry = {
57
+ version: '1.0',
58
+ skills: [
59
+ { name: 'cc-devflow-orchestrator', description: 'Router', type: 'domain', enforcement: 'suggest' },
60
+ { name: 'devflow-tdd-enforcer', description: 'TDD', type: 'guardrail', enforcement: 'block' }
61
+ ]
62
+ };
63
+
64
+ const content = emitter.format(registry, []);
65
+ const parsed = TOML.parse(content);
66
+
67
+ // 验证 [skills] 段存在
68
+ expect(parsed).toHaveProperty('skills');
69
+ expect(parsed.skills).toHaveProperty('cc-devflow-orchestrator');
70
+ expect(parsed.skills).toHaveProperty('devflow-tdd-enforcer');
71
+
72
+ // 验证技能属性
73
+ expect(parsed.skills['cc-devflow-orchestrator'].description).toBe('Router');
74
+ expect(parsed.skills['cc-devflow-orchestrator'].type).toBe('domain');
75
+ });
76
+
77
+ test('should contain [commands] section', async () => {
78
+ const { QwenRulesEmitter } = require('../../rules-emitters/qwen-rules-emitter');
79
+
80
+ const emitter = new QwenRulesEmitter();
81
+ const commands = [
82
+ { name: 'flow-init', description: 'Initialize' },
83
+ { name: 'flow-prd', description: 'Generate PRD' }
84
+ ];
85
+
86
+ const content = emitter.format({ skills: [] }, commands);
87
+ const parsed = TOML.parse(content);
88
+
89
+ // 验证 [commands] 段存在
90
+ expect(parsed).toHaveProperty('commands');
91
+ expect(parsed.commands).toHaveProperty('flow-init');
92
+ expect(parsed.commands).toHaveProperty('flow-prd');
93
+
94
+ expect(parsed.commands['flow-init'].description).toBe('Initialize');
95
+ });
96
+ });
97
+
98
+ describe('emit()', () => {
99
+ test('should output to .qwen/commands/devflow.toml', async () => {
100
+ const { QwenRulesEmitter } = require('../../rules-emitters/qwen-rules-emitter');
101
+
102
+ const emitter = new QwenRulesEmitter();
103
+
104
+ expect(emitter.outputPath).toBe('.qwen/commands/devflow.toml');
105
+ });
106
+
107
+ test('should write file with correct content', async () => {
108
+ const { QwenRulesEmitter } = require('../../rules-emitters/qwen-rules-emitter');
109
+
110
+ const emitter = new QwenRulesEmitter();
111
+ const registry = { version: '1.0', skills: [] };
112
+
113
+ const result = await emitter.emit(registry, []);
114
+
115
+ expect(result).toHaveProperty('path');
116
+ expect(result).toHaveProperty('hash');
117
+ expect(result).toHaveProperty('timestamp');
118
+
119
+ expect(result.path).toBe('.qwen/commands/devflow.toml');
120
+ expect(result.hash).toMatch(/^[a-f0-9]{64}$/);
121
+ });
122
+ });
123
+ });