prizmkit 1.1.107 → 1.1.109
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 +4 -0
- package/bundled/VERSION.json +3 -3
- package/bundled/dev-pipeline/prizmkit_runtime/cli.py +20 -0
- package/bundled/dev-pipeline/prizmkit_runtime/commands.py +1 -0
- package/bundled/dev-pipeline/prizmkit_runtime/config.py +81 -14
- package/bundled/dev-pipeline/prizmkit_runtime/gitops.py +21 -0
- package/bundled/dev-pipeline/prizmkit_runtime/heartbeat.py +19 -8
- package/bundled/dev-pipeline/prizmkit_runtime/interoperability.py +1 -1
- package/bundled/dev-pipeline/prizmkit_runtime/launch_profiles.py +18 -0
- package/bundled/dev-pipeline/prizmkit_runtime/platform_detection.py +208 -0
- package/bundled/dev-pipeline/prizmkit_runtime/runner_bookkeeping.py +22 -2
- package/bundled/dev-pipeline/prizmkit_runtime/runner_recovery.py +3 -1
- package/bundled/dev-pipeline/prizmkit_runtime/runners.py +20 -1
- package/bundled/dev-pipeline/prizmkit_runtime/runtime_helper.py +508 -0
- package/bundled/dev-pipeline/prizmkit_runtime/sessions.py +151 -30
- package/bundled/dev-pipeline/scripts/continuation.py +0 -1
- package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +8 -46
- package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +9 -34
- package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +42 -33
- package/bundled/dev-pipeline/scripts/prizmkit-runtime-helper.py +27 -0
- package/bundled/dev-pipeline/scripts/utils.py +94 -0
- package/bundled/dev-pipeline/templates/agent-prompts/critic-plan-challenge.md +4 -3
- package/bundled/dev-pipeline/templates/bootstrap-prompt.md +1 -1
- package/bundled/dev-pipeline/templates/bootstrap-tier1.md +39 -65
- package/bundled/dev-pipeline/templates/bootstrap-tier2.md +58 -96
- package/bundled/dev-pipeline/templates/bootstrap-tier3.md +54 -95
- package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +6 -18
- package/bundled/dev-pipeline/templates/refactor-bootstrap-prompt.md +5 -17
- package/bundled/dev-pipeline/templates/sections/checkpoint-system.md +14 -48
- package/bundled/dev-pipeline/templates/sections/context-budget-rules.md +7 -13
- package/bundled/dev-pipeline/templates/sections/feature-context.md +0 -4
- package/bundled/dev-pipeline/templates/sections/phase-browser-verification-auto.md +31 -61
- package/bundled/dev-pipeline/templates/sections/phase-browser-verification-opencli.md +21 -37
- package/bundled/dev-pipeline/templates/sections/phase-browser-verification.md +22 -69
- package/bundled/dev-pipeline/templates/sections/phase-commit-full.md +0 -14
- package/bundled/dev-pipeline/templates/sections/phase-commit.md +0 -14
- package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-agent-suffix.md +0 -7
- package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-base.md +1 -3
- package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-lite-suffix.md +0 -7
- package/bundled/dev-pipeline/templates/sections/phase-critic-plan-full.md +7 -9
- package/bundled/dev-pipeline/templates/sections/phase-critic-plan.md +4 -8
- package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +0 -7
- package/bundled/dev-pipeline/templates/sections/phase-implement-full.md +0 -7
- package/bundled/dev-pipeline/templates/sections/phase-implement-lite.md +0 -7
- package/bundled/dev-pipeline/templates/sections/phase-plan-agent.md +3 -10
- package/bundled/dev-pipeline/templates/sections/phase-plan-lite.md +2 -9
- package/bundled/dev-pipeline/templates/sections/phase-prizmkit-test.md +15 -16
- package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +1 -8
- package/bundled/dev-pipeline/templates/sections/phase-review-full.md +1 -8
- package/bundled/dev-pipeline/templates/sections/phase-specify-plan-full.md +9 -15
- package/bundled/dev-pipeline/templates/sections/phase0-init.md +1 -8
- package/bundled/dev-pipeline/templates/sections/phase0-test-baseline.md +2 -15
- package/bundled/dev-pipeline/templates/sections/subagent-timeout-recovery.md +1 -1
- package/bundled/dev-pipeline/tests/conftest.py +0 -1
- package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +392 -23
- package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +37 -17
- package/bundled/dev-pipeline/tests/test_generate_refactor_prompt.py +118 -14
- package/bundled/dev-pipeline/tests/test_python_runner_parity.py +79 -2
- package/bundled/dev-pipeline/tests/test_runtime_helper.py +211 -0
- package/bundled/dev-pipeline/tests/test_unified_cli.py +663 -13
- package/bundled/skills/_metadata.json +4 -4
- package/bundled/skills/app-planner/SKILL.md +1 -1
- package/bundled/skills/app-planner/references/architecture-decisions.md +1 -1
- package/bundled/skills/bug-fix-workflow/SKILL.md +174 -128
- package/bundled/skills/bug-planner/SKILL.md +101 -15
- package/bundled/skills/bug-planner/references/severity-rules.md +20 -8
- package/bundled/skills/feature-planner/SKILL.md +87 -8
- package/bundled/skills/feature-planner/assets/planning-guide.md +34 -10
- package/bundled/skills/feature-workflow/SKILL.md +100 -81
- package/bundled/skills/{prizm-kit → prizmkit}/SKILL.md +1 -1
- package/bundled/skills/prizmkit-code-review/SKILL.md +1 -1
- package/bundled/skills/refactor-planner/SKILL.md +88 -7
- package/bundled/skills/refactor-planner/references/fast-path.md +2 -1
- package/bundled/skills/refactor-planner/references/planning-phases.md +29 -11
- package/bundled/skills/refactor-workflow/SKILL.md +116 -57
- package/bundled/templates/project-memory-template.md +1 -1
- package/package.json +1 -1
- package/src/ai-cli-launch.js +194 -0
- package/src/config.js +26 -14
- package/src/index.js +11 -44
- package/src/platforms.js +10 -3
- package/src/prompts.js +60 -2
- package/src/scaffold.js +26 -14
- package/bundled/dev-pipeline/scripts/prizmkit-test-gate.py +0 -446
- package/bundled/dev-pipeline/templates/sections/log-size-awareness.md +0 -20
- package/bundled/dev-pipeline/tests/test_prizmkit_test_gate.py +0 -107
package/src/config.js
CHANGED
|
@@ -48,7 +48,7 @@ import {
|
|
|
48
48
|
import { detectPlatform } from './detect-platform.js';
|
|
49
49
|
import {
|
|
50
50
|
selectPlatform,
|
|
51
|
-
|
|
51
|
+
selectAiCliLaunch,
|
|
52
52
|
selectSkillSuite,
|
|
53
53
|
selectRulesPreset,
|
|
54
54
|
confirmTeamMode,
|
|
@@ -56,6 +56,7 @@ import {
|
|
|
56
56
|
} from './prompts.js';
|
|
57
57
|
import { isKnownPlatform, platformLabel, projectMemoryFile, resolvePayloadPlatforms } from './platforms.js';
|
|
58
58
|
import { normalizeRuntime, runtimeLabel } from './runtimes.js';
|
|
59
|
+
import { applyAiCliLaunchToConfig, resolveAiCliLaunchSelection, storedAiCliLaunch } from './ai-cli-launch.js';
|
|
59
60
|
|
|
60
61
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
61
62
|
const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));
|
|
@@ -367,6 +368,7 @@ export async function runConfig(directory, options = {}) {
|
|
|
367
368
|
team: oldManifest.options?.team ?? true,
|
|
368
369
|
pipeline: oldManifest.options?.pipeline ?? true,
|
|
369
370
|
aiCli: userConfig.ai_cli || oldManifest.options?.aiCli || '',
|
|
371
|
+
aiCliLaunch: storedAiCliLaunch(userConfig),
|
|
370
372
|
};
|
|
371
373
|
|
|
372
374
|
if (options.platform !== undefined && !isKnownPlatform(options.platform)) {
|
|
@@ -393,12 +395,18 @@ export async function runConfig(directory, options = {}) {
|
|
|
393
395
|
if (nonInteractive) {
|
|
394
396
|
// Non-interactive: only change what's explicitly specified via CLI options
|
|
395
397
|
if (!platformManifestNeedsNormalization && !runtimeManifestNeedsNormalization && !runtimeOptionNeedsNormalization && !options.platform && !options.skills && !options.rules && options.runtime === undefined
|
|
396
|
-
&& options.aiCli === undefined && options.team === undefined && options.pipeline === undefined) {
|
|
398
|
+
&& options.aiCli === undefined && options.headlessPromptArg === undefined && options.headlessExtraArgs === undefined && options.team === undefined && options.pipeline === undefined) {
|
|
397
399
|
console.log(chalk.yellow(' ⚠ 非交互式模式下未指定任何变更。'));
|
|
398
|
-
console.log(chalk.gray(' 使用 --platform, --runtime, --skills, --rules, --ai-cli, --team/--no-team, --pipeline/--no-pipeline'));
|
|
400
|
+
console.log(chalk.gray(' 使用 --platform, --runtime, --skills, --rules, --ai-cli, --headless-prompt-arg, --headless-extra-args, --team/--no-team, --pipeline/--no-pipeline'));
|
|
399
401
|
return;
|
|
400
402
|
}
|
|
401
403
|
|
|
404
|
+
const aiCliValue = options.aiCli !== undefined ? options.aiCli : currentConfig.aiCli;
|
|
405
|
+
const aiCliLaunchValue = resolveAiCliLaunchSelection(aiCliValue, {
|
|
406
|
+
headlessPromptArg: options.headlessPromptArg,
|
|
407
|
+
headlessExtraArgs: options.headlessExtraArgs,
|
|
408
|
+
existingLaunch: currentConfig.aiCliLaunch,
|
|
409
|
+
});
|
|
402
410
|
newConfig = {
|
|
403
411
|
platform: options.platform || currentConfig.platform,
|
|
404
412
|
runtime: optionRuntime || currentConfig.runtime,
|
|
@@ -406,7 +414,8 @@ export async function runConfig(directory, options = {}) {
|
|
|
406
414
|
rules: options.rules || currentConfig.rules,
|
|
407
415
|
team: options.team !== undefined ? options.team : currentConfig.team,
|
|
408
416
|
pipeline: options.pipeline !== undefined ? options.pipeline : currentConfig.pipeline,
|
|
409
|
-
aiCli:
|
|
417
|
+
aiCli: aiCliLaunchValue.aiCli,
|
|
418
|
+
aiCliLaunch: aiCliLaunchValue.aiCliLaunch,
|
|
410
419
|
};
|
|
411
420
|
} else {
|
|
412
421
|
// Interactive: let user select each setting
|
|
@@ -417,7 +426,7 @@ export async function runConfig(directory, options = {}) {
|
|
|
417
426
|
|
|
418
427
|
const newRuntime = optionRuntime || currentConfig.runtime;
|
|
419
428
|
const newPlatform = await selectPlatform(currentConfig.platform, detected);
|
|
420
|
-
const
|
|
429
|
+
const aiCliSelection = await selectAiCliLaunch(currentConfig.aiCli, detected, currentConfig.aiCliLaunch);
|
|
421
430
|
|
|
422
431
|
const metadata = await loadMetadata();
|
|
423
432
|
const newSuite = await selectSkillSuite(currentConfig.suite, metadata);
|
|
@@ -432,7 +441,8 @@ export async function runConfig(directory, options = {}) {
|
|
|
432
441
|
rules: newRules,
|
|
433
442
|
team: newTeam,
|
|
434
443
|
pipeline: newPipeline,
|
|
435
|
-
aiCli:
|
|
444
|
+
aiCli: aiCliSelection.aiCli,
|
|
445
|
+
aiCliLaunch: aiCliSelection.aiCliLaunch,
|
|
436
446
|
};
|
|
437
447
|
} catch (err) {
|
|
438
448
|
if (err.message?.includes('User force closed')) {
|
|
@@ -463,6 +473,9 @@ export async function runConfig(directory, options = {}) {
|
|
|
463
473
|
if (newConfig.aiCli !== currentConfig.aiCli) {
|
|
464
474
|
changes.push(`AI CLI: ${currentConfig.aiCli || '(未设置)'} → ${newConfig.aiCli || '(未设置)'}`);
|
|
465
475
|
}
|
|
476
|
+
if (JSON.stringify(newConfig.aiCliLaunch || null) !== JSON.stringify(currentConfig.aiCliLaunch || null)) {
|
|
477
|
+
changes.push('AI CLI 无头启动参数已更新');
|
|
478
|
+
}
|
|
466
479
|
if (newConfig.suite !== currentConfig.suite) {
|
|
467
480
|
changes.push(`技能套件: ${currentConfig.suite} → ${newConfig.suite}`);
|
|
468
481
|
}
|
|
@@ -646,20 +659,19 @@ export async function runConfig(directory, options = {}) {
|
|
|
646
659
|
await installPrizmkitScripts(projectRoot, false, newConfig.runtime);
|
|
647
660
|
}
|
|
648
661
|
|
|
649
|
-
// 5h. Update .prizmkit/config.json (ai_cli)
|
|
650
|
-
if (newConfig.aiCli !== currentConfig.aiCli) {
|
|
662
|
+
// 5h. Update .prizmkit/config.json (ai_cli + custom launch profile)
|
|
663
|
+
if (newConfig.aiCli !== currentConfig.aiCli || JSON.stringify(newConfig.aiCliLaunch || null) !== JSON.stringify(currentConfig.aiCliLaunch || null)) {
|
|
651
664
|
const prizmkitDir = path.join(projectRoot, '.prizmkit');
|
|
652
665
|
await fs.ensureDir(prizmkitDir);
|
|
653
666
|
let existingConfig = {};
|
|
654
667
|
if (await fs.pathExists(configPath)) {
|
|
655
668
|
try { existingConfig = await fs.readJSON(configPath); } catch { /* ignore */ }
|
|
656
669
|
}
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
}
|
|
662
|
-
await fs.writeJSON(configPath, existingConfig, { spaces: 2 });
|
|
670
|
+
const nextConfig = applyAiCliLaunchToConfig(existingConfig, {
|
|
671
|
+
aiCli: newConfig.aiCli,
|
|
672
|
+
aiCliLaunch: newConfig.aiCliLaunch,
|
|
673
|
+
});
|
|
674
|
+
await fs.writeJSON(configPath, nextConfig, { spaces: 2 });
|
|
663
675
|
console.log(chalk.green(`\n ✓ .prizmkit/config.json (ai_cli: ${newConfig.aiCli || '(cleared)'})`));
|
|
664
676
|
}
|
|
665
677
|
|
package/src/index.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* 然后调用 scaffold.js 执行纯净安装。
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { select, confirm
|
|
8
|
+
import { select, confirm } from '@inquirer/prompts';
|
|
9
9
|
import chalk from 'chalk';
|
|
10
10
|
import { readFileSync } from 'fs';
|
|
11
11
|
import { dirname, join } from 'path';
|
|
@@ -16,6 +16,8 @@ import { scaffold } from './scaffold.js';
|
|
|
16
16
|
import { loadMetadata } from './metadata.js';
|
|
17
17
|
import { platformLabel } from './platforms.js';
|
|
18
18
|
import { normalizeRuntime, runtimeLabel } from './runtimes.js';
|
|
19
|
+
import { resolveAiCliLaunchSelection } from './ai-cli-launch.js';
|
|
20
|
+
import { selectAiCliLaunch } from './prompts.js';
|
|
19
21
|
|
|
20
22
|
export { runUpgrade } from './upgrade.js';
|
|
21
23
|
|
|
@@ -75,6 +77,10 @@ export async function runScaffold(directory, options) {
|
|
|
75
77
|
openCliAutoDownload: options.openCliAutoDownload !== false,
|
|
76
78
|
rules: options.rules || 'recommended',
|
|
77
79
|
aiCli: options.aiCli || '',
|
|
80
|
+
aiCliLaunch: resolveAiCliLaunchSelection(options.aiCli || '', {
|
|
81
|
+
headlessPromptArg: options.headlessPromptArg,
|
|
82
|
+
headlessExtraArgs: options.headlessExtraArgs,
|
|
83
|
+
}).aiCliLaunch,
|
|
78
84
|
externalSkills: options.externalSkills ? options.externalSkills.split(',').map(s => s.trim()).filter(Boolean) : [],
|
|
79
85
|
projectRoot,
|
|
80
86
|
dryRun: options.dryRun || false,
|
|
@@ -112,49 +118,9 @@ export async function runScaffold(directory, options) {
|
|
|
112
118
|
});
|
|
113
119
|
|
|
114
120
|
// 2.5. AI CLI 命令配置(独立于平台,决定实际运行的可执行命令)
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
value: 'cbc',
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
name: `claude — Claude Code${detected.claude ? chalk.green(' ✓ 已安装') : chalk.gray(' (未检测到)')}`,
|
|
122
|
-
value: 'claude',
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
name: `codex — Codex CLI${detected.codex ? chalk.green(' ✓ 已安装') : chalk.gray(' (未检测到)')}`,
|
|
126
|
-
value: 'codex',
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
name: '自定义 — 输入其他命令',
|
|
130
|
-
value: '__custom__',
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
name: '跳过 — 稍后手动配置',
|
|
134
|
-
value: '',
|
|
135
|
-
},
|
|
136
|
-
];
|
|
137
|
-
|
|
138
|
-
// 如果检测到的推荐命令不在固定列表里,默认选"自定义"
|
|
139
|
-
const knownCliValues = ['cbc', 'claude', 'codex'];
|
|
140
|
-
const cliDefault = knownCliValues.includes(detected.suggestedCli)
|
|
141
|
-
? detected.suggestedCli
|
|
142
|
-
: (detected.suggestedCli ? '__custom__' : '');
|
|
143
|
-
|
|
144
|
-
const cliSelection = await select({
|
|
145
|
-
message: '选择底层 AI CLI 可执行命令:',
|
|
146
|
-
choices: cliChoices,
|
|
147
|
-
default: cliDefault,
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
let aiCli = cliSelection;
|
|
151
|
-
if (cliSelection === '__custom__') {
|
|
152
|
-
aiCli = await input({
|
|
153
|
-
message: '输入自定义 AI CLI 命令:',
|
|
154
|
-
default: knownCliValues.includes(detected.suggestedCli) ? '' : detected.suggestedCli,
|
|
155
|
-
validate: (v) => v.trim() ? true : '请输入命令',
|
|
156
|
-
});
|
|
157
|
-
}
|
|
121
|
+
const aiCliSelection = await selectAiCliLaunch('', detected);
|
|
122
|
+
const aiCli = aiCliSelection.aiCli;
|
|
123
|
+
const aiCliLaunch = aiCliSelection.aiCliLaunch;
|
|
158
124
|
|
|
159
125
|
// 2. 选择技能套件
|
|
160
126
|
const skillSuiteChoice = await select({
|
|
@@ -275,6 +241,7 @@ export async function runScaffold(directory, options) {
|
|
|
275
241
|
openCliAutoDownload,
|
|
276
242
|
rules: rulesPreset,
|
|
277
243
|
aiCli: aiCli || '',
|
|
244
|
+
aiCliLaunch,
|
|
278
245
|
externalSkills: selectedExternalSkills,
|
|
279
246
|
projectRoot,
|
|
280
247
|
dryRun: options.dryRun || false,
|
package/src/platforms.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { isBuiltInAiCli } from './ai-cli-launch.js';
|
|
2
|
+
|
|
1
3
|
export const PLATFORM_IDS = ['codebuddy', 'claude', 'codex'];
|
|
2
4
|
export const PLATFORM_GROUPS = {
|
|
3
5
|
all: PLATFORM_IDS,
|
|
@@ -12,11 +14,16 @@ export function expandPlatforms(platform) {
|
|
|
12
14
|
|
|
13
15
|
export function platformFromAiCli(aiCli) {
|
|
14
16
|
if (!aiCli || typeof aiCli !== 'string') return null;
|
|
17
|
+
try {
|
|
18
|
+
if (!isBuiltInAiCli(aiCli)) return null;
|
|
19
|
+
} catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
15
22
|
const token = aiCli.trim().split(/\s+/)[0]?.replace(/^['"]|['"]$/g, '');
|
|
16
23
|
const name = token.split(/[\\/]/).pop()?.toLowerCase() || '';
|
|
17
|
-
if (name
|
|
18
|
-
if (name
|
|
19
|
-
if (name
|
|
24
|
+
if (name === 'claude') return 'claude';
|
|
25
|
+
if (name === 'codex') return 'codex';
|
|
26
|
+
if (name === 'cbc' || name === 'codebuddy') return 'codebuddy';
|
|
20
27
|
return null;
|
|
21
28
|
}
|
|
22
29
|
|
package/src/prompts.js
CHANGED
|
@@ -6,17 +6,36 @@
|
|
|
6
6
|
import { select, confirm, checkbox, input } from '@inquirer/prompts';
|
|
7
7
|
import chalk from 'chalk';
|
|
8
8
|
import { platformLabel } from './platforms.js';
|
|
9
|
+
import {
|
|
10
|
+
formatCliArgsForPrompt,
|
|
11
|
+
isCustomAiCli,
|
|
12
|
+
resolveAiCliLaunchSelection,
|
|
13
|
+
storedAiCliLaunch,
|
|
14
|
+
tokenizeCliArgs,
|
|
15
|
+
} from './ai-cli-launch.js';
|
|
9
16
|
|
|
10
17
|
let selectPlatformPrompt = select;
|
|
18
|
+
let selectAiCliPrompt = select;
|
|
19
|
+
let inputPrompt = input;
|
|
11
20
|
|
|
12
21
|
export function __setSelectPlatformPromptForTests(promptFn) {
|
|
13
22
|
selectPlatformPrompt = promptFn;
|
|
14
23
|
}
|
|
15
24
|
|
|
25
|
+
export function __setAiCliPromptsForTests({ select: selectFn, input: inputFn } = {}) {
|
|
26
|
+
if (selectFn) selectAiCliPrompt = selectFn;
|
|
27
|
+
if (inputFn) inputPrompt = inputFn;
|
|
28
|
+
}
|
|
29
|
+
|
|
16
30
|
export function __resetSelectPlatformPromptForTests() {
|
|
17
31
|
selectPlatformPrompt = select;
|
|
18
32
|
}
|
|
19
33
|
|
|
34
|
+
export function __resetAiCliPromptsForTests() {
|
|
35
|
+
selectAiCliPrompt = select;
|
|
36
|
+
inputPrompt = input;
|
|
37
|
+
}
|
|
38
|
+
|
|
20
39
|
/**
|
|
21
40
|
* Select target platform (codebuddy, claude, codex, or all).
|
|
22
41
|
* @param {string} currentPlatform - current platform value
|
|
@@ -94,7 +113,7 @@ export async function selectAiCli(currentCommand, detected = {}) {
|
|
|
94
113
|
? currentCommand
|
|
95
114
|
: (currentCommand ? '__custom__' : (detected.suggestedCli || ''));
|
|
96
115
|
|
|
97
|
-
const cliSelection = await
|
|
116
|
+
const cliSelection = await selectAiCliPrompt({
|
|
98
117
|
message: '选择底层 AI CLI 可执行命令:',
|
|
99
118
|
choices: cliChoices,
|
|
100
119
|
default: cliDefault,
|
|
@@ -102,7 +121,7 @@ export async function selectAiCli(currentCommand, detected = {}) {
|
|
|
102
121
|
|
|
103
122
|
let aiCli = cliSelection;
|
|
104
123
|
if (cliSelection === '__custom__') {
|
|
105
|
-
aiCli = await
|
|
124
|
+
aiCli = await inputPrompt({
|
|
106
125
|
message: '输入自定义 AI CLI 命令:',
|
|
107
126
|
default: currentCommand || (detected.suggestedCli || ''),
|
|
108
127
|
validate: (v) => v.trim() ? true : '请输入命令',
|
|
@@ -112,6 +131,45 @@ export async function selectAiCli(currentCommand, detected = {}) {
|
|
|
112
131
|
return aiCli;
|
|
113
132
|
}
|
|
114
133
|
|
|
134
|
+
export async function selectAiCliLaunch(currentCommand, detected = {}, currentLaunch = null) {
|
|
135
|
+
const aiCli = await selectAiCli(currentCommand, detected);
|
|
136
|
+
if (!isCustomAiCli(aiCli)) {
|
|
137
|
+
return resolveAiCliLaunchSelection(aiCli);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const existingLaunch = storedAiCliLaunch({ ai_cli_launch: currentLaunch }) || currentLaunch || {};
|
|
141
|
+
const promptArg = await inputPrompt({
|
|
142
|
+
message: '无头模式的参数(比如-p):',
|
|
143
|
+
default: existingLaunch.prompt_arg || '-p',
|
|
144
|
+
validate: (v) => {
|
|
145
|
+
try {
|
|
146
|
+
resolveAiCliLaunchSelection(aiCli, { headlessPromptArg: v, headlessExtraArgs: existingLaunch.extra_args || [] });
|
|
147
|
+
return true;
|
|
148
|
+
} catch (err) {
|
|
149
|
+
return err.message;
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
const extraArgsDefault = formatCliArgsForPrompt(existingLaunch.extra_args || []);
|
|
154
|
+
const extraArgs = await inputPrompt({
|
|
155
|
+
message: '无头模式希望添加的参数:',
|
|
156
|
+
default: extraArgsDefault,
|
|
157
|
+
validate: (v) => {
|
|
158
|
+
try {
|
|
159
|
+
tokenizeCliArgs(v);
|
|
160
|
+
return true;
|
|
161
|
+
} catch (err) {
|
|
162
|
+
return err.message;
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
return resolveAiCliLaunchSelection(aiCli, {
|
|
168
|
+
headlessPromptArg: promptArg,
|
|
169
|
+
headlessExtraArgs: extraArgs,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
115
173
|
/**
|
|
116
174
|
* Select skill suite (core, minimal, or recommended:<type>).
|
|
117
175
|
* @param {string} currentSuite - current suite value
|
package/src/scaffold.js
CHANGED
|
@@ -29,6 +29,7 @@ import { generateGitignore } from './gitignore-template.js';
|
|
|
29
29
|
import { buildManifest, writeManifest } from './manifest.js';
|
|
30
30
|
import { defaultCliForPlatform, expandPlatforms, isKnownPlatform, platformLabel, projectMemoryFile, resolvePayloadPlatforms } from './platforms.js';
|
|
31
31
|
import { normalizeRuntime, runtimeLabel } from './runtimes.js';
|
|
32
|
+
import { applyAiCliLaunchToConfig, resolveAiCliLaunchSelection } from './ai-cli-launch.js';
|
|
32
33
|
|
|
33
34
|
const __scaffoldDirname = dirname(fileURLToPath(import.meta.url));
|
|
34
35
|
const scaffoldPkg = JSON.parse(readFileSync(join(__scaffoldDirname, '..', 'package.json'), 'utf-8'));
|
|
@@ -895,11 +896,11 @@ export async function installProjectMemory(platform, projectRoot, dryRun) {
|
|
|
895
896
|
let templateContent = (await fs.readFile(templatePath, 'utf-8')).trimEnd();
|
|
896
897
|
if (platform === 'codex') {
|
|
897
898
|
templateContent = templateContent.replace(
|
|
898
|
-
'### Available Commands\nRun `/
|
|
899
|
+
'### Available Commands\nRun `/prizmkit` to see all available PrizmKit commands.',
|
|
899
900
|
`### Available PrizmKit Skills
|
|
900
901
|
Codex discovers repository skills from \`.agents/skills/\`. When a user or prompt mentions \`/prizmkit-xxx\`, use the matching skill at \`.agents/skills/prizmkit-xxx/SKILL.md\`.
|
|
901
902
|
|
|
902
|
-
- Start with \`.agents/skills/
|
|
903
|
+
- Start with \`.agents/skills/prizmkit/SKILL.md\` to see all available PrizmKit skills.
|
|
903
904
|
- Skill assets and references live inside each \`.agents/skills/<skill>/\` directory.
|
|
904
905
|
- PrizmKit behavioral rules live in \`.agents/rules/\`; read the relevant Markdown guidance before commit, documentation, or context-loading work.
|
|
905
906
|
- Native Codex subagents live in \`.codex/agents/*.toml\`; use them when spawning or coordinating subagents.`
|
|
@@ -1430,13 +1431,18 @@ export const EXTRAS_REGISTRY = {
|
|
|
1430
1431
|
* @param {boolean} config.dryRun - 是否为预览模式
|
|
1431
1432
|
*/
|
|
1432
1433
|
export async function scaffold(config) {
|
|
1433
|
-
const { platform, skills, team, pipeline, rules, aiCli, externalSkills, playwrightCli, openCli, openCliAutoDownload, projectRoot, dryRun } = config;
|
|
1434
|
+
const { platform, skills, team, pipeline, rules, aiCli, aiCliLaunch, externalSkills, playwrightCli, openCli, openCliAutoDownload, projectRoot, dryRun } = config;
|
|
1434
1435
|
const runtime = normalizeRuntime(config.runtime);
|
|
1436
|
+
const launchSelection = resolveAiCliLaunchSelection(aiCli || '', {
|
|
1437
|
+
aiCliLaunch,
|
|
1438
|
+
existingLaunch: aiCliLaunch,
|
|
1439
|
+
});
|
|
1440
|
+
const resolvedAiCli = launchSelection.aiCli;
|
|
1435
1441
|
if (!isKnownPlatform(platform)) {
|
|
1436
1442
|
throw new Error(`Unknown platform "${platform}". Expected codebuddy, claude, codex, or all.`);
|
|
1437
1443
|
}
|
|
1438
1444
|
const platforms = expandPlatforms(platform);
|
|
1439
|
-
const payloadPlatforms = resolvePayloadPlatforms(platform,
|
|
1445
|
+
const payloadPlatforms = resolvePayloadPlatforms(platform, resolvedAiCli);
|
|
1440
1446
|
|
|
1441
1447
|
if (dryRun) {
|
|
1442
1448
|
console.log(chalk.yellow('\n [DRY RUN] 预览将要安装的内容:\n'));
|
|
@@ -1488,21 +1494,27 @@ export async function scaffold(config) {
|
|
|
1488
1494
|
await installGitignore(projectRoot, { pipeline }, dryRun);
|
|
1489
1495
|
|
|
1490
1496
|
// 8. 写入 .prizmkit/config.json(如果指定了 aiCli)
|
|
1491
|
-
if (
|
|
1497
|
+
if (resolvedAiCli) {
|
|
1492
1498
|
const prizmkitDir = path.join(projectRoot, '.prizmkit');
|
|
1493
1499
|
const configPath = path.join(prizmkitDir, 'config.json');
|
|
1494
1500
|
|
|
1495
1501
|
if (dryRun) {
|
|
1496
|
-
|
|
1502
|
+
const customText = launchSelection.aiCliLaunch
|
|
1503
|
+
? `, prompt_arg: ${launchSelection.aiCliLaunch.prompt_arg}`
|
|
1504
|
+
: '';
|
|
1505
|
+
console.log(chalk.gray(` [dry-run] .prizmkit/config.json (ai_cli: ${resolvedAiCli}${customText})`));
|
|
1497
1506
|
} else {
|
|
1498
1507
|
await fs.ensureDir(prizmkitDir);
|
|
1499
1508
|
let existingConfig = {};
|
|
1500
1509
|
if (await fs.pathExists(configPath)) {
|
|
1501
1510
|
existingConfig = await fs.readJSON(configPath);
|
|
1502
1511
|
}
|
|
1503
|
-
|
|
1504
|
-
await fs.writeJSON(configPath,
|
|
1505
|
-
|
|
1512
|
+
const nextConfig = applyAiCliLaunchToConfig(existingConfig, launchSelection);
|
|
1513
|
+
await fs.writeJSON(configPath, nextConfig, { spaces: 2 });
|
|
1514
|
+
const customText = launchSelection.aiCliLaunch
|
|
1515
|
+
? `, prompt_arg: ${launchSelection.aiCliLaunch.prompt_arg}`
|
|
1516
|
+
: '';
|
|
1517
|
+
console.log(chalk.green(` ✓ .prizmkit/config.json (ai_cli: ${resolvedAiCli}${customText})`));
|
|
1506
1518
|
}
|
|
1507
1519
|
}
|
|
1508
1520
|
|
|
@@ -1516,7 +1528,7 @@ export async function scaffold(config) {
|
|
|
1516
1528
|
const skillDef = knownSkills.find(s => s.name === name);
|
|
1517
1529
|
if (skillDef) {
|
|
1518
1530
|
try {
|
|
1519
|
-
await installExternalSkill(skillDef, platform, projectRoot, dryRun,
|
|
1531
|
+
await installExternalSkill(skillDef, platform, projectRoot, dryRun, resolvedAiCli);
|
|
1520
1532
|
console.log(chalk.green(` ✓ ${name} (external)`));
|
|
1521
1533
|
} catch (e) {
|
|
1522
1534
|
console.log(chalk.yellow(` ⚠ ${name} 安装失败,跳过: ${e.message}`));
|
|
@@ -1524,7 +1536,7 @@ export async function scaffold(config) {
|
|
|
1524
1536
|
}
|
|
1525
1537
|
}
|
|
1526
1538
|
if (!dryRun) {
|
|
1527
|
-
await cleanExternalSkillArtifacts(projectRoot, platform,
|
|
1539
|
+
await cleanExternalSkillArtifacts(projectRoot, platform, resolvedAiCli);
|
|
1528
1540
|
}
|
|
1529
1541
|
}
|
|
1530
1542
|
|
|
@@ -1582,7 +1594,7 @@ export async function scaffold(config) {
|
|
|
1582
1594
|
rules: ruleFileNames,
|
|
1583
1595
|
pipeline: installedPipelineFiles,
|
|
1584
1596
|
team,
|
|
1585
|
-
aiCli,
|
|
1597
|
+
aiCli: resolvedAiCli,
|
|
1586
1598
|
rulesPreset: rulesPresetName,
|
|
1587
1599
|
extras: activeExtras,
|
|
1588
1600
|
payloadPlatforms,
|
|
@@ -1608,7 +1620,7 @@ export async function scaffold(config) {
|
|
|
1608
1620
|
: platforms.includes('codebuddy') ? 'codebuddy'
|
|
1609
1621
|
: platforms[0];
|
|
1610
1622
|
const defaultCli = defaultCliForPlatform(mainPlatform);
|
|
1611
|
-
const cli =
|
|
1623
|
+
const cli = resolvedAiCli || defaultCli;
|
|
1612
1624
|
|
|
1613
1625
|
console.log('');
|
|
1614
1626
|
console.log(' 下一步:');
|
|
@@ -1643,7 +1655,7 @@ export async function scaffold(config) {
|
|
|
1643
1655
|
const browserTools = [playwrightCli && 'playwright-cli', openCli && 'opencli'].filter(Boolean);
|
|
1644
1656
|
console.log(chalk.gray(` 浏览器工具: ${browserTools.length ? '已安装 (' + browserTools.join(' + ') + ')' : '未安装'}`));
|
|
1645
1657
|
console.log(chalk.gray(` 规则: ${rules || 'recommended'}`));
|
|
1646
|
-
if (
|
|
1658
|
+
if (resolvedAiCli) console.log(chalk.gray(` AI CLI: ${resolvedAiCli}`));
|
|
1647
1659
|
console.log('');
|
|
1648
1660
|
}
|
|
1649
1661
|
}
|