prizmkit 1.1.57 → 1.1.60
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/bin/create-prizmkit.js +8 -6
- package/bundled/VERSION.json +3 -3
- package/bundled/adapters/codex/agent-adapter.js +38 -0
- package/bundled/adapters/codex/paths.js +27 -0
- package/bundled/adapters/codex/rules-adapter.js +30 -0
- package/bundled/adapters/codex/settings-adapter.js +27 -0
- package/bundled/adapters/codex/skill-adapter.js +65 -0
- package/bundled/adapters/codex/team-adapter.js +37 -0
- package/bundled/dev-pipeline/.env.example +2 -1
- package/bundled/dev-pipeline/README.md +10 -7
- package/bundled/dev-pipeline/lib/common.sh +278 -37
- package/bundled/dev-pipeline/run-bugfix.sh +10 -61
- package/bundled/dev-pipeline/run-feature.sh +10 -78
- package/bundled/dev-pipeline/run-recovery.sh +10 -46
- package/bundled/dev-pipeline/run-refactor.sh +10 -61
- package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +17 -7
- package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +9 -3
- package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +9 -3
- package/bundled/dev-pipeline/scripts/utils.py +6 -4
- package/bundled/dev-pipeline-windows/.env.example +28 -0
- package/bundled/dev-pipeline-windows/README.md +30 -0
- package/bundled/dev-pipeline-windows/SCHEMA_ANALYSIS.md +525 -0
- package/bundled/dev-pipeline-windows/assets/feature-list-example.json +146 -0
- package/bundled/dev-pipeline-windows/assets/prizm-dev-team-integration.md +138 -0
- package/bundled/dev-pipeline-windows/launch-bugfix-daemon.ps1 +9 -0
- package/bundled/dev-pipeline-windows/launch-feature-daemon.ps1 +9 -0
- package/bundled/dev-pipeline-windows/launch-refactor-daemon.ps1 +9 -0
- package/bundled/dev-pipeline-windows/lib/common.ps1 +432 -0
- package/bundled/dev-pipeline-windows/lib/daemon.ps1 +140 -0
- package/bundled/dev-pipeline-windows/lib/pipeline.ps1 +446 -0
- package/bundled/dev-pipeline-windows/lib/reset.ps1 +87 -0
- package/bundled/dev-pipeline-windows/reset-bug.ps1 +9 -0
- package/bundled/dev-pipeline-windows/reset-feature.ps1 +9 -0
- package/bundled/dev-pipeline-windows/reset-refactor.ps1 +9 -0
- package/bundled/dev-pipeline-windows/run-bugfix.ps1 +9 -0
- package/bundled/dev-pipeline-windows/run-feature.ps1 +9 -0
- package/bundled/dev-pipeline-windows/run-recovery.ps1 +76 -0
- package/bundled/dev-pipeline-windows/run-refactor.ps1 +9 -0
- package/bundled/dev-pipeline-windows/scripts/check-session-status.py +228 -0
- package/bundled/dev-pipeline-windows/scripts/cleanup-logs.py +192 -0
- package/bundled/dev-pipeline-windows/scripts/detect-stuck.py +530 -0
- package/bundled/dev-pipeline-windows/scripts/generate-bootstrap-prompt.py +1737 -0
- package/bundled/dev-pipeline-windows/scripts/generate-bugfix-prompt.py +685 -0
- package/bundled/dev-pipeline-windows/scripts/generate-recovery-prompt.py +805 -0
- package/bundled/dev-pipeline-windows/scripts/generate-refactor-prompt.py +763 -0
- package/bundled/dev-pipeline-windows/scripts/init-bugfix-pipeline.py +316 -0
- package/bundled/dev-pipeline-windows/scripts/init-dev-team.py +134 -0
- package/bundled/dev-pipeline-windows/scripts/init-pipeline.py +380 -0
- package/bundled/dev-pipeline-windows/scripts/init-refactor-pipeline.py +399 -0
- package/bundled/dev-pipeline-windows/scripts/parse-stream-progress.py +388 -0
- package/bundled/dev-pipeline-windows/scripts/patch-completion-notes.py +191 -0
- package/bundled/dev-pipeline-windows/scripts/update-bug-status.py +864 -0
- package/bundled/dev-pipeline-windows/scripts/update-checkpoint.py +173 -0
- package/bundled/dev-pipeline-windows/scripts/update-feature-status.py +1501 -0
- package/bundled/dev-pipeline-windows/scripts/update-refactor-status.py +1073 -0
- package/bundled/dev-pipeline-windows/scripts/utils.py +542 -0
- package/bundled/dev-pipeline-windows/templates/agent-prompts/critic-plan-challenge.md +7 -0
- package/bundled/dev-pipeline-windows/templates/agent-prompts/dev-fix.md +7 -0
- package/bundled/dev-pipeline-windows/templates/agent-prompts/dev-implement.md +30 -0
- package/bundled/dev-pipeline-windows/templates/agent-prompts/dev-resume.md +5 -0
- package/bundled/dev-pipeline-windows/templates/agent-prompts/reviewer-review.md +7 -0
- package/bundled/dev-pipeline-windows/templates/bootstrap-prompt.md +46 -0
- package/bundled/dev-pipeline-windows/templates/bootstrap-tier1.md +43 -0
- package/bundled/dev-pipeline-windows/templates/bootstrap-tier2.md +43 -0
- package/bundled/dev-pipeline-windows/templates/bootstrap-tier3.md +43 -0
- package/bundled/dev-pipeline-windows/templates/bug-fix-list-schema.json +263 -0
- package/bundled/dev-pipeline-windows/templates/bugfix-bootstrap-prompt.md +320 -0
- package/bundled/dev-pipeline-windows/templates/feature-list-schema.json +237 -0
- package/bundled/dev-pipeline-windows/templates/refactor-bootstrap-prompt.md +331 -0
- package/bundled/dev-pipeline-windows/templates/refactor-list-schema.json +270 -0
- package/bundled/dev-pipeline-windows/templates/sections/ac-verification-checklist.md +13 -0
- package/bundled/dev-pipeline-windows/templates/sections/checkpoint-system.md +91 -0
- package/bundled/dev-pipeline-windows/templates/sections/context-budget-rules.md +33 -0
- package/bundled/dev-pipeline-windows/templates/sections/critical-paths-agent.md +10 -0
- package/bundled/dev-pipeline-windows/templates/sections/critical-paths-full.md +12 -0
- package/bundled/dev-pipeline-windows/templates/sections/critical-paths-lite.md +7 -0
- package/bundled/dev-pipeline-windows/templates/sections/directory-convention-agent.md +8 -0
- package/bundled/dev-pipeline-windows/templates/sections/directory-convention-full.md +9 -0
- package/bundled/dev-pipeline-windows/templates/sections/directory-convention-lite.md +6 -0
- package/bundled/dev-pipeline-windows/templates/sections/failure-capture.md +21 -0
- package/bundled/dev-pipeline-windows/templates/sections/feature-context.md +31 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-browser-verification-auto.md +72 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-browser-verification-opencli.md +63 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-browser-verification.md +62 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-commit-full.md +71 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-commit.md +64 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-context-snapshot-agent-suffix.md +23 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-context-snapshot-base.md +24 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-context-snapshot-lite-suffix.md +12 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-critic-plan-full.md +53 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-critic-plan.md +32 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-implement-agent.md +37 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-implement-full.md +50 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-implement-lite.md +52 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-plan-agent.md +27 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-plan-lite.md +27 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-review-agent.md +27 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-review-full.md +29 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-specify-plan-full.md +77 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase0-init.md +13 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase0-test-baseline.md +23 -0
- package/bundled/dev-pipeline-windows/templates/sections/session-context.md +5 -0
- package/bundled/dev-pipeline-windows/templates/sections/subagent-timeout-recovery.md +6 -0
- package/bundled/dev-pipeline-windows/templates/sections/test-failure-recovery-agent.md +67 -0
- package/bundled/dev-pipeline-windows/templates/sections/test-failure-recovery-lite.md +58 -0
- package/bundled/dev-pipeline-windows/templates/session-status-schema.json +83 -0
- package/bundled/skills/_metadata.json +1 -1
- package/bundled/skills/app-planner/SKILL.md +26 -18
- package/bundled/skills/app-planner/references/architecture-decisions.md +9 -5
- package/bundled/skills/app-planner/references/frontend-design-guide.md +1 -1
- package/bundled/skills/feature-planner/SKILL.md +9 -2
- package/bundled/skills/prizmkit-init/SKILL.md +7 -6
- package/bundled/skills/recovery-workflow/scripts/detect-recovery-state.py +2 -0
- package/bundled/skills-windows/app-planner/SKILL.md +639 -0
- package/bundled/skills-windows/app-planner/assets/app-design-guide.md +101 -0
- package/bundled/skills-windows/app-planner/references/architecture-decisions.md +52 -0
- package/bundled/skills-windows/app-planner/references/brainstorm-guide.md +101 -0
- package/bundled/skills-windows/app-planner/references/frontend-design-guide.md +71 -0
- package/bundled/skills-windows/app-planner/references/project-brief-guide.md +82 -0
- package/bundled/skills-windows/app-planner/references/red-team-checklist.md +40 -0
- package/bundled/skills-windows/app-planner/references/rules/backend/derivation-rules.md +609 -0
- package/bundled/skills-windows/app-planner/references/rules/backend/fixed-rules.md +285 -0
- package/bundled/skills-windows/app-planner/references/rules/backend/question-bank.md +249 -0
- package/bundled/skills-windows/app-planner/references/rules/backend/template.md +173 -0
- package/bundled/skills-windows/app-planner/references/rules/database/derivation-rules.md +373 -0
- package/bundled/skills-windows/app-planner/references/rules/database/fixed-rules.md +211 -0
- package/bundled/skills-windows/app-planner/references/rules/database/question-bank.md +184 -0
- package/bundled/skills-windows/app-planner/references/rules/database/template.md +158 -0
- package/bundled/skills-windows/app-planner/references/rules/frontend/derivation-rules.md +810 -0
- package/bundled/skills-windows/app-planner/references/rules/frontend/fixed-rules.md +188 -0
- package/bundled/skills-windows/app-planner/references/rules/frontend/question-bank.md +302 -0
- package/bundled/skills-windows/app-planner/references/rules/frontend/template.md +320 -0
- package/bundled/skills-windows/app-planner/references/rules/mobile/derivation-rules.md +639 -0
- package/bundled/skills-windows/app-planner/references/rules/mobile/fixed-rules.md +290 -0
- package/bundled/skills-windows/app-planner/references/rules/mobile/question-bank.md +232 -0
- package/bundled/skills-windows/app-planner/references/rules/mobile/template.md +175 -0
- package/bundled/skills-windows/bug-fix-workflow/SKILL.md +415 -0
- package/bundled/skills-windows/bug-planner/SKILL.md +395 -0
- package/bundled/skills-windows/bug-planner/assets/bug-confirmation-template.md +43 -0
- package/bundled/skills-windows/bug-planner/references/critic-and-verification.md +44 -0
- package/bundled/skills-windows/bug-planner/references/error-recovery.md +73 -0
- package/bundled/skills-windows/bug-planner/references/input-formats.md +53 -0
- package/bundled/skills-windows/bug-planner/references/schema-validation.md +25 -0
- package/bundled/skills-windows/bug-planner/references/severity-rules.md +16 -0
- package/bundled/skills-windows/bug-planner/scripts/validate-bug-list.py +322 -0
- package/bundled/skills-windows/bugfix-pipeline-launcher/SKILL.md +380 -0
- package/bundled/skills-windows/feature-pipeline-launcher/SKILL.md +441 -0
- package/bundled/skills-windows/feature-pipeline-launcher/scripts/preflight-check.py +462 -0
- package/bundled/skills-windows/feature-planner/SKILL.md +401 -0
- package/bundled/skills-windows/feature-planner/assets/evaluation-guide.md +64 -0
- package/bundled/skills-windows/feature-planner/assets/planning-guide.md +214 -0
- package/bundled/skills-windows/feature-planner/references/browser-interaction.md +59 -0
- package/bundled/skills-windows/feature-planner/references/completeness-review.md +57 -0
- package/bundled/skills-windows/feature-planner/references/decomposition-patterns.md +75 -0
- package/bundled/skills-windows/feature-planner/references/error-recovery.md +90 -0
- package/bundled/skills-windows/feature-planner/references/incremental-feature-planning.md +112 -0
- package/bundled/skills-windows/feature-planner/references/new-project-planning.md +85 -0
- package/bundled/skills-windows/feature-planner/scripts/validate-and-generate.py +1029 -0
- package/bundled/skills-windows/feature-workflow/SKILL.md +531 -0
- package/bundled/skills-windows/prizmkit-init/SKILL.md +356 -0
- package/bundled/skills-windows/prizmkit-init/assets/project-brief-template.md +82 -0
- package/bundled/skills-windows/prizmkit-init/references/config-schema.md +68 -0
- package/bundled/skills-windows/prizmkit-init/references/rules/layer-detection.md +41 -0
- package/bundled/skills-windows/prizmkit-init/references/tech-stack-catalog.md +13 -0
- package/bundled/skills-windows/prizmkit-init/references/update-supplement.md +9 -0
- package/bundled/skills-windows/recovery-workflow/SKILL.md +456 -0
- package/bundled/skills-windows/recovery-workflow/evals/evals.json +46 -0
- package/bundled/skills-windows/recovery-workflow/scripts/detect-recovery-state.py +544 -0
- package/bundled/skills-windows/refactor-pipeline-launcher/SKILL.md +406 -0
- package/bundled/skills-windows/refactor-planner/SKILL.md +540 -0
- package/bundled/skills-windows/refactor-planner/assets/planning-guide.md +292 -0
- package/bundled/skills-windows/refactor-planner/references/behavior-preservation.md +301 -0
- package/bundled/skills-windows/refactor-planner/references/refactor-scoping-guide.md +221 -0
- package/bundled/skills-windows/refactor-planner/scripts/validate-and-generate-refactor.py +858 -0
- package/bundled/skills-windows/refactor-workflow/SKILL.md +503 -0
- package/package.json +3 -2
- package/src/clean.js +73 -2
- package/src/config.js +159 -50
- package/src/detect-platform.js +16 -8
- package/src/external-skills.js +26 -19
- package/src/index.js +31 -9
- package/src/manifest.js +6 -2
- package/src/metadata.js +43 -5
- package/src/platforms.js +36 -0
- package/src/prompts.js +31 -6
- package/src/runtimes.js +20 -0
- package/src/scaffold.js +314 -110
- package/src/upgrade.js +81 -41
package/src/config.js
CHANGED
|
@@ -31,8 +31,11 @@ import {
|
|
|
31
31
|
installProjectMemory,
|
|
32
32
|
installPipeline,
|
|
33
33
|
installGitignore,
|
|
34
|
+
installGitHook,
|
|
35
|
+
installPrizmkitScripts,
|
|
34
36
|
resolveSkillList,
|
|
35
37
|
resolvePipelineFileList,
|
|
38
|
+
resolveRuleNamesForRuntime,
|
|
36
39
|
} from './scaffold.js';
|
|
37
40
|
import {
|
|
38
41
|
removeSkillFiles,
|
|
@@ -44,11 +47,14 @@ import { detectPlatform } from './detect-platform.js';
|
|
|
44
47
|
import {
|
|
45
48
|
selectPlatform,
|
|
46
49
|
selectAiCli,
|
|
50
|
+
selectRuntime,
|
|
47
51
|
selectSkillSuite,
|
|
48
52
|
selectRulesPreset,
|
|
49
53
|
confirmTeamMode,
|
|
50
54
|
confirmPipeline,
|
|
51
55
|
} from './prompts.js';
|
|
56
|
+
import { expandPlatforms, platformLabel, projectMemoryFile } from './platforms.js';
|
|
57
|
+
import { normalizeRuntime, runtimeLabel } from './runtimes.js';
|
|
52
58
|
|
|
53
59
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
54
60
|
const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));
|
|
@@ -57,36 +63,53 @@ const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-
|
|
|
57
63
|
// Helpers
|
|
58
64
|
// ============================================================
|
|
59
65
|
|
|
66
|
+
async function removeGeneratedCodexConfig(projectRoot, dryRun) {
|
|
67
|
+
const configPath = path.join(projectRoot, '.codex', 'config.toml');
|
|
68
|
+
if (!await fs.pathExists(configPath)) return;
|
|
69
|
+
|
|
70
|
+
const content = await fs.readFile(configPath, 'utf8');
|
|
71
|
+
if (!content.includes('Generated by PrizmKit for Codex CLI project configuration')) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (dryRun) {
|
|
76
|
+
console.log(chalk.gray(' [dry-run] remove .codex/config.toml'));
|
|
77
|
+
} else {
|
|
78
|
+
await fs.remove(configPath);
|
|
79
|
+
console.log(chalk.red(' ✗ removed .codex/config.toml'));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
60
83
|
/**
|
|
61
84
|
* Detect which platforms are actually installed on filesystem.
|
|
62
85
|
*/
|
|
63
86
|
async function detectInstalledPlatforms(projectRoot) {
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
87
|
+
const hasPlatformFiles = async (dir) => {
|
|
88
|
+
if (!await fs.pathExists(dir)) return false;
|
|
89
|
+
try {
|
|
90
|
+
return (await fs.readdir(dir)).length > 0;
|
|
91
|
+
} catch {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
68
95
|
|
|
96
|
+
const hasClaude = await hasPlatformFiles(path.join(projectRoot, '.claude', 'commands'))
|
|
97
|
+
|| await hasPlatformFiles(path.join(projectRoot, '.claude', 'agents'));
|
|
98
|
+
const hasCodeBuddy = await hasPlatformFiles(path.join(projectRoot, '.codebuddy', 'skills'))
|
|
99
|
+
|| await hasPlatformFiles(path.join(projectRoot, '.codebuddy', 'agents'));
|
|
100
|
+
const hasCodex = await hasPlatformFiles(path.join(projectRoot, '.agents', 'skills'))
|
|
101
|
+
|| await hasPlatformFiles(path.join(projectRoot, '.codex', 'agents'));
|
|
102
|
+
|
|
103
|
+
if (hasClaude && hasCodeBuddy && hasCodex) return 'all';
|
|
69
104
|
if (hasClaude && hasCodeBuddy) return 'both';
|
|
105
|
+
if (hasCodex) return 'codex';
|
|
70
106
|
if (hasCodeBuddy) return 'codebuddy';
|
|
71
107
|
if (hasClaude) return 'claude';
|
|
72
108
|
return null;
|
|
73
109
|
}
|
|
74
110
|
|
|
75
|
-
/**
|
|
76
|
-
* Expand a platform string to an array of individual platforms.
|
|
77
|
-
*/
|
|
78
|
-
function expandPlatforms(platform) {
|
|
79
|
-
return platform === 'both' ? ['codebuddy', 'claude'] : [platform];
|
|
80
|
-
}
|
|
81
|
-
|
|
82
111
|
function getProjectMemoryFile(platform) {
|
|
83
|
-
|
|
84
|
-
if (platform === 'codebuddy') return 'CODEBUDDY.md';
|
|
85
|
-
return null;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function getCounterpartPlatform(platform) {
|
|
89
|
-
return platform === 'claude' ? 'codebuddy' : platform === 'codebuddy' ? 'claude' : null;
|
|
112
|
+
return projectMemoryFile(platform);
|
|
90
113
|
}
|
|
91
114
|
|
|
92
115
|
async function migrateProjectMemoryOnPlatformDrop(droppedPlatform, newPlatforms, projectRoot, dryRun) {
|
|
@@ -96,10 +119,7 @@ async function migrateProjectMemoryOnPlatformDrop(droppedPlatform, newPlatforms,
|
|
|
96
119
|
const sourcePath = path.join(projectRoot, sourceFile);
|
|
97
120
|
if (!await fs.pathExists(sourcePath)) return;
|
|
98
121
|
|
|
99
|
-
const
|
|
100
|
-
const targetPlatform = (counterpart && newPlatforms.includes(counterpart))
|
|
101
|
-
? counterpart
|
|
102
|
-
: newPlatforms.find(p => p !== droppedPlatform);
|
|
122
|
+
const targetPlatform = newPlatforms.find(p => p !== droppedPlatform) || newPlatforms[0];
|
|
103
123
|
|
|
104
124
|
if (!targetPlatform || targetPlatform === droppedPlatform) return;
|
|
105
125
|
|
|
@@ -138,9 +158,6 @@ async function migrateProjectMemoryOnPlatformDrop(droppedPlatform, newPlatforms,
|
|
|
138
158
|
console.log(chalk.green(` ✓ merged ${sourceFile} content into ${targetFile}`));
|
|
139
159
|
}
|
|
140
160
|
|
|
141
|
-
const platformLabel = (p) => p === 'both' ? 'CodeBuddy + Claude Code'
|
|
142
|
-
: p === 'codebuddy' ? 'CodeBuddy' : 'Claude Code';
|
|
143
|
-
|
|
144
161
|
/**
|
|
145
162
|
* Remove all PrizmKit-owned platform-specific files for a single platform.
|
|
146
163
|
* Selective removal — only removes known PrizmKit files, leaves user-created files intact.
|
|
@@ -166,15 +183,28 @@ async function removePlatformFiles(platform, projectRoot, manifest, dryRun) {
|
|
|
166
183
|
}
|
|
167
184
|
|
|
168
185
|
// Settings
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
186
|
+
if (platform === 'codex') {
|
|
187
|
+
await removeGeneratedCodexConfig(projectRoot, dryRun);
|
|
188
|
+
const legacySettingsFile = path.join(projectRoot, '.codex', 'prizmkit-settings.json');
|
|
189
|
+
if (await fs.pathExists(legacySettingsFile)) {
|
|
190
|
+
if (dryRun) {
|
|
191
|
+
console.log(chalk.gray(' [dry-run] remove .codex/prizmkit-settings.json (legacy)'));
|
|
192
|
+
} else {
|
|
193
|
+
await fs.remove(legacySettingsFile);
|
|
194
|
+
console.log(chalk.red(' ✗ removed .codex/prizmkit-settings.json (legacy)'));
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
} else {
|
|
198
|
+
const settingsFile = platform === 'claude'
|
|
199
|
+
? path.join(projectRoot, '.claude', 'settings.json')
|
|
200
|
+
: path.join(projectRoot, '.codebuddy', 'settings.json');
|
|
201
|
+
if (await fs.pathExists(settingsFile)) {
|
|
202
|
+
if (dryRun) {
|
|
203
|
+
console.log(chalk.gray(` [dry-run] remove ${path.relative(projectRoot, settingsFile)}`));
|
|
204
|
+
} else {
|
|
205
|
+
await fs.remove(settingsFile);
|
|
206
|
+
console.log(chalk.red(` ✗ removed ${path.relative(projectRoot, settingsFile)}`));
|
|
207
|
+
}
|
|
178
208
|
}
|
|
179
209
|
}
|
|
180
210
|
|
|
@@ -200,10 +230,21 @@ async function removePlatformFiles(platform, projectRoot, manifest, dryRun) {
|
|
|
200
230
|
console.log(chalk.red(' ✗ removed ~/.codebuddy/teams/prizm-dev-team/'));
|
|
201
231
|
}
|
|
202
232
|
}
|
|
233
|
+
} else if (platform === 'codex') {
|
|
234
|
+
const teamInfo = path.join(projectRoot, '.codex', 'team-info.json');
|
|
235
|
+
if (await fs.pathExists(teamInfo)) {
|
|
236
|
+
if (dryRun) {
|
|
237
|
+
console.log(chalk.gray(' [dry-run] remove .codex/team-info.json'));
|
|
238
|
+
} else {
|
|
239
|
+
await fs.remove(teamInfo);
|
|
240
|
+
console.log(chalk.red(' ✗ removed .codex/team-info.json'));
|
|
241
|
+
}
|
|
242
|
+
}
|
|
203
243
|
}
|
|
204
244
|
|
|
205
245
|
// Project memory file
|
|
206
|
-
const memoryFile = platform
|
|
246
|
+
const memoryFile = projectMemoryFile(platform);
|
|
247
|
+
if (!memoryFile) return;
|
|
207
248
|
const memoryPath = path.join(projectRoot, memoryFile);
|
|
208
249
|
if (await fs.pathExists(memoryPath)) {
|
|
209
250
|
if (dryRun) {
|
|
@@ -225,6 +266,48 @@ async function removePlatformFiles(platform, projectRoot, manifest, dryRun) {
|
|
|
225
266
|
console.log(chalk.red(' ✗ removed .claude/command-assets/'));
|
|
226
267
|
}
|
|
227
268
|
}
|
|
269
|
+
} else if (platform === 'codex') {
|
|
270
|
+
const agentsSkillsDir = path.join(projectRoot, '.agents', 'skills');
|
|
271
|
+
if (await fs.pathExists(agentsSkillsDir)) {
|
|
272
|
+
if (dryRun) {
|
|
273
|
+
console.log(chalk.gray(' [dry-run] remove .agents/skills/ if empty'));
|
|
274
|
+
} else if ((await fs.readdir(agentsSkillsDir)).length === 0) {
|
|
275
|
+
await fs.remove(agentsSkillsDir);
|
|
276
|
+
console.log(chalk.red(' ✗ removed .agents/skills/'));
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
const agentsDir = path.join(projectRoot, '.agents');
|
|
280
|
+
if (await fs.pathExists(agentsDir)) {
|
|
281
|
+
if (dryRun) {
|
|
282
|
+
console.log(chalk.gray(' [dry-run] remove .agents/ if empty'));
|
|
283
|
+
} else if ((await fs.readdir(agentsDir)).length === 0) {
|
|
284
|
+
await fs.remove(agentsDir);
|
|
285
|
+
console.log(chalk.red(' ✗ removed .agents/'));
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const codexAgentsDir = path.join(projectRoot, '.codex', 'agents');
|
|
290
|
+
if (await fs.pathExists(codexAgentsDir)) {
|
|
291
|
+
if (dryRun) {
|
|
292
|
+
console.log(chalk.gray(' [dry-run] remove .codex/agents/ if empty'));
|
|
293
|
+
} else if ((await fs.readdir(codexAgentsDir)).length === 0) {
|
|
294
|
+
await fs.remove(codexAgentsDir);
|
|
295
|
+
console.log(chalk.red(' ✗ removed .codex/agents/'));
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const codexDir = path.join(projectRoot, '.codex');
|
|
300
|
+
if (await fs.pathExists(codexDir)) {
|
|
301
|
+
if (dryRun) {
|
|
302
|
+
console.log(chalk.gray(' [dry-run] remove .codex/ if empty'));
|
|
303
|
+
} else {
|
|
304
|
+
const remaining = await fs.readdir(codexDir);
|
|
305
|
+
if (remaining.length === 0) {
|
|
306
|
+
await fs.remove(codexDir);
|
|
307
|
+
console.log(chalk.red(' ✗ removed .codex/'));
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
228
311
|
}
|
|
229
312
|
}
|
|
230
313
|
|
|
@@ -265,11 +348,13 @@ export async function runConfig(directory, options = {}) {
|
|
|
265
348
|
try { userConfig = await fs.readJSON(configPath); } catch { /* ignore */ }
|
|
266
349
|
}
|
|
267
350
|
|
|
268
|
-
// Filesystem
|
|
269
|
-
|
|
351
|
+
// Existing manifests are the source of truth. Filesystem detection is only a
|
|
352
|
+
// legacy fallback for manifests created before platform was recorded.
|
|
353
|
+
const detectedPlatform = oldManifest.platform || await detectInstalledPlatforms(projectRoot) || 'claude';
|
|
270
354
|
|
|
271
355
|
const currentConfig = {
|
|
272
356
|
platform: detectedPlatform,
|
|
357
|
+
runtime: normalizeRuntime(oldManifest.runtime || 'unix'),
|
|
273
358
|
suite: oldManifest.suite || 'core',
|
|
274
359
|
rules: oldManifest.options?.rules || 'recommended',
|
|
275
360
|
team: oldManifest.options?.team ?? true,
|
|
@@ -280,6 +365,7 @@ export async function runConfig(directory, options = {}) {
|
|
|
280
365
|
// Display current config
|
|
281
366
|
console.log(chalk.bold(' 当前配置:'));
|
|
282
367
|
console.log(` 平台: ${chalk.cyan(platformLabel(currentConfig.platform))}`);
|
|
368
|
+
console.log(` 运行系统: ${chalk.cyan(runtimeLabel(currentConfig.runtime))}`);
|
|
283
369
|
console.log(` AI CLI: ${currentConfig.aiCli ? chalk.cyan(currentConfig.aiCli) : chalk.gray('(未设置)')}`);
|
|
284
370
|
console.log(` 技能套件: ${chalk.cyan(currentConfig.suite)}`);
|
|
285
371
|
console.log(` 规则: ${chalk.cyan(currentConfig.rules)}`);
|
|
@@ -290,18 +376,20 @@ export async function runConfig(directory, options = {}) {
|
|
|
290
376
|
// ── Phase 2: PROMPT for new config ───────────────────────────────────────
|
|
291
377
|
|
|
292
378
|
let newConfig;
|
|
379
|
+
const optionRuntime = options.runtime !== undefined ? normalizeRuntime(options.runtime) : undefined;
|
|
293
380
|
|
|
294
381
|
if (nonInteractive) {
|
|
295
382
|
// Non-interactive: only change what's explicitly specified via CLI options
|
|
296
|
-
if (!options.platform && !options.skills && !options.rules
|
|
383
|
+
if (!options.platform && !options.skills && !options.rules && options.runtime === undefined
|
|
297
384
|
&& options.aiCli === undefined && options.team === undefined && options.pipeline === undefined) {
|
|
298
385
|
console.log(chalk.yellow(' ⚠ 非交互式模式下未指定任何变更。'));
|
|
299
|
-
console.log(chalk.gray(' 使用 --platform, --skills, --rules, --ai-cli, --team/--no-team, --pipeline/--no-pipeline'));
|
|
386
|
+
console.log(chalk.gray(' 使用 --platform, --runtime, --skills, --rules, --ai-cli, --team/--no-team, --pipeline/--no-pipeline'));
|
|
300
387
|
return;
|
|
301
388
|
}
|
|
302
389
|
|
|
303
390
|
newConfig = {
|
|
304
391
|
platform: options.platform || currentConfig.platform,
|
|
392
|
+
runtime: optionRuntime || currentConfig.runtime,
|
|
305
393
|
suite: options.skills || currentConfig.suite,
|
|
306
394
|
rules: options.rules || currentConfig.rules,
|
|
307
395
|
team: options.team !== undefined ? options.team : currentConfig.team,
|
|
@@ -315,6 +403,7 @@ export async function runConfig(directory, options = {}) {
|
|
|
315
403
|
try {
|
|
316
404
|
console.log(chalk.bold(' 选择新配置(按 Enter 保持当前值):\n'));
|
|
317
405
|
|
|
406
|
+
const newRuntime = optionRuntime || await selectRuntime(currentConfig.runtime);
|
|
318
407
|
const newPlatform = await selectPlatform(currentConfig.platform, detected);
|
|
319
408
|
const newAiCli = await selectAiCli(currentConfig.aiCli, detected);
|
|
320
409
|
|
|
@@ -326,6 +415,7 @@ export async function runConfig(directory, options = {}) {
|
|
|
326
415
|
|
|
327
416
|
newConfig = {
|
|
328
417
|
platform: newPlatform,
|
|
418
|
+
runtime: newRuntime,
|
|
329
419
|
suite: newSuite,
|
|
330
420
|
rules: newRules,
|
|
331
421
|
team: newTeam,
|
|
@@ -347,6 +437,9 @@ export async function runConfig(directory, options = {}) {
|
|
|
347
437
|
if (newConfig.platform !== currentConfig.platform) {
|
|
348
438
|
changes.push(`平台: ${platformLabel(currentConfig.platform)} → ${platformLabel(newConfig.platform)}`);
|
|
349
439
|
}
|
|
440
|
+
if (newConfig.runtime !== currentConfig.runtime) {
|
|
441
|
+
changes.push(`运行系统: ${runtimeLabel(currentConfig.runtime)} → ${runtimeLabel(newConfig.runtime)}`);
|
|
442
|
+
}
|
|
350
443
|
if (newConfig.aiCli !== currentConfig.aiCli) {
|
|
351
444
|
changes.push(`AI CLI: ${currentConfig.aiCli || '(未设置)'} → ${newConfig.aiCli || '(未设置)'}`);
|
|
352
445
|
}
|
|
@@ -419,9 +512,8 @@ export async function runConfig(directory, options = {}) {
|
|
|
419
512
|
const agentsDir = getAgentsDir();
|
|
420
513
|
const newAgentFiles = (await fs.readdir(agentsDir)).filter(f => f.endsWith('.md'));
|
|
421
514
|
const rulesMeta = await loadRulesMetadata();
|
|
422
|
-
const
|
|
423
|
-
const
|
|
424
|
-
const newPipelineFiles = newConfig.pipeline ? resolvePipelineFileList() : [];
|
|
515
|
+
const newRuleFiles = resolveRuleNamesForRuntime(rulesMeta, newConfig.rules, newConfig.runtime).map(name => `${name}.md`);
|
|
516
|
+
const newPipelineFiles = newConfig.pipeline ? resolvePipelineFileList(newConfig.runtime) : [];
|
|
425
517
|
|
|
426
518
|
// 5a. Migrate project memory before removing dropped platforms
|
|
427
519
|
for (const p of platformsToRemove) {
|
|
@@ -434,13 +526,15 @@ export async function runConfig(directory, options = {}) {
|
|
|
434
526
|
await removePlatformFiles(p, projectRoot, oldManifest, false);
|
|
435
527
|
}
|
|
436
528
|
|
|
437
|
-
// 5c. Handle skill/rule diff for existing platforms (suite or
|
|
438
|
-
if (newConfig.suite !== currentConfig.suite
|
|
529
|
+
// 5c. Handle skill/rule diff for existing platforms (suite, rules, or runtime changed)
|
|
530
|
+
if (newConfig.suite !== currentConfig.suite
|
|
531
|
+
|| newConfig.rules !== currentConfig.rules
|
|
532
|
+
|| newConfig.runtime !== currentConfig.runtime) {
|
|
439
533
|
const newTempManifest = buildManifest({
|
|
440
534
|
version: pkg.version, platform: newConfig.platform, suite: newConfig.suite,
|
|
441
535
|
skills: newSkillList, agents: newAgentFiles, rules: newRuleFiles,
|
|
442
536
|
pipeline: newPipelineFiles, team: newConfig.team, aiCli: newConfig.aiCli,
|
|
443
|
-
rulesPreset: newConfig.rules, extras: oldManifest?.files?.extras || [],
|
|
537
|
+
runtime: newConfig.runtime, rulesPreset: newConfig.rules, extras: oldManifest?.files?.extras || [],
|
|
444
538
|
});
|
|
445
539
|
const diff = diffManifest(oldManifest, newTempManifest);
|
|
446
540
|
|
|
@@ -460,6 +554,7 @@ export async function runConfig(directory, options = {}) {
|
|
|
460
554
|
// 5d. Install/update files for new + existing platforms
|
|
461
555
|
const allTargetPlatforms = [...platformsToAdd, ...platformsToUpdate];
|
|
462
556
|
const needsReinstall = newConfig.platform !== currentConfig.platform
|
|
557
|
+
|| newConfig.runtime !== currentConfig.runtime
|
|
463
558
|
|| newConfig.suite !== currentConfig.suite
|
|
464
559
|
|| newConfig.rules !== currentConfig.rules
|
|
465
560
|
|| newConfig.team !== currentConfig.team;
|
|
@@ -471,13 +566,13 @@ export async function runConfig(directory, options = {}) {
|
|
|
471
566
|
console.log(chalk.bold(`\n ${isNew ? '安装' : '更新'} ${platformLabel(p)} 环境...\n`));
|
|
472
567
|
|
|
473
568
|
console.log(chalk.blue(' Skills:'));
|
|
474
|
-
await installSkills(p, newSkillList, projectRoot, false);
|
|
569
|
+
await installSkills(p, newSkillList, projectRoot, false, newConfig.runtime);
|
|
475
570
|
|
|
476
571
|
console.log(chalk.blue('\n Agents:'));
|
|
477
572
|
await installAgents(p, projectRoot, false);
|
|
478
573
|
|
|
479
574
|
console.log(chalk.blue('\n Settings & Rules:'));
|
|
480
|
-
await installSettings(p, projectRoot, { pipeline: newConfig.pipeline, rules: newConfig.rules }, false);
|
|
575
|
+
await installSettings(p, projectRoot, { pipeline: newConfig.pipeline, rules: newConfig.rules }, false, newConfig.runtime);
|
|
481
576
|
|
|
482
577
|
if (isNew) {
|
|
483
578
|
console.log(chalk.blue('\n Project Memory:'));
|
|
@@ -492,10 +587,13 @@ export async function runConfig(directory, options = {}) {
|
|
|
492
587
|
}
|
|
493
588
|
|
|
494
589
|
// 5e. Pipeline changes
|
|
495
|
-
if (newConfig.pipeline !== currentConfig.pipeline) {
|
|
590
|
+
if (newConfig.pipeline !== currentConfig.pipeline || (newConfig.pipeline && newConfig.runtime !== currentConfig.runtime)) {
|
|
496
591
|
if (newConfig.pipeline) {
|
|
497
592
|
console.log(chalk.blue('\n 安装 Pipeline:'));
|
|
498
|
-
await installPipeline(projectRoot, false
|
|
593
|
+
await installPipeline(projectRoot, false, {
|
|
594
|
+
runtime: newConfig.runtime,
|
|
595
|
+
previousRuntime: currentConfig.runtime,
|
|
596
|
+
});
|
|
499
597
|
} else {
|
|
500
598
|
console.log(chalk.blue('\n 移除 Pipeline 框架文件(保留 state/):'));
|
|
501
599
|
const oldPipelineFiles = oldManifest?.files?.pipeline || [];
|
|
@@ -509,7 +607,16 @@ export async function runConfig(directory, options = {}) {
|
|
|
509
607
|
console.log(chalk.blue('\n Gitignore:'));
|
|
510
608
|
await installGitignore(projectRoot, { pipeline: newConfig.pipeline }, false);
|
|
511
609
|
|
|
512
|
-
// 5g.
|
|
610
|
+
// 5g. Runtime-aware git hook and PrizmKit helper scripts
|
|
611
|
+
if (newConfig.runtime !== currentConfig.runtime) {
|
|
612
|
+
console.log(chalk.blue('\n Git Hook:'));
|
|
613
|
+
await installGitHook(projectRoot, false, newConfig.runtime);
|
|
614
|
+
|
|
615
|
+
console.log(chalk.blue('\n PrizmKit Scripts:'));
|
|
616
|
+
await installPrizmkitScripts(projectRoot, false, newConfig.runtime);
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
// 5h. Update .prizmkit/config.json (ai_cli)
|
|
513
620
|
if (newConfig.aiCli !== currentConfig.aiCli) {
|
|
514
621
|
const prizmkitDir = path.join(projectRoot, '.prizmkit');
|
|
515
622
|
await fs.ensureDir(prizmkitDir);
|
|
@@ -530,6 +637,7 @@ export async function runConfig(directory, options = {}) {
|
|
|
530
637
|
const newManifest = buildManifest({
|
|
531
638
|
version: pkg.version,
|
|
532
639
|
platform: newConfig.platform,
|
|
640
|
+
runtime: newConfig.runtime,
|
|
533
641
|
suite: newConfig.suite,
|
|
534
642
|
skills: newSkillList,
|
|
535
643
|
agents: newAgentFiles,
|
|
@@ -559,6 +667,7 @@ export async function runConfig(directory, options = {}) {
|
|
|
559
667
|
|
|
560
668
|
console.log(chalk.gray(' 新配置:'));
|
|
561
669
|
console.log(chalk.gray(` 平台: ${platformLabel(newConfig.platform)}`));
|
|
670
|
+
console.log(chalk.gray(` 运行系统: ${runtimeLabel(newConfig.runtime)}`));
|
|
562
671
|
console.log(chalk.gray(` AI CLI: ${newConfig.aiCli || '(未设置)'}`));
|
|
563
672
|
console.log(chalk.gray(` 技能套件: ${newConfig.suite}`));
|
|
564
673
|
console.log(chalk.gray(` 规则: ${newConfig.rules}`));
|
package/src/detect-platform.js
CHANGED
|
@@ -4,11 +4,12 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { execFileSync } from 'child_process';
|
|
7
|
+
import os from 'os';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* 允许检测的命令白名单(仅用于 which 检测)
|
|
10
11
|
*/
|
|
11
|
-
const ALLOWED_COMMANDS = ['cbc', 'claude'];
|
|
12
|
+
const ALLOWED_COMMANDS = ['cbc', 'claude', 'codex'];
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* 检查命令是否存在于 PATH 中
|
|
@@ -18,7 +19,8 @@ function commandExists(cmd) {
|
|
|
18
19
|
throw new Error(`Unknown command: ${cmd}`);
|
|
19
20
|
}
|
|
20
21
|
try {
|
|
21
|
-
|
|
22
|
+
const isWindows = os.platform() === 'win32';
|
|
23
|
+
execFileSync(isWindows ? 'where.exe' : 'which', [cmd], { stdio: 'ignore' });
|
|
22
24
|
return true;
|
|
23
25
|
} catch {
|
|
24
26
|
return false;
|
|
@@ -31,26 +33,32 @@ function commandExists(cmd) {
|
|
|
31
33
|
* 注意:platform 控制目录结构(.codebuddy/ 或 .claude/),
|
|
32
34
|
* suggestedCli 是实际运行的可执行命令,二者相互独立。
|
|
33
35
|
*
|
|
34
|
-
* @returns {{ cbc: boolean, claude: boolean,
|
|
36
|
+
* @returns {{ cbc: boolean, claude: boolean, codex: boolean, suggested: string, suggestedCli: string }}
|
|
35
37
|
*/
|
|
36
38
|
export function detectPlatform() {
|
|
37
39
|
const cbc = commandExists('cbc');
|
|
38
40
|
const claude = commandExists('claude');
|
|
41
|
+
const codex = commandExists('codex');
|
|
39
42
|
|
|
40
|
-
// platform
|
|
43
|
+
// platform 建议:基于目录结构
|
|
41
44
|
let suggested = 'codebuddy';
|
|
42
|
-
if (
|
|
45
|
+
if (cbc && claude && codex) {
|
|
46
|
+
suggested = 'all';
|
|
47
|
+
} else if ((cbc) && (claude)) {
|
|
43
48
|
suggested = 'both';
|
|
49
|
+
} else if (codex && !cbc && !claude) {
|
|
50
|
+
suggested = 'codex';
|
|
44
51
|
} else if ((claude) && !cbc) {
|
|
45
52
|
suggested = 'claude';
|
|
46
53
|
} else if (cbc && !claude) {
|
|
47
54
|
suggested = 'codebuddy';
|
|
48
55
|
}
|
|
49
56
|
|
|
50
|
-
// CLI 命令建议:优先 cbc,其次 claude
|
|
57
|
+
// CLI 命令建议:优先 cbc,其次 claude,再次 codex
|
|
51
58
|
let suggestedCli = '';
|
|
52
59
|
if (cbc) suggestedCli = 'cbc';
|
|
53
60
|
else if (claude) suggestedCli = 'claude';
|
|
61
|
+
else if (codex) suggestedCli = 'codex';
|
|
54
62
|
|
|
55
|
-
return { cbc, claude, suggested, suggestedCli };
|
|
56
|
-
}
|
|
63
|
+
return { cbc, claude, codex, suggested, suggestedCli };
|
|
64
|
+
}
|
package/src/external-skills.js
CHANGED
|
@@ -7,20 +7,21 @@
|
|
|
7
7
|
* - Install all: installs all skills from a repo (e.g. pbakaus/impeccable)
|
|
8
8
|
*
|
|
9
9
|
* When run non-interactively (stdio: 'pipe'), npx skills writes canonical
|
|
10
|
-
* .agents/skills/<name>/SKILL.md files.
|
|
11
|
-
*
|
|
10
|
+
* .agents/skills/<name>/SKILL.md files. Codex uses that location directly;
|
|
11
|
+
* other platforms get copied into their platform-specific skill directories.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import { execSync } from 'node:child_process';
|
|
15
15
|
import path from 'path';
|
|
16
16
|
import fs from 'fs-extra';
|
|
17
|
+
import { expandPlatforms } from './platforms.js';
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* @param {Object} skill - Skill definition from external_skills.known
|
|
20
21
|
* skill.repo {string} - GitHub short ref (e.g. "pbakaus/impeccable") or full URL
|
|
21
22
|
* skill.name {string} - Skill name (used for display / single-skill mode)
|
|
22
23
|
* skill.installAll {boolean} - If true, install all skills from the repo
|
|
23
|
-
* @param {string} platform - 'claude' | 'codebuddy' | 'both'
|
|
24
|
+
* @param {string} platform - 'claude' | 'codebuddy' | 'codex' | 'both' | 'all'
|
|
24
25
|
* @param {string} projectRoot - Target project root
|
|
25
26
|
* @param {boolean} dryRun
|
|
26
27
|
*/
|
|
@@ -64,6 +65,9 @@ export async function installExternalSkill(skill, platform, projectRoot, dryRun)
|
|
|
64
65
|
for (const skillName of skillDirs) {
|
|
65
66
|
const srcDir = path.join(agentsSkillsDir, skillName);
|
|
66
67
|
const destDir = path.join(targetDir, skillName);
|
|
68
|
+
if (path.resolve(srcDir) === path.resolve(destDir)) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
67
71
|
await fs.remove(destDir).catch(() => {});
|
|
68
72
|
await fs.copy(srcDir, destDir);
|
|
69
73
|
}
|
|
@@ -79,14 +83,20 @@ export async function installExternalSkill(skill, platform, projectRoot, dryRun)
|
|
|
79
83
|
|
|
80
84
|
for (const targetDir of getTargetDirs(platform, projectRoot)) {
|
|
81
85
|
const skillDir = path.join(targetDir, skill.name);
|
|
86
|
+
if (path.resolve(skillDir) === path.resolve(path.dirname(canonicalSkillMd))) {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
82
89
|
await fs.remove(skillDir).catch(() => {});
|
|
83
90
|
await fs.ensureDir(skillDir);
|
|
84
91
|
await fs.writeFile(path.join(skillDir, 'SKILL.md'), content);
|
|
85
92
|
}
|
|
86
93
|
}
|
|
87
94
|
|
|
88
|
-
// Clean up npx skills artifacts after copying
|
|
89
|
-
|
|
95
|
+
// Clean up npx skills artifacts after copying. Preserve .agents/skills when
|
|
96
|
+
// Codex is selected because it is the official repository skill location.
|
|
97
|
+
if (!expandPlatforms(platform).includes('codex')) {
|
|
98
|
+
await fs.remove(path.join(projectRoot, '.agents')).catch(() => {});
|
|
99
|
+
}
|
|
90
100
|
await fs.remove(path.join(projectRoot, 'skills-lock.json')).catch(() => {});
|
|
91
101
|
}
|
|
92
102
|
|
|
@@ -95,21 +105,23 @@ export async function installExternalSkill(skill, platform, projectRoot, dryRun)
|
|
|
95
105
|
* Call this once after all external skills have been installed.
|
|
96
106
|
*
|
|
97
107
|
* @param {string} projectRoot
|
|
98
|
-
* @param {string} platform - 'claude' | 'codebuddy' | 'both'
|
|
108
|
+
* @param {string} platform - 'claude' | 'codebuddy' | 'codex' | 'both' | 'all'
|
|
99
109
|
*/
|
|
100
110
|
export async function cleanExternalSkillArtifacts(projectRoot, platform) {
|
|
101
111
|
const keepDirs = new Set(
|
|
102
112
|
getTargetDirs(platform, projectRoot).map(d => path.resolve(d))
|
|
103
113
|
);
|
|
104
114
|
|
|
115
|
+
const selectedPlatforms = expandPlatforms(platform);
|
|
105
116
|
const dirsToCheck = [
|
|
106
|
-
'.agents',
|
|
117
|
+
selectedPlatforms.includes('codex') ? null : '.agents',
|
|
107
118
|
'.agent',
|
|
108
119
|
'.trae',
|
|
109
120
|
'skills',
|
|
110
121
|
'.claude/skills',
|
|
111
122
|
'.codebuddy/skills',
|
|
112
|
-
|
|
123
|
+
'.codex/skills',
|
|
124
|
+
].filter(Boolean);
|
|
113
125
|
|
|
114
126
|
for (const dir of dirsToCheck) {
|
|
115
127
|
const abs = path.join(projectRoot, dir);
|
|
@@ -135,7 +147,7 @@ export async function cleanExternalSkillArtifacts(projectRoot, platform) {
|
|
|
135
147
|
}
|
|
136
148
|
|
|
137
149
|
// Remove empty parent dirs left behind (e.g. .codebuddy/ after removing .codebuddy/skills)
|
|
138
|
-
const parentDirs = ['.claude', '.codebuddy', '.trae', '.agent'];
|
|
150
|
+
const parentDirs = ['.claude', '.codebuddy', '.codex', '.trae', '.agent'];
|
|
139
151
|
for (const dir of parentDirs) {
|
|
140
152
|
const abs = path.join(projectRoot, dir);
|
|
141
153
|
if (!await fs.pathExists(abs)) continue;
|
|
@@ -155,14 +167,9 @@ export async function cleanExternalSkillArtifacts(projectRoot, platform) {
|
|
|
155
167
|
}
|
|
156
168
|
|
|
157
169
|
function getTargetDirs(platform, projectRoot) {
|
|
158
|
-
|
|
159
|
-
return
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
}
|
|
164
|
-
if (platform === 'codebuddy') {
|
|
165
|
-
return [path.join(projectRoot, '.codebuddy', 'skills')];
|
|
166
|
-
}
|
|
167
|
-
return [path.join(projectRoot, '.claude', 'skills')];
|
|
170
|
+
return expandPlatforms(platform).map(p => {
|
|
171
|
+
if (p === 'codebuddy') return path.join(projectRoot, '.codebuddy', 'skills');
|
|
172
|
+
if (p === 'codex') return path.join(projectRoot, '.agents', 'skills');
|
|
173
|
+
return path.join(projectRoot, '.claude', 'skills');
|
|
174
|
+
});
|
|
168
175
|
}
|