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.
Files changed (86) hide show
  1. package/bin/create-prizmkit.js +4 -0
  2. package/bundled/VERSION.json +3 -3
  3. package/bundled/dev-pipeline/prizmkit_runtime/cli.py +20 -0
  4. package/bundled/dev-pipeline/prizmkit_runtime/commands.py +1 -0
  5. package/bundled/dev-pipeline/prizmkit_runtime/config.py +81 -14
  6. package/bundled/dev-pipeline/prizmkit_runtime/gitops.py +21 -0
  7. package/bundled/dev-pipeline/prizmkit_runtime/heartbeat.py +19 -8
  8. package/bundled/dev-pipeline/prizmkit_runtime/interoperability.py +1 -1
  9. package/bundled/dev-pipeline/prizmkit_runtime/launch_profiles.py +18 -0
  10. package/bundled/dev-pipeline/prizmkit_runtime/platform_detection.py +208 -0
  11. package/bundled/dev-pipeline/prizmkit_runtime/runner_bookkeeping.py +22 -2
  12. package/bundled/dev-pipeline/prizmkit_runtime/runner_recovery.py +3 -1
  13. package/bundled/dev-pipeline/prizmkit_runtime/runners.py +20 -1
  14. package/bundled/dev-pipeline/prizmkit_runtime/runtime_helper.py +508 -0
  15. package/bundled/dev-pipeline/prizmkit_runtime/sessions.py +151 -30
  16. package/bundled/dev-pipeline/scripts/continuation.py +0 -1
  17. package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +8 -46
  18. package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +9 -34
  19. package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +42 -33
  20. package/bundled/dev-pipeline/scripts/prizmkit-runtime-helper.py +27 -0
  21. package/bundled/dev-pipeline/scripts/utils.py +94 -0
  22. package/bundled/dev-pipeline/templates/agent-prompts/critic-plan-challenge.md +4 -3
  23. package/bundled/dev-pipeline/templates/bootstrap-prompt.md +1 -1
  24. package/bundled/dev-pipeline/templates/bootstrap-tier1.md +39 -65
  25. package/bundled/dev-pipeline/templates/bootstrap-tier2.md +58 -96
  26. package/bundled/dev-pipeline/templates/bootstrap-tier3.md +54 -95
  27. package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +6 -18
  28. package/bundled/dev-pipeline/templates/refactor-bootstrap-prompt.md +5 -17
  29. package/bundled/dev-pipeline/templates/sections/checkpoint-system.md +14 -48
  30. package/bundled/dev-pipeline/templates/sections/context-budget-rules.md +7 -13
  31. package/bundled/dev-pipeline/templates/sections/feature-context.md +0 -4
  32. package/bundled/dev-pipeline/templates/sections/phase-browser-verification-auto.md +31 -61
  33. package/bundled/dev-pipeline/templates/sections/phase-browser-verification-opencli.md +21 -37
  34. package/bundled/dev-pipeline/templates/sections/phase-browser-verification.md +22 -69
  35. package/bundled/dev-pipeline/templates/sections/phase-commit-full.md +0 -14
  36. package/bundled/dev-pipeline/templates/sections/phase-commit.md +0 -14
  37. package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-agent-suffix.md +0 -7
  38. package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-base.md +1 -3
  39. package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-lite-suffix.md +0 -7
  40. package/bundled/dev-pipeline/templates/sections/phase-critic-plan-full.md +7 -9
  41. package/bundled/dev-pipeline/templates/sections/phase-critic-plan.md +4 -8
  42. package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +0 -7
  43. package/bundled/dev-pipeline/templates/sections/phase-implement-full.md +0 -7
  44. package/bundled/dev-pipeline/templates/sections/phase-implement-lite.md +0 -7
  45. package/bundled/dev-pipeline/templates/sections/phase-plan-agent.md +3 -10
  46. package/bundled/dev-pipeline/templates/sections/phase-plan-lite.md +2 -9
  47. package/bundled/dev-pipeline/templates/sections/phase-prizmkit-test.md +15 -16
  48. package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +1 -8
  49. package/bundled/dev-pipeline/templates/sections/phase-review-full.md +1 -8
  50. package/bundled/dev-pipeline/templates/sections/phase-specify-plan-full.md +9 -15
  51. package/bundled/dev-pipeline/templates/sections/phase0-init.md +1 -8
  52. package/bundled/dev-pipeline/templates/sections/phase0-test-baseline.md +2 -15
  53. package/bundled/dev-pipeline/templates/sections/subagent-timeout-recovery.md +1 -1
  54. package/bundled/dev-pipeline/tests/conftest.py +0 -1
  55. package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +392 -23
  56. package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +37 -17
  57. package/bundled/dev-pipeline/tests/test_generate_refactor_prompt.py +118 -14
  58. package/bundled/dev-pipeline/tests/test_python_runner_parity.py +79 -2
  59. package/bundled/dev-pipeline/tests/test_runtime_helper.py +211 -0
  60. package/bundled/dev-pipeline/tests/test_unified_cli.py +663 -13
  61. package/bundled/skills/_metadata.json +4 -4
  62. package/bundled/skills/app-planner/SKILL.md +1 -1
  63. package/bundled/skills/app-planner/references/architecture-decisions.md +1 -1
  64. package/bundled/skills/bug-fix-workflow/SKILL.md +174 -128
  65. package/bundled/skills/bug-planner/SKILL.md +101 -15
  66. package/bundled/skills/bug-planner/references/severity-rules.md +20 -8
  67. package/bundled/skills/feature-planner/SKILL.md +87 -8
  68. package/bundled/skills/feature-planner/assets/planning-guide.md +34 -10
  69. package/bundled/skills/feature-workflow/SKILL.md +100 -81
  70. package/bundled/skills/{prizm-kit → prizmkit}/SKILL.md +1 -1
  71. package/bundled/skills/prizmkit-code-review/SKILL.md +1 -1
  72. package/bundled/skills/refactor-planner/SKILL.md +88 -7
  73. package/bundled/skills/refactor-planner/references/fast-path.md +2 -1
  74. package/bundled/skills/refactor-planner/references/planning-phases.md +29 -11
  75. package/bundled/skills/refactor-workflow/SKILL.md +116 -57
  76. package/bundled/templates/project-memory-template.md +1 -1
  77. package/package.json +1 -1
  78. package/src/ai-cli-launch.js +194 -0
  79. package/src/config.js +26 -14
  80. package/src/index.js +11 -44
  81. package/src/platforms.js +10 -3
  82. package/src/prompts.js +60 -2
  83. package/src/scaffold.js +26 -14
  84. package/bundled/dev-pipeline/scripts/prizmkit-test-gate.py +0 -446
  85. package/bundled/dev-pipeline/templates/sections/log-size-awareness.md +0 -20
  86. 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
