cc-devflow 2.4.6 → 4.1.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.
- package/.claude/CLAUDE.md +1065 -48
- package/.claude/agents/dev-implementer.md +195 -0
- package/.claude/commands/{flow-archive.md → flow/archive.md} +46 -11
- package/.claude/commands/flow/context.md +150 -0
- package/.claude/commands/flow/delta.md +245 -0
- package/.claude/commands/{flow-dev.md → flow/dev.md} +112 -11
- package/.claude/commands/flow/init.md +45 -0
- package/.claude/commands/flow/quality.md +159 -0
- package/.claude/commands/flow/spec.md +186 -0
- package/.claude/commands/flow/workspace.md +146 -0
- package/.claude/commands/{cancel-ralph.md → util/cancel-ralph.md} +1 -0
- package/.claude/config/quality-gates.yml +305 -0
- package/.claude/docs/guides/TEAM_MODE_GUIDE.md +313 -0
- package/.claude/docs/templates/DELTA_SPEC_TEMPLATE.md +91 -0
- package/.claude/docs/templates/DESIGN_DECISIONS_TEMPLATE.md +151 -0
- package/.claude/docs/templates/JOURNAL_TEMPLATE.md +75 -0
- package/.claude/docs/templates/_shared/CLAUDE.md +36 -0
- package/.claude/docs/templates/_shared/CONSTITUTION_CHECK.md +125 -0
- package/.claude/docs/templates/_shared/VALIDATION_CHECKLIST.md +187 -0
- package/.claude/docs/templates/_shared/YAML_FRONTMATTER.md +164 -0
- package/.claude/docs/templates/context/dev.jsonl.template +6 -0
- package/.claude/docs/templates/context/epic.jsonl.template +5 -0
- package/.claude/docs/templates/context/prd.jsonl.template +4 -0
- package/.claude/docs/templates/context/research.jsonl.template +4 -0
- package/.claude/docs/templates/context/review.jsonl.template +5 -0
- package/.claude/docs/templates/context/tech.jsonl.template +5 -0
- package/.claude/hooks/CLAUDE.md +342 -0
- package/.claude/hooks/inject-agent-context.ts +480 -0
- package/.claude/hooks/inject-skill-context.ts +359 -0
- package/.claude/hooks/ralph-loop.ts +931 -0
- package/.claude/hooks/task-completed-hook.ts +593 -0
- package/.claude/hooks/teammate-idle-hook.ts +690 -0
- package/.claude/hooks/types/team-types.d.ts +238 -0
- package/.claude/rules/devflow-conventions.md +82 -9
- package/.claude/scripts/archive-requirement.sh +44 -1
- package/.claude/scripts/common.sh +670 -3
- package/.claude/scripts/delta-parser.ts +527 -0
- package/.claude/scripts/detect-file-conflicts.sh +151 -0
- package/.claude/scripts/flow-context-add.sh +134 -0
- package/.claude/scripts/flow-context-init.sh +133 -0
- package/.claude/scripts/flow-context-validate.sh +144 -0
- package/.claude/scripts/flow-delta-apply.sh +297 -0
- package/.claude/scripts/flow-delta-archive.sh +71 -0
- package/.claude/scripts/flow-delta-create.sh +202 -0
- package/.claude/scripts/flow-delta-list.sh +142 -0
- package/.claude/scripts/flow-delta-status.sh +235 -0
- package/.claude/scripts/flow-quality-full.sh +184 -0
- package/.claude/scripts/flow-quality-quick.sh +64 -0
- package/.claude/scripts/flow-workspace-init.sh +117 -0
- package/.claude/scripts/flow-workspace-record.sh +164 -0
- package/.claude/scripts/flow-workspace-start.sh +88 -0
- package/.claude/scripts/get-workflow-status.sh +415 -0
- package/.claude/scripts/parse-task-dependencies.js +334 -0
- package/.claude/scripts/record-quality-error.sh +165 -0
- package/.claude/scripts/run-quality-gates.sh +242 -0
- package/.claude/scripts/team-dev-init.sh +319 -0
- package/.claude/scripts/team-state-recovery.sh +229 -0
- package/.claude/scripts/workflow-status.ts +433 -0
- package/.claude/settings.json +19 -0
- package/.claude/skills/cc-devflow-orchestrator/SKILL.md +85 -200
- package/.claude/skills/domain/using-git-worktrees/SKILL.md +252 -0
- package/.claude/skills/domain/using-git-worktrees/assets/SHELL_ALIASES.md +133 -0
- package/.claude/skills/domain/using-git-worktrees/context.jsonl +4 -0
- package/.claude/skills/domain/using-git-worktrees/scripts/worktree-cleanup.sh +218 -0
- package/.claude/skills/domain/using-git-worktrees/scripts/worktree-create.sh +232 -0
- package/.claude/skills/domain/using-git-worktrees/scripts/worktree-list.sh +130 -0
- package/.claude/skills/domain/using-git-worktrees/scripts/worktree-status.sh +140 -0
- package/.claude/skills/domain/using-git-worktrees/scripts/worktree-switch.sh +70 -0
- package/.claude/skills/skill-rules.json +72 -1
- package/.claude/skills/utility/journey-checker/SKILL.md +199 -0
- package/.claude/skills/utility/journey-checker/pressure-scenarios.md +164 -0
- package/.claude/skills/utility/skill-creator/LICENSE.txt +202 -0
- package/.claude/skills/utility/skill-creator/SKILL.md +356 -0
- package/.claude/skills/utility/skill-creator/references/output-patterns.md +82 -0
- package/.claude/skills/utility/skill-creator/references/workflows.md +28 -0
- package/.claude/skills/utility/skill-creator/scripts/init_skill.py +303 -0
- package/.claude/skills/utility/skill-creator/scripts/package_skill.py +110 -0
- package/.claude/skills/utility/skill-creator/scripts/quick_validate.py +95 -0
- package/.claude/skills/workflow/flow-dev/CLAUDE.md +78 -0
- package/.claude/skills/workflow/flow-dev/SKILL.md +96 -0
- package/.claude/skills/workflow/flow-dev/assets/IMPLEMENTATION_PLAN_TEMPLATE.md +71 -0
- package/.claude/skills/workflow/flow-dev/context.jsonl +8 -0
- package/.claude/skills/workflow/flow-dev/dev-implementer.jsonl +8 -0
- package/.claude/skills/workflow/flow-dev/scripts/entry-gate.sh +116 -0
- package/.claude/skills/workflow/flow-dev/scripts/exit-gate.sh +101 -0
- package/.claude/skills/workflow/flow-dev/scripts/task-orchestrator.sh +106 -0
- package/.claude/skills/workflow/flow-fix/SKILL.md +105 -0
- package/.claude/skills/workflow/flow-fix/context.jsonl +6 -0
- package/.claude/skills/workflow/flow-fix/references/bug-analyzer.md +381 -0
- package/.claude/skills/workflow/flow-init/SKILL.md +211 -0
- package/.claude/skills/workflow/flow-init/assets/BRAINSTORM_TEMPLATE.md +148 -0
- package/.claude/skills/workflow/flow-init/assets/INIT_FLOW_TEMPLATE.md +198 -0
- package/.claude/skills/workflow/flow-init/assets/RESEARCH_TEMPLATE.md +276 -0
- package/.claude/skills/workflow/flow-init/context.jsonl +5 -0
- package/.claude/skills/workflow/flow-init/references/flow-researcher.md +132 -0
- package/.claude/skills/workflow/flow-init/scripts/check-prerequisites.sh +232 -0
- package/.claude/skills/workflow/flow-init/scripts/consolidate-research.sh +182 -0
- package/.claude/skills/workflow/flow-init/scripts/create-requirement.sh +515 -0
- package/.claude/skills/workflow/flow-init/scripts/generate-research-tasks.sh +157 -0
- package/.claude/skills/workflow/flow-init/scripts/populate-research-tasks.sh +284 -0
- package/.claude/skills/workflow/flow-init/scripts/validate-research.sh +332 -0
- package/.claude/skills/workflow/flow-quality/SKILL.md +94 -0
- package/.claude/skills/workflow/flow-quality/context.jsonl +6 -0
- package/.claude/skills/workflow/flow-quality/references/code-quality-reviewer.md +205 -0
- package/.claude/skills/workflow/flow-quality/references/qa-tester.md +313 -0
- package/.claude/skills/workflow/flow-quality/references/security-reviewer.md +314 -0
- package/.claude/skills/workflow/flow-quality/references/spec-reviewer.md +221 -0
- package/.claude/skills/workflow/flow-release/SKILL.md +126 -0
- package/.claude/skills/workflow/flow-release/context.jsonl +7 -0
- package/.claude/skills/workflow/flow-release/references/release-manager.md +295 -0
- package/.claude/skills/workflow/flow-spec/CLAUDE.md +103 -0
- package/.claude/skills/workflow/flow-spec/SKILL.md +545 -0
- package/.claude/skills/workflow/flow-spec/context.jsonl +7 -0
- package/.claude/skills/workflow/flow-spec/scripts/entry-gate.sh +194 -0
- package/.claude/skills/workflow/flow-spec/scripts/exit-gate.sh +244 -0
- package/.claude/skills/workflow/flow-spec/scripts/parallel-orchestrator.sh +205 -0
- package/.claude/skills/workflow/flow-spec/scripts/team-communication.sh +353 -0
- package/.claude/skills/workflow/flow-spec/scripts/team-init.sh +195 -0
- package/.claude/skills/workflow/flow-spec/scripts/test-team-mode.sh +496 -0
- package/.claude/skills/workflow/flow-spec/team-config.json +165 -0
- package/.claude/skills/workflow.yaml +417 -0
- package/CHANGELOG.md +254 -0
- package/README.md +193 -33
- package/README.zh-CN.md +206 -46
- package/lib/compiler/CLAUDE.md +77 -46
- package/lib/compiler/__tests__/multi-module-emitters.test.js +508 -0
- package/lib/compiler/context-expander.js +179 -0
- package/lib/compiler/emitters/antigravity-emitter.js +195 -5
- package/lib/compiler/emitters/base-emitter.js +217 -2
- package/lib/compiler/emitters/codex-emitter.js +200 -4
- package/lib/compiler/emitters/cursor-emitter.js +307 -3
- package/lib/compiler/emitters/qwen-emitter.js +196 -4
- package/lib/compiler/index.js +197 -2
- package/lib/compiler/platforms.js +270 -21
- package/package.json +1 -1
- package/.claude/commands/flow-epic.md +0 -183
- package/.claude/commands/flow-init.md +0 -370
- package/.claude/commands/flow-prd.md +0 -144
- package/.claude/commands/flow-qa.md +0 -93
- package/.claude/commands/flow-review.md +0 -257
- package/.claude/commands/flow-tech.md +0 -142
- package/.claude/commands/flow-ui.md +0 -189
- package/.claude/skills/file-header-guardian/SKILL.md +0 -56
- package/.claude/skills/skill-developer/ADVANCED.md +0 -197
- package/.claude/skills/skill-developer/HOOK_MECHANISMS.md +0 -306
- package/.claude/skills/skill-developer/PATTERNS_LIBRARY.md +0 -152
- package/.claude/skills/skill-developer/SKILL.md +0 -426
- package/.claude/skills/skill-developer/SKILL_RULES_REFERENCE.md +0 -315
- package/.claude/skills/skill-developer/TRIGGER_TYPES.md +0 -305
- package/.claude/skills/skill-developer/TROUBLESHOOTING.md +0 -514
- package/.claude/skills/writing-skills/SKILL.md +0 -655
- package/.claude/skills/writing-skills/anthropic-best-practices.md +0 -1150
- package/.claude/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +0 -189
- package/.claude/skills/writing-skills/graphviz-conventions.dot +0 -172
- package/.claude/skills/writing-skills/persuasion-principles.md +0 -187
- package/.claude/skills/writing-skills/render-graphs.js +0 -168
- package/.claude/skills/writing-skills/testing-skills-with-subagents.md +0 -384
- package/.claude/tsc-cache/795ba6e3-b98a-423b-bab2-51aa62812569/affected-repos.txt +0 -1
- package/.claude/tsc-cache/ae335694-be5a-4ba4-a1a0-b676c09a7906/affected-repos.txt +0 -1
- /package/.claude/commands/{core-architecture.md → core/architecture.md} +0 -0
- /package/.claude/commands/{core-guidelines.md → core/guidelines.md} +0 -0
- /package/.claude/commands/{core-roadmap.md → core/roadmap.md} +0 -0
- /package/.claude/commands/{core-style.md → core/style.md} +0 -0
- /package/.claude/commands/{flow-checklist.md → flow/checklist.md} +0 -0
- /package/.claude/commands/{flow-clarify.md → flow/clarify.md} +0 -0
- /package/.claude/commands/{flow-constitution.md → flow/constitution.md} +0 -0
- /package/.claude/commands/{flow-fix.md → flow/fix.md} +0 -0
- /package/.claude/commands/{flow-ideate.md → flow/ideate.md} +0 -0
- /package/.claude/commands/{flow-new.md → flow/new.md} +0 -0
- /package/.claude/commands/{flow-release.md → flow/release.md} +0 -0
- /package/.claude/commands/{flow-restart.md → flow/restart.md} +0 -0
- /package/.claude/commands/{flow-status.md → flow/status.md} +0 -0
- /package/.claude/commands/{flow-update.md → flow/update.md} +0 -0
- /package/.claude/commands/{flow-upgrade.md → flow/upgrade.md} +0 -0
- /package/.claude/commands/{flow-verify.md → flow/verify.md} +0 -0
- /package/.claude/commands/{code-review-high.md → util/code-review.md} +0 -0
- /package/.claude/commands/{git-commit.md → util/git-commit.md} +0 -0
- /package/.claude/commands/{problem-analyzer.md → util/problem-analyzer.md} +0 -0
- /package/.claude/skills/{flow-attention-refresh → domain/attention-refresh}/SKILL.md +0 -0
- /package/.claude/skills/{flow-brainstorming → domain/brainstorming}/SKILL.md +0 -0
- /package/.claude/skills/{flow-debugging → domain/debugging}/SKILL.md +0 -0
- /package/.claude/skills/{flow-finishing-branch → domain/finishing-branch}/SKILL.md +0 -0
- /package/.claude/skills/{flow-receiving-review → domain/receiving-review}/SKILL.md +0 -0
- /package/.claude/skills/{flow-tdd → domain/tdd}/SKILL.md +0 -0
- /package/.claude/skills/{verification-before-completion → domain/verification}/SKILL.md +0 -0
- /package/.claude/skills/{constitution-guardian → guardrail/constitution-guardian}/SKILL.md +0 -0
- /package/.claude/skills/{devflow-tdd-enforcer → guardrail/tdd-enforcer}/SKILL.md +0 -0
- /package/.claude/skills/{devflow-constitution-quick-ref → utility/constitution-quick-ref}/SKILL.md +0 -0
- /package/.claude/skills/{devflow-file-standards → utility/file-standards}/SKILL.md +0 -0
- /package/.claude/skills/{fractal-docs-generator → utility/fractal-docs}/SKILL.md +0 -0
- /package/.claude/skills/{npm-release → utility/npm-release}/SKILL.md +0 -0
package/lib/compiler/CLAUDE.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Command Emitter - Compiler Module Architecture
|
|
2
2
|
|
|
3
3
|
## Purpose
|
|
4
|
-
Multi-platform
|
|
4
|
+
Multi-platform compiler that transforms `.claude/` modules (commands, skills, agents, rules, hooks) into native formats for Codex, Cursor, Qwen, and Antigravity platforms.
|
|
5
5
|
|
|
6
|
-
## Architecture
|
|
6
|
+
## Architecture (v3.0)
|
|
7
7
|
|
|
8
8
|
```
|
|
9
9
|
lib/compiler/
|
|
@@ -13,63 +13,90 @@ lib/compiler/
|
|
|
13
13
|
├── schemas.js # Zod validation schemas (CommandIR, Manifest)
|
|
14
14
|
├── errors.js # Custom error types (MissingFrontmatter, UnknownAlias, etc.)
|
|
15
15
|
├── skills-registry.js # Generate skills registry from .claude/skills/
|
|
16
|
+
├── platforms.js # Platform configuration registry (v2.0)
|
|
17
|
+
├── context-expander.js # context.jsonl expansion (v3.0)
|
|
16
18
|
├── index.js # Compiler entry point, orchestrates pipeline
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
├── emitters/
|
|
20
|
+
│ ├── base-emitter.js # Abstract base class (v2.0: multi-module support)
|
|
21
|
+
│ ├── codex-emitter.js # .codex/prompts/*.md, .codex/skills/*, AGENTS.md
|
|
22
|
+
│ ├── cursor-emitter.js # .cursor/commands/*.md, .cursor/rules/*.mdc, subagents/
|
|
23
|
+
│ ├── qwen-emitter.js # .qwen/commands/*.toml, .qwen/agents/*, CONTEXT.md
|
|
24
|
+
│ ├── antigravity-emitter.js # .agent/workflows/*.md, .agent/skills/*, rules/
|
|
25
|
+
│ └── index.js # Emitter factory
|
|
26
|
+
└── rules-emitters/ # Legacy rules emitters (deprecated)
|
|
27
|
+
└── ...
|
|
24
28
|
```
|
|
25
29
|
|
|
26
|
-
##
|
|
30
|
+
## Multi-Module Compilation (v3.0)
|
|
31
|
+
|
|
32
|
+
### Supported Modules
|
|
33
|
+
|
|
34
|
+
| Module | Source | Codex | Cursor | Qwen | Antigravity |
|
|
35
|
+
|--------|--------|-------|--------|------|-------------|
|
|
36
|
+
| skills | `.claude/skills/` | `.codex/skills/` | `.cursor/rules/*.mdc` | `.qwen/commands/*.toml` | `.agent/skills/` |
|
|
37
|
+
| commands | `.claude/commands/` | `.codex/prompts/` | `.cursor/commands/` | `.qwen/commands/` | `.agent/workflows/` |
|
|
38
|
+
| agents | `.claude/agents/` | `AGENTS.md` | `.cursor/subagents/` | `.qwen/agents/` | `AGENTS.md` |
|
|
39
|
+
| rules | `.claude/rules/` | `AGENTS.md` | `.cursor/rules/*.mdc` | `CONTEXT.md` | `.agent/rules/` |
|
|
40
|
+
| hooks | `.claude/hooks/` | ❌ | `hooks.json` + `hooks/` | ❌ | ❌ |
|
|
41
|
+
|
|
42
|
+
### Data Flow (v3.0)
|
|
27
43
|
|
|
28
44
|
```
|
|
29
|
-
.claude/
|
|
45
|
+
.claude/
|
|
46
|
+
├── skills/*/SKILL.md
|
|
47
|
+
├── commands/*.md
|
|
48
|
+
├── agents/*.md
|
|
49
|
+
├── rules/*.md
|
|
50
|
+
└── hooks/*.ts
|
|
30
51
|
│
|
|
31
52
|
▼
|
|
32
|
-
|
|
33
|
-
│
|
|
34
|
-
│
|
|
35
|
-
|
|
36
|
-
│ │ - Compute SHA-256 hash
|
|
37
|
-
└────────┬────────┘
|
|
38
|
-
│ CommandIR[]
|
|
39
|
-
▼
|
|
40
|
-
┌─────────────────┐
|
|
41
|
-
│ Transformer │ Platform-specific transforms
|
|
42
|
-
│(transformer.js) │ - {SCRIPT:alias} → "bash <path>"
|
|
43
|
-
│ │ - $ARGUMENTS → {{args}} / [arguments]
|
|
44
|
-
│ │ - {AGENT_SCRIPT} + __AGENT__ substitution
|
|
45
|
-
└────────┬────────┘
|
|
46
|
-
│ TransformedContent
|
|
47
|
-
▼
|
|
48
|
-
┌─────────────────┐
|
|
49
|
-
│ Emitters │ Platform format + file write
|
|
50
|
-
│ (emitters/*.js) │ - Codex: MD + YAML frontmatter
|
|
51
|
-
│ │ - Cursor: pure MD
|
|
52
|
-
│ │ - Qwen: TOML
|
|
53
|
-
│ │ - Antigravity: MD + YAML (12K limit)
|
|
54
|
-
└────────┬────────┘
|
|
53
|
+
┌─────────────────────┐
|
|
54
|
+
│ compileMultiModule │ Orchestrates all modules
|
|
55
|
+
│ (index.js) │
|
|
56
|
+
└────────┬────────────┘
|
|
55
57
|
│
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
│
|
|
60
|
-
│
|
|
61
|
-
|
|
62
|
-
|
|
58
|
+
┌────┴────┬────────┬────────┬────────┐
|
|
59
|
+
▼ ▼ ▼ ▼ ▼
|
|
60
|
+
┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐
|
|
61
|
+
│Skills │ │Commands│ │Agents │ │Rules │ │Hooks │
|
|
62
|
+
│Emitter│ │Emitter │ │Emitter│ │Emitter│ │Emitter│
|
|
63
|
+
└───┬───┘ └───┬───┘ └───┬───┘ └───┬───┘ └───┬───┘
|
|
64
|
+
│ │ │ │ │
|
|
65
|
+
▼ ▼ ▼ ▼ ▼
|
|
66
|
+
Platform-specific output directories
|
|
63
67
|
```
|
|
64
68
|
|
|
65
69
|
## CLI Usage
|
|
66
70
|
|
|
67
71
|
```bash
|
|
72
|
+
# Legacy: Compile commands only
|
|
68
73
|
npm run adapt # Compile all platforms
|
|
69
74
|
npm run adapt -- --platform codex # Compile single platform
|
|
70
75
|
npm run adapt -- --check # Drift detection only
|
|
71
|
-
|
|
72
|
-
|
|
76
|
+
|
|
77
|
+
# v3.0: Multi-module compilation
|
|
78
|
+
npm run adapt -- --modules skills,commands,agents,rules
|
|
79
|
+
npm run adapt -- --modules skills --platform cursor
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Key APIs
|
|
83
|
+
|
|
84
|
+
### compile(options) - Legacy
|
|
85
|
+
Compiles commands only (backward compatible).
|
|
86
|
+
|
|
87
|
+
### compileMultiModule(options) - v3.0
|
|
88
|
+
Compiles all specified modules.
|
|
89
|
+
|
|
90
|
+
```javascript
|
|
91
|
+
const { compileMultiModule } = require('./lib/compiler');
|
|
92
|
+
|
|
93
|
+
await compileMultiModule({
|
|
94
|
+
sourceBaseDir: '.claude/',
|
|
95
|
+
outputBaseDir: '.',
|
|
96
|
+
platforms: ['codex', 'cursor', 'qwen', 'antigravity'],
|
|
97
|
+
modules: ['skills', 'commands', 'agents', 'rules'],
|
|
98
|
+
verbose: true
|
|
99
|
+
});
|
|
73
100
|
```
|
|
74
101
|
|
|
75
102
|
## Key Schemas
|
|
@@ -77,16 +104,20 @@ npm run adapt -- --verbose # Detailed output
|
|
|
77
104
|
- **CommandIR**: Intermediate representation after parsing
|
|
78
105
|
- **ManifestEntry**: Single compilation record (source, target, hash, platform)
|
|
79
106
|
- **Manifest**: Complete compilation history
|
|
107
|
+
- **PlatformConfig**: Platform-specific configuration (v2.0)
|
|
80
108
|
|
|
81
109
|
## Dependencies
|
|
82
110
|
|
|
83
111
|
- `gray-matter`: Frontmatter parsing
|
|
84
112
|
- `@iarna/toml`: TOML serialization (Qwen)
|
|
85
|
-
- `js-yaml`: YAML serialization (Codex, Antigravity)
|
|
113
|
+
- `js-yaml`: YAML serialization (Codex, Antigravity, Cursor)
|
|
86
114
|
- `zod`: Schema validation
|
|
87
115
|
|
|
88
116
|
---
|
|
89
117
|
|
|
90
118
|
**Created**: 2025-12-18
|
|
91
|
-
**
|
|
92
|
-
**
|
|
119
|
+
**Updated**: 2026-02-07
|
|
120
|
+
**REQ**: REQ-005 (RM-007), Multi-Platform Adaptation
|
|
121
|
+
**Version**: 3.0.0
|
|
122
|
+
|
|
123
|
+
[PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md
|
|
@@ -0,0 +1,508 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-Module Emitters Test Suite
|
|
3
|
+
*
|
|
4
|
+
* [INPUT]: 测试 fixtures
|
|
5
|
+
* [OUTPUT]: 测试结果
|
|
6
|
+
* [POS]: 编译器测试套件,验证多模块编译功能
|
|
7
|
+
* [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md
|
|
8
|
+
*
|
|
9
|
+
* 测试覆盖:
|
|
10
|
+
* - context-expander.js
|
|
11
|
+
* - 各平台 Emitter 的多模块方法
|
|
12
|
+
* - compileMultiModule 集成测试
|
|
13
|
+
*/
|
|
14
|
+
const fs = require('fs');
|
|
15
|
+
const path = require('path');
|
|
16
|
+
const os = require('os');
|
|
17
|
+
|
|
18
|
+
const { ContextExpander } = require('../context-expander.js');
|
|
19
|
+
const CodexEmitter = require('../emitters/codex-emitter.js');
|
|
20
|
+
const CursorEmitter = require('../emitters/cursor-emitter.js');
|
|
21
|
+
const QwenEmitter = require('../emitters/qwen-emitter.js');
|
|
22
|
+
const AntigravityEmitter = require('../emitters/antigravity-emitter.js');
|
|
23
|
+
const { compileMultiModule, PLATFORMS, DEFAULT_MODULES } = require('../index.js');
|
|
24
|
+
|
|
25
|
+
// ============================================================
|
|
26
|
+
// Test Fixtures
|
|
27
|
+
// ============================================================
|
|
28
|
+
const FIXTURES_DIR = path.join(__dirname, 'fixtures', 'multi-module');
|
|
29
|
+
|
|
30
|
+
// 创建临时目录
|
|
31
|
+
function createTempDir() {
|
|
32
|
+
return fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-test-'));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// 清理临时目录
|
|
36
|
+
function cleanupTempDir(dir) {
|
|
37
|
+
if (fs.existsSync(dir)) {
|
|
38
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 创建测试 fixtures
|
|
43
|
+
function setupFixtures(tempDir) {
|
|
44
|
+
// 创建 skills 目录结构
|
|
45
|
+
const skillsDir = path.join(tempDir, '.claude', 'skills', 'workflow', 'test-skill');
|
|
46
|
+
fs.mkdirSync(skillsDir, { recursive: true });
|
|
47
|
+
|
|
48
|
+
// 创建 SKILL.md
|
|
49
|
+
fs.writeFileSync(path.join(skillsDir, 'SKILL.md'), `---
|
|
50
|
+
name: test-skill
|
|
51
|
+
description: A test skill for unit testing
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
# Test Skill
|
|
55
|
+
|
|
56
|
+
This is a test skill.
|
|
57
|
+
|
|
58
|
+
## Usage
|
|
59
|
+
|
|
60
|
+
Use this skill for testing.
|
|
61
|
+
`);
|
|
62
|
+
|
|
63
|
+
// 创建 context.jsonl
|
|
64
|
+
fs.writeFileSync(path.join(skillsDir, 'context.jsonl'), `{"file": "devflow/requirements/REQ-001/PRD.md", "reason": "Product requirements"}
|
|
65
|
+
{"file": "devflow/spec/frontend/index.md", "reason": "Frontend conventions", "optional": true}
|
|
66
|
+
`);
|
|
67
|
+
|
|
68
|
+
// 创建 agents 目录
|
|
69
|
+
const agentsDir = path.join(tempDir, '.claude', 'agents');
|
|
70
|
+
fs.mkdirSync(agentsDir, { recursive: true });
|
|
71
|
+
|
|
72
|
+
fs.writeFileSync(path.join(agentsDir, 'test-agent.md'), `---
|
|
73
|
+
name: test-agent
|
|
74
|
+
description: A test agent
|
|
75
|
+
tools: Read, Write
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
# Test Agent
|
|
79
|
+
|
|
80
|
+
This agent is for testing.
|
|
81
|
+
`);
|
|
82
|
+
|
|
83
|
+
// 创建 rules 目录
|
|
84
|
+
const rulesDir = path.join(tempDir, '.claude', 'rules');
|
|
85
|
+
fs.mkdirSync(rulesDir, { recursive: true });
|
|
86
|
+
|
|
87
|
+
fs.writeFileSync(path.join(rulesDir, 'test-rule.md'), `---
|
|
88
|
+
description: A test rule
|
|
89
|
+
alwaysApply: true
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
# Test Rule
|
|
93
|
+
|
|
94
|
+
This rule is for testing.
|
|
95
|
+
`);
|
|
96
|
+
|
|
97
|
+
// 创建 hooks 目录
|
|
98
|
+
const hooksDir = path.join(tempDir, '.claude', 'hooks');
|
|
99
|
+
fs.mkdirSync(hooksDir, { recursive: true });
|
|
100
|
+
|
|
101
|
+
fs.writeFileSync(path.join(hooksDir, 'preToolUse-test.ts'), `// Test hook
|
|
102
|
+
export default function preToolUseTest() {
|
|
103
|
+
console.log('Hook triggered');
|
|
104
|
+
}
|
|
105
|
+
`);
|
|
106
|
+
|
|
107
|
+
return tempDir;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ============================================================
|
|
111
|
+
// ContextExpander Tests
|
|
112
|
+
// ============================================================
|
|
113
|
+
describe('ContextExpander', () => {
|
|
114
|
+
describe('parseJsonl', () => {
|
|
115
|
+
test('parses valid JSONL content', () => {
|
|
116
|
+
const jsonl = `{"file": "a.md", "reason": "test"}
|
|
117
|
+
{"file": "b.md", "reason": "test2", "optional": true}`;
|
|
118
|
+
|
|
119
|
+
const result = ContextExpander.parseJsonl(jsonl);
|
|
120
|
+
|
|
121
|
+
expect(result).toHaveLength(2);
|
|
122
|
+
expect(result[0]).toEqual({ file: 'a.md', reason: 'test', optional: false });
|
|
123
|
+
expect(result[1]).toEqual({ file: 'b.md', reason: 'test2', optional: true });
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test('handles empty content', () => {
|
|
127
|
+
expect(ContextExpander.parseJsonl('')).toEqual([]);
|
|
128
|
+
expect(ContextExpander.parseJsonl(' ')).toEqual([]);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test('skips invalid lines', () => {
|
|
132
|
+
const jsonl = `{"file": "a.md", "reason": "test"}
|
|
133
|
+
invalid json
|
|
134
|
+
{"file": "b.md", "reason": "test2"}`;
|
|
135
|
+
|
|
136
|
+
const result = ContextExpander.parseJsonl(jsonl);
|
|
137
|
+
expect(result).toHaveLength(2);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
describe('expand', () => {
|
|
142
|
+
const contexts = [
|
|
143
|
+
{ file: 'a.md', reason: 'test', optional: false },
|
|
144
|
+
{ file: 'b.md', reason: 'test2', optional: true }
|
|
145
|
+
];
|
|
146
|
+
|
|
147
|
+
test('expands for Cursor with @file references', () => {
|
|
148
|
+
const result = ContextExpander.expand(contexts, 'cursor');
|
|
149
|
+
|
|
150
|
+
expect(result).toContain('@a.md');
|
|
151
|
+
expect(result).toContain('@b.md (optional)');
|
|
152
|
+
expect(result).toContain('## Context Files');
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test('expands for Codex with Required Context section', () => {
|
|
156
|
+
const result = ContextExpander.expand(contexts, 'codex');
|
|
157
|
+
|
|
158
|
+
expect(result).toContain('## Required Context');
|
|
159
|
+
expect(result).toContain('`a.md`');
|
|
160
|
+
expect(result).toContain('`b.md`');
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
test('expands for Qwen with Required Context section', () => {
|
|
164
|
+
const result = ContextExpander.expand(contexts, 'qwen');
|
|
165
|
+
|
|
166
|
+
expect(result).toContain('## Required Context');
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test('expands for Antigravity with Required Context section', () => {
|
|
170
|
+
const result = ContextExpander.expand(contexts, 'antigravity');
|
|
171
|
+
|
|
172
|
+
expect(result).toContain('## Required Context');
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test('returns empty string for empty contexts', () => {
|
|
176
|
+
expect(ContextExpander.expand([], 'cursor')).toBe('');
|
|
177
|
+
expect(ContextExpander.expand(null, 'cursor')).toBe('');
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// ============================================================
|
|
183
|
+
// CodexEmitter Multi-Module Tests
|
|
184
|
+
// ============================================================
|
|
185
|
+
describe('CodexEmitter Multi-Module', () => {
|
|
186
|
+
let tempDir;
|
|
187
|
+
let emitter;
|
|
188
|
+
|
|
189
|
+
beforeEach(() => {
|
|
190
|
+
tempDir = createTempDir();
|
|
191
|
+
setupFixtures(tempDir);
|
|
192
|
+
emitter = new CodexEmitter();
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
afterEach(() => {
|
|
196
|
+
cleanupTempDir(tempDir);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
test('emitSkills creates SKILL.md in target directory', async () => {
|
|
200
|
+
const sourceDir = path.join(tempDir, '.claude', 'skills');
|
|
201
|
+
const targetDir = path.join(tempDir, '.codex', 'skills');
|
|
202
|
+
|
|
203
|
+
const results = await emitter.emitSkills(sourceDir, targetDir);
|
|
204
|
+
|
|
205
|
+
expect(results.length).toBeGreaterThan(0);
|
|
206
|
+
expect(results[0].skillName).toBe('test-skill');
|
|
207
|
+
|
|
208
|
+
const targetPath = path.join(targetDir, 'test-skill', 'SKILL.md');
|
|
209
|
+
expect(fs.existsSync(targetPath)).toBe(true);
|
|
210
|
+
|
|
211
|
+
const content = fs.readFileSync(targetPath, 'utf8');
|
|
212
|
+
expect(content).toContain('name: test-skill');
|
|
213
|
+
expect(content).toContain('## Required Context');
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
test('emitAgents merges to AGENTS.md', async () => {
|
|
217
|
+
const sourceDir = path.join(tempDir, '.claude', 'agents');
|
|
218
|
+
const targetPath = path.join(tempDir, 'AGENTS.md');
|
|
219
|
+
|
|
220
|
+
const results = await emitter.emitAgents(sourceDir, targetPath);
|
|
221
|
+
|
|
222
|
+
expect(results.length).toBe(1);
|
|
223
|
+
expect(fs.existsSync(targetPath)).toBe(true);
|
|
224
|
+
|
|
225
|
+
const content = fs.readFileSync(targetPath, 'utf8');
|
|
226
|
+
expect(content).toContain('# Agents');
|
|
227
|
+
expect(content).toContain('## test-agent');
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
test('emitRules appends to AGENTS.md', async () => {
|
|
231
|
+
const sourceDir = path.join(tempDir, '.claude', 'rules');
|
|
232
|
+
const targetPath = path.join(tempDir, 'AGENTS.md');
|
|
233
|
+
|
|
234
|
+
// 先创建 AGENTS.md
|
|
235
|
+
fs.writeFileSync(targetPath, '# Agents\n\nExisting content.\n');
|
|
236
|
+
|
|
237
|
+
const results = await emitter.emitRules(sourceDir, targetPath);
|
|
238
|
+
|
|
239
|
+
expect(results.length).toBe(1);
|
|
240
|
+
|
|
241
|
+
const content = fs.readFileSync(targetPath, 'utf8');
|
|
242
|
+
expect(content).toContain('# Agents');
|
|
243
|
+
expect(content).toContain('## Rules');
|
|
244
|
+
expect(content).toContain('### test-rule');
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
// ============================================================
|
|
249
|
+
// CursorEmitter Multi-Module Tests
|
|
250
|
+
// ============================================================
|
|
251
|
+
describe('CursorEmitter Multi-Module', () => {
|
|
252
|
+
let tempDir;
|
|
253
|
+
let emitter;
|
|
254
|
+
|
|
255
|
+
beforeEach(() => {
|
|
256
|
+
tempDir = createTempDir();
|
|
257
|
+
setupFixtures(tempDir);
|
|
258
|
+
emitter = new CursorEmitter();
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
afterEach(() => {
|
|
262
|
+
cleanupTempDir(tempDir);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
test('emitSkills creates .mdc files in rules directory', async () => {
|
|
266
|
+
const sourceDir = path.join(tempDir, '.claude', 'skills');
|
|
267
|
+
const targetDir = path.join(tempDir, '.cursor', 'rules');
|
|
268
|
+
|
|
269
|
+
const results = await emitter.emitSkills(sourceDir, targetDir);
|
|
270
|
+
|
|
271
|
+
expect(results.length).toBeGreaterThan(0);
|
|
272
|
+
|
|
273
|
+
const targetPath = path.join(targetDir, 'test-skill.mdc');
|
|
274
|
+
expect(fs.existsSync(targetPath)).toBe(true);
|
|
275
|
+
|
|
276
|
+
const content = fs.readFileSync(targetPath, 'utf8');
|
|
277
|
+
expect(content).toContain('description:');
|
|
278
|
+
expect(content).toContain('globs:');
|
|
279
|
+
expect(content).toContain('@devflow/requirements/REQ-001/PRD.md');
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
test('emitAgents creates subagent files', async () => {
|
|
283
|
+
const sourceDir = path.join(tempDir, '.claude', 'agents');
|
|
284
|
+
const targetDir = path.join(tempDir, '.cursor', 'subagents');
|
|
285
|
+
|
|
286
|
+
const results = await emitter.emitAgents(sourceDir, targetDir);
|
|
287
|
+
|
|
288
|
+
expect(results.length).toBe(1);
|
|
289
|
+
|
|
290
|
+
const targetPath = path.join(targetDir, 'test-agent.md');
|
|
291
|
+
expect(fs.existsSync(targetPath)).toBe(true);
|
|
292
|
+
|
|
293
|
+
const content = fs.readFileSync(targetPath, 'utf8');
|
|
294
|
+
expect(content).toContain('name: test-agent');
|
|
295
|
+
expect(content).toContain('description:');
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
test('emitRules creates .mdc files', async () => {
|
|
299
|
+
const sourceDir = path.join(tempDir, '.claude', 'rules');
|
|
300
|
+
const targetDir = path.join(tempDir, '.cursor', 'rules');
|
|
301
|
+
|
|
302
|
+
const results = await emitter.emitRules(sourceDir, targetDir);
|
|
303
|
+
|
|
304
|
+
expect(results.length).toBe(1);
|
|
305
|
+
|
|
306
|
+
const targetPath = path.join(targetDir, 'test-rule.mdc');
|
|
307
|
+
expect(fs.existsSync(targetPath)).toBe(true);
|
|
308
|
+
|
|
309
|
+
const content = fs.readFileSync(targetPath, 'utf8');
|
|
310
|
+
expect(content).toContain('description:');
|
|
311
|
+
expect(content).toContain('alwaysApply:');
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
test('emitHooks creates hooks.json and shell scripts', async () => {
|
|
315
|
+
const sourceDir = path.join(tempDir, '.claude', 'hooks');
|
|
316
|
+
const targetDir = path.join(tempDir, '.cursor');
|
|
317
|
+
|
|
318
|
+
const results = await emitter.emitHooks(sourceDir, targetDir);
|
|
319
|
+
|
|
320
|
+
expect(results.length).toBeGreaterThan(0);
|
|
321
|
+
|
|
322
|
+
const configPath = path.join(targetDir, 'hooks.json');
|
|
323
|
+
expect(fs.existsSync(configPath)).toBe(true);
|
|
324
|
+
|
|
325
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
326
|
+
expect(config.version).toBe(1);
|
|
327
|
+
expect(config.hooks).toBeDefined();
|
|
328
|
+
});
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
// ============================================================
|
|
332
|
+
// QwenEmitter Multi-Module Tests
|
|
333
|
+
// ============================================================
|
|
334
|
+
describe('QwenEmitter Multi-Module', () => {
|
|
335
|
+
let tempDir;
|
|
336
|
+
let emitter;
|
|
337
|
+
|
|
338
|
+
beforeEach(() => {
|
|
339
|
+
tempDir = createTempDir();
|
|
340
|
+
setupFixtures(tempDir);
|
|
341
|
+
emitter = new QwenEmitter();
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
afterEach(() => {
|
|
345
|
+
cleanupTempDir(tempDir);
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
test('emitSkills creates .toml files', async () => {
|
|
349
|
+
const sourceDir = path.join(tempDir, '.claude', 'skills');
|
|
350
|
+
const targetDir = path.join(tempDir, '.qwen', 'commands');
|
|
351
|
+
|
|
352
|
+
const results = await emitter.emitSkills(sourceDir, targetDir);
|
|
353
|
+
|
|
354
|
+
expect(results.length).toBeGreaterThan(0);
|
|
355
|
+
|
|
356
|
+
const targetPath = path.join(targetDir, 'test-skill.toml');
|
|
357
|
+
expect(fs.existsSync(targetPath)).toBe(true);
|
|
358
|
+
|
|
359
|
+
const content = fs.readFileSync(targetPath, 'utf8');
|
|
360
|
+
expect(content).toContain('description =');
|
|
361
|
+
expect(content).toContain('prompt =');
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
test('emitAgents creates agent files', async () => {
|
|
365
|
+
const sourceDir = path.join(tempDir, '.claude', 'agents');
|
|
366
|
+
const targetDir = path.join(tempDir, '.qwen', 'agents');
|
|
367
|
+
|
|
368
|
+
const results = await emitter.emitAgents(sourceDir, targetDir);
|
|
369
|
+
|
|
370
|
+
expect(results.length).toBe(1);
|
|
371
|
+
|
|
372
|
+
const targetPath = path.join(targetDir, 'test-agent.md');
|
|
373
|
+
expect(fs.existsSync(targetPath)).toBe(true);
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
test('emitRules creates CONTEXT.md', async () => {
|
|
377
|
+
const sourceDir = path.join(tempDir, '.claude', 'rules');
|
|
378
|
+
const targetPath = path.join(tempDir, 'CONTEXT.md');
|
|
379
|
+
|
|
380
|
+
const results = await emitter.emitRules(sourceDir, targetPath);
|
|
381
|
+
|
|
382
|
+
expect(results.length).toBe(1);
|
|
383
|
+
expect(fs.existsSync(targetPath)).toBe(true);
|
|
384
|
+
|
|
385
|
+
const content = fs.readFileSync(targetPath, 'utf8');
|
|
386
|
+
expect(content).toContain('# Project Context');
|
|
387
|
+
expect(content).toContain('## test-rule');
|
|
388
|
+
});
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
// ============================================================
|
|
392
|
+
// AntigravityEmitter Multi-Module Tests
|
|
393
|
+
// ============================================================
|
|
394
|
+
describe('AntigravityEmitter Multi-Module', () => {
|
|
395
|
+
let tempDir;
|
|
396
|
+
let emitter;
|
|
397
|
+
|
|
398
|
+
beforeEach(() => {
|
|
399
|
+
tempDir = createTempDir();
|
|
400
|
+
setupFixtures(tempDir);
|
|
401
|
+
emitter = new AntigravityEmitter();
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
afterEach(() => {
|
|
405
|
+
cleanupTempDir(tempDir);
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
test('emitSkills creates SKILL.md in skills directory', async () => {
|
|
409
|
+
const sourceDir = path.join(tempDir, '.claude', 'skills');
|
|
410
|
+
const targetDir = path.join(tempDir, '.agent', 'skills');
|
|
411
|
+
|
|
412
|
+
const results = await emitter.emitSkills(sourceDir, targetDir);
|
|
413
|
+
|
|
414
|
+
expect(results.length).toBeGreaterThan(0);
|
|
415
|
+
|
|
416
|
+
const targetPath = path.join(targetDir, 'test-skill', 'SKILL.md');
|
|
417
|
+
expect(fs.existsSync(targetPath)).toBe(true);
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
test('emitRules creates rule files', async () => {
|
|
421
|
+
const sourceDir = path.join(tempDir, '.claude', 'rules');
|
|
422
|
+
const targetDir = path.join(tempDir, '.agent', 'rules');
|
|
423
|
+
|
|
424
|
+
const results = await emitter.emitRules(sourceDir, targetDir);
|
|
425
|
+
|
|
426
|
+
expect(results.length).toBe(1);
|
|
427
|
+
|
|
428
|
+
const targetPath = path.join(targetDir, 'test-rule.md');
|
|
429
|
+
expect(fs.existsSync(targetPath)).toBe(true);
|
|
430
|
+
});
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
// ============================================================
|
|
434
|
+
// compileMultiModule Integration Tests
|
|
435
|
+
// ============================================================
|
|
436
|
+
describe('compileMultiModule Integration', () => {
|
|
437
|
+
let tempDir;
|
|
438
|
+
|
|
439
|
+
beforeEach(() => {
|
|
440
|
+
tempDir = createTempDir();
|
|
441
|
+
setupFixtures(tempDir);
|
|
442
|
+
|
|
443
|
+
// 创建 devflow/.generated 目录
|
|
444
|
+
fs.mkdirSync(path.join(tempDir, 'devflow', '.generated'), { recursive: true });
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
afterEach(() => {
|
|
448
|
+
cleanupTempDir(tempDir);
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
test('compiles all modules for all platforms', async () => {
|
|
452
|
+
const result = await compileMultiModule({
|
|
453
|
+
sourceBaseDir: path.join(tempDir, '.claude'),
|
|
454
|
+
outputBaseDir: tempDir,
|
|
455
|
+
platforms: ['codex', 'cursor'],
|
|
456
|
+
modules: ['skills', 'agents', 'rules'],
|
|
457
|
+
verbose: false
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
expect(result.success).toBe(true);
|
|
461
|
+
expect(result.skillsEmitted).toBeGreaterThan(0);
|
|
462
|
+
expect(result.agentsEmitted).toBeGreaterThan(0);
|
|
463
|
+
expect(result.rulesEmitted).toBeGreaterThan(0);
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
test('compiles only specified modules', async () => {
|
|
467
|
+
const result = await compileMultiModule({
|
|
468
|
+
sourceBaseDir: path.join(tempDir, '.claude'),
|
|
469
|
+
outputBaseDir: tempDir,
|
|
470
|
+
platforms: ['codex'],
|
|
471
|
+
modules: ['skills'],
|
|
472
|
+
verbose: false
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
expect(result.success).toBe(true);
|
|
476
|
+
expect(result.skillsEmitted).toBeGreaterThan(0);
|
|
477
|
+
expect(result.agentsEmitted).toBe(0);
|
|
478
|
+
expect(result.rulesEmitted).toBe(0);
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
test('handles missing source directories gracefully', async () => {
|
|
482
|
+
const emptyDir = createTempDir();
|
|
483
|
+
|
|
484
|
+
try {
|
|
485
|
+
const result = await compileMultiModule({
|
|
486
|
+
sourceBaseDir: path.join(emptyDir, '.claude'),
|
|
487
|
+
outputBaseDir: emptyDir,
|
|
488
|
+
platforms: ['codex'],
|
|
489
|
+
modules: ['skills', 'agents', 'rules'],
|
|
490
|
+
verbose: false
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
expect(result.success).toBe(true);
|
|
494
|
+
expect(result.skillsEmitted).toBe(0);
|
|
495
|
+
expect(result.agentsEmitted).toBe(0);
|
|
496
|
+
expect(result.rulesEmitted).toBe(0);
|
|
497
|
+
} finally {
|
|
498
|
+
cleanupTempDir(emptyDir);
|
|
499
|
+
}
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
test('exports DEFAULT_MODULES', () => {
|
|
503
|
+
expect(DEFAULT_MODULES).toContain('skills');
|
|
504
|
+
expect(DEFAULT_MODULES).toContain('commands');
|
|
505
|
+
expect(DEFAULT_MODULES).toContain('agents');
|
|
506
|
+
expect(DEFAULT_MODULES).toContain('rules');
|
|
507
|
+
});
|
|
508
|
+
});
|