claudekit-codex-sync 0.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.
Files changed (56) hide show
  1. package/AGENTS.md +45 -0
  2. package/README.md +131 -0
  3. package/bin/ck-codex-sync +12 -0
  4. package/bin/ck-codex-sync.js +9 -0
  5. package/docs/code-standards.md +62 -0
  6. package/docs/codebase-summary.md +83 -0
  7. package/docs/codex-vs-claude-agents.md +74 -0
  8. package/docs/installation-guide.md +64 -0
  9. package/docs/project-overview-pdr.md +44 -0
  10. package/docs/project-roadmap.md +51 -0
  11. package/docs/system-architecture.md +106 -0
  12. package/package.json +16 -0
  13. package/plans/260222-2051-claudekit-codex-community-sync/phase-01-productization.md +36 -0
  14. package/plans/260222-2051-claudekit-codex-community-sync/phase-02-core-refactor.md +32 -0
  15. package/plans/260222-2051-claudekit-codex-community-sync/phase-03-agent-transpiler.md +33 -0
  16. package/plans/260222-2051-claudekit-codex-community-sync/phase-04-parity-harness.md +43 -0
  17. package/plans/260222-2051-claudekit-codex-community-sync/phase-05-distribution-npm.md +35 -0
  18. package/plans/260222-2051-claudekit-codex-community-sync/phase-06-git-clone-docs.md +28 -0
  19. package/plans/260222-2051-claudekit-codex-community-sync/phase-07-qa-release.md +35 -0
  20. package/plans/260222-2051-claudekit-codex-community-sync/plan.md +99 -0
  21. package/plans/260223-0951-refactor-and-upgrade/phase-01-project-structure.md +79 -0
  22. package/plans/260223-0951-refactor-and-upgrade/phase-02-extract-templates.md +36 -0
  23. package/plans/260223-0951-refactor-and-upgrade/phase-03-modularize-python.md +107 -0
  24. package/plans/260223-0951-refactor-and-upgrade/phase-04-live-source-detection.md +76 -0
  25. package/plans/260223-0951-refactor-and-upgrade/phase-05-agent-toml-config.md +88 -0
  26. package/plans/260223-0951-refactor-and-upgrade/phase-06-backup-registry.md +58 -0
  27. package/plans/260223-0951-refactor-and-upgrade/phase-07-tests-docs-push.md +54 -0
  28. package/plans/260223-0951-refactor-and-upgrade/plan.md +72 -0
  29. package/reports/brainstorm-260222-2051-claudekit-codex-community-sync.md +113 -0
  30. package/scripts/bootstrap-claudekit-skill-scripts.sh +150 -0
  31. package/scripts/claudekit-sync-all.py +1150 -0
  32. package/scripts/export-claudekit-prompts.sh +221 -0
  33. package/scripts/normalize-claudekit-for-codex.sh +261 -0
  34. package/src/claudekit_codex_sync/__init__.py +0 -0
  35. package/src/claudekit_codex_sync/asset_sync_dir.py +125 -0
  36. package/src/claudekit_codex_sync/asset_sync_zip.py +140 -0
  37. package/src/claudekit_codex_sync/bridge_generator.py +33 -0
  38. package/src/claudekit_codex_sync/cli.py +199 -0
  39. package/src/claudekit_codex_sync/config_enforcer.py +140 -0
  40. package/src/claudekit_codex_sync/constants.py +104 -0
  41. package/src/claudekit_codex_sync/dep_bootstrapper.py +73 -0
  42. package/src/claudekit_codex_sync/path_normalizer.py +248 -0
  43. package/src/claudekit_codex_sync/prompt_exporter.py +89 -0
  44. package/src/claudekit_codex_sync/runtime_verifier.py +32 -0
  45. package/src/claudekit_codex_sync/source_resolver.py +78 -0
  46. package/src/claudekit_codex_sync/sync_registry.py +77 -0
  47. package/src/claudekit_codex_sync/utils.py +130 -0
  48. package/templates/agents-md.md +45 -0
  49. package/templates/bridge-docs-init.sh +25 -0
  50. package/templates/bridge-project-status.sh +49 -0
  51. package/templates/bridge-resolve-command.py +52 -0
  52. package/templates/bridge-skill.md +63 -0
  53. package/templates/command-map.md +44 -0
  54. package/tests/__init__.py +1 -0
  55. package/tests/test_config_enforcer.py +44 -0
  56. package/tests/test_path_normalizer.py +61 -0
