prizmkit 1.1.143 → 1.1.145
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 +83 -7
- package/bundled/dev-pipeline/tests/test_unified_cli.py +117 -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/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 +72 -20
- package/src/upgrade.js +12 -5
|
@@ -18,66 +18,62 @@ Main Agent builds and executes project-native tests
|
|
|
18
18
|
→ TEST_PASS | TEST_NEEDS_FIXES | TEST_BLOCKED
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
Keep at most one Reviewer active for this invocation and permit at most one replacement. Prefer native continuation and never reuse a Reviewer from another lifecycle stage. A compliant replacement may continue the same shared response budget only with complete latest state, never only a conversation summary.
|
|
22
22
|
|
|
23
23
|
## Host Capability Gate
|
|
24
24
|
|
|
25
|
-
The gate is all-or-nothing. Before creating a Reviewer, the host
|
|
25
|
+
The gate is all-or-nothing. Before creating a Reviewer, inspect the current host's actual execution-unit configuration and prove this semantic contract without relying on platform identity or implementation-specific parameters:
|
|
26
26
|
|
|
27
27
|
```yaml
|
|
28
28
|
execution_unit:
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
mutation: unavailable
|
|
32
|
-
|
|
29
|
+
concurrency: at-most-one-active-reviewer
|
|
30
|
+
workspace_access: read-only-active-checkout
|
|
31
|
+
mutation: structurally-unavailable
|
|
32
|
+
command_execution: structurally-unavailable
|
|
33
|
+
network_access: structurally-unavailable
|
|
34
|
+
external_process_execution: structurally-unavailable
|
|
33
35
|
downstream_execution: structurally-unavailable
|
|
34
|
-
context_continuation: same-unit-native-resume
|
|
35
|
-
workspace_observation: bounded-active-checkout-input
|
|
36
36
|
model_configuration: inherit-current-session
|
|
37
|
+
scope_expansion: concrete-coupling-only
|
|
38
|
+
continuation: prefer-same-unit
|
|
39
|
+
replacement: compliant-replacement-allowed
|
|
37
40
|
```
|
|
38
41
|
|
|
39
42
|
Rules:
|
|
40
43
|
|
|
41
44
|
- Prompt instructions cannot satisfy a missing structural capability.
|
|
42
|
-
- Do not branch on platform identity, tool name, execution-unit type name, adapter output, or an allowlist.
|
|
43
|
-
-
|
|
45
|
+
- Do not branch on platform identity, provider, tool name, command name, execution-unit type name, adapter output, CLI parameter, or an allowlist.
|
|
46
|
+
- The Reviewer cannot create, modify, delete, rename, stage, or commit files; execute shell, Git, tests, builds, network calls, or external processes; or create, invoke, resume, or coordinate downstream execution units.
|
|
47
|
+
- A general execution unit that merely promises to stay read-only is ineligible while prohibited capabilities remain available.
|
|
44
48
|
- The Reviewer inherits the current session's model configuration.
|
|
45
49
|
- If any capability is missing or unproven, create no Reviewer and use Strict Downgrade.
|
|
46
50
|
|
|
47
|
-
##
|
|
51
|
+
## Stage-Specific Review Input
|
|
48
52
|
|
|
49
|
-
|
|
53
|
+
Resolve exact requirement identity from workflow state or explicit handoff on every response:
|
|
50
54
|
|
|
51
55
|
```text
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
│ ├── relevant unchanged path inventory
|
|
57
|
-
│ └── consistency markers
|
|
58
|
-
├── change context
|
|
59
|
-
│ ├── requirement and acceptance criteria
|
|
60
|
-
│ ├── current production change
|
|
61
|
-
│ └── applicable project rules
|
|
62
|
-
├── coverage context
|
|
63
|
-
│ ├── affected business module
|
|
64
|
-
│ ├── observable behaviors
|
|
65
|
-
│ ├── risk and boundary assessment
|
|
66
|
-
│ └── Regression Ring
|
|
67
|
-
├── test context
|
|
68
|
-
│ ├── existing, added, and modified tests
|
|
69
|
-
│ ├── fixtures, mocks, and contracts
|
|
70
|
-
│ ├── selected test layers
|
|
71
|
-
│ └── native execution results
|
|
72
|
-
└── targeted supporting context
|
|
73
|
-
├── relevant callers and consumers
|
|
74
|
-
├── shared schemas and contracts
|
|
75
|
-
└── necessary public official contract excerpts
|
|
56
|
+
artifact_dir: [EXACT_ARTIFACT_DIR]
|
|
57
|
+
spec_path: [EXACT_SPEC_PATH]
|
|
58
|
+
plan_path: [EXACT_PLAN_PATH]
|
|
59
|
+
checkout_root: [ACTIVE_CHECKOUT_ROOT]
|
|
76
60
|
```
|
|
77
61
|
|
|
78
|
-
|
|
62
|
+
These paths remain authoritative even when ignored by Git. Never ask the Reviewer to discover a latest artifact or guess among multiple `spec.md` and `plan.md` files.
|
|
79
63
|
|
|
80
|
-
|
|
64
|
+
The Main Agent supplies:
|
|
65
|
+
|
|
66
|
+
- original requirement and confirmed clarifications;
|
|
67
|
+
- exact artifact, spec, and plan paths plus current contents;
|
|
68
|
+
- complete current production-and-test change;
|
|
69
|
+
- affected business module, observable behaviors, applicable risks, and Regression Ring;
|
|
70
|
+
- existing, added, and modified tests, fixtures, mocks, schemas, contracts, and selected layers;
|
|
71
|
+
- native test commands and results executed by Main Agent;
|
|
72
|
+
- test-stage repairs;
|
|
73
|
+
- response number and total budget;
|
|
74
|
+
- prior adjudication and actual corrections on continuation or replacement.
|
|
75
|
+
|
|
76
|
+
The Reviewer may use structurally read-only checkout access to inspect production code, tests, fixtures, schemas, callers, consumers, and contracts only through concrete coupling evidence. It cannot run Git, tests, builds, network calls, or external processes and must not perform an unconditional repository-wide scan. Do not include secrets, credentials, production data, or unrelated private content. Missing or inconsistent required input produces `REVIEW_BLOCKED`, never partial success.
|
|
81
77
|
|
|
82
78
|
## Initial Reviewer Prompt
|
|
83
79
|
|
|
@@ -91,12 +87,14 @@ Objectively determine whether the complete current project-native tests credibly
|
|
|
91
87
|
|
|
92
88
|
Response:
|
|
93
89
|
This is response [RESPONSE_NUMBER] of a maximum five responses.
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
90
|
+
Artifact directory: [ARTIFACT_DIR]
|
|
91
|
+
Specification path and content: [SPEC_PATH_AND_CONTENT]
|
|
92
|
+
Plan path and content: [PLAN_PATH_AND_CONTENT]
|
|
93
|
+
Checkout root: [CHECKOUT_ROOT]
|
|
94
|
+
Requirement and clarifications: [REQUIREMENT_CONTEXT]
|
|
95
|
+
Current production-and-test change: [CURRENT_CHANGE]
|
|
97
96
|
Coverage context: [COVERAGE_CONTEXT]
|
|
98
|
-
Test context: [TEST_CONTEXT]
|
|
99
|
-
Targeted supporting context: [SUPPORTING_CONTEXT]
|
|
97
|
+
Test context and Main-Agent execution results: [TEST_CONTEXT]
|
|
100
98
|
|
|
101
99
|
Execution boundaries:
|
|
102
100
|
- Complete this review personally.
|
|
@@ -104,9 +102,9 @@ Execution boundaries:
|
|
|
104
102
|
- Do not ask the Main Agent to create a helper.
|
|
105
103
|
- Do not re-enter orchestration, delegation, another review workflow, or an equivalent process.
|
|
106
104
|
- Do not modify, create, delete, rename, stage, commit, or otherwise mutate files.
|
|
107
|
-
- Do not execute
|
|
108
|
-
-
|
|
109
|
-
- Do not perform
|
|
105
|
+
- Do not execute shell, Git, tests, builds, network calls, external processes, or any operation that can change state.
|
|
106
|
+
- Use read-only checkout access only for concrete module, caller, consumer, schema, type, configuration, fixture, test, or contract coupling.
|
|
107
|
+
- Do not perform unconditional repository discovery or a full repository scan.
|
|
110
108
|
- Report only corrections supported by a concrete target and evidence.
|
|
111
109
|
- Do not invent an issue merely to return feedback.
|
|
112
110
|
- Return REVIEW_BLOCKED rather than delegate or provide an incomplete success result.
|
|
@@ -134,19 +132,22 @@ Return exactly one result using the Reviewer Output Protocol.
|
|
|
134
132
|
|
|
135
133
|
## Resume Prompt
|
|
136
134
|
|
|
137
|
-
|
|
135
|
+
Prefer native continuation of the same Reviewer. If unavailable, use this complete prompt for one compliant replacement under the replacement rules below.
|
|
138
136
|
|
|
139
137
|
```text
|
|
140
138
|
Continue as the same independent Test Reviewer.
|
|
141
139
|
|
|
142
140
|
Response:
|
|
143
141
|
This is response [RESPONSE_NUMBER] of a maximum five responses.
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
142
|
+
Continuation mode: [NATIVE_OR_REPLACEMENT]
|
|
143
|
+
Artifact directory: [ARTIFACT_DIR]
|
|
144
|
+
Specification path and content: [SPEC_PATH_AND_CONTENT]
|
|
145
|
+
Plan path and content: [PLAN_PATH_AND_CONTENT]
|
|
146
|
+
Checkout root: [CHECKOUT_ROOT]
|
|
147
|
+
Requirement and clarifications: [REQUIREMENT_CONTEXT]
|
|
148
|
+
Current production-and-test change: [CURRENT_CHANGE]
|
|
147
149
|
Current coverage context: [COVERAGE_CONTEXT]
|
|
148
|
-
Current test context: [TEST_CONTEXT]
|
|
149
|
-
Current supporting context: [SUPPORTING_CONTEXT]
|
|
150
|
+
Current test context and Main-Agent execution results: [TEST_CONTEXT]
|
|
150
151
|
Previously accepted corrections: [ACCEPTED_CORRECTIONS_OR_NONE]
|
|
151
152
|
Repairs actually made: [REPAIRS_OR_NONE]
|
|
152
153
|
Main-Agent native verification: [VERIFICATION]
|
|
@@ -233,28 +234,25 @@ Independent review converges when:
|
|
|
233
234
|
4. Validate the response against the output protocol and record it in the report.
|
|
234
235
|
5. Adjudicate every correction and record accepted, rejected, or unresolved with evidence.
|
|
235
236
|
6. For accepted corrections, the Main Agent repairs the current workspace, executes focused and required regressions, then performs a complete Main-Agent review round over the new state within its ten-round budget.
|
|
236
|
-
7. If responses remain,
|
|
237
|
-
8.
|
|
238
|
-
9. If response five contains an
|
|
239
|
-
10.
|
|
237
|
+
7. If responses remain, prepare the complete latest Test input and prefer native continuation. If unavailable or failed and no replacement has been used in this stage, create one compliant replacement only after the prior Reviewer is no longer active; reapply the full gate and continue with the next response number.
|
|
238
|
+
8. A replacement receives complete current state and all prior adjudication, never only a conversation summary. Replacement does not reset the five-response budget. At most one replacement may be created in the stage, and only one Reviewer may be active.
|
|
239
|
+
9. If response five contains an accepted correction, do not repair and claim pass without independent recheck. Return `TEST_NEEDS_FIXES` with the known correction.
|
|
240
|
+
10. If response five contains an unresolved correction or `REVIEW_BLOCKED` that cannot be corrected safely, return `TEST_BLOCKED`.
|
|
241
|
+
11. Stop sending messages when the review converges, reaches its limit, or becomes blocked. Explicitly terminate the unit only when the host safely supports it.
|
|
240
242
|
|
|
241
243
|
## Strict Downgrade
|
|
242
244
|
|
|
243
|
-
Use Strict Downgrade when
|
|
244
|
-
|
|
245
|
-
- required capability is unavailable or unproven before creation;
|
|
246
|
-
- creation fails before a valid response;
|
|
247
|
-
- a required structural capability disappears;
|
|
248
|
-
- exact native resume fails after mutation.
|
|
245
|
+
Use Strict Downgrade when a required capability is unavailable or unproven, creation fails before a valid response, prohibited capability appears, the prior Reviewer may still be active, or no compliant continuation/replacement can be established.
|
|
249
246
|
|
|
250
247
|
Behavior:
|
|
251
248
|
|
|
252
|
-
1. Never create a weaker
|
|
253
|
-
2.
|
|
254
|
-
3. Before creation or before any valid response, record
|
|
255
|
-
4.
|
|
256
|
-
5.
|
|
257
|
-
6.
|
|
249
|
+
1. Never create a weaker Reviewer whose prohibited capabilities remain available.
|
|
250
|
+
2. Prefer native continuation, but permit a fresh compliant replacement with complete latest input and prior adjudication; a summary alone is insufficient.
|
|
251
|
+
3. Before creation or before any valid response, record downgrade and preserve the converged mandatory Main-Agent review.
|
|
252
|
+
4. Creation failure without a response does not consume response budget; a produced malformed response follows the existing response-budget rule.
|
|
253
|
+
5. When continuation and compliant replacement both fail after mutation, rerun mandatory Main-Agent review over the mutation within remaining budget, record downgrade, and set `final_state_rechecked=false`.
|
|
254
|
+
6. A semantic `REVIEW_BLOCKED` caused by incomplete required input is not silently downgraded. Correct input within remaining shared budget using native continuation or compliant replacement, or return `TEST_BLOCKED`.
|
|
255
|
+
7. Strict Downgrade is visible reduced assurance, not a new testing result and not permission to weaken Main-Agent review or native execution.
|
|
258
256
|
|
|
259
257
|
## Report Recording
|
|
260
258
|
|
|
@@ -264,6 +262,7 @@ Record:
|
|
|
264
262
|
- each response number `1..5`, input identity, result, and correction count;
|
|
265
263
|
- every Main-Agent adjudication and its evidence;
|
|
266
264
|
- actual repair and native verification;
|
|
267
|
-
- whether the exact final state was independently rechecked
|
|
265
|
+
- whether the exact final state was independently rechecked;
|
|
266
|
+
- capability basis, continuation mode (`native`, `replacement`, `mixed`, or `not-applicable`), and replacement count.
|
|
268
267
|
|
|
269
268
|
The report remains the human-readable test artifact. Do not create a separate Reviewer state machine or evidence package.
|
|
@@ -78,8 +78,12 @@ Coverage metrics, when available: <diagnostic values or not collected>. Percenta
|
|
|
78
78
|
## Independent Test Review
|
|
79
79
|
|
|
80
80
|
- Status: completed / downgraded / not_applicable
|
|
81
|
+
- Capability Gate: <ENABLED | DOWNGRADED | NOT_APPLICABLE>
|
|
82
|
+
- Capability Basis: <platform-neutral structural evidence or unavailable>
|
|
83
|
+
- Downgrade Reason: <reason or none>
|
|
81
84
|
- Responses: <0..5>
|
|
82
|
-
-
|
|
85
|
+
- Continuation Mode: <native | replacement | mixed | not-applicable>
|
|
86
|
+
- Reviewer Replacements: <0..1>
|
|
83
87
|
- Corrections and Main-Agent adjudication: <summary or none>
|
|
84
88
|
- Exact final state independently rechecked: yes / no
|
|
85
89
|
|
package/package.json
CHANGED
package/src/ai-cli-launch.js
CHANGED
package/src/clean.js
CHANGED
|
@@ -252,6 +252,10 @@ export async function runClean(directory, options = {}) {
|
|
|
252
252
|
const codexSkillsDir = path.join(projectRoot, '.agents', 'skills');
|
|
253
253
|
results.push(...await removeKnownEntries(codexSkillsDir, allSkillNames, dryRun));
|
|
254
254
|
|
|
255
|
+
// .pi/skills/ — Pi project skills
|
|
256
|
+
const piSkillsDir = path.join(projectRoot, '.pi', 'skills');
|
|
257
|
+
results.push(...await removeKnownEntries(piSkillsDir, allSkillNames, dryRun));
|
|
258
|
+
|
|
255
259
|
// .claude/agents/ — retired PrizmKit named-agent files
|
|
256
260
|
const claudeAgentsDir = path.join(projectRoot, '.claude', 'agents');
|
|
257
261
|
results.push(...await removeKnownEntries(claudeAgentsDir, agentFiles, dryRun));
|
|
@@ -280,13 +284,18 @@ export async function runClean(directory, options = {}) {
|
|
|
280
284
|
const legacyCodexRulesDir = path.join(projectRoot, '.codex', 'rules');
|
|
281
285
|
results.push(...await removeKnownEntries(legacyCodexRulesDir, ruleFileNames.map(n => `${n}.md`), dryRun));
|
|
282
286
|
|
|
283
|
-
|
|
287
|
+
const piRulesDir = path.join(projectRoot, '.pi', 'rules');
|
|
288
|
+
results.push(...await removeKnownEntries(piRulesDir, ruleFileNames.map(n => `${n}.md`), dryRun));
|
|
289
|
+
|
|
290
|
+
for (const platform of ['codebuddy', 'claude', 'codex', 'pi']) {
|
|
284
291
|
const memoryFile = projectMemoryFile(platform);
|
|
285
292
|
const privateMemoryFile = privateProjectMemoryFile(platform);
|
|
286
|
-
if (!
|
|
287
|
-
|
|
293
|
+
if (!privateMemoryFile) continue;
|
|
294
|
+
if (memoryFile) {
|
|
295
|
+
results.push(await cleanProjectMemoryImport(projectRoot, memoryFile, privateMemoryFile, dryRun));
|
|
296
|
+
results.push(await cleanMarkedProjectMemory(projectRoot, memoryFile, dryRun));
|
|
297
|
+
}
|
|
288
298
|
results.push(await cleanMarkedProjectMemory(projectRoot, privateMemoryFile, dryRun));
|
|
289
|
-
results.push(await cleanMarkedProjectMemory(projectRoot, memoryFile, dryRun));
|
|
290
299
|
}
|
|
291
300
|
|
|
292
301
|
// ── .gitignore cleanup ────────────────────────────────────────────────────
|
package/src/config.js
CHANGED
|
@@ -99,9 +99,11 @@ async function detectInstalledPlatforms(projectRoot) {
|
|
|
99
99
|
const hasClaude = await hasPlatformFiles(path.join(projectRoot, '.claude', 'commands'));
|
|
100
100
|
const hasCodeBuddy = await hasPlatformFiles(path.join(projectRoot, '.codebuddy', 'skills'));
|
|
101
101
|
const hasCodex = await hasPlatformFiles(path.join(projectRoot, '.agents', 'skills'));
|
|
102
|
+
const hasPi = await hasPlatformFiles(path.join(projectRoot, '.pi', 'skills'));
|
|
103
|
+
const detected = [hasClaude && 'claude', hasCodeBuddy && 'codebuddy', hasCodex && 'codex', hasPi && 'pi'].filter(Boolean);
|
|
102
104
|
|
|
103
|
-
if (hasClaude && hasCodeBuddy
|
|
104
|
-
if (
|
|
105
|
+
if (detected.length > 1) return detected.length === 2 && hasClaude && hasCodeBuddy ? 'both' : 'all';
|
|
106
|
+
if (hasPi) return 'pi';
|
|
105
107
|
if (hasCodex) return 'codex';
|
|
106
108
|
if (hasCodeBuddy) return 'codebuddy';
|
|
107
109
|
if (hasClaude) return 'claude';
|
|
@@ -121,18 +123,25 @@ function logManagedMemoryWarnings(mainFile, warnings) {
|
|
|
121
123
|
async function removeProjectMemoryArtifacts(platform, projectRoot, dryRun) {
|
|
122
124
|
const mainFile = projectMemoryFile(platform);
|
|
123
125
|
const privateFile = privateProjectMemoryFile(platform);
|
|
124
|
-
if (!
|
|
126
|
+
if (!privateFile) return;
|
|
125
127
|
|
|
126
128
|
const privatePath = path.join(projectRoot, privateFile);
|
|
127
129
|
if (await fs.pathExists(privatePath)) {
|
|
130
|
+
const currentPrivate = await fs.readFile(privatePath, 'utf-8');
|
|
131
|
+
const normalizedPrivate = normalizeMainProjectMemoryContent(currentPrivate, null);
|
|
132
|
+
const remainingPrivate = normalizedPrivate.content.trim();
|
|
128
133
|
if (dryRun) {
|
|
129
|
-
console.log(chalk.gray(` [dry-run]
|
|
134
|
+
console.log(chalk.gray(` [dry-run] update ${privateFile} (remove PrizmKit block)`));
|
|
135
|
+
} else if (remainingPrivate) {
|
|
136
|
+
await fs.writeFile(privatePath, `${remainingPrivate}\n`, 'utf-8');
|
|
137
|
+
console.log(chalk.green(` ✓ updated ${privateFile} (removed PrizmKit block)`));
|
|
130
138
|
} else {
|
|
131
139
|
await fs.remove(privatePath);
|
|
132
140
|
console.log(chalk.red(` ✗ removed ${privateFile}`));
|
|
133
141
|
}
|
|
134
142
|
}
|
|
135
143
|
|
|
144
|
+
if (!mainFile) return;
|
|
136
145
|
const mainPath = path.join(projectRoot, mainFile);
|
|
137
146
|
if (!await fs.pathExists(mainPath)) return;
|
|
138
147
|
|
|
@@ -252,10 +261,21 @@ async function removePlatformFiles(platform, projectRoot, manifest, dryRun) {
|
|
|
252
261
|
} else {
|
|
253
262
|
const settingsFile = platform === 'claude'
|
|
254
263
|
? path.join(projectRoot, '.claude', 'settings.json')
|
|
255
|
-
:
|
|
264
|
+
: platform === 'pi'
|
|
265
|
+
? path.join(projectRoot, '.pi', 'settings.json')
|
|
266
|
+
: path.join(projectRoot, '.codebuddy', 'settings.json');
|
|
256
267
|
if (await fs.pathExists(settingsFile)) {
|
|
257
268
|
if (dryRun) {
|
|
258
269
|
console.log(chalk.gray(` [dry-run] remove ${path.relative(projectRoot, settingsFile)}`));
|
|
270
|
+
} else if (platform === 'pi') {
|
|
271
|
+
let settings = {};
|
|
272
|
+
try { settings = await fs.readJSON(settingsFile); } catch { settings = null; }
|
|
273
|
+
if (settings && !Array.isArray(settings) && typeof settings === 'object') {
|
|
274
|
+
delete settings.enableSkillCommands;
|
|
275
|
+
if (Object.keys(settings).length) await fs.writeJSON(settingsFile, settings, { spaces: 2 });
|
|
276
|
+
else await fs.remove(settingsFile);
|
|
277
|
+
console.log(chalk.green(' ✓ removed PrizmKit Pi setting'));
|
|
278
|
+
}
|
|
259
279
|
} else {
|
|
260
280
|
await fs.remove(settingsFile);
|
|
261
281
|
console.log(chalk.red(` ✗ removed ${path.relative(projectRoot, settingsFile)}`));
|
|
@@ -353,6 +373,13 @@ async function removePlatformFiles(platform, projectRoot, manifest, dryRun) {
|
|
|
353
373
|
}
|
|
354
374
|
}
|
|
355
375
|
}
|
|
376
|
+
} else if (platform === 'pi') {
|
|
377
|
+
for (const relativeDir of ['.pi/skills', '.pi/rules', '.pi']) {
|
|
378
|
+
const dir = path.join(projectRoot, relativeDir);
|
|
379
|
+
if (await fs.pathExists(dir) && !dryRun && (await fs.readdir(dir)).length === 0) {
|
|
380
|
+
await fs.remove(dir);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
356
383
|
}
|
|
357
384
|
}
|
|
358
385
|
|
package/src/detect-platform.js
CHANGED
|
@@ -9,7 +9,7 @@ import os from 'os';
|
|
|
9
9
|
/**
|
|
10
10
|
* 允许检测的命令白名单(仅用于 which 检测)
|
|
11
11
|
*/
|
|
12
|
-
const ALLOWED_COMMANDS = ['cbc', 'claude', 'codex'];
|
|
12
|
+
const ALLOWED_COMMANDS = ['cbc', 'claude', 'codex', 'pi'];
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* 检查命令是否存在于 PATH 中
|
|
@@ -33,30 +33,34 @@ function commandExists(cmd) {
|
|
|
33
33
|
* 注意:platform 控制目录结构(.codebuddy/ 或 .claude/),
|
|
34
34
|
* suggestedCli 是实际运行的可执行命令,二者相互独立。
|
|
35
35
|
*
|
|
36
|
-
* @returns {{ cbc: boolean, claude: boolean, codex: boolean, suggested: string, suggestedCli: string }}
|
|
36
|
+
* @returns {{ cbc: boolean, claude: boolean, codex: boolean, pi: boolean, suggested: string, suggestedCli: string }}
|
|
37
37
|
*/
|
|
38
38
|
export function detectPlatform() {
|
|
39
39
|
const cbc = commandExists('cbc');
|
|
40
40
|
const claude = commandExists('claude');
|
|
41
41
|
const codex = commandExists('codex');
|
|
42
|
+
const pi = commandExists('pi');
|
|
42
43
|
|
|
43
|
-
//
|
|
44
|
+
// Preserve historical recommendations when Pi is absent.
|
|
44
45
|
let suggested = 'codebuddy';
|
|
45
|
-
if (
|
|
46
|
+
if (pi) {
|
|
47
|
+
suggested = (cbc || claude || codex) ? 'all' : 'pi';
|
|
48
|
+
} else if (cbc && claude && codex) {
|
|
46
49
|
suggested = 'all';
|
|
47
50
|
} else if (codex && !cbc && !claude) {
|
|
48
51
|
suggested = 'codex';
|
|
49
|
-
} else if (
|
|
52
|
+
} else if (claude && !cbc) {
|
|
50
53
|
suggested = 'claude';
|
|
51
54
|
} else if (cbc && !claude) {
|
|
52
55
|
suggested = 'codebuddy';
|
|
53
56
|
}
|
|
54
57
|
|
|
55
|
-
//
|
|
58
|
+
// Preserve historical precedence and use Pi when it is the first available CLI.
|
|
56
59
|
let suggestedCli = '';
|
|
57
60
|
if (cbc) suggestedCli = 'cbc';
|
|
58
61
|
else if (claude) suggestedCli = 'claude';
|
|
59
62
|
else if (codex) suggestedCli = 'codex';
|
|
63
|
+
else if (pi) suggestedCli = 'pi';
|
|
60
64
|
|
|
61
|
-
return { cbc, claude, codex, suggested, suggestedCli };
|
|
65
|
+
return { cbc, claude, codex, pi, suggested, suggestedCli };
|
|
62
66
|
}
|
package/src/index.js
CHANGED
|
@@ -52,6 +52,7 @@ export async function runScaffold(directory, options) {
|
|
|
52
52
|
detected.cbc ? chalk.green('cbc ✓') : chalk.gray('cbc ✗'),
|
|
53
53
|
detected.claude ? chalk.green('claude ✓') : chalk.gray('claude ✗'),
|
|
54
54
|
detected.codex ? chalk.green('codex ✓') : chalk.gray('codex ✗'),
|
|
55
|
+
detected.pi ? chalk.green('pi ✓') : chalk.gray('pi ✗'),
|
|
55
56
|
].join(' ');
|
|
56
57
|
console.log(` 检测到的 CLI 工具: ${cliStatus}`);
|
|
57
58
|
console.log(` 目标目录: ${projectRoot}`);
|
|
@@ -108,6 +109,10 @@ export async function runScaffold(directory, options) {
|
|
|
108
109
|
name: `Codex (AGENTS.md + .agents/skills + .codex/)${detected.codex ? chalk.green(' ← 已检测到 codex') : ''}`,
|
|
109
110
|
value: 'codex',
|
|
110
111
|
},
|
|
112
|
+
{
|
|
113
|
+
name: `Pi (.pi/skills + .pi/APPEND_SYSTEM.md)${detected.pi ? chalk.green(' ← 已检测到 pi') : ''}`,
|
|
114
|
+
value: 'pi',
|
|
115
|
+
},
|
|
111
116
|
{
|
|
112
117
|
name: '同时安装全部平台',
|
|
113
118
|
value: 'all',
|
package/src/platforms.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isBuiltInAiCli } from './ai-cli-launch.js';
|
|
2
2
|
|
|
3
|
-
export const PLATFORM_IDS = ['codebuddy', 'claude', 'codex'];
|
|
3
|
+
export const PLATFORM_IDS = ['codebuddy', 'claude', 'codex', 'pi'];
|
|
4
4
|
export const PLATFORM_GROUPS = {
|
|
5
5
|
all: PLATFORM_IDS,
|
|
6
6
|
};
|
|
@@ -23,6 +23,7 @@ export function platformFromAiCli(aiCli) {
|
|
|
23
23
|
const name = token.split(/[\\/]/).pop()?.toLowerCase() || '';
|
|
24
24
|
if (name === 'claude') return 'claude';
|
|
25
25
|
if (name === 'codex') return 'codex';
|
|
26
|
+
if (name === 'pi') return 'pi';
|
|
26
27
|
if (name === 'cbc' || name === 'codebuddy') return 'codebuddy';
|
|
27
28
|
return null;
|
|
28
29
|
}
|
|
@@ -48,10 +49,11 @@ export function isKnownPlatform(platform) {
|
|
|
48
49
|
|
|
49
50
|
export function platformLabel(platform) {
|
|
50
51
|
if (platform === 'both') return 'legacy codebuddy/claude group';
|
|
51
|
-
if (platform === 'all') return 'All platforms (CodeBuddy, Claude Code, Codex)';
|
|
52
|
+
if (platform === 'all') return 'All platforms (CodeBuddy, Claude Code, Codex, Pi)';
|
|
52
53
|
if (platform === 'codebuddy') return 'CodeBuddy';
|
|
53
54
|
if (platform === 'claude') return 'Claude Code';
|
|
54
55
|
if (platform === 'codex') return 'Codex';
|
|
56
|
+
if (platform === 'pi') return 'Pi';
|
|
55
57
|
return platform;
|
|
56
58
|
}
|
|
57
59
|
|
|
@@ -63,6 +65,7 @@ export function projectMemoryFile(platform) {
|
|
|
63
65
|
}
|
|
64
66
|
|
|
65
67
|
export function privateProjectMemoryFile(platform) {
|
|
68
|
+
if (platform === 'pi') return '.pi/APPEND_SYSTEM.md';
|
|
66
69
|
const mainFile = projectMemoryFile(platform);
|
|
67
70
|
if (!mainFile) return null;
|
|
68
71
|
return mainFile.replace(/\.md$/i, '.private.md');
|
|
@@ -80,5 +83,6 @@ export function defaultCliForPlatform(platform) {
|
|
|
80
83
|
if (platform === 'claude') return 'claude';
|
|
81
84
|
if (platform === 'codebuddy') return 'cbc';
|
|
82
85
|
if (platform === 'codex') return 'codex';
|
|
86
|
+
if (platform === 'pi') return 'pi';
|
|
83
87
|
return '';
|
|
84
88
|
}
|
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 || ''));
|