prizmkit 1.1.1 → 1.1.4
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/bundled/VERSION.json +3 -3
- package/bundled/adapters/claude/agent-adapter.js +18 -0
- package/bundled/adapters/claude/command-adapter.js +1 -27
- package/bundled/agents/prizm-dev-team-critic.md +2 -0
- package/bundled/agents/prizm-dev-team-dev.md +2 -0
- package/bundled/agents/prizm-dev-team-reviewer.md +2 -0
- package/bundled/dev-pipeline/README.md +63 -63
- package/bundled/dev-pipeline/assets/feature-list-example.json +1 -1
- package/bundled/dev-pipeline/assets/prizm-dev-team-integration.md +1 -1
- package/bundled/dev-pipeline/{launch-daemon.sh → launch-feature-daemon.sh} +33 -33
- package/bundled/dev-pipeline/launch-refactor-daemon.sh +454 -0
- package/bundled/dev-pipeline/lib/branch.sh +1 -1
- package/bundled/dev-pipeline/reset-feature.sh +3 -3
- package/bundled/dev-pipeline/reset-refactor.sh +312 -0
- package/bundled/dev-pipeline/{retry-bug.sh → retry-bugfix.sh} +47 -59
- package/bundled/dev-pipeline/retry-feature.sh +41 -54
- package/bundled/dev-pipeline/retry-refactor.sh +358 -0
- package/bundled/dev-pipeline/run-bugfix.sh +41 -0
- package/bundled/dev-pipeline/{run.sh → run-feature.sh} +64 -31
- package/bundled/dev-pipeline/run-refactor.sh +787 -0
- package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +398 -10
- package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +124 -0
- package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +419 -0
- package/bundled/dev-pipeline/scripts/init-refactor-pipeline.py +393 -0
- package/bundled/dev-pipeline/scripts/update-refactor-status.py +726 -0
- package/bundled/dev-pipeline/templates/agent-prompts/critic-code-challenge.md +13 -0
- package/bundled/dev-pipeline/templates/agent-prompts/critic-plan-challenge.md +7 -0
- package/bundled/dev-pipeline/templates/agent-prompts/dev-fix.md +7 -0
- package/bundled/dev-pipeline/templates/agent-prompts/dev-implement.md +27 -0
- package/bundled/dev-pipeline/templates/agent-prompts/dev-resume.md +5 -0
- package/bundled/dev-pipeline/templates/agent-prompts/reviewer-analyze.md +5 -0
- package/bundled/dev-pipeline/templates/agent-prompts/reviewer-review.md +12 -0
- package/bundled/dev-pipeline/templates/bootstrap-tier1.md +33 -2
- package/bundled/dev-pipeline/templates/bootstrap-tier2.md +13 -9
- package/bundled/dev-pipeline/templates/bootstrap-tier3.md +16 -12
- package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +22 -4
- package/bundled/dev-pipeline/templates/feature-list-schema.json +1 -1
- package/bundled/dev-pipeline/templates/refactor-list-schema.json +159 -0
- package/bundled/dev-pipeline/templates/sections/ac-verification-checklist.md +13 -0
- package/bundled/dev-pipeline/templates/sections/checkpoint-system.md +36 -0
- package/bundled/dev-pipeline/templates/sections/failure-log-check.md +2 -1
- package/bundled/dev-pipeline/templates/sections/feature-context.md +1 -1
- package/bundled/dev-pipeline/templates/sections/phase-analyze-agent.md +11 -7
- package/bundled/dev-pipeline/templates/sections/phase-analyze-full.md +11 -7
- package/bundled/dev-pipeline/templates/sections/phase-browser-verification.md +5 -1
- package/bundled/dev-pipeline/templates/sections/phase-commit-full.md +3 -0
- package/bundled/dev-pipeline/templates/sections/phase-commit.md +3 -0
- package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-agent-suffix.md +3 -0
- package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-lite-suffix.md +3 -0
- package/bundled/dev-pipeline/templates/sections/phase-critic-code.md +11 -10
- package/bundled/dev-pipeline/templates/sections/phase-critic-plan-full.md +12 -10
- package/bundled/dev-pipeline/templates/sections/phase-critic-plan.md +11 -9
- package/bundled/dev-pipeline/templates/sections/phase-deploy-verification.md +3 -0
- package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +10 -10
- package/bundled/dev-pipeline/templates/sections/phase-implement-full.md +12 -16
- package/bundled/dev-pipeline/templates/sections/phase-implement-lite.md +3 -0
- package/bundled/dev-pipeline/templates/sections/phase-plan-agent.md +3 -0
- package/bundled/dev-pipeline/templates/sections/phase-plan-lite.md +3 -0
- package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +11 -13
- package/bundled/dev-pipeline/templates/sections/phase-review-full.md +12 -20
- package/bundled/dev-pipeline/templates/sections/phase-specify-plan-full.md +3 -0
- package/bundled/dev-pipeline/templates/sections/phase0-init.md +3 -0
- package/bundled/dev-pipeline/templates/sections/phase0-test-baseline.md +3 -0
- package/bundled/dev-pipeline/templates/sections/resume-header.md +4 -1
- package/bundled/dev-pipeline/templates/sections/test-failure-recovery.md +75 -0
- package/bundled/rules/prizm/prizm-commit-workflow.md +1 -0
- package/bundled/rules/prizm/prizm-documentation.md +15 -15
- package/bundled/rules/prizm/prizm-progressive-loading.md +2 -1
- package/bundled/skills/_metadata.json +33 -6
- package/bundled/skills/app-planner/SKILL.md +105 -320
- package/bundled/skills/app-planner/assets/app-design-guide.md +101 -0
- package/bundled/skills/app-planner/references/frontend-design-guide.md +1 -1
- package/bundled/skills/app-planner/references/project-brief-guide.md +49 -80
- package/bundled/skills/bug-fix-workflow/SKILL.md +2 -2
- package/bundled/skills/bug-planner/SKILL.md +68 -5
- package/bundled/skills/bug-planner/scripts/validate-bug-list.py +3 -2
- package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +19 -5
- package/bundled/skills/{dev-pipeline-launcher → feature-pipeline-launcher}/SKILL.md +32 -32
- package/bundled/skills/feature-planner/SKILL.md +337 -0
- package/bundled/skills/{app-planner → feature-planner}/assets/evaluation-guide.md +4 -4
- package/bundled/skills/{app-planner → feature-planner}/assets/planning-guide.md +3 -171
- package/bundled/skills/{app-planner → feature-planner}/references/browser-interaction.md +6 -5
- package/bundled/skills/feature-planner/references/decomposition-patterns.md +75 -0
- package/bundled/skills/{app-planner → feature-planner}/references/error-recovery.md +8 -8
- package/bundled/skills/{app-planner → feature-planner}/references/incremental-feature-planning.md +1 -1
- package/bundled/skills/{app-planner/references/new-app-planning.md → feature-planner/references/new-project-planning.md} +1 -1
- package/bundled/skills/{app-planner → feature-planner}/scripts/validate-and-generate.py +4 -4
- package/bundled/skills/feature-workflow/SKILL.md +23 -23
- package/bundled/skills/prizm-kit/SKILL.md +1 -3
- package/bundled/skills/prizm-kit/assets/project-memory-template.md +4 -2
- package/bundled/skills/prizmkit-analyze/SKILL.md +2 -5
- package/bundled/skills/prizmkit-code-review/SKILL.md +2 -2
- package/bundled/skills/prizmkit-committer/SKILL.md +32 -8
- package/bundled/skills/prizmkit-deploy/SKILL.md +1 -5
- package/bundled/skills/prizmkit-implement/SKILL.md +5 -51
- package/bundled/skills/prizmkit-init/SKILL.md +7 -78
- package/bundled/skills/prizmkit-plan/SKILL.md +1 -12
- package/bundled/skills/prizmkit-prizm-docs/SKILL.md +13 -28
- package/bundled/skills/prizmkit-prizm-docs/assets/PRIZM-SPEC.md +52 -1
- package/bundled/skills/prizmkit-retrospective/SKILL.md +12 -117
- package/bundled/skills/recovery-workflow/SKILL.md +168 -316
- package/bundled/skills/recovery-workflow/evals/evals.json +29 -13
- package/bundled/skills/recovery-workflow/scripts/detect-recovery-state.py +232 -274
- package/bundled/skills/refactor-pipeline-launcher/SKILL.md +352 -0
- package/bundled/skills/refactor-planner/SKILL.md +436 -0
- package/bundled/skills/refactor-planner/assets/planning-guide.md +292 -0
- package/bundled/skills/refactor-planner/references/behavior-preservation.md +301 -0
- package/bundled/skills/refactor-planner/references/refactor-scoping-guide.md +221 -0
- package/bundled/skills/refactor-planner/scripts/validate-and-generate-refactor.py +786 -0
- package/bundled/skills/refactor-workflow/SKILL.md +299 -319
- package/bundled/team/prizm-dev-team.json +1 -1
- package/package.json +1 -1
- package/src/clean.js +3 -3
- package/src/scaffold.js +6 -6
- package/bundled/skills/prizmkit-plan/assets/spec-template.md +0 -56
- package/bundled/skills/prizmkit-plan/references/clarify-guide.md +0 -67
- package/src/config.js +0 -504
- package/src/prompts.js +0 -210
- /package/bundled/skills/{dev-pipeline-launcher → feature-pipeline-launcher}/scripts/preflight-check.py +0 -0
package/src/config.js
DELETED
|
@@ -1,504 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PrizmKit Config Command
|
|
3
|
-
*
|
|
4
|
-
* Reconfigure an existing PrizmKit installation without a full reinstall.
|
|
5
|
-
* Supports changing platform, AI CLI, skills suite, rules, team, and pipeline.
|
|
6
|
-
*
|
|
7
|
-
* Flow: READ manifest → PROMPT user → COMPUTE DIFF → DISPLAY SUMMARY → EXECUTE
|
|
8
|
-
*
|
|
9
|
-
* Preserves runtime files (.prizm-docs/, dev-pipeline/state/, .prizmkit/specs/).
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import chalk from 'chalk';
|
|
13
|
-
import fs from 'fs-extra';
|
|
14
|
-
import path from 'path';
|
|
15
|
-
import { readFileSync } from 'fs';
|
|
16
|
-
import { dirname, join } from 'path';
|
|
17
|
-
import { fileURLToPath } from 'url';
|
|
18
|
-
import { confirm } from '@inquirer/prompts';
|
|
19
|
-
|
|
20
|
-
import { readManifest, writeManifest, buildManifest, diffManifest } from './manifest.js';
|
|
21
|
-
import {
|
|
22
|
-
loadMetadata,
|
|
23
|
-
loadRulesMetadata,
|
|
24
|
-
getAgentsDir,
|
|
25
|
-
} from './metadata.js';
|
|
26
|
-
import {
|
|
27
|
-
installSkills,
|
|
28
|
-
installAgents,
|
|
29
|
-
installSettings,
|
|
30
|
-
installTeamConfig,
|
|
31
|
-
installProjectMemory,
|
|
32
|
-
installPipeline,
|
|
33
|
-
installGitignore,
|
|
34
|
-
resolveSkillList,
|
|
35
|
-
resolvePipelineFileList,
|
|
36
|
-
} from './scaffold.js';
|
|
37
|
-
import {
|
|
38
|
-
removeSkillFiles,
|
|
39
|
-
removeAgentFiles,
|
|
40
|
-
removeRuleFiles,
|
|
41
|
-
removePipelineFiles,
|
|
42
|
-
} from './upgrade.js';
|
|
43
|
-
import { detectPlatform } from './detect-platform.js';
|
|
44
|
-
import {
|
|
45
|
-
selectPlatform,
|
|
46
|
-
selectAiCli,
|
|
47
|
-
selectSkillSuite,
|
|
48
|
-
selectRulesPreset,
|
|
49
|
-
confirmTeamMode,
|
|
50
|
-
confirmPipeline,
|
|
51
|
-
} from './prompts.js';
|
|
52
|
-
|
|
53
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
54
|
-
const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));
|
|
55
|
-
|
|
56
|
-
// ============================================================
|
|
57
|
-
// Helpers
|
|
58
|
-
// ============================================================
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Detect which platforms are actually installed on filesystem.
|
|
62
|
-
*/
|
|
63
|
-
async function detectInstalledPlatforms(projectRoot) {
|
|
64
|
-
const hasClaude = await fs.pathExists(path.join(projectRoot, '.claude', 'commands'))
|
|
65
|
-
|| await fs.pathExists(path.join(projectRoot, '.claude', 'agents'));
|
|
66
|
-
const hasCodeBuddy = await fs.pathExists(path.join(projectRoot, '.codebuddy', 'skills'))
|
|
67
|
-
|| await fs.pathExists(path.join(projectRoot, '.codebuddy', 'agents'));
|
|
68
|
-
|
|
69
|
-
if (hasClaude && hasCodeBuddy) return 'both';
|
|
70
|
-
if (hasCodeBuddy) return 'codebuddy';
|
|
71
|
-
if (hasClaude) return 'claude';
|
|
72
|
-
return null;
|
|
73
|
-
}
|
|
74
|
-
|
|
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
|
-
const platformLabel = (p) => p === 'both' ? 'CodeBuddy + Claude Code'
|
|
83
|
-
: p === 'codebuddy' ? 'CodeBuddy' : 'Claude Code';
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Remove all PrizmKit-owned platform-specific files for a single platform.
|
|
87
|
-
* Selective removal — only removes known PrizmKit files, leaves user-created files intact.
|
|
88
|
-
*/
|
|
89
|
-
async function removePlatformFiles(platform, projectRoot, manifest, dryRun) {
|
|
90
|
-
const skillNames = manifest?.files?.skills || [];
|
|
91
|
-
const agentFileNames = manifest?.files?.agents || [];
|
|
92
|
-
const ruleFileNames = manifest?.files?.rules || [];
|
|
93
|
-
|
|
94
|
-
if (skillNames.length) {
|
|
95
|
-
console.log(chalk.blue(`\n 删除 ${platformLabel(platform)} skills:`));
|
|
96
|
-
await removeSkillFiles(platform, projectRoot, skillNames, dryRun);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (agentFileNames.length) {
|
|
100
|
-
console.log(chalk.blue(`\n 删除 ${platformLabel(platform)} agents:`));
|
|
101
|
-
await removeAgentFiles(platform, projectRoot, agentFileNames, dryRun);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (ruleFileNames.length) {
|
|
105
|
-
console.log(chalk.blue(`\n 删除 ${platformLabel(platform)} rules:`));
|
|
106
|
-
await removeRuleFiles(platform, projectRoot, ruleFileNames, dryRun);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Settings
|
|
110
|
-
const settingsFile = platform === 'claude'
|
|
111
|
-
? path.join(projectRoot, '.claude', 'settings.json')
|
|
112
|
-
: path.join(projectRoot, '.codebuddy', 'settings.json');
|
|
113
|
-
if (await fs.pathExists(settingsFile)) {
|
|
114
|
-
if (dryRun) {
|
|
115
|
-
console.log(chalk.gray(` [dry-run] remove ${path.relative(projectRoot, settingsFile)}`));
|
|
116
|
-
} else {
|
|
117
|
-
await fs.remove(settingsFile);
|
|
118
|
-
console.log(chalk.red(` ✗ removed ${path.relative(projectRoot, settingsFile)}`));
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Team info
|
|
123
|
-
if (platform === 'claude') {
|
|
124
|
-
const teamInfo = path.join(projectRoot, '.claude', 'team-info.json');
|
|
125
|
-
if (await fs.pathExists(teamInfo)) {
|
|
126
|
-
if (dryRun) {
|
|
127
|
-
console.log(chalk.gray(' [dry-run] remove .claude/team-info.json'));
|
|
128
|
-
} else {
|
|
129
|
-
await fs.remove(teamInfo);
|
|
130
|
-
console.log(chalk.red(' ✗ removed .claude/team-info.json'));
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
} else if (platform === 'codebuddy') {
|
|
134
|
-
const homeDir = process.env.HOME || process.env.USERPROFILE;
|
|
135
|
-
const teamDir = path.join(homeDir, '.codebuddy', 'teams', 'prizm-dev-team');
|
|
136
|
-
if (await fs.pathExists(teamDir)) {
|
|
137
|
-
if (dryRun) {
|
|
138
|
-
console.log(chalk.gray(' [dry-run] remove ~/.codebuddy/teams/prizm-dev-team/'));
|
|
139
|
-
} else {
|
|
140
|
-
await fs.remove(teamDir);
|
|
141
|
-
console.log(chalk.red(' ✗ removed ~/.codebuddy/teams/prizm-dev-team/'));
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Project memory file
|
|
147
|
-
const memoryFile = platform === 'claude' ? 'CLAUDE.md' : 'CODEBUDDY.md';
|
|
148
|
-
const memoryPath = path.join(projectRoot, memoryFile);
|
|
149
|
-
if (await fs.pathExists(memoryPath)) {
|
|
150
|
-
if (dryRun) {
|
|
151
|
-
console.log(chalk.gray(` [dry-run] remove ${memoryFile}`));
|
|
152
|
-
} else {
|
|
153
|
-
await fs.remove(memoryPath);
|
|
154
|
-
console.log(chalk.red(` ✗ removed ${memoryFile}`));
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// Command assets (Claude only)
|
|
159
|
-
if (platform === 'claude') {
|
|
160
|
-
const assetsDir = path.join(projectRoot, '.claude', 'command-assets');
|
|
161
|
-
if (await fs.pathExists(assetsDir)) {
|
|
162
|
-
if (dryRun) {
|
|
163
|
-
console.log(chalk.gray(' [dry-run] remove .claude/command-assets/'));
|
|
164
|
-
} else {
|
|
165
|
-
await fs.remove(assetsDir);
|
|
166
|
-
console.log(chalk.red(' ✗ removed .claude/command-assets/'));
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// ============================================================
|
|
173
|
-
// Main
|
|
174
|
-
// ============================================================
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Run the config reconfiguration command.
|
|
178
|
-
* @param {string} directory - target project directory
|
|
179
|
-
* @param {Object} options - CLI options from commander
|
|
180
|
-
*/
|
|
181
|
-
export async function runConfig(directory, options = {}) {
|
|
182
|
-
const projectRoot = path.resolve(directory || '.');
|
|
183
|
-
const dryRun = Boolean(options.dryRun);
|
|
184
|
-
const nonInteractive = Boolean(options.nonInteractive);
|
|
185
|
-
|
|
186
|
-
console.log('');
|
|
187
|
-
console.log(chalk.bold(' PrizmKit Config'));
|
|
188
|
-
console.log(` Target: ${projectRoot}`);
|
|
189
|
-
if (dryRun) console.log(chalk.yellow(' Mode: dry-run'));
|
|
190
|
-
console.log('');
|
|
191
|
-
|
|
192
|
-
// ── Phase 1: READ current state ──────────────────────────────────────────
|
|
193
|
-
|
|
194
|
-
const oldManifest = await readManifest(projectRoot);
|
|
195
|
-
if (!oldManifest) {
|
|
196
|
-
console.log(chalk.red(' ✗ 未找到 .prizmkit/manifest.json'));
|
|
197
|
-
console.log(chalk.gray(' 请先运行 `npx prizmkit install .` 安装 PrizmKit。'));
|
|
198
|
-
console.log('');
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// Read user config
|
|
203
|
-
const configPath = path.join(projectRoot, '.prizmkit', 'config.json');
|
|
204
|
-
let userConfig = {};
|
|
205
|
-
if (await fs.pathExists(configPath)) {
|
|
206
|
-
try { userConfig = await fs.readJSON(configPath); } catch { /* ignore */ }
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// Filesystem-based platform detection (overrides manifest)
|
|
210
|
-
const detectedPlatform = await detectInstalledPlatforms(projectRoot) || oldManifest.platform || 'claude';
|
|
211
|
-
|
|
212
|
-
const currentConfig = {
|
|
213
|
-
platform: detectedPlatform,
|
|
214
|
-
suite: oldManifest.suite || 'core',
|
|
215
|
-
rules: oldManifest.options?.rules || 'recommended',
|
|
216
|
-
team: oldManifest.options?.team ?? true,
|
|
217
|
-
pipeline: oldManifest.options?.pipeline ?? true,
|
|
218
|
-
aiCli: userConfig.ai_cli || oldManifest.options?.aiCli || '',
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
// Display current config
|
|
222
|
-
console.log(chalk.bold(' 当前配置:'));
|
|
223
|
-
console.log(` 平台: ${chalk.cyan(platformLabel(currentConfig.platform))}`);
|
|
224
|
-
console.log(` AI CLI: ${currentConfig.aiCli ? chalk.cyan(currentConfig.aiCli) : chalk.gray('(未设置)')}`);
|
|
225
|
-
console.log(` 技能套件: ${chalk.cyan(currentConfig.suite)}`);
|
|
226
|
-
console.log(` 规则: ${chalk.cyan(currentConfig.rules)}`);
|
|
227
|
-
console.log(` 团队模式: ${currentConfig.team ? chalk.green('启用') : chalk.gray('禁用')}`);
|
|
228
|
-
console.log(` 流水线: ${currentConfig.pipeline ? chalk.green('启用') : chalk.gray('禁用')}`);
|
|
229
|
-
console.log('');
|
|
230
|
-
|
|
231
|
-
// ── Phase 2: PROMPT for new config ───────────────────────────────────────
|
|
232
|
-
|
|
233
|
-
let newConfig;
|
|
234
|
-
|
|
235
|
-
if (nonInteractive) {
|
|
236
|
-
// Non-interactive: only change what's explicitly specified via CLI options
|
|
237
|
-
if (!options.platform && !options.skills && !options.rules
|
|
238
|
-
&& options.aiCli === undefined && options.team === undefined && options.pipeline === undefined) {
|
|
239
|
-
console.log(chalk.yellow(' ⚠ 非交互式模式下未指定任何变更。'));
|
|
240
|
-
console.log(chalk.gray(' 使用 --platform, --skills, --rules, --ai-cli, --team/--no-team, --pipeline/--no-pipeline'));
|
|
241
|
-
return;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
newConfig = {
|
|
245
|
-
platform: options.platform || currentConfig.platform,
|
|
246
|
-
suite: options.skills || currentConfig.suite,
|
|
247
|
-
rules: options.rules || currentConfig.rules,
|
|
248
|
-
team: options.team !== undefined ? options.team : currentConfig.team,
|
|
249
|
-
pipeline: options.pipeline !== undefined ? options.pipeline : currentConfig.pipeline,
|
|
250
|
-
aiCli: options.aiCli !== undefined ? options.aiCli : currentConfig.aiCli,
|
|
251
|
-
};
|
|
252
|
-
} else {
|
|
253
|
-
// Interactive: let user select each setting
|
|
254
|
-
const detected = detectPlatform();
|
|
255
|
-
|
|
256
|
-
try {
|
|
257
|
-
console.log(chalk.bold(' 选择新配置(按 Enter 保持当前值):\n'));
|
|
258
|
-
|
|
259
|
-
const newPlatform = await selectPlatform(currentConfig.platform, detected);
|
|
260
|
-
const newAiCli = await selectAiCli(currentConfig.aiCli, detected);
|
|
261
|
-
|
|
262
|
-
const metadata = await loadMetadata();
|
|
263
|
-
const newSuite = await selectSkillSuite(currentConfig.suite, metadata);
|
|
264
|
-
const newRules = await selectRulesPreset(currentConfig.rules);
|
|
265
|
-
const newTeam = await confirmTeamMode(currentConfig.team);
|
|
266
|
-
const newPipeline = await confirmPipeline(currentConfig.pipeline);
|
|
267
|
-
|
|
268
|
-
newConfig = {
|
|
269
|
-
platform: newPlatform,
|
|
270
|
-
suite: newSuite,
|
|
271
|
-
rules: newRules,
|
|
272
|
-
team: newTeam,
|
|
273
|
-
pipeline: newPipeline,
|
|
274
|
-
aiCli: newAiCli,
|
|
275
|
-
};
|
|
276
|
-
} catch (err) {
|
|
277
|
-
if (err.message?.includes('User force closed')) {
|
|
278
|
-
console.log(chalk.yellow('\n 配置已取消。'));
|
|
279
|
-
return;
|
|
280
|
-
}
|
|
281
|
-
throw err;
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// ── Phase 3: COMPUTE DIFF ────────────────────────────────────────────────
|
|
286
|
-
|
|
287
|
-
const changes = [];
|
|
288
|
-
if (newConfig.platform !== currentConfig.platform) {
|
|
289
|
-
changes.push(`平台: ${platformLabel(currentConfig.platform)} → ${platformLabel(newConfig.platform)}`);
|
|
290
|
-
}
|
|
291
|
-
if (newConfig.aiCli !== currentConfig.aiCli) {
|
|
292
|
-
changes.push(`AI CLI: ${currentConfig.aiCli || '(未设置)'} → ${newConfig.aiCli || '(未设置)'}`);
|
|
293
|
-
}
|
|
294
|
-
if (newConfig.suite !== currentConfig.suite) {
|
|
295
|
-
changes.push(`技能套件: ${currentConfig.suite} → ${newConfig.suite}`);
|
|
296
|
-
}
|
|
297
|
-
if (newConfig.rules !== currentConfig.rules) {
|
|
298
|
-
changes.push(`规则: ${currentConfig.rules} → ${newConfig.rules}`);
|
|
299
|
-
}
|
|
300
|
-
if (newConfig.team !== currentConfig.team) {
|
|
301
|
-
changes.push(`团队模式: ${currentConfig.team ? '启用' : '禁用'} → ${newConfig.team ? '启用' : '禁用'}`);
|
|
302
|
-
}
|
|
303
|
-
if (newConfig.pipeline !== currentConfig.pipeline) {
|
|
304
|
-
changes.push(`流水线: ${currentConfig.pipeline ? '启用' : '禁用'} → ${newConfig.pipeline ? '启用' : '禁用'}`);
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// ── Phase 4: DISPLAY SUMMARY + CONFIRM ───────────────────────────────────
|
|
308
|
-
|
|
309
|
-
if (changes.length === 0) {
|
|
310
|
-
console.log(chalk.green('\n ✓ 配置未变更,无需操作。'));
|
|
311
|
-
console.log('');
|
|
312
|
-
return;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
console.log(chalk.bold('\n 变更摘要:'));
|
|
316
|
-
for (const change of changes) {
|
|
317
|
-
console.log(` ${chalk.yellow('→')} ${change}`);
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
// Warn about destructive changes
|
|
321
|
-
if (newConfig.platform !== currentConfig.platform) {
|
|
322
|
-
const oldPlatforms = expandPlatforms(currentConfig.platform);
|
|
323
|
-
const newPlatforms = expandPlatforms(newConfig.platform);
|
|
324
|
-
const dropping = oldPlatforms.filter(p => !newPlatforms.includes(p));
|
|
325
|
-
if (dropping.length) {
|
|
326
|
-
console.log(chalk.yellow(`\n ⚠ 将移除 ${dropping.map(platformLabel).join(', ')} 的 PrizmKit 文件`));
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
console.log('');
|
|
330
|
-
|
|
331
|
-
if (dryRun) {
|
|
332
|
-
console.log(chalk.yellow(' [dry-run] 预览完成,未修改任何文件。'));
|
|
333
|
-
console.log('');
|
|
334
|
-
return;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
if (!nonInteractive) {
|
|
338
|
-
const proceed = await confirm({
|
|
339
|
-
message: '确认应用配置变更?',
|
|
340
|
-
default: true,
|
|
341
|
-
});
|
|
342
|
-
if (!proceed) {
|
|
343
|
-
console.log(chalk.yellow(' 配置已取消。'));
|
|
344
|
-
return;
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
// ── Phase 5: EXECUTE ─────────────────────────────────────────────────────
|
|
349
|
-
|
|
350
|
-
console.log(chalk.bold('\n 应用配置变更...\n'));
|
|
351
|
-
|
|
352
|
-
const oldPlatforms = expandPlatforms(currentConfig.platform);
|
|
353
|
-
const newPlatforms = expandPlatforms(newConfig.platform);
|
|
354
|
-
const platformsToRemove = oldPlatforms.filter(p => !newPlatforms.includes(p));
|
|
355
|
-
const platformsToAdd = newPlatforms.filter(p => !oldPlatforms.includes(p));
|
|
356
|
-
const platformsToUpdate = newPlatforms.filter(p => oldPlatforms.includes(p));
|
|
357
|
-
|
|
358
|
-
// Resolve new file lists
|
|
359
|
-
const newSkillList = await resolveSkillList(newConfig.suite);
|
|
360
|
-
const agentsDir = getAgentsDir();
|
|
361
|
-
const newAgentFiles = (await fs.readdir(agentsDir)).filter(f => f.endsWith('.md'));
|
|
362
|
-
const rulesMeta = await loadRulesMetadata();
|
|
363
|
-
const rulesPresetDef = rulesMeta.presets[newConfig.rules] || rulesMeta.presets.recommended;
|
|
364
|
-
const newRuleFiles = (rulesPresetDef?.rules || []).map(name => `${name}.md`);
|
|
365
|
-
const newPipelineFiles = newConfig.pipeline ? resolvePipelineFileList() : [];
|
|
366
|
-
|
|
367
|
-
// 5a. Remove files for platforms being dropped
|
|
368
|
-
for (const p of platformsToRemove) {
|
|
369
|
-
console.log(chalk.bold(` 移除 ${platformLabel(p)} 平台文件...`));
|
|
370
|
-
await removePlatformFiles(p, projectRoot, oldManifest, false);
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
// 5b. Handle skill/rule diff for existing platforms (suite or rules changed)
|
|
374
|
-
if (newConfig.suite !== currentConfig.suite || newConfig.rules !== currentConfig.rules) {
|
|
375
|
-
const newTempManifest = buildManifest({
|
|
376
|
-
version: pkg.version, platform: newConfig.platform, suite: newConfig.suite,
|
|
377
|
-
skills: newSkillList, agents: newAgentFiles, rules: newRuleFiles,
|
|
378
|
-
pipeline: newPipelineFiles, team: newConfig.team, aiCli: newConfig.aiCli,
|
|
379
|
-
rulesPreset: newConfig.rules, extras: oldManifest?.files?.extras || [],
|
|
380
|
-
});
|
|
381
|
-
const diff = diffManifest(oldManifest, newTempManifest);
|
|
382
|
-
|
|
383
|
-
// Remove orphaned skills/rules from existing platforms
|
|
384
|
-
for (const p of platformsToUpdate) {
|
|
385
|
-
if (diff.skills.removed.length) {
|
|
386
|
-
console.log(chalk.blue(`\n 删除多余 skills (${platformLabel(p)}):`));
|
|
387
|
-
await removeSkillFiles(p, projectRoot, diff.skills.removed, false);
|
|
388
|
-
}
|
|
389
|
-
if (diff.rules.removed.length) {
|
|
390
|
-
console.log(chalk.blue(`\n 删除多余 rules (${platformLabel(p)}):`));
|
|
391
|
-
await removeRuleFiles(p, projectRoot, diff.rules.removed, false);
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
// 5c. Install/update files for new + existing platforms
|
|
397
|
-
const allTargetPlatforms = [...platformsToAdd, ...platformsToUpdate];
|
|
398
|
-
const needsReinstall = newConfig.platform !== currentConfig.platform
|
|
399
|
-
|| newConfig.suite !== currentConfig.suite
|
|
400
|
-
|| newConfig.rules !== currentConfig.rules
|
|
401
|
-
|| newConfig.team !== currentConfig.team;
|
|
402
|
-
|
|
403
|
-
for (const p of allTargetPlatforms) {
|
|
404
|
-
const isNew = platformsToAdd.includes(p);
|
|
405
|
-
|
|
406
|
-
if (isNew || needsReinstall) {
|
|
407
|
-
console.log(chalk.bold(`\n ${isNew ? '安装' : '更新'} ${platformLabel(p)} 环境...\n`));
|
|
408
|
-
|
|
409
|
-
console.log(chalk.blue(' Skills:'));
|
|
410
|
-
await installSkills(p, newSkillList, projectRoot, false);
|
|
411
|
-
|
|
412
|
-
console.log(chalk.blue('\n Agents:'));
|
|
413
|
-
await installAgents(p, projectRoot, false);
|
|
414
|
-
|
|
415
|
-
console.log(chalk.blue('\n Settings & Rules:'));
|
|
416
|
-
await installSettings(p, projectRoot, { pipeline: newConfig.pipeline, rules: newConfig.rules }, false);
|
|
417
|
-
|
|
418
|
-
if (isNew) {
|
|
419
|
-
console.log(chalk.blue('\n Project Memory:'));
|
|
420
|
-
await installProjectMemory(p, projectRoot, false);
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
if (newConfig.team) {
|
|
424
|
-
console.log(chalk.blue('\n Team Config:'));
|
|
425
|
-
await installTeamConfig(p, projectRoot, false);
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
// 5d. Pipeline changes
|
|
431
|
-
if (newConfig.pipeline !== currentConfig.pipeline) {
|
|
432
|
-
if (newConfig.pipeline) {
|
|
433
|
-
console.log(chalk.blue('\n 安装 Pipeline:'));
|
|
434
|
-
await installPipeline(projectRoot, false);
|
|
435
|
-
} else {
|
|
436
|
-
console.log(chalk.blue('\n 移除 Pipeline 框架文件(保留 state/):'));
|
|
437
|
-
const oldPipelineFiles = oldManifest?.files?.pipeline || [];
|
|
438
|
-
if (oldPipelineFiles.length) {
|
|
439
|
-
await removePipelineFiles(projectRoot, oldPipelineFiles, false);
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
// 5e. Update .gitignore
|
|
445
|
-
console.log(chalk.blue('\n Gitignore:'));
|
|
446
|
-
await installGitignore(projectRoot, { pipeline: newConfig.pipeline }, false);
|
|
447
|
-
|
|
448
|
-
// 5f. Update .prizmkit/config.json (ai_cli)
|
|
449
|
-
if (newConfig.aiCli !== currentConfig.aiCli) {
|
|
450
|
-
const prizmkitDir = path.join(projectRoot, '.prizmkit');
|
|
451
|
-
await fs.ensureDir(prizmkitDir);
|
|
452
|
-
let existingConfig = {};
|
|
453
|
-
if (await fs.pathExists(configPath)) {
|
|
454
|
-
try { existingConfig = await fs.readJSON(configPath); } catch { /* ignore */ }
|
|
455
|
-
}
|
|
456
|
-
if (newConfig.aiCli) {
|
|
457
|
-
existingConfig.ai_cli = newConfig.aiCli;
|
|
458
|
-
} else {
|
|
459
|
-
delete existingConfig.ai_cli;
|
|
460
|
-
}
|
|
461
|
-
await fs.writeJSON(configPath, existingConfig, { spaces: 2 });
|
|
462
|
-
console.log(chalk.green(`\n ✓ .prizmkit/config.json (ai_cli: ${newConfig.aiCli || '(cleared)'})`));
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
// 5g. Write new manifest
|
|
466
|
-
const newManifest = buildManifest({
|
|
467
|
-
version: pkg.version,
|
|
468
|
-
platform: newConfig.platform,
|
|
469
|
-
suite: newConfig.suite,
|
|
470
|
-
skills: newSkillList,
|
|
471
|
-
agents: newAgentFiles,
|
|
472
|
-
rules: newRuleFiles,
|
|
473
|
-
pipeline: newPipelineFiles,
|
|
474
|
-
team: newConfig.team,
|
|
475
|
-
aiCli: newConfig.aiCli,
|
|
476
|
-
rulesPreset: newConfig.rules,
|
|
477
|
-
extras: oldManifest?.files?.extras || [],
|
|
478
|
-
});
|
|
479
|
-
|
|
480
|
-
// Preserve original installedAt
|
|
481
|
-
if (oldManifest?.installedAt) {
|
|
482
|
-
newManifest.installedAt = oldManifest.installedAt;
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
await writeManifest(projectRoot, newManifest);
|
|
486
|
-
console.log(chalk.green(' ✓ .prizmkit/manifest.json'));
|
|
487
|
-
|
|
488
|
-
// ── Done ─────────────────────────────────────────────────────────────────
|
|
489
|
-
|
|
490
|
-
console.log('');
|
|
491
|
-
console.log(chalk.bold(' ════════════════════════════════════════════════'));
|
|
492
|
-
console.log(chalk.green.bold(' ✅ 配置变更完成!'));
|
|
493
|
-
console.log(chalk.bold(' ════════════════════════════════════════════════'));
|
|
494
|
-
console.log('');
|
|
495
|
-
|
|
496
|
-
console.log(chalk.gray(' 新配置:'));
|
|
497
|
-
console.log(chalk.gray(` 平台: ${platformLabel(newConfig.platform)}`));
|
|
498
|
-
console.log(chalk.gray(` AI CLI: ${newConfig.aiCli || '(未设置)'}`));
|
|
499
|
-
console.log(chalk.gray(` 技能套件: ${newConfig.suite}`));
|
|
500
|
-
console.log(chalk.gray(` 规则: ${newConfig.rules}`));
|
|
501
|
-
console.log(chalk.gray(` 团队模式: ${newConfig.team ? '启用' : '禁用'}`));
|
|
502
|
-
console.log(chalk.gray(` 流水线: ${newConfig.pipeline ? '启用' : '禁用'}`));
|
|
503
|
-
console.log('');
|
|
504
|
-
}
|