@@ -0,0 +1,88 @@
1
+ # Phase 5: Agent TOML Normalization + Multi-Agent Config
2
+
3
+ Status: pending
4
+ Priority: critical
5
+ Effort: 0.5d
6
+
7
+ ## Goal
8
+ Fix 16 `.claude` references in agent TOMLs. Enable `multi_agent = true`.
9
+
10
+ ## Agent TOML Normalization
11
+
12
+ Add to `path_normalizer.py`:
13
+ ```python
14
+ AGENT_TOML_REPLACEMENTS: List[Tuple[str, str]] = [
15
+ ("$HOME/.claude/skills/", "${CODEX_HOME:-$HOME/.codex}/skills/"),
16
+ ("$HOME/.claude/scripts/", "${CODEX_HOME:-$HOME/.codex}/claudekit/scripts/"),
17
+ ("$HOME/.claude/rules/", "${CODEX_HOME:-$HOME/.codex}/claudekit/rules/"),
18
+ ("$HOME/.claude/.ck.json", "${CODEX_HOME:-$HOME/.codex}/claudekit/.ck.json"),
19
+ ("$HOME/.claude/.mcp.json", "${CODEX_HOME:-$HOME/.codex}/claudekit/.mcp.json"),
20
+ ("$HOME/.claude/", "${CODEX_HOME:-$HOME/.codex}/"),
21
+ ("~/.claude/", "~/.codex/"),
22
+ ]
23
+
24
+ def normalize_agent_tomls(*, codex_home: Path, dry_run: bool) -> int:
25
+ agents_dir = codex_home / "agents"
26
+ if not agents_dir.exists():
27
+ return 0
28
+ changed = 0
29
+ for toml_file in sorted(agents_dir.glob("*.toml")):
30
+ text = toml_file.read_text(encoding="utf-8")
31
+ new_text = apply_replacements(text, AGENT_TOML_REPLACEMENTS)
32
+ if new_text != text:
33
+ changed += 1
34
+ if not dry_run:
35
+ toml_file.write_text(new_text, encoding="utf-8")
36
+ return changed
37
+ ```
38
+
39
+ ## Adapt Claude-Specific Syntax
40
+
41
+ Strip from developer_instructions:
42
+ ```python
43
+ CLAUDE_SYNTAX_ADAPTATIONS = [
44
+ # Task() tool references → natural language
45
+ ("Task(Explore)", "the explore agent"),
46
+ ("Task(researcher)", "the researcher agent"),
47
+ ("Task(", "delegate to "),
48
+ # Claude-specific paths
49
+ ("$HOME/.claude/skills/*", "${CODEX_HOME:-$HOME/.codex}/skills/*"),
50
+ ]
51
+ ```
52
+
53
+ ## Multi-Agent Config
54
+
55
+ Add to `config_enforcer.py`:
56
+ ```python
57
+ def enforce_multi_agent_flag(config_path: Path, dry_run: bool) -> bool:
58
+ text = config_path.read_text() if config_path.exists() else ""
59
+ if "[features]" in text:
60
+ if "multi_agent" not in text:
61
+ text = text.replace("[features]", "[features]\nmulti_agent = true")
62
+ else:
63
+ text += "\n[features]\nmulti_agent = true\n"
64
+ if not dry_run:
65
+ config_path.write_text(text)
66
+ return True
67
+ ```
68
+
69
+ ## Verification
70
+ ```bash
71
+ # Before: expect 16 hits
72
+ grep -c '\.claude' ~/.codex/agents/*.toml
73
+
74
+ # After: expect 0
75
+ grep -c '\.claude' ~/.codex/agents/*.toml
76
+
77
+ # Multi-agent:
78
+ codex features list | grep multi_agent
79
+ # Expected: multi_agent experimental true
80
+ ```
81
+
82
+ ## Todo
83
+ - [ ] Add AGENT_TOML_REPLACEMENTS
84
+ - [ ] Add normalize_agent_tomls()
85
+ - [ ] Add Claude syntax adaptations
86
+ - [ ] Add enforce_multi_agent_flag()
87
+ - [ ] Test: 0 .claude refs in TOMLs
88
+ - [ ] Test: multi_agent = true
@@ -0,0 +1,58 @@
1
+ # Phase 6: Backup + Registry
2
+
3
+ Status: pending
4
+ Priority: high
5
+ Effort: 0.5d
6
+
7
+ ## Goal
8
+ Track synced files with SHA-256 checksums. Backup before overwrite.
9
+
10
+ ## Registry Format (`~/.codex/.claudekit-sync-registry.json`)
11
+ ```json
12
+ {
13
+ "version": 1,
14
+ "lastSync": "2026-02-23T02:26:00Z",
15
+ "sourceDir": "~/.claude",
16
+ "entries": {
17
+ "skills/brainstorm/SKILL.md": {
18
+ "sourceHash": "abc...",
19
+ "targetHash": "def...",
20
+ "syncedAt": "2026-02-23T02:26:00Z"
21
+ }
22
+ }
23
+ }
24
+ ```
25
+
26
+ ## Add to utils.py
27
+ ```python
28
+ import hashlib, json, datetime
29
+
30
+ def compute_hash(path: Path) -> str:
31
+ return hashlib.sha256(path.read_bytes()).hexdigest()
32
+
33
+ def create_backup(path: Path) -> Path:
34
+ ts = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
35
+ backup = path.with_suffix(f".ck-backup-{ts}{path.suffix}")
36
+ shutil.copy2(path, backup)
37
+ return backup
38
+ ```
39
+
40
+ ## New `sync_registry.py` (~120 lines)
41
+ ```python
42
+ def load_registry(codex_home: Path) -> dict: ...
43
+ def save_registry(codex_home: Path, registry: dict): ...
44
+ def check_user_edit(entry: dict, target: Path) -> bool:
45
+ return compute_hash(target) != entry["targetHash"]
46
+ def update_entry(registry, rel_path, source, target): ...
47
+ ```
48
+
49
+ ## Integration
50
+ Before overwriting:
51
+ 1. Check registry → if user edited, backup + warn
52
+ 2. After writing → update registry with new hashes
53
+
54
+ ## Todo
55
+ - [ ] Add compute_hash, create_backup to utils
56
+ - [ ] Create sync_registry.py
57
+ - [ ] Integrate into asset_sync and path_normalizer
58
+ - [ ] Add --respect-edits flag
@@ -0,0 +1,54 @@
1
+ # Phase 7: Tests + Docs + Git Push
2
+
3
+ Status: pending
4
+ Priority: high
5
+ Effort: 0.5d
6
+
7
+ ## Tests
8
+
9
+ ### `tests/test_path_normalizer.py`
10
+ ```python
11
+ from claudekit_codex_sync.path_normalizer import apply_replacements, SKILL_MD_REPLACEMENTS
12
+
13
+ def test_claude_to_codex_path():
14
+ text = "$HOME/.claude/skills/brainstorm/SKILL.md"
15
+ result = apply_replacements(text, SKILL_MD_REPLACEMENTS)
16
+ assert ".claude" not in result
17
+ assert ".codex" in result or "CODEX_HOME" in result
18
+ ```
19
+
20
+ ### `tests/test_config_enforcer.py`
21
+ ```python
22
+ from claudekit_codex_sync.config_enforcer import enforce_multi_agent_flag
23
+
24
+ def test_adds_multi_agent(tmp_path):
25
+ config = tmp_path / "config.toml"
26
+ config.write_text("[features]\n")
27
+ enforce_multi_agent_flag(config, dry_run=False)
28
+ assert "multi_agent = true" in config.read_text()
29
+ ```
30
+
31
+ ## Docs
32
+
33
+ ### `docs/codex-vs-claude-agents.md`
34
+ Sub-agent limitations doc:
35
+ - Claude Code: tools/model/memory frontmatter, Task() delegation
36
+ - Codex: developer_instructions text only, auto-spawn via multi_agent
37
+ - What transfers: text instructions, sandbox_mode
38
+ - What's lost: tool restriction, model selection, explicit delegation
39
+
40
+ ## Git Push
41
+
42
+ ```bash
43
+ cd /home/vinhawk/claudekit-codex-sync
44
+ git add -A
45
+ git commit -m "refactor: modularize codebase, npm structure, upgrade for Codex"
46
+ git push
47
+ ```
48
+
49
+ ## Todo
50
+ - [ ] Write test_path_normalizer.py
51
+ - [ ] Write test_config_enforcer.py
52
+ - [ ] Write codex-vs-claude-agents.md
53
+ - [ ] Run tests
54
+ - [ ] Git add, commit, push
@@ -0,0 +1,72 @@
1
+ # Plan: Refactor & Upgrade ClaudeKit-Codex-Sync
2
+
3
+ Status: ready
4
+ Priority: high
5
+
6
+ ## Overview
7
+
8
+ Refactor monolithic codebase (1151-line Python + 635-line bash) into modular npm-based project, then upgrade with new capabilities for near-100% Codex effectiveness.
9
+
10
+ ## Phases
11
+
12
+ - [Phase 1: Project Structure](./phase-01-project-structure.md) — npm init, .gitignore, module dirs | **0.5d**
13
+ - [Phase 2: Extract Templates](./phase-02-extract-templates.md) — Move 295 lines of inline strings to files | **0.25d**
14
+ - [Phase 3: Modularize Python](./phase-03-modularize-python.md) — Split into 11 modules <200 lines each | **1d**
15
+ - [Phase 4: Live Source + Detection](./phase-04-live-source-detection.md) — Add ~/.claude/ direct read + auto-detection | **0.5d**
16
+ - [Phase 5: Agent TOML + Config](./phase-05-agent-toml-config.md) — Normalize paths + multi_agent flag | **0.5d**
17
+ - [Phase 6: Backup + Registry](./phase-06-backup-registry.md) — SHA-256 checksum tracking + rollback | **0.5d**
18
+ - [Phase 7: Tests + Docs + Push](./phase-07-tests-docs-push.md) — Tests, docs, git push | **0.5d**
19
+
20
+ **Total: ~3.75 days**
21
+
22
+ ## Key Decisions
23
+
24
+ - **npm + git push** (not pip/PyPI)
25
+ - **Python scripts** remain Python, npm wraps them as CLI
26
+ - **Bash scripts** deleted (duplicate Python logic)
27
+ - **Plans/reports** kept as reference
28
+ - **`~/.claude/` live read** as default source (zip fallback)
29
+ - **Sub-agent instructions adapted** for Codex model (strip Claude-specific syntax)
30
+
31
+ ## Architecture
32
+
33
+ ```
34
+ claudekit-codex-sync/
35
+ ├── package.json # npm package
36
+ ├── bin/
37
+ │ └── ck-codex-sync.js # npm CLI entry → calls Python
38
+ ├── src/
39
+ │ └── claudekit_codex_sync/
40
+ │ ├── __init__.py
41
+ │ ├── cli.py # (~100 lines)
42
+ │ ├── source_resolver.py # (~80 lines)
43
+ │ ├── asset_sync.py # (~160 lines)
44
+ │ ├── path_normalizer.py # (~120 lines)
45
+ │ ├── config_enforcer.py # (~80 lines)
46
+ │ ├── prompt_exporter.py # (~100 lines)
47
+ │ ├── dep_bootstrapper.py# (~60 lines)
48
+ │ ├── runtime_verifier.py# (~30 lines)
49
+ │ ├── bridge_generator.py# (~30 lines)
50
+ │ └── utils.py # (~90 lines)
51
+ ├── templates/
52
+ │ ├── agents-md.md
53
+ │ ├── command-map.md
54
+ │ ├── bridge-skill.md
55
+ │ ├── bridge-resolve-command.py
56
+ │ ├── bridge-docs-init.sh
57
+ │ └── bridge-project-status.sh
58
+ ├── tests/
59
+ ├── docs/
60
+ ├── plans/
61
+ └── reports/
62
+ ```
63
+
64
+ ## Success Criteria
65
+
66
+ - [ ] All Python modules < 200 lines
67
+ - [ ] `npm install -g .` works
68
+ - [ ] `ck-codex-sync --source-mode live` syncs from ~/.claude/
69
+ - [ ] Agent TOMLs: 0 `.claude` references after sync
70
+ - [ ] `codex features list | grep multi_agent` → true after sync
71
+ - [ ] Tests pass
72
+ - [ ] Git clean, ready to push
@@ -0,0 +1,113 @@
1
+ # Brainstorm Report: ClaudeKit -> Codex Community Toolkit
2
+
3
+ ## Problem Statement
4
+ You want a community-shareable toolkit that syncs ClaudeKit assets into Codex with minimal manual work, supports latest zip detection, and proves behavior is close to Claude workflows.
5
+
6
+ ## Requirements
7
+ - Full-auto sync entrypoint (latest zip auto-select).
8
+ - Pull from both zip and local `~/.claude` where needed.
9
+ - Keep current exclusions default (`mcp`, `hooks`) but support opt-in.
10
+ - Add agent-role sync compatible with Codex multi-agent system.
11
+ - Publish for community consumption via:
12
+ - `npm`/`npx` install path.
13
+ - `git clone` + local run path.
14
+ - Provide evidence that behavior is close to ClaudeKit orchestration (not only file-copy parity).
15
+
16
+ ## Current Reality Check
17
+ - Current script (`~/.codex/scripts/claudekit-sync-all.py`) is strong for assets/skills/rules/prompts sync.
18
+ - It is not yet productized as a public package.
19
+ - It does not yet implement Claude-agent -> Codex-agent role transpilation + parity benchmark harness.
20
+ - Behavior parity is therefore not yet provable by metrics.
21
+
22
+ ## Approaches Evaluated
23
+
24
+ ### Approach A: Keep Python Core + Add NPM Wrapper (Recommended for v1)
25
+ Pros:
26
+ - Fastest to ship.
27
+ - Reuses proven sync logic now.
28
+ - Lower regression risk.
29
+ - Easy to support both `npx` and `python3` direct run.
30
+
31
+ Cons:
32
+ - Requires Python on user machine.
33
+ - Wrapper layer adds runtime dependency checks.
34
+
35
+ ### Approach B: Full Rewrite to TypeScript Core
36
+ Pros:
37
+ - Native npm experience.
38
+ - Simpler JS ecosystem integration.
39
+
40
+ Cons:
41
+ - High rewrite cost.
42
+ - High regression risk in edge behavior already solved in Python.
43
+ - Slower time-to-community release.
44
+
45
+ ### Approach C: Maintain Two Cores (Python + TS)
46
+ Pros:
47
+ - Maximum flexibility.
48
+
49
+ Cons:
50
+ - Highest maintenance burden.
51
+ - Divergence risk.
52
+ - Not YAGNI.
53
+
54
+ ## Recommended Strategy
55
+ - **Ship staged hybrid strategy**:
56
+ 1. **v1**: Python core as source of truth + npm wrapper + git-clone workflow.
57
+ 2. **v1.1**: Add agent transpiler and parity benchmark harness.
58
+ 3. **v2**: Consider TS native core only if adoption justifies rewrite.
59
+
60
+ This gives speed now and keeps path to long-term polish without over-engineering.
61
+
62
+ ## Claude -> Codex Customization That Matters Most
63
+ - Agent transpiler that converts Claude `agents/*.md` into Codex role config:
64
+ - `~/.codex/config.toml` `[agents.<role>]`
65
+ - `~/.codex/agents/<role>.toml`
66
+ - Role strategy:
67
+ - Prefix custom roles (`ck-*`) to avoid overriding built-ins accidentally.
68
+ - Allow explicit override mode if user wants `default/worker/explorer` replacement.
69
+ - Instruction normalization:
70
+ - rewrite Claude-specific paths/tooling references to Codex equivalents.
71
+ - preserve intent, not literal syntax.
72
+ - Execution guardrails:
73
+ - per-role `sandbox_mode`, `model_reasoning_effort`, `developer_instructions`.
74
+
75
+ ## Proof Plan: “Near-Similar Behavior”
76
+ Define parity suite and publish numbers:
77
+ - 20-30 canonical scenarios:
78
+ - planning, research, review, debug, docs update, testing loops.
79
+ - A/B runs:
80
+ - A: Claude original flow.
81
+ - B: Codex transpiled flow.
82
+ - Score dimensions:
83
+ - task success rate.
84
+ - required artifact completeness.
85
+ - policy compliance (test/lint/docs gates).
86
+ - orchestration quality (spawn/wait/close behavior).
87
+ - defect quality (severity-weighted findings for review/debug cases).
88
+
89
+ Target thresholds:
90
+ - >=85% parity: acceptable “near-similar”.
91
+ - >=90% parity: strong community-grade claim.
92
+
93
+ ## Risks and Mitigations
94
+ - Risk: Codex/Claude runtime semantics differ.
95
+ - Mitigation: parity scoring by outcomes, not literal step parity.
96
+ - Risk: multi-agent feature drift across Codex versions.
97
+ - Mitigation: version compatibility matrix + CI smoke tests.
98
+ - Risk: wrapper install friction.
99
+ - Mitigation: clear preflight checks + actionable errors.
100
+
101
+ ## Success Metrics
102
+ - Install success rate >=95% on Ubuntu/macOS/WSL for default path.
103
+ - End-to-end sync success rate >=98% on supported fixtures.
104
+ - Parity benchmark >=85% before public “near-similar” claim.
105
+ - Time to run full sync + verify under 3 minutes on standard machine.
106
+
107
+ ## Next Steps
108
+ - Create implementation plan with phases for:
109
+ - productization,
110
+ - transpiler,
111
+ - benchmark harness,
112
+ - npm + git distribution,
113
+ - release process.
@@ -0,0 +1,150 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"
5
+ SKILLS_DIR="${CODEX_HOME}/skills"
6
+ VENV_DIR="${SKILLS_DIR}/.venv"
7
+ RUN_PYTHON=true
8
+ RUN_NODE=true
9
+ DRY_RUN=false
10
+ INCLUDE_TEST_DEPS=false
11
+ INCLUDE_MCP=false
12
+
13
+ usage() {
14
+ cat <<'EOF'
15
+ Install runtime dependencies for ClaudeKit skills synced into Codex.
16
+
17
+ Usage:
18
+ bootstrap-claudekit-skill-scripts.sh [options]
19
+
20
+ Options:
21
+ --python-only Install Python dependencies only
22
+ --node-only Install Node.js dependencies only
23
+ --include-test-deps Also install requirements from test folders
24
+ --include-mcp Also include mcp-builder and mcp-management skills
25
+ --dry-run Print actions only
26
+ -h, --help Show help
27
+ EOF
28
+ }
29
+
30
+ while [[ $# -gt 0 ]]; do
31
+ case "$1" in
32
+ --python-only)
33
+ RUN_PYTHON=true
34
+ RUN_NODE=false
35
+ ;;
36
+ --node-only)
37
+ RUN_PYTHON=false
38
+ RUN_NODE=true
39
+ ;;
40
+ --include-test-deps)
41
+ INCLUDE_TEST_DEPS=true
42
+ ;;
43
+ --include-mcp)
44
+ INCLUDE_MCP=true
45
+ ;;
46
+ --dry-run)
47
+ DRY_RUN=true
48
+ ;;
49
+ -h|--help)
50
+ usage
51
+ exit 0
52
+ ;;
53
+ *)
54
+ echo "Unknown option: $1" >&2
55
+ usage >&2
56
+ exit 1
57
+ ;;
58
+ esac
59
+ shift
60
+ done
61
+
62
+ if [[ ! -d "$SKILLS_DIR" ]]; then
63
+ echo "Skills directory not found: $SKILLS_DIR" >&2
64
+ exit 1
65
+ fi
66
+
67
+ py_ok=0
68
+ py_fail=0
69
+ node_ok=0
70
+ node_fail=0
71
+
72
+ skip_mcp_path() {
73
+ local p="$1"
74
+ if [[ "$INCLUDE_MCP" == true ]]; then
75
+ return 1
76
+ fi
77
+ [[ "$p" == *"/mcp-builder/"* || "$p" == *"/mcp-management/"* ]]
78
+ }
79
+
80
+ if [[ "$RUN_PYTHON" == true ]]; then
81
+ if ! command -v python3 >/dev/null 2>&1; then
82
+ echo "python3 not found" >&2
83
+ exit 1
84
+ fi
85
+
86
+ if [[ "$DRY_RUN" == true ]]; then
87
+ echo "[dry-run] python3 -m venv \"$VENV_DIR\""
88
+ else
89
+ python3 -m venv "$VENV_DIR"
90
+ "$VENV_DIR/bin/python3" -m pip install --upgrade pip >/dev/null
91
+ fi
92
+
93
+ while IFS= read -r req; do
94
+ if skip_mcp_path "$req"; then
95
+ continue
96
+ fi
97
+ if [[ "$DRY_RUN" == true ]]; then
98
+ echo "[dry-run] $VENV_DIR/bin/python3 -m pip install -r \"$req\""
99
+ py_ok=$((py_ok + 1))
100
+ continue
101
+ fi
102
+ if "$VENV_DIR/bin/python3" -m pip install -r "$req" >/dev/null; then
103
+ py_ok=$((py_ok + 1))
104
+ else
105
+ echo "python deps failed: $req" >&2
106
+ py_fail=$((py_fail + 1))
107
+ fi
108
+ done < <(
109
+ find "$SKILLS_DIR" \
110
+ \( -path '*/.system/*' -o -path '*/node_modules/*' -o -path '*/.venv/*' -o -path '*/dist/*' -o -path '*/build/*' \) -prune -o \
111
+ -type f -name 'requirements*.txt' -print \
112
+ | if [[ "$INCLUDE_TEST_DEPS" == true ]]; then cat; else grep -Ev '/tests?/'; fi \
113
+ | sort -u
114
+ )
115
+ fi
116
+
117
+ if [[ "$RUN_NODE" == true ]]; then
118
+ if ! command -v npm >/dev/null 2>&1; then
119
+ echo "npm not found" >&2
120
+ exit 1
121
+ fi
122
+
123
+ while IFS= read -r pkg; do
124
+ if skip_mcp_path "$pkg"; then
125
+ continue
126
+ fi
127
+ dir="$(dirname "$pkg")"
128
+ if [[ "$DRY_RUN" == true ]]; then
129
+ echo "[dry-run] npm install --prefix \"$dir\""
130
+ node_ok=$((node_ok + 1))
131
+ continue
132
+ fi
133
+ if npm install --prefix "$dir" >/dev/null; then
134
+ node_ok=$((node_ok + 1))
135
+ else
136
+ echo "node deps failed: $dir" >&2
137
+ node_fail=$((node_fail + 1))
138
+ fi
139
+ done < <(
140
+ find "$SKILLS_DIR" \
141
+ \( -path '*/.system/*' -o -path '*/node_modules/*' -o -path '*/.venv/*' -o -path '*/dist/*' -o -path '*/build/*' \) -prune -o \
142
+ -type f -name package.json -print \
143
+ | sort -u
144
+ )
145
+ fi
146
+
147
+ echo "python_ok=$py_ok python_fail=$py_fail node_ok=$node_ok node_fail=$node_fail"
148
+ if [[ $py_fail -gt 0 || $node_fail -gt 0 ]]; then
149
+ exit 2
150
+ fi