- selectAiCli,
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: options.aiCli !== undefined ? options.aiCli : currentConfig.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 newAiCli = await selectAiCli(currentConfig.aiCli, detected);
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: newAiCli,
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
- if (newConfig.aiCli) {
658
- existingConfig.ai_cli = newConfig.aiCli;
659
- } else {
660
- delete existingConfig.ai_cli;
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, input } from '@inquirer/prompts';
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 cliChoices = [
116
- {
117
- name: `cbc CodeBuddy CLI${detected.cbc ? chalk.green(' ✓ 已安装') : chalk.gray(' (未检测到)')}`,
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.includes('claude')) return 'claude';
18
- if (name.includes('codex')) return 'codex';
19
- if (name.includes('cbc') || name.includes('codebuddy')) return 'codebuddy';
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 select({
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 input({
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 `/prizm-kit` to see all available PrizmKit commands.',
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/prizm-kit/SKILL.md\` to see all available PrizmKit 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, aiCli);
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 (aiCli) {
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
- console.log(chalk.gray(` [dry-run] .prizmkit/config.json (ai_cli: ${aiCli})`));
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
- existingConfig.ai_cli = aiCli;
1504
- await fs.writeJSON(configPath, existingConfig, { spaces: 2 });
1505
- console.log(chalk.green(` ✓ .prizmkit/config.json (ai_cli: ${aiCli})`));
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, aiCli);
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, aiCli);
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 = aiCli || defaultCli;
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 (aiCli) console.log(chalk.gray(` AI CLI: ${aiCli}`));
1658
+ if (resolvedAiCli) console.log(chalk.gray(` AI CLI: ${resolvedAiCli}`));
1647
1659
  console.log('');
1648
1660
  }
1649
1661
  }