prizmkit 1.1.142 → 1.1.144
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/pi/paths.js +9 -0
- package/bundled/adapters/pi/rules-adapter.js +13 -0
- package/bundled/adapters/pi/settings-adapter.js +23 -0
- package/bundled/adapters/pi/skill-adapter.js +18 -0
- package/bundled/dev-pipeline/prizmkit_runtime/config.py +15 -3
- package/bundled/dev-pipeline/prizmkit_runtime/gitops.py +3 -1
- package/bundled/dev-pipeline/prizmkit_runtime/platform_detection.py +10 -2
- package/bundled/dev-pipeline/prizmkit_runtime/runner_bookkeeping.py +1 -0
- package/bundled/dev-pipeline/prizmkit_runtime/runner_recovery.py +1 -0
- package/bundled/dev-pipeline/prizmkit_runtime/sessions.py +26 -2
- package/bundled/dev-pipeline/scripts/parse-stream-progress.py +61 -7
- package/bundled/dev-pipeline/tests/test_unified_cli.py +88 -0
- package/bundled/skills/_metadata.json +1 -1
- package/bundled/skills/prizmkit-code-review/SKILL.md +3 -3
- package/bundled/skills/prizmkit-code-review/references/independent-code-review.md +63 -58
- package/bundled/skills/prizmkit-code-review/references/review-report-template.md +8 -1
- package/bundled/skills/prizmkit-plan/SKILL.md +3 -3
- package/bundled/skills/prizmkit-plan/assets/plan-template.md +3 -0
- package/bundled/skills/prizmkit-plan/references/independent-plan-review.md +55 -52
- package/bundled/skills/prizmkit-test/SKILL.md +3 -3
- package/bundled/skills/prizmkit-test/references/independent-test-review.md +68 -69
- package/bundled/skills/prizmkit-test/references/test-report-template.md +5 -1
- package/bundled/templates/hooks/commit-intent-status.py +50 -0
- package/bundled/templates/hooks/commit-intent.json +2 -2
- package/bundled/templates/hooks/post-command-prizm-drift.py +44 -0
- package/package.json +1 -1
- package/src/ai-cli-launch.js +1 -1
- package/src/clean.js +13 -4
- package/src/config.js +32 -5
- package/src/detect-platform.js +11 -7
- package/src/index.js +5 -0
- package/src/platforms.js +6 -2
- package/src/prompts.js +12 -4
- package/src/scaffold.js +74 -20
- package/src/upgrade.js +12 -5
package/src/prompts.js
CHANGED
|
@@ -37,13 +37,13 @@ export function __resetAiCliPromptsForTests() {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
|
-
* Select target platform (codebuddy, claude, codex, or all).
|
|
40
|
+
* Select target platform (codebuddy, claude, codex, pi, or all).
|
|
41
41
|
* @param {string} currentPlatform - current platform value
|
|
42
42
|
* @param {Object} detected - detected environment info (e.g., { cbc: true, claude: false })
|
|
43
43
|
* @returns {Promise<string>}
|
|
44
44
|
*/
|
|
45
45
|
export async function selectPlatform(currentPlatform, detected = {}) {
|
|
46
|
-
const selectablePlatforms = ['codebuddy', 'claude', 'codex', 'all'];
|
|
46
|
+
const selectablePlatforms = ['codebuddy', 'claude', 'codex', 'pi', 'all'];
|
|
47
47
|
const detectedDefault = selectablePlatforms.includes(detected.suggested)
|
|
48
48
|
? detected.suggested
|
|
49
49
|
: 'claude';
|
|
@@ -68,6 +68,10 @@ export async function selectPlatform(currentPlatform, detected = {}) {
|
|
|
68
68
|
name: `Codex (AGENTS.md + .agents/skills + .codex/)${detected.codex ? chalk.green(' ← 已检测到 codex') : ''}`,
|
|
69
69
|
value: 'codex',
|
|
70
70
|
},
|
|
71
|
+
{
|
|
72
|
+
name: `Pi (.pi/skills + .pi/APPEND_SYSTEM.md)${detected.pi ? chalk.green(' ← 已检测到 pi') : ''}`,
|
|
73
|
+
value: 'pi',
|
|
74
|
+
},
|
|
71
75
|
{
|
|
72
76
|
name: `同时安装全部平台 (${platformLabel('all')})`,
|
|
73
77
|
value: 'all',
|
|
@@ -79,7 +83,7 @@ export async function selectPlatform(currentPlatform, detected = {}) {
|
|
|
79
83
|
}
|
|
80
84
|
|
|
81
85
|
/**
|
|
82
|
-
* Select AI CLI command (cbc, claude, codex, custom, or skip).
|
|
86
|
+
* Select AI CLI command (cbc, claude, codex, pi, custom, or skip).
|
|
83
87
|
* @param {string} currentCommand - current AI CLI command
|
|
84
88
|
* @param {Object} detected - detected environment info
|
|
85
89
|
* @returns {Promise<string>} - known command, custom string, or ''
|
|
@@ -98,6 +102,10 @@ export async function selectAiCli(currentCommand, detected = {}) {
|
|
|
98
102
|
name: `codex — Codex CLI${detected.codex ? chalk.green(' ✓ 已安装') : chalk.gray(' (未检测到)')}`,
|
|
99
103
|
value: 'codex',
|
|
100
104
|
},
|
|
105
|
+
{
|
|
106
|
+
name: `pi — Pi Coding Agent${detected.pi ? chalk.green(' ✓ 已安装') : chalk.gray(' (未检测到)')}`,
|
|
107
|
+
value: 'pi',
|
|
108
|
+
},
|
|
101
109
|
{
|
|
102
110
|
name: '自定义 — 输入其他命令',
|
|
103
111
|
value: '__custom__',
|
|
@@ -108,7 +116,7 @@ export async function selectAiCli(currentCommand, detected = {}) {
|
|
|
108
116
|
},
|
|
109
117
|
];
|
|
110
118
|
|
|
111
|
-
const knownCliValues = ['cbc', 'claude', 'codex'];
|
|
119
|
+
const knownCliValues = ['cbc', 'claude', 'codex', 'pi'];
|
|
112
120
|
const cliDefault = knownCliValues.includes(currentCommand)
|
|
113
121
|
? currentCommand
|
|
114
122
|
: (currentCommand ? '__custom__' : (detected.suggestedCli || ''));
|
package/src/scaffold.js
CHANGED
|
@@ -96,6 +96,7 @@ async function removeEmptyDirectory(dirPath) {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
export async function removeRetiredAgentTeamArtifacts(platform, projectRoot, dryRun) {
|
|
99
|
+
if (platform === 'pi') return;
|
|
99
100
|
const agentDir = platform === 'claude'
|
|
100
101
|
? path.join(projectRoot, '.claude', 'agents')
|
|
101
102
|
: platform === 'codex'
|
|
@@ -231,12 +232,16 @@ export async function installSkills(platform, skills, projectRoot, dryRun, runti
|
|
|
231
232
|
// Load Claude command adapter for skill conversion
|
|
232
233
|
let convertSkillToCommand;
|
|
233
234
|
let convertSkillToCodex;
|
|
235
|
+
let convertSkillToPi;
|
|
234
236
|
if (platform === 'claude') {
|
|
235
237
|
const commandAdapter = await loadAdapter('claude', 'command-adapter.js');
|
|
236
238
|
convertSkillToCommand = commandAdapter.convertSkillToCommand;
|
|
237
239
|
} else if (platform === 'codex') {
|
|
238
240
|
const codexSkillAdapter = await loadAdapter('codex', 'skill-adapter.js');
|
|
239
241
|
convertSkillToCodex = codexSkillAdapter.convertSkill;
|
|
242
|
+
} else if (platform === 'pi') {
|
|
243
|
+
const piSkillAdapter = await loadAdapter('pi', 'skill-adapter.js');
|
|
244
|
+
convertSkillToPi = piSkillAdapter.convertSkill;
|
|
240
245
|
}
|
|
241
246
|
|
|
242
247
|
for (const skillName of skills) {
|
|
@@ -347,6 +352,25 @@ export async function installSkills(platform, skills, projectRoot, dryRun, runti
|
|
|
347
352
|
}
|
|
348
353
|
}
|
|
349
354
|
console.log(chalk.green(` ✓ .agents/skills/${skillName}/`));
|
|
355
|
+
} else if (platform === 'pi') {
|
|
356
|
+
const content = await fs.readFile(skillMdPath, 'utf8');
|
|
357
|
+
const converted = convertSkillToPi(content, skillName);
|
|
358
|
+
const targetDir = path.join(projectRoot, '.pi', 'skills', skillName);
|
|
359
|
+
|
|
360
|
+
if (dryRun) {
|
|
361
|
+
console.log(chalk.gray(` [dry-run] .pi/skills/${skillName}/`));
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
await fs.remove(targetDir);
|
|
366
|
+
await fs.ensureDir(targetDir);
|
|
367
|
+
await fs.writeFile(path.join(targetDir, 'SKILL.md'), converted);
|
|
368
|
+
for (const entry of await fs.readdir(corePath, { withFileTypes: true })) {
|
|
369
|
+
if (entry.isDirectory()) {
|
|
370
|
+
await fs.copy(path.join(corePath, entry.name), path.join(targetDir, entry.name));
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
console.log(chalk.green(` ✓ .pi/skills/${skillName}/`));
|
|
350
374
|
}
|
|
351
375
|
}
|
|
352
376
|
}
|
|
@@ -503,6 +527,18 @@ job_max_runtime_seconds = 3300
|
|
|
503
527
|
await installCodexRules(projectRoot, ruleFiles);
|
|
504
528
|
removeLegacyCodexRules(projectRoot, allRuleFileNames);
|
|
505
529
|
console.log(chalk.green(` ✓ .agents/rules/ (${ruleFiles.length} 条规则)`));
|
|
530
|
+
} else if (platform === 'pi') {
|
|
531
|
+
if (dryRun) {
|
|
532
|
+
console.log(chalk.gray(' [dry-run] .pi/settings.json'));
|
|
533
|
+
console.log(chalk.gray(` [dry-run] .pi/rules/ (${ruleFiles.length} 条规则)`));
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
const { generateSettings } = await loadAdapter('pi', 'settings-adapter.js');
|
|
537
|
+
const { installRules } = await loadAdapter('pi', 'rules-adapter.js');
|
|
538
|
+
await generateSettings(projectRoot);
|
|
539
|
+
await installRules(projectRoot, ruleFiles);
|
|
540
|
+
console.log(chalk.green(' ✓ .pi/settings.json'));
|
|
541
|
+
console.log(chalk.green(` ✓ .pi/rules/ (${ruleFiles.length} 条规则)`));
|
|
506
542
|
}
|
|
507
543
|
}
|
|
508
544
|
|
|
@@ -724,6 +760,8 @@ export async function installPrizmkitScripts(projectRoot, dryRun, runtime = 'pyt
|
|
|
724
760
|
const scripts = [
|
|
725
761
|
'validate-prizm-docs.py',
|
|
726
762
|
'diff-prizm-docs.py',
|
|
763
|
+
'commit-intent-status.py',
|
|
764
|
+
'post-command-prizm-drift.py',
|
|
727
765
|
];
|
|
728
766
|
const legacyManagedScripts = [
|
|
729
767
|
'validate-prizm-docs.sh',
|
|
@@ -925,11 +963,11 @@ export async function installProjectMemory(platform, projectRoot, dryRun) {
|
|
|
925
963
|
const templateName = 'project-memory-template.md';
|
|
926
964
|
const mainName = projectMemoryFile(platform);
|
|
927
965
|
const privateName = privateProjectMemoryFile(platform);
|
|
928
|
-
if (!
|
|
966
|
+
if (!privateName) return;
|
|
929
967
|
|
|
930
|
-
const mainPath = path.join(projectRoot, mainName);
|
|
968
|
+
const mainPath = mainName ? path.join(projectRoot, mainName) : null;
|
|
931
969
|
const privatePath = path.join(projectRoot, privateName);
|
|
932
|
-
const importPointer = `@./${privateName}
|
|
970
|
+
const importPointer = mainName ? `@./${privateName}` : null;
|
|
933
971
|
|
|
934
972
|
const templateCandidates = [
|
|
935
973
|
path.join(templatesDir, templateName),
|
|
@@ -942,7 +980,18 @@ export async function installProjectMemory(platform, projectRoot, dryRun) {
|
|
|
942
980
|
}
|
|
943
981
|
|
|
944
982
|
let templateContent = (await fs.readFile(templatePath, 'utf-8')).trimEnd();
|
|
945
|
-
if (platform === '
|
|
983
|
+
if (platform === 'pi') {
|
|
984
|
+
templateContent = templateContent.replace(
|
|
985
|
+
'### Available Commands\nRun `/prizmkit` to see all available PrizmKit commands.',
|
|
986
|
+
`### Available PrizmKit Skills
|
|
987
|
+
Pi discovers project skills from \`.pi/skills/\`. Invoke them with \`/skill:<name>\` (for example \`/skill:prizmkit-plan\`).
|
|
988
|
+
|
|
989
|
+
- Start with \`/skill:prizmkit\` to see all available PrizmKit skills.
|
|
990
|
+
- Skill assets and references live inside each \`.pi/skills/<skill>/\` directory.
|
|
991
|
+
- PrizmKit behavioral rules live in \`.pi/rules/\`; read the relevant Markdown guidance before commit, documentation, or context-loading work.
|
|
992
|
+
`
|
|
993
|
+
);
|
|
994
|
+
} else if (platform === 'codex') {
|
|
946
995
|
templateContent = templateContent.replace(
|
|
947
996
|
'### Available Commands\nRun `/prizmkit` to see all available PrizmKit commands.',
|
|
948
997
|
`### Available PrizmKit Skills
|
|
@@ -957,10 +1006,11 @@ Codex discovers repository skills from \`.agents/skills/\`. When a user or promp
|
|
|
957
1006
|
|
|
958
1007
|
if (dryRun) {
|
|
959
1008
|
console.log(chalk.gray(` [dry-run] ${privateName}`));
|
|
960
|
-
console.log(chalk.gray(` [dry-run] ${mainName} import ${importPointer}`));
|
|
1009
|
+
if (mainName) console.log(chalk.gray(` [dry-run] ${mainName} import ${importPointer}`));
|
|
961
1010
|
return;
|
|
962
1011
|
}
|
|
963
1012
|
|
|
1013
|
+
await fs.ensureDir(path.dirname(privatePath));
|
|
964
1014
|
if (!await fs.pathExists(privatePath)) {
|
|
965
1015
|
await fs.writeFile(privatePath, `${templateContent}\n`, 'utf-8');
|
|
966
1016
|
console.log(chalk.green(` ✓ ${privateName} (created PrizmKit section)`));
|
|
@@ -975,18 +1025,20 @@ Codex discovers repository skills from \`.agents/skills/\`. When a user or promp
|
|
|
975
1025
|
}
|
|
976
1026
|
}
|
|
977
1027
|
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
1028
|
+
if (mainPath && importPointer) {
|
|
1029
|
+
const existingMain = await fs.pathExists(mainPath)
|
|
1030
|
+
? await fs.readFile(mainPath, 'utf-8')
|
|
1031
|
+
: '';
|
|
1032
|
+
const mainMerge = ensureSingleImportPointer(existingMain, importPointer);
|
|
1033
|
+
logManagedProjectMemoryWarnings(mainName, mainMerge.warnings);
|
|
1034
|
+
const nextMain = mainMerge.content;
|
|
1035
|
+
if (nextMain !== existingMain) {
|
|
1036
|
+
await fs.writeFile(mainPath, nextMain, 'utf-8');
|
|
1037
|
+
const migrationSuffix = mainMerge.removedBlocks.length ? ' and migrated managed block' : '';
|
|
1038
|
+
console.log(chalk.green(` ✓ ${mainName} (imports ${privateName}${migrationSuffix})`));
|
|
1039
|
+
} else {
|
|
1040
|
+
console.log(chalk.green(` ✓ ${mainName} (import up-to-date)`));
|
|
1041
|
+
}
|
|
990
1042
|
}
|
|
991
1043
|
}
|
|
992
1044
|
|
|
@@ -1475,7 +1527,7 @@ export const EXTRAS_REGISTRY = {
|
|
|
1475
1527
|
/**
|
|
1476
1528
|
* 执行纯净安装
|
|
1477
1529
|
* @param {Object} config
|
|
1478
|
-
* @param {string} config.platform - 'codebuddy' | 'claude' | 'codex' | 'all'
|
|
1530
|
+
* @param {string} config.platform - 'codebuddy' | 'claude' | 'codex' | 'pi' | 'all'
|
|
1479
1531
|
* @param {string} [config.runtime] - 'python' (legacy aliases accepted: 'unix' | 'windows')
|
|
1480
1532
|
* @param {string} config.skills - 'core' | 'minimal' | 'recommended:<type>'
|
|
1481
1533
|
* @param {boolean} config.pipeline - 是否安装 dev-pipeline
|
|
@@ -1497,7 +1549,7 @@ export async function scaffold(config) {
|
|
|
1497
1549
|
});
|
|
1498
1550
|
const resolvedAiCli = launchSelection.aiCli;
|
|
1499
1551
|
if (!isKnownPlatform(platform)) {
|
|
1500
|
-
throw new Error(`Unknown platform "${platform}". Expected codebuddy, claude, codex, or all.`);
|
|
1552
|
+
throw new Error(`Unknown platform "${platform}". Expected codebuddy, claude, codex, pi, or all.`);
|
|
1501
1553
|
}
|
|
1502
1554
|
const platforms = expandPlatforms(platform);
|
|
1503
1555
|
const payloadPlatforms = resolvePayloadPlatforms(platform, resolvedAiCli);
|
|
@@ -1677,7 +1729,9 @@ export async function scaffold(config) {
|
|
|
1677
1729
|
console.log(` 2. ${chalk.cyan(cli)} ${chalk.gray('# 启动 AI 对话')}`);
|
|
1678
1730
|
const initInstruction = mainPlatform === 'codex'
|
|
1679
1731
|
? '说 "运行 prizmkit-init"'
|
|
1680
|
-
:
|
|
1732
|
+
: mainPlatform === 'pi'
|
|
1733
|
+
? '输入 "/skill:prizmkit-init"'
|
|
1734
|
+
: '说 "/prizmkit-init"';
|
|
1681
1735
|
console.log(` 3. ${chalk.cyan(initInstruction)} ${chalk.gray('# 初始化项目上下文')}`);
|
|
1682
1736
|
|
|
1683
1737
|
if (pipeline) {
|
package/src/upgrade.js
CHANGED
|
@@ -73,14 +73,16 @@ export async function removeSkillFiles(platform, projectRoot, skillNames, dryRun
|
|
|
73
73
|
console.log(chalk.red(` ✗ removed .codebuddy/skills/${skillName}/`));
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
|
-
} else if (platform === 'codex') {
|
|
77
|
-
const skillDir =
|
|
76
|
+
} else if (platform === 'codex' || platform === 'pi') {
|
|
77
|
+
const skillDir = platform === 'pi'
|
|
78
|
+
? path.join(projectRoot, '.pi', 'skills', skillName)
|
|
79
|
+
: path.join(projectRoot, '.agents', 'skills', skillName);
|
|
78
80
|
if (await fs.pathExists(skillDir)) {
|
|
79
81
|
if (dryRun) {
|
|
80
|
-
console.log(chalk.gray(` [dry-run] remove .
|
|
82
|
+
console.log(chalk.gray(` [dry-run] remove ${path.relative(projectRoot, skillDir)}/`));
|
|
81
83
|
} else {
|
|
82
84
|
await fs.remove(skillDir);
|
|
83
|
-
console.log(chalk.red(` ✗ removed .
|
|
85
|
+
console.log(chalk.red(` ✗ removed ${path.relative(projectRoot, skillDir)}/`));
|
|
84
86
|
}
|
|
85
87
|
}
|
|
86
88
|
}
|
|
@@ -91,6 +93,7 @@ export async function removeSkillFiles(platform, projectRoot, skillNames, dryRun
|
|
|
91
93
|
* Remove agent files for a specific platform.
|
|
92
94
|
*/
|
|
93
95
|
export async function removeAgentFiles(platform, projectRoot, agentFileNames, dryRun) {
|
|
96
|
+
if (platform === 'pi') return;
|
|
94
97
|
for (const fileName of agentFileNames) {
|
|
95
98
|
const dir = platform === 'claude'
|
|
96
99
|
? path.join(projectRoot, '.claude', 'agents')
|
|
@@ -124,7 +127,9 @@ export async function removeRuleFiles(platform, projectRoot, ruleFileNames, dryR
|
|
|
124
127
|
? path.join(projectRoot, '.claude', 'rules')
|
|
125
128
|
: platform === 'codex'
|
|
126
129
|
? path.join(projectRoot, '.agents', 'rules')
|
|
127
|
-
:
|
|
130
|
+
: platform === 'pi'
|
|
131
|
+
? path.join(projectRoot, '.pi', 'rules')
|
|
132
|
+
: path.join(projectRoot, '.codebuddy', 'rules');
|
|
128
133
|
// Rules are stored as .md for claude, .mdc for codebuddy
|
|
129
134
|
const targetName = platform === 'codebuddy'
|
|
130
135
|
? baseName.replace(/\.md$/, '.mdc')
|
|
@@ -243,11 +248,13 @@ export async function runUpgrade(directory, options = {}) {
|
|
|
243
248
|
const hasClaude = await hasPlatformFiles(path.join(projectRoot, '.claude', 'commands'));
|
|
244
249
|
const hasCodeBuddy = await hasPlatformFiles(path.join(projectRoot, '.codebuddy', 'skills'));
|
|
245
250
|
const hasCodex = await hasPlatformFiles(path.join(projectRoot, '.agents', 'skills'));
|
|
251
|
+
const hasPi = await hasPlatformFiles(path.join(projectRoot, '.pi', 'skills'));
|
|
246
252
|
|
|
247
253
|
const detectedPlatforms = [
|
|
248
254
|
hasCodeBuddy && 'codebuddy',
|
|
249
255
|
hasClaude && 'claude',
|
|
250
256
|
hasCodex && 'codex',
|
|
257
|
+
hasPi && 'pi',
|
|
251
258
|
].filter(Boolean);
|
|
252
259
|
|
|
253
260
|
if (detectedPlatforms.length > 1) platform = 'all';
|