prizmkit 1.1.60 → 1.1.62
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 +2 -2
- package/bundled/VERSION.json +3 -3
- package/bundled/adapters/codex/skill-adapter.js +17 -2
- package/bundled/agents/prizm-dev-team-dev.md +6 -5
- package/bundled/rules/prizm/prizm-documentation.md +2 -4
- package/bundled/rules/prizm/prizm-progressive-loading.md +2 -1
- package/bundled/skills/_metadata.json +1 -1
- package/bundled/skills/app-planner/SKILL.md +1 -1
- package/bundled/skills/app-planner/references/architecture-decisions.md +1 -1
- package/bundled/skills/feature-planner/SKILL.md +1 -1
- package/bundled/skills/prizmkit-implement/SKILL.md +1 -0
- package/bundled/skills/prizmkit-init/SKILL.md +1 -1
- package/bundled/skills/prizmkit-init/references/config-schema.md +3 -1
- package/bundled/skills/prizmkit-plan/SKILL.md +2 -0
- package/bundled/skills/prizmkit-prizm-docs/assets/prizm-docs-format.md +6 -1
- package/bundled/skills/prizmkit-prizm-docs/references/op-init.md +2 -2
- package/bundled/skills/prizmkit-prizm-docs/references/op-update.md +2 -1
- package/bundled/skills/prizmkit-prizm-docs/references/op-validate.md +2 -2
- package/bundled/skills/prizmkit-retrospective/SKILL.md +2 -0
- package/bundled/skills/prizmkit-retrospective/references/knowledge-injection-steps.md +2 -0
- package/bundled/skills/prizmkit-retrospective/references/structural-sync-steps.md +2 -0
- package/bundled/skills-windows/app-planner/SKILL.md +1 -1
- package/bundled/skills-windows/app-planner/references/architecture-decisions.md +1 -1
- package/bundled/skills-windows/feature-planner/SKILL.md +1 -1
- package/bundled/skills-windows/prizmkit-init/SKILL.md +1 -1
- package/bundled/skills-windows/prizmkit-init/references/config-schema.md +3 -1
- package/bundled/templates/hooks/diff-prizm-docs.sh +1 -1
- package/bundled/templates/hooks/prizm-pre-commit.sh +53 -4
- package/bundled/templates/hooks/validate-prizm-docs.sh +62 -7
- package/bundled/templates/project-memory-template.md +2 -1
- package/package.json +1 -1
- package/src/config.js +9 -1
- package/src/detect-platform.js +0 -2
- package/src/external-skills.js +2 -2
- package/src/index.js +0 -4
- package/src/manifest.js +1 -1
- package/src/platforms.js +6 -4
- package/src/prompts.js +23 -7
- package/src/scaffold.js +145 -16
- package/src/upgrade.js +9 -6
package/bin/create-prizmkit.js
CHANGED
|
@@ -31,7 +31,7 @@ program
|
|
|
31
31
|
program
|
|
32
32
|
.command('install [directory]')
|
|
33
33
|
.description('Install PrizmKit into a project directory')
|
|
34
|
-
.option('--platform <platform>', 'Target platform: codebuddy, claude, codex,
|
|
34
|
+
.option('--platform <platform>', 'Target platform: codebuddy, claude, codex, or all')
|
|
35
35
|
.option('--runtime <runtime>', 'Runtime assets: unix, windows, or auto')
|
|
36
36
|
.option('--skills <suite>', 'Skill suite: core, minimal, or recommended:<type> (frontend/backend/fullstack/library)', 'core')
|
|
37
37
|
.option('--team', 'Enable multi-agent team mode (default: true)')
|
|
@@ -90,7 +90,7 @@ program
|
|
|
90
90
|
program
|
|
91
91
|
.command('config [directory]')
|
|
92
92
|
.description('Reconfigure existing PrizmKit installation (change platform, skills, rules, options)')
|
|
93
|
-
.option('--platform <platform>', 'Target platform: codebuddy, claude, codex,
|
|
93
|
+
.option('--platform <platform>', 'Target platform: codebuddy, claude, codex, or all')
|
|
94
94
|
.option('--runtime <runtime>', 'Runtime assets: unix, windows, or auto')
|
|
95
95
|
.option('--skills <suite>', 'Skill suite: core, minimal, or recommended:<type>')
|
|
96
96
|
.option('--rules <preset>', 'Rules preset: recommended, minimal, or none')
|
package/bundled/VERSION.json
CHANGED
|
@@ -16,12 +16,27 @@ function toCodexSkillReference(commandName) {
|
|
|
16
16
|
return `PrizmKit skill \`${commandName}\` (\`.agents/skills/${commandName}/SKILL.md\`)`;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
function applyCodexInteractionCompatibility(content) {
|
|
20
|
+
const fallbackInstruction = 'Use `request_user_input` when available. If unavailable in the current Codex surface, including Default mode, ask the same options directly in chat and wait for an explicit answer. Tool unavailability is not permission to choose defaults.';
|
|
21
|
+
|
|
22
|
+
return content
|
|
23
|
+
.replace(/\bAskUserQuestion\b/g, 'request_user_input')
|
|
24
|
+
.replace(
|
|
25
|
+
/Do NOT render options as plain text — the user must be able to click\/select\./g,
|
|
26
|
+
fallbackInstruction
|
|
27
|
+
)
|
|
28
|
+
.replace(
|
|
29
|
+
/Do NOT render options as plain text \(e\.g\., `\[A\] option \[B\] option`\) — the user must be able to click\/select, not type a letter\./g,
|
|
30
|
+
fallbackInstruction
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
19
34
|
export function convertSkill(skillContent, skillName) {
|
|
20
35
|
const { frontmatter, body } = parseFrontmatter(skillContent);
|
|
21
36
|
|
|
22
37
|
if (!frontmatter.name) frontmatter.name = skillName;
|
|
23
38
|
|
|
24
|
-
let convertedBody = body.replace(
|
|
39
|
+
let convertedBody = applyCodexInteractionCompatibility(body).replace(
|
|
25
40
|
/\$\{SKILL_DIR\}/g,
|
|
26
41
|
`.agents/skills/${skillName}`
|
|
27
42
|
);
|
|
@@ -34,7 +49,7 @@ export function convertSkill(skillContent, skillName) {
|
|
|
34
49
|
}
|
|
35
50
|
);
|
|
36
51
|
|
|
37
|
-
const codexNote = `> Codex project install: when instructions mention a PrizmKit slash command such as \`/prizmkit-plan\`, read and execute the matching project skill at \`.agents/skills/prizmkit-plan/SKILL.md\`.\n\n`;
|
|
52
|
+
const codexNote = `> Codex project install: when instructions mention a PrizmKit slash command such as \`/prizmkit-plan\`, read and execute the matching project skill at \`.agents/skills/prizmkit-plan/SKILL.md\`.\n>\n> Codex interaction compatibility: when this skill or any referenced PrizmKit file says \`AskUserQuestion\`, use Codex \`request_user_input\` if it is available. If the current Codex surface does not expose \`request_user_input\`, including Default mode, ask the same question directly in chat and wait for explicit user input. Tool unavailability is not permission to choose defaults. If a source instruction asks more questions than Codex allows in one call, split them into multiple calls while preserving order. Only true headless/non-interactive runs, such as \`codex exec\` automation with no conversational user available, may skip interaction and choose documented defaults; never silently choose defaults in an interactive session.\n\n`;
|
|
38
53
|
|
|
39
54
|
return buildMarkdown(frontmatter, codexNote + convertedBody);
|
|
40
55
|
}
|
|
@@ -48,8 +48,8 @@ If the snapshot does not exist:
|
|
|
48
48
|
8. Checkpoint tasks must verify that build and tests pass before proceeding to the next phase
|
|
49
49
|
9. Execute sequential tasks in order; stop on failure. Parallel `[P]` tasks may continue
|
|
50
50
|
10. When creating a new sub-module, generate the corresponding `.prizmkit/prizm-docs/` L2 document. **Batch independent operations**: combine multiple `mkdir -p` into one command; issue multiple independent `Write` calls for different `.prizmkit/prizm-docs/` files in a single message turn (they have no dependencies between them).
|
|
51
|
-
11. **`.prizmkit/prizm-docs/` write safety**: Before writing ANY `.prizmkit/prizm-docs/` file, check if it already exists (`ls <path>`). If it **exists**: only
|
|
52
|
-
|
|
51
|
+
11. **`.prizmkit/prizm-docs/` write safety**: Before writing ANY `.prizmkit/prizm-docs/` file, check if it already exists (`ls <path>`). If it **exists**: update only durable structural/knowledge fields (KEY_FILES, INTERFACES, DEPENDENCIES, file counts, RULES, TRAPS, DECISIONS) — **never overwrite the full file**. Do not add CHANGELOG, UPDATED/date fields, Bug IDs, feature IDs, refactor IDs, task IDs, session IDs, run IDs, pipeline IDs, workflow IDs, branch names, absolute worktree paths, pipeline artifact paths, or `.prizmkit/specs` / `.prizmkit/dev-pipeline` artifact paths. If a durable fact changes, update the existing section in place. If the file does **not** exist: create it only for sub-modules you are actively creating in this session. Do NOT write `.prizmkit/prizm-docs/` files for modules you are not directly creating.
|
|
52
|
+
12. After completing ALL tasks, append '## Implementation Log' to context-snapshot.md: files changed/created, key decisions, notable discoveries
|
|
53
53
|
|
|
54
54
|
### Never Do (NEVER)
|
|
55
55
|
|
|
@@ -59,7 +59,8 @@ If the snapshot does not exist:
|
|
|
59
59
|
- **Do not execute any git operations** (git commit / git add / git reset / git push are all prohibited — the Orchestrator handles commits via /prizmkit-committer)
|
|
60
60
|
- Do not modify any files in `.prizmkit/specs/` except `plan.md` (marking Tasks [x]) and `context-snapshot.md` (appending Implementation Log)
|
|
61
61
|
- Do not use TaskCreate/TaskUpdate to create or modify Orchestrator-level tasks (Task tools are for internal progress tracking only, and task IDs are not shared across agent sub-sessions)
|
|
62
|
-
- **Do not overwrite existing `.prizmkit/prizm-docs/` files in full** — if a doc already exists, only update
|
|
62
|
+
- **Do not overwrite existing `.prizmkit/prizm-docs/` files in full** — if a doc already exists, only update the affected durable fields; never replace the entire file. Do NOT write `.prizmkit/prizm-docs/` entries for modules you are not actively creating in this session.
|
|
63
|
+
- **Do not leak internal PrizmKit metadata into product surfaces or memory docs** — feature IDs (`F-001`), bug/refactor IDs, task IDs, session IDs, run IDs, pipeline IDs, workflow IDs, branch names, absolute worktree paths, pipeline artifact paths, and `.prizmkit/specs` / `.prizmkit/dev-pipeline` artifact paths must not appear in `.prizmkit/prizm-docs/`, user-visible UI copy, API responses, emails, notifications, or tests that assert visible product text.
|
|
63
64
|
|
|
64
65
|
### Behavioral Rules
|
|
65
66
|
|
|
@@ -83,7 +84,8 @@ DEV-15: After ALL tasks, append '## Implementation Log' to context-snapshot.md (
|
|
|
83
84
|
DEV-16: Without context-snapshot: read .prizmkit/prizm-docs/ → read source files directly
|
|
84
85
|
DEV-17: DO NOT re-read source files already listed in context-snapshot.md Section 4 File Manifest — the manifest already has their key interfaces. Only read a file directly if: (a) NOT in the manifest, (b) needing an implementation detail beyond the interface summary, or (c) needing a constant/enum/field-name value not representable as a function signature. Unnecessary re-reads waste significant context budget.
|
|
85
86
|
DEV-18: When tests fail, run `$TEST_CMD 2>&1 | tee /tmp/test-out.txt` ONCE, then grep `/tmp/test-out.txt` for failure details. Never re-run the full test suite just to apply a different grep filter to its output.
|
|
86
|
-
DEV-19: Before writing any `.prizmkit/prizm-docs/` file, check if it exists. If it exists: only update
|
|
87
|
+
DEV-19: Before writing any `.prizmkit/prizm-docs/` file, check if it exists. If it exists: only update durable fields (KEY_FILES, INTERFACES, DEPENDENCIES, file counts, RULES, TRAPS, DECISIONS) — never overwrite the full file. Never add CHANGELOG, UPDATED/date fields, or workflow metadata. Only create new L2 docs for sub-modules you are actively creating in this session.
|
|
88
|
+
DEV-20: Internal tracking IDs are not product copy. Before writing UI text or UI-copy assertions, translate references like `F-003 guard` into product-language behavior such as `the high-risk guard`. Add regression coverage when a feature touches user-visible text.
|
|
87
89
|
```
|
|
88
90
|
|
|
89
91
|
### Workflow
|
|
@@ -121,4 +123,3 @@ Direct communication between Agents is allowed, but key messages and conclusions
|
|
|
121
123
|
- Send COMPLETION_SIGNAL to indicate all tasks are complete
|
|
122
124
|
- Send ESCALATION to report interface ambiguities or task blockers
|
|
123
125
|
- Receive TASK_ASSIGNMENT to get assigned work
|
|
124
|
-
|
|
@@ -22,6 +22,7 @@ FORMAT RULES (enforced by pre-commit hook — violations block commit):
|
|
|
22
22
|
- KEY: value pairs and dash-prefixed lists only
|
|
23
23
|
- PROHIBITED: prose paragraphs, markdown headers (##/###), code blocks (```), emoji, ASCII art
|
|
24
24
|
- No UPDATED timestamps — git is the authoritative source for temporal information
|
|
25
|
+
- PROHIBITED: CHANGELOG sections/files, UPDATED/date metadata, feature/bug/refactor/task/session/run/pipeline/workflow IDs, branch names, absolute worktree paths, and `.prizmkit/specs` / `.prizmkit/dev-pipeline` artifact paths
|
|
25
26
|
- This format is designed for AI token efficiency, not human readability. Do not add human-friendly formatting.
|
|
26
27
|
|
|
27
28
|
SIZE LIMITS (hard — pre-commit hook blocks commits exceeding these):
|
|
@@ -32,7 +33,7 @@ SIZE LIMITS (hard — pre-commit hook blocks commits exceeding these):
|
|
|
32
33
|
SIZE OVERFLOW HANDLING:
|
|
33
34
|
- L0 approaching 4KB: if MODULE_INDEX has > 15 entries, convert to MODULE_GROUPS format (group by domain). Otherwise consolidate descriptions, keep only top-5 RULES, remove PATTERNS detail.
|
|
34
35
|
- L1 approaching 4KB: trim KEY_FILES descriptions, ensure RULES <= 3 entries, move detail to L2
|
|
35
|
-
- L2 approaching 5KB:
|
|
36
|
+
- L2 approaching 5KB: remove stale or trivially derivable entries; never create changelog-archive.prizm
|
|
36
37
|
- NEVER exceed hard limits — pre-commit hook will block the commit
|
|
37
38
|
|
|
38
39
|
REQUIRED FIELDS PER LEVEL:
|
|
@@ -58,7 +59,6 @@ L2 detail.prizm:
|
|
|
58
59
|
- DEPENDENCIES
|
|
59
60
|
- INTERFACES
|
|
60
61
|
- TRAPS (with severity prefix: [CRITICAL], [HIGH], or [LOW])
|
|
61
|
-
- CHANGELOG
|
|
62
62
|
|
|
63
63
|
L2 GENERATION TEMPLATE (use when AI first touches a sub-module with no L2 doc):
|
|
64
64
|
|
|
@@ -74,7 +74,5 @@ INTERFACES:
|
|
|
74
74
|
- <exported function/class>: <signature and purpose>
|
|
75
75
|
TRAPS:
|
|
76
76
|
- [LOW] <gotcha, race condition, or non-obvious coupling> | FIX: <approach>
|
|
77
|
-
CHANGELOG:
|
|
78
|
-
- root | add: initial L2 documentation
|
|
79
77
|
|
|
80
78
|
TRAPS is critical — always record gotchas, race conditions, non-obvious behavior, and surprising coupling between modules. Every TRAP must have a severity prefix ([CRITICAL], [HIGH], or [LOW]).
|
|
@@ -9,4 +9,5 @@ This project uses PrizmKit's progressive loading protocol:
|
|
|
9
9
|
- ON FILE EDIT: Read L2 (`.prizmkit/prizm-docs/<module>/<submodule>.prizm`) before modifying
|
|
10
10
|
- NEVER load all .prizm docs at once
|
|
11
11
|
- Arrow notation (->) in .prizm files indicates load pointers
|
|
12
|
-
-
|
|
12
|
+
- .prizm files do not contain CHANGELOG sections/files, UPDATED/date metadata, feature/bug/refactor/task/session/run/pipeline/workflow IDs, branch names, absolute worktree paths, or `.prizmkit/specs` / `.prizmkit/dev-pipeline` artifact paths
|
|
13
|
+
- Update stale durable knowledge in place; git history is the change log
|
|
@@ -45,7 +45,7 @@ If you believe the task is better suited for a different workflow, you MUST:
|
|
|
45
45
|
- Codex → `AGENTS.md`
|
|
46
46
|
- Claude Code → `CLAUDE.md`
|
|
47
47
|
- CodeBuddy → `CODEBUDDY.md`
|
|
48
|
-
- `
|
|
48
|
+
- `all` → all three files.
|
|
49
49
|
- Only when the manifest is missing, fall back to installed PrizmKit-owned platform files such as `.codex/agents/*.toml`, `.claude/commands/prizm-kit.md`, or `.codebuddy/skills/prizm-kit/SKILL.md`. Do not treat a generic `.agents/` directory as Codex.
|
|
50
50
|
|
|
51
51
|
**After planning is complete**, you MUST:
|
|
@@ -29,7 +29,7 @@ After Phase 2 (Confirm constraints and tech assumptions), before Phase 3 (Captur
|
|
|
29
29
|
- `codex` → append to `AGENTS.md`
|
|
30
30
|
- `claude` → append to `CLAUDE.md`
|
|
31
31
|
- `codebuddy` → append to `CODEBUDDY.md`
|
|
32
|
-
- `
|
|
32
|
+
- `all` → append to all three files. Legacy manifests may contain `both`; treat it as read-only compatibility and append to `CLAUDE.md` and `CODEBUDDY.md` only when encountered.
|
|
33
33
|
- Only when the manifest is missing, fall back to PrizmKit-owned install artifacts: `.codex/agents/*.toml`, `.claude/commands/prizm-kit.md`, `.codebuddy/skills/prizm-kit/SKILL.md`.
|
|
34
34
|
- Do not treat a generic `.agents/` directory as Codex; it may contain unrelated third-party skills.
|
|
35
35
|
- If no platform can be determined, skip (no project instruction file).
|
|
@@ -111,7 +111,7 @@ Before questions, check optional context files (never block if absent):
|
|
|
111
111
|
- `.prizmkit/config.json` (existing stack preferences and detected tech stack)
|
|
112
112
|
- `.prizmkit/plans/project-brief.md` (project context from app-planner, if available)
|
|
113
113
|
- existing `.prizmkit/plans/feature-list.json` (required for incremental mode)
|
|
114
|
-
- Platform instruction file: use the `platform` field in `.prizmkit/manifest.json` as source of truth when present (`codex` → `AGENTS.md`, `claude` → `CLAUDE.md`, `codebuddy` → `CODEBUDDY.md
|
|
114
|
+
- Platform instruction file: use the `platform` field in `.prizmkit/manifest.json` as source of truth when present (`codex` → `AGENTS.md`, `claude` → `CLAUDE.md`, `codebuddy` → `CODEBUDDY.md`, `all` → read every matching file). Legacy manifests may contain `both`; treat it as read-only compatibility and read `CLAUDE.md` plus `CODEBUDDY.md` only when encountered.
|
|
115
115
|
- If `.prizmkit/prizm-docs/root.prizm` is absent and the project has existing source code, scan the directory structure to understand the codebase layout:
|
|
116
116
|
```bash
|
|
117
117
|
find . -maxdepth 2 -type d \
|
|
@@ -41,6 +41,7 @@ For each unchecked task in plan.md, in order:
|
|
|
41
41
|
|
|
42
42
|
1. Read L1/L2 doc for the target file's module — check TRAPS and DECISIONS before modifying files
|
|
43
43
|
2. Apply TDD where applicable: write a failing test first, then implement until it passes. For UI components or configuration changes where unit tests don't apply, skip the test-first step.
|
|
44
|
+
- **Internal ID hygiene**: Do not place PrizmKit feature/bug/refactor IDs (`F-001`, `B-001`, `R-001`), task IDs, session IDs, run IDs, branch names, absolute worktree paths, or `.prizmkit/specs` / `.prizmkit/dev-pipeline` artifact paths in `.prizmkit/prizm-docs/`, user-visible UI text, API responses, emails, notifications, or tests that assert visible product copy. Translate internal references into durable product/domain language before writing memory docs, tests, or UI copy.
|
|
44
45
|
- **Cover three paths for each function**: happy path (valid inputs producing expected behavior), edge cases (boundary values specific to the parameter type and domain — e.g., zero/min/max for numeric, empty collection, boundary index), and error conditions (inputs that should trigger error handling). Determine edge cases from the function's parameter types and domain logic, not from a fixed checklist. If a function has no edge or error paths, don't force them.
|
|
45
46
|
- **No redundant tests**: Check if a test for this behavior already exists before writing. Each test must verify a uniquely different code path — don't write multiple tests that exercise the same logic.
|
|
46
47
|
- **Test your own code only**: Don't test framework behavior, third-party library internals, or language built-ins. For library calls, test the integration point (correct parameters passed, return value correctly handled), not the library itself.
|
|
@@ -183,7 +183,7 @@ Invoke prizmkit-prizm-docs (Init operation), passing the two-tier module structu
|
|
|
183
183
|
- For each module entry in MODULE_INDEX/MODULE_GROUPS, include keyword tags extracted from the module's source files — scan for: exported symbols, imported packages, domain terms in file/directory names. Format: `- module-name [tag1, tag2, tag3]: ...`. Tags help AI match user intent to relevant modules.
|
|
184
184
|
- Generate L1 docs for top-level modules at `.prizmkit/prizm-docs/<M>.prizm` and for sub-modules at `.prizmkit/prizm-docs/<M>/<S>.prizm`
|
|
185
185
|
- Skip L2 (lazy generation) — L2 is generated on first file modification, saving tokens upfront
|
|
186
|
-
- Do not create auxiliary `changelog.prizm
|
|
186
|
+
- Do not create auxiliary `changelog.prizm`, CHANGELOG sections/files, UPDATED/date metadata, feature/bug/refactor/task/session/run/pipeline/workflow IDs, branch names, absolute worktree paths, or `.prizmkit/specs` / `.prizmkit/dev-pipeline` artifact paths; git history is the source of change history
|
|
187
187
|
|
|
188
188
|
**Phase 6: Workspace Initialization**
|
|
189
189
|
6a. Create `.prizmkit/` directory structure (if missing):
|
|
@@ -19,11 +19,13 @@ Handles re-init without losing user edits:
|
|
|
19
19
|
| Field | Type | Description |
|
|
20
20
|
|-------|------|-------------|
|
|
21
21
|
| `adoption_mode` | string | `"passive"` \| `"advisory"` \| `"active"` |
|
|
22
|
-
| `platform` | string | `"codebuddy"` \| `"claude"` \| `"
|
|
22
|
+
| `platform` | string | `"codebuddy"` \| `"claude"` \| `"codex"` \| `"all"` |
|
|
23
23
|
| `tech_stack` | object | Detected or user-provided tech stack |
|
|
24
24
|
| `tech_stack._auto_detected` | boolean | `true` if auto-detected, `false` if user-provided |
|
|
25
25
|
| `detected_layers` | string[] | Development layers detected in the project. Written by prizmkit-init Phase 4.5. Used to determine available rule configuration options. Values: `frontend` / `backend` / `database` / `mobile`. Empty array when no layers detected or user skipped rules. Always updated on every init run based on fresh code detection — not gated by `_auto_detected` (see Merge Strategy above). |
|
|
26
26
|
|
|
27
|
+
Legacy manifests may still contain `both` for read-only migration compatibility. New config writes must use `codebuddy`, `claude`, `codex`, or `all`.
|
|
28
|
+
|
|
27
29
|
## Examples
|
|
28
30
|
|
|
29
31
|
Fullstack project:
|
|
@@ -49,6 +49,8 @@ A universal spec + plan generator. Takes a natural-language description of ANY d
|
|
|
49
49
|
|
|
50
50
|
**Writing principles**: Focus on WHAT and WHY, never HOW. Every goal needs acceptance criteria. Scope boundaries must be explicit. Mark all genuine ambiguities — the clarification phase resolves them.
|
|
51
51
|
|
|
52
|
+
**Internal ID hygiene**: PrizmKit IDs (`F-001`, `B-001`, `R-001`), task IDs (`T-100`), session IDs, run IDs, branch names, absolute worktree paths, and `.prizmkit/specs` / `.prizmkit/dev-pipeline` artifact paths are internal tracking metadata. They may appear in specs, plans, commit messages, and non-memory pipeline artifacts, but must never be written to `.prizmkit/prizm-docs/`, user-visible product copy, UI text, API responses, or expected UI strings in tests. If a behavior is scoped to the current feature, describe the product behavior without the ID.
|
|
53
|
+
|
|
52
54
|
### Phase 1: Design (spec.md → plan.md)
|
|
53
55
|
|
|
54
56
|
**Precondition**: `spec.md` exists in the artifact directory.
|
|
@@ -37,6 +37,7 @@ CORE_PRINCIPLES:
|
|
|
37
37
|
- Self-updating (docs stay fresh via commit-time hooks)
|
|
38
38
|
- Universal (language and framework agnostic)
|
|
39
39
|
- Durable project knowledge over auxiliary history (decisions, traps, interfaces, dependencies)
|
|
40
|
+
- Memory hygiene over traceability noise (no CHANGELOG sections/files, UPDATED/date metadata, feature/bug/refactor/task/session/run/pipeline/workflow IDs, branch names, absolute worktree paths, or `.prizmkit/specs` / `.prizmkit/dev-pipeline` artifact paths)
|
|
40
41
|
- Size-enforced (hard limits per level prevent bloat)
|
|
41
42
|
- Lazy L2 generation (detail docs created on first modification or deep read, not during init)
|
|
42
43
|
- Rules hierarchy (root.prizm RULES are authoritative, module RULES supplement only)
|
|
@@ -294,7 +295,7 @@ CONSTRAINTS:
|
|
|
294
295
|
- DATA_FLOW: describes how data moves through the module (moved here from L1 in V4)
|
|
295
296
|
- RULES: full module-specific rules list (L1 only has a 1-3 item summary)
|
|
296
297
|
- DOMAIN-SPECIFIC SECTIONS are flexible, not prescribed
|
|
297
|
-
- DECISIONS
|
|
298
|
+
- DECISIONS records durable rationale only; update or remove stale entries in place when code reality changes
|
|
298
299
|
- TRAPS section is CRITICAL for preventing AI from making known mistakes
|
|
299
300
|
- TRAPS entries MUST have severity prefix ([CRITICAL], [HIGH], or [LOW]). [REVIEW] may precede severity as a temporary staleness marker.
|
|
300
301
|
- TRAPS optional fields: append `| REF: <7-char-hash>` for traceability, `| STALE_IF: <glob>` for auto-expiry detection
|
|
@@ -307,6 +308,7 @@ CONSTRAINTS:
|
|
|
307
308
|
|
|
308
309
|
TEMPORAL_INFO: Git history is the authoritative source for change timing and edit history.
|
|
309
310
|
AUXILIARY_FIELDS: Do not generate CHANGELOG or UPDATED fields in .prizm files.
|
|
311
|
+
WORKFLOW_METADATA: Do not write feature/bug/refactor/task/session/run/pipeline/workflow IDs, branch names, absolute worktree paths, or `.prizmkit/specs` / `.prizmkit/dev-pipeline` artifact paths into .prizm files.
|
|
310
312
|
RATIONALE: Keep project memory focused on durable architecture, interfaces, dependencies, traps, rules, and decisions.
|
|
311
313
|
|
|
312
314
|
---
|
|
@@ -429,6 +431,7 @@ DETAILED_STEPS: → ${SKILL_DIR}/references/op-update.md
|
|
|
429
431
|
|
|
430
432
|
NEVER: Add CHANGELOG sections or changelog.prizm during doc sync.
|
|
431
433
|
NEVER: Add UPDATED/date/time fields to .prizm files.
|
|
434
|
+
NEVER: Add workflow metadata such as feature/bug/refactor/task/session/run/pipeline/workflow IDs, branch names, absolute worktree paths, or `.prizmkit/specs` / `.prizmkit/dev-pipeline` artifact paths.
|
|
432
435
|
RATIONALE: Git already provides history; .prizm files should store only durable project memory.
|
|
433
436
|
|
|
434
437
|
---
|
|
@@ -446,6 +449,8 @@ NEVER: Stale information (update or delete, never leave outdated entries)
|
|
|
446
449
|
NEVER: Full file contents or large code blocks (summarize purpose and interfaces)
|
|
447
450
|
NEVER: TODO items or future plans (those belong in issue trackers)
|
|
448
451
|
NEVER: Session-specific context or conversation history (docs are session-independent)
|
|
452
|
+
NEVER: Workflow metadata such as feature/bug/refactor/task/session/run/pipeline/workflow IDs, branch names, absolute worktree paths, or `.prizmkit/specs` / `.prizmkit/dev-pipeline` artifact paths
|
|
453
|
+
NEVER: CHANGELOG sections, changelog.prizm, or update-history sections
|
|
449
454
|
NEVER: Flowcharts, diagrams, mermaid blocks, or ASCII art (wastes tokens, AI cannot parse visually)
|
|
450
455
|
NEVER: Markdown headers (## / ###) inside .prizm files (use ALL CAPS KEY: format instead)
|
|
451
456
|
NEVER: Rewrite entire .prizm files on update (modify only affected sections)
|
|
@@ -13,7 +13,7 @@ STEPS:
|
|
|
13
13
|
- HIERARCHY RULE: directory X inside top-level module M maps to .prizmkit/prizm-docs/<M>/<X>.prizm, never to .prizmkit/prizm-docs/<X>.prizm.
|
|
14
14
|
- Exclude .git/, node_modules/, vendor/, build/, dist/, __pycache__/, target/, bin/, .claude/, .codebuddy/, .prizmkit/, .prizmkit/prizm-docs/, dev-pipeline/. If total module count > 30, ask user for include/exclude patterns.
|
|
15
15
|
3. Create .prizmkit/prizm-docs/ directory structure mirroring the source tree exactly. For each top-level module M that has sub-modules, create the subdirectory .prizmkit/prizm-docs/<M>/.
|
|
16
|
-
4. Generate root.prizm (L0) with PROJECT, LANG, FRAMEWORK, BUILD, TEST, ENTRY, MODULE_INDEX with multi-level entries as needed for efficient navigation (constrained by 4KB limit), RULES extracted from CODEBUDDY.md/CLAUDE.md/README/linter configs, PATTERNS, and CROSS_CUTTING (cross-module concerns spanning 2+ modules). Set PRIZM_VERSION: 4. Max 4KB. No
|
|
16
|
+
4. Generate root.prizm (L0) with PROJECT, LANG, FRAMEWORK, BUILD, TEST, ENTRY, MODULE_INDEX with multi-level entries as needed for efficient navigation (constrained by 4KB limit), RULES extracted from CODEBUDDY.md/CLAUDE.md/README/linter configs, PATTERNS, and CROSS_CUTTING (cross-module concerns spanning 2+ modules). Set PRIZM_VERSION: 4. Max 4KB. No CHANGELOG sections/files, UPDATED/date metadata, feature/bug/refactor/task/session/run/pipeline/workflow IDs, branch names, absolute worktree paths, or `.prizmkit/specs` / `.prizmkit/dev-pipeline` artifact paths — git tracks history.
|
|
17
17
|
- If `.prizmkit/plans/project-brief.md` exists: add `PROJECT_BRIEF: .prizmkit/plans/project-brief.md` to root.prizm (generated by prizmkit-init). If not present, skip — prizmkit-init Phase 7 will add it later.
|
|
18
18
|
- If module count > 15: use MODULE_GROUPS format instead of MODULE_INDEX — group modules by functional domain (3-8 domains, inferred from directory structure and module responsibilities). See prizm-docs-format.md for MODULE_GROUPS format.
|
|
19
19
|
- For each module entry, auto-generate 3-6 keyword tags by scanning the module's key source files for: exported function/class names, imported library names, domain-specific terms in file/directory names. Add tags in square brackets after the module name (e.g., `- auth [login, session, jwt]: ...`). Tags are optional but recommended for projects with 10+ modules.
|
|
@@ -23,7 +23,7 @@ STEPS:
|
|
|
23
23
|
Each L1 includes MODULE (full relative path), FILES count, RESPONSIBILITY, SUBDIRS with pointers, KEY_FILES (5-10 most important), DEPENDENCIES (imports, imported-by, external), RULES (1-3 most critical only). L1 does NOT include INTERFACES, DATA_FLOW, TRAPS, or DECISIONS (those are L2, generated lazily). Max 4KB each.
|
|
24
24
|
6. Skip L2 docs during init — L2 is created lazily on first file modification or when AI needs deep understanding (ON_DEEP_READ trigger). L2 contains behavioral detail: INTERFACES, DATA_FLOW, TRAPS, DECISIONS, full RULES, domain-specific sections.
|
|
25
25
|
7. Configure UserPromptSubmit hook in platform settings per ${SKILL_DIR}/assets/prizm-docs-format.md.md Section 11.
|
|
26
|
-
8. Validate all generated docs: size limits (L0 <= 4KB, L1 <= 4KB), pointer resolution (every -> reference resolves), no circular dependencies, KEY: value format compliance, no anti-patterns (prose, code blocks, markdown headers), L1 does not contain INTERFACES/DATA_FLOW/TRAPS/DECISIONS, no
|
|
26
|
+
8. Validate all generated docs: size limits (L0 <= 4KB, L1 <= 4KB), pointer resolution (every -> reference resolves), no circular dependencies, KEY: value format compliance, no anti-patterns (prose, code blocks, markdown headers), L1 does not contain INTERFACES/DATA_FLOW/TRAPS/DECISIONS, no CHANGELOG sections/files, no UPDATED/date metadata, no feature/bug/refactor/task/session/run/pipeline/workflow IDs, no branch names, no absolute worktree paths, and no `.prizmkit/specs` / `.prizmkit/dev-pipeline` artifact paths.
|
|
27
27
|
9. Report summary: modules discovered, L1 docs generated, files excluded, warnings.
|
|
28
28
|
|
|
29
29
|
OUTPUT: List of generated files, module count, and validation results.
|
|
@@ -8,11 +8,12 @@ STEPS:
|
|
|
8
8
|
1. Get changed files via `git diff --cached --name-status`. If nothing staged, use `git diff --name-status`. If no git changes at all, do full rescan comparing code against existing docs — this includes checking for modules that have source files but no L2 doc.
|
|
9
9
|
2. Map changed files to modules by matching against MODULE_INDEX or MODULE_GROUPS in root.prizm. Group changes by module.
|
|
10
10
|
3. Classify each change: A (added) -> new KEY_FILES entries. D (deleted) -> remove entries, update counts. M (modified) -> check dependency changes. R (renamed) -> update all path references.
|
|
11
|
-
4. Update affected docs: L2 first (KEY_FILES, INTERFACES, DATA_FLOW, DEPENDENCIES, TRAPS, DECISIONS), then L1 (FILES count, KEY_FILES, DEPENDENCIES — L1 does NOT contain INTERFACES/DATA_FLOW/TRAPS/DECISIONS), then L0 (MODULE_INDEX or MODULE_GROUPS counts, CROSS_CUTTING) only if structural change.
|
|
11
|
+
4. Update affected docs: L2 first (KEY_FILES, INTERFACES, DATA_FLOW, DEPENDENCIES, TRAPS, DECISIONS), then L1 (FILES count, KEY_FILES, DEPENDENCIES — L1 does NOT contain INTERFACES/DATA_FLOW/TRAPS/DECISIONS), then L0 (MODULE_INDEX or MODULE_GROUPS counts, CROSS_CUTTING) only if structural change. Do not write CHANGELOG sections/files, UPDATED/date metadata, feature/bug/refactor/task/session/run/pipeline/workflow IDs, branch names, absolute worktree paths, or `.prizmkit/specs` / `.prizmkit/dev-pipeline` artifact paths — git tracks history. **Preserve** any `PROJECT_BRIEF:` line in root.prizm — it is managed by prizmkit-init, not by this skill.
|
|
12
12
|
5. Skip updates if: only internal implementation changed (no interface/dependency change), only comments/whitespace/formatting, only .prizm files changed. DO NOT skip test file changes or bug fixes — they may reveal TRAPS worth capturing in L2.
|
|
13
13
|
6. If new directory qualifies as a module (per MODULE_DISCOVERY_CRITERIA) and matches no existing module: create L1 immediately, add to MODULE_INDEX. If the current diff includes Added or Modified source files in this module → also create L2 immediately with sections: MODULE, FILES, RESPONSIBILITY, INTERFACES, DATA_FLOW, KEY_FILES, DEPENDENCIES, RULES, TRAPS, DECISIONS. Otherwise defer L2.
|
|
14
14
|
6a. **L2 gap check** (runs during full rescan mode only — when no git changes detected): For each existing module in MODULE_INDEX, check if L2 doc exists. If L2 is missing and the module has source files with meaningful logic (not trivial config/wrapper) → create L2 with sections: MODULE, FILES, RESPONSIBILITY, INTERFACES, DATA_FLOW, KEY_FILES, DEPENDENCIES, RULES, TRAPS, DECISIONS. This ensures Update fills documentation gaps left by previous sessions.
|
|
15
15
|
7. Enforce size limits: L0 > 4KB -> consolidate. L1 > 4KB -> trim KEY_FILES descriptions, ensure RULES <= 3 entries. L2 > 5KB -> trim non-essential derived detail or split oversized cross-cutting detail.
|
|
16
|
+
7a. Validate memory hygiene: no CHANGELOG/UPDATED fields, no workflow metadata, no L1 behavioral sections.
|
|
16
17
|
8. Stage updated .prizm files via `git add .prizmkit/prizm-docs/`
|
|
17
18
|
|
|
18
19
|
OUTPUT: List of updated/created/skipped docs with reasons.
|
|
@@ -5,12 +5,12 @@ Check format compliance and consistency of all .prizm docs.
|
|
|
5
5
|
PRECONDITION: .prizmkit/prizm-docs/ exists.
|
|
6
6
|
|
|
7
7
|
STEPS:
|
|
8
|
-
1. FORMAT CHECK: Verify all .prizm files use KEY: value format. Flag any prose paragraphs, code blocks (```), markdown headers (##), emoji, ASCII art, or horizontal rules. Flag TRAPS entries missing severity prefix ([CRITICAL], [HIGH], or [LOW]). Flag CHANGELOG/UPDATED/date
|
|
8
|
+
1. FORMAT CHECK: Verify all .prizm files use KEY: value format. Flag any prose paragraphs, code blocks (```), markdown headers (##), emoji, ASCII art, or horizontal rules. Flag TRAPS entries missing severity prefix ([CRITICAL], [HIGH], or [LOW]). Flag CHANGELOG sections/files, UPDATED/date metadata, feature/bug/refactor/task/session/run/pipeline/workflow IDs, branch names, absolute worktree paths, and `.prizmkit/specs` / `.prizmkit/dev-pipeline` artifact paths as auxiliary noise. Note: [REVIEW] preceding severity (e.g., `[REVIEW][HIGH]`) is a valid temporary staleness marker, not a format violation.
|
|
9
9
|
2. SIZE CHECK: Verify size limits: L0 <= 4KB, L1 <= 4KB, L2 <= 5KB. Report files exceeding limits with current size.
|
|
10
10
|
3. POINTER CHECK: Verify all arrow (->) references resolve to existing .prizm files. Report broken pointers.
|
|
11
11
|
4. STALENESS CHECK: Compare git modification time of each .prizm file against source directory. Flag docs where source was modified more recently.
|
|
12
12
|
5. COMPLETENESS CHECK: Verify root.prizm has all required fields (PRIZM_VERSION, PROJECT, LANG, MODULE_INDEX or MODULE_GROUPS). Verify L1 docs have MODULE, FILES, RESPONSIBILITY, DEPENDENCIES (no INTERFACES/TRAPS/DECISIONS). Verify L2 docs have MODULE, FILES, KEY_FILES, DEPENDENCIES, INTERFACES, TRAPS.
|
|
13
|
-
6. ANTI-PATTERN CHECK: Flag duplicate information across levels, implementation details in L0/L1, TODO items, session-specific context.
|
|
13
|
+
6. ANTI-PATTERN CHECK: Flag duplicate information across levels, implementation details in L0/L1, TODO items, session-specific context, changelog/history sections, and workflow metadata.
|
|
14
14
|
7. RULES HIERARCHY CHECK: Verify L1/L2 RULES do not contradict root.prizm RULES. L1/L2 may only supplement with module-specific exceptions.
|
|
15
15
|
8. TRAPS STALENESS CHECK: For each L2 doc where TRAPS section has more than 8 entries, verify that TRAPS include staleness metadata (`STALE_IF:` or `REF:` fields). Flag TRAPS without any staleness metadata as `NEEDS_METADATA` — these are not auto-removed, but flagged for the next `/prizmkit-retrospective` to enrich with `STALE_IF:` globs or `REF:` hashes.
|
|
16
16
|
|
|
@@ -43,6 +43,8 @@ Synchronize `.prizmkit/prizm-docs/` structure with actual codebase changes from
|
|
|
43
43
|
|
|
44
44
|
**Key outputs**: Synced L1 file counts, L2 INTERFACES/DATA_FLOW, DEPENDENCIES, and stale TRAPS cleanup.
|
|
45
45
|
|
|
46
|
+
**Memory hygiene**: `.prizmkit/prizm-docs/` must not contain CHANGELOG sections/files, UPDATED/date metadata, feature/bug/refactor/task/session/run/pipeline/workflow IDs, branch names, absolute worktree paths, or `.prizmkit/specs` / `.prizmkit/dev-pipeline` artifact paths. Convert artifact-scoped wording into durable product/domain language before writing.
|
|
47
|
+
|
|
46
48
|
---
|
|
47
49
|
|
|
48
50
|
### Job 2: Knowledge Injection (conditional)
|
|
@@ -40,6 +40,8 @@ When writing TRAPS:
|
|
|
40
40
|
|
|
41
41
|
**QUALITY GATE**: Every item must answer: "If a new AI session reads only `.prizmkit/prizm-docs/` and this entry, does it gain actionable understanding?" If not, discard. Do not record trivially observable code patterns — the AI can read the code directly.
|
|
42
42
|
|
|
43
|
+
**MEMORY HYGIENE GATE**: Before writing any `.prizmkit/prizm-docs/` entry, remove or translate workflow metadata. Never write CHANGELOG sections/files, UPDATED/date metadata, feature/bug/refactor/task/session/run/pipeline/workflow IDs, branch names, absolute worktree paths, or `.prizmkit/specs` / `.prizmkit/dev-pipeline` artifact paths. If source artifacts say "fixed in B-001" or "implemented in F-003", write only the durable product/domain fact.
|
|
44
|
+
|
|
43
45
|
**2c.** Inject into the correct `.prizmkit/prizm-docs/` file:
|
|
44
46
|
- Module-level TRAPS/RULES/DECISIONS → the affected **L2** `.prizm` file. If the target L2 does not exist, create it first using the L2 GENERATION TEMPLATE before injecting knowledge. (TRAPS/DECISIONS/RULES belong in L2, not L1.)
|
|
45
47
|
- Project-level RULES/PATTERNS → `root.prizm` (respect the current format — MODULE_INDEX or MODULE_GROUPS — do not convert between them during injection)
|
|
@@ -19,6 +19,8 @@ git diff HEAD --name-status
|
|
|
19
19
|
- **L1**: Update FILES count, KEY_FILES (if major files added/removed), DEPENDENCIES (if module-level deps changed). **L1 does NOT contain INTERFACES, DATA_FLOW, TRAPS, or DECISIONS** — those belong in L2 only.
|
|
20
20
|
- **L0 root.prizm**: Update MODULE_INDEX file counts only if counts changed. Update CROSS_CUTTING if cross-module concerns changed. Update only if structural change (module added/removed). **Preserve** any `PROJECT_BRIEF:` line — it is managed by prizmkit-init.
|
|
21
21
|
|
|
22
|
+
**Memory hygiene**: During L0/L1/L2 updates, do not write CHANGELOG sections/files, UPDATED/date metadata, feature/bug/refactor/task/session/run/pipeline/workflow IDs, branch names, absolute worktree paths, or `.prizmkit/specs` / `.prizmkit/dev-pipeline` artifact paths. Update durable sections in place; git history is the change log.
|
|
23
|
+
|
|
22
24
|
**1e.** If new directory qualifies as a module and matches no existing module:
|
|
23
25
|
- A directory qualifies as a module if any of: contains source files forming a logical unit, contains entry/config/interface files, contains qualifying sub-modules, or is referenced by multiple modules as dependency.
|
|
24
26
|
- Create L1 doc immediately, add to MODULE_INDEX.
|
|
@@ -45,7 +45,7 @@ If you believe the task is better suited for a different workflow, you MUST:
|
|
|
45
45
|
- Codex → `AGENTS.md`
|
|
46
46
|
- Claude Code → `CLAUDE.md`
|
|
47
47
|
- CodeBuddy → `CODEBUDDY.md`
|
|
48
|
-
- `
|
|
48
|
+
- `all` → all three files. Legacy manifests may contain `both`; treat it as read-only compatibility and update `CLAUDE.md` and `CODEBUDDY.md` only when encountered.
|
|
49
49
|
- Only when the manifest is missing, fall back to installed PrizmKit-owned platform files such as `.codex/agents/*.toml`, `.claude/commands/prizm-kit.md`, or `.codebuddy/skills/prizm-kit/SKILL.md`. Do not treat a generic `.agents/` directory as Codex.
|
|
50
50
|
|
|
51
51
|
**After planning is complete**, you MUST:
|
|
@@ -29,7 +29,7 @@ After Phase 2 (Confirm constraints and tech assumptions), before Phase 3 (Captur
|
|
|
29
29
|
- `codex` → append to `AGENTS.md`
|
|
30
30
|
- `claude` → append to `CLAUDE.md`
|
|
31
31
|
- `codebuddy` → append to `CODEBUDDY.md`
|
|
32
|
-
- `
|
|
32
|
+
- `all` → append to all three files. Legacy manifests may contain `both`; treat it as read-only compatibility and append to `CLAUDE.md` and `CODEBUDDY.md` only when encountered.
|
|
33
33
|
- Only when the manifest is missing, fall back to PrizmKit-owned install artifacts: `.codex/agents/*.toml`, `.claude/commands/prizm-kit.md`, `.codebuddy/skills/prizm-kit/SKILL.md`.
|
|
34
34
|
- Do not treat a generic `.agents/` directory as Codex; it may contain unrelated third-party skills.
|
|
35
35
|
- If no platform can be determined, skip (no project instruction file).
|
|
@@ -135,7 +135,7 @@ Before questions, check optional context files (never block if absent):
|
|
|
135
135
|
- `.prizmkit/config.json` (existing stack preferences and detected tech stack)
|
|
136
136
|
- `.prizmkit/plans/project-brief.md` (project context from app-planner, if available)
|
|
137
137
|
- existing `.prizmkit/plans/feature-list.json` (required for incremental mode)
|
|
138
|
-
- Platform instruction file: use the `platform` field in `.prizmkit/manifest.json` as source of truth when present (`codex` → `AGENTS.md`, `claude` → `CLAUDE.md`, `codebuddy` → `CODEBUDDY.md
|
|
138
|
+
- Platform instruction file: use the `platform` field in `.prizmkit/manifest.json` as source of truth when present (`codex` → `AGENTS.md`, `claude` → `CLAUDE.md`, `codebuddy` → `CODEBUDDY.md`, `all` → read every matching file). Legacy manifests may contain `both`; treat it as read-only compatibility and read `CLAUDE.md` plus `CODEBUDDY.md` only when encountered.
|
|
139
139
|
- If `.prizmkit/prizm-docs/root.prizm` is absent and the project has existing source code, scan the directory structure to understand the codebase layout:
|
|
140
140
|
```powershell
|
|
141
141
|
Get-ChildItem -Path . -Directory -Recurse -Depth 2 -ErrorAction SilentlyContinue |
|
|
@@ -184,7 +184,7 @@ Invoke prizmkit-prizm-docs (Init operation), passing the two-tier module structu
|
|
|
184
184
|
- For each module entry in MODULE_INDEX/MODULE_GROUPS, include keyword tags extracted from the module's source files — scan for: exported symbols, imported packages, domain terms in file/directory names. Format: `- module-name [tag1, tag2, tag3]: ...`. Tags help AI match user intent to relevant modules.
|
|
185
185
|
- Generate L1 docs for top-level modules at `.prizmkit/prizm-docs/<M>.prizm` and for sub-modules at `.prizmkit/prizm-docs/<M>/<S>.prizm`
|
|
186
186
|
- Skip L2 (lazy generation) — L2 is generated on first file modification, saving tokens upfront
|
|
187
|
-
- Do not create auxiliary `changelog.prizm
|
|
187
|
+
- Do not create auxiliary `changelog.prizm`, CHANGELOG sections/files, UPDATED/date metadata, feature/bug/refactor/task/session/run/pipeline/workflow IDs, branch names, absolute worktree paths, or `.prizmkit/specs` / `.prizmkit/dev-pipeline` artifact paths; git history is the source of change history
|
|
188
188
|
|
|
189
189
|
**Phase 6: Workspace Initialization**
|
|
190
190
|
6a. Create `.prizmkit/` directory structure (if missing):
|
|
@@ -19,11 +19,13 @@ Handles re-init without losing user edits:
|
|
|
19
19
|
| Field | Type | Description |
|
|
20
20
|
|-------|------|-------------|
|
|
21
21
|
| `adoption_mode` | string | `"passive"` \| `"advisory"` \| `"active"` |
|
|
22
|
-
| `platform` | string | `"codebuddy"` \| `"claude"` \| `"
|
|
22
|
+
| `platform` | string | `"codebuddy"` \| `"claude"` \| `"codex"` \| `"all"` |
|
|
23
23
|
| `tech_stack` | object | Detected or user-provided tech stack |
|
|
24
24
|
| `tech_stack._auto_detected` | boolean | `true` if auto-detected, `false` if user-provided |
|
|
25
25
|
| `detected_layers` | string[] | Development layers detected in the project. Written by prizmkit-init Phase 4.5. Used to determine available rule configuration options. Values: `frontend` / `backend` / `database` / `mobile`. Empty array when no layers detected or user skipped rules. Always updated on every init run based on fresh code detection — not gated by `_auto_detected` (see Merge Strategy above). |
|
|
26
26
|
|
|
27
|
+
Legacy manifests may still contain `both` for read-only migration compatibility. New config writes must use `codebuddy`, `claude`, `codex`, or `all`.
|
|
28
|
+
|
|
27
29
|
## Examples
|
|
28
30
|
|
|
29
31
|
Fullstack project:
|
|
@@ -107,7 +107,7 @@ done
|
|
|
107
107
|
find .prizmkit/prizm-docs -name '*.prizm' 2>/dev/null | while IFS= read -r prizm_file; do
|
|
108
108
|
_basename=$(basename "$prizm_file")
|
|
109
109
|
case "$_basename" in
|
|
110
|
-
root.prizm
|
|
110
|
+
root.prizm)
|
|
111
111
|
continue
|
|
112
112
|
;;
|
|
113
113
|
esac
|
|
@@ -19,20 +19,69 @@ FILES=$(git diff --cached --name-only 2>/dev/null | grep '\.prizm$')
|
|
|
19
19
|
[ -z "$FILES" ] && exit 0
|
|
20
20
|
|
|
21
21
|
ERRORS=0
|
|
22
|
+
TEMP_FILES=""
|
|
23
|
+
|
|
24
|
+
cleanup() {
|
|
25
|
+
# shellcheck disable=SC2086
|
|
26
|
+
[ -z "$TEMP_FILES" ] || rm -f $TEMP_FILES
|
|
27
|
+
}
|
|
28
|
+
trap cleanup EXIT HUP INT TERM
|
|
29
|
+
|
|
22
30
|
for FILE in $FILES; do
|
|
23
|
-
|
|
31
|
+
git cat-file -e ":$FILE" 2>/dev/null || continue
|
|
32
|
+
CHECK_FILE=$(mktemp "${TMPDIR:-/tmp}/prizm-doc.XXXXXX") || exit 1
|
|
33
|
+
TEMP_FILES="$TEMP_FILES $CHECK_FILE"
|
|
34
|
+
git show ":$FILE" > "$CHECK_FILE" 2>/dev/null || continue
|
|
24
35
|
|
|
25
|
-
if grep -qE '^#{1,6} ' "$
|
|
36
|
+
if grep -qE '^#{1,6} ' "$CHECK_FILE"; then
|
|
26
37
|
echo "ERROR: $FILE contains markdown headers (##). Use KEY: value format." >&2
|
|
27
38
|
ERRORS=$((ERRORS + 1))
|
|
28
39
|
fi
|
|
29
40
|
|
|
30
|
-
if grep -q '^```' "$
|
|
41
|
+
if grep -q '^```' "$CHECK_FILE"; then
|
|
31
42
|
echo "ERROR: $FILE contains code blocks. Use file_path:line_number reference." >&2
|
|
32
43
|
ERRORS=$((ERRORS + 1))
|
|
33
44
|
fi
|
|
34
45
|
|
|
35
|
-
|
|
46
|
+
BASE_NAME=$(basename "$FILE" | tr '[:upper:]' '[:lower:]')
|
|
47
|
+
case "$BASE_NAME" in
|
|
48
|
+
changelog.prizm|changelog-archive.prizm|*changelog*.prizm)
|
|
49
|
+
echo "ERROR: $FILE is auxiliary history. Use git history instead of changelog .prizm files." >&2
|
|
50
|
+
ERRORS=$((ERRORS + 1))
|
|
51
|
+
;;
|
|
52
|
+
esac
|
|
53
|
+
if grep -qiE '^[[:space:]]*[-*]?[[:space:]]*(CHANGELOG|CREATED([ _-]?(AT|ON|DATE))?|UPDATED([ _-]?(AT|ON|DATE))?|MODIFIED([ _-]?(AT|ON|DATE))?|LAST[ _-]?(UPDATED|MODIFIED)([ _-]?(AT|ON|DATE))?|DATE|TIMESTAMP):' "$CHECK_FILE"; then
|
|
54
|
+
echo "ERROR: $FILE contains auxiliary history metadata. Use durable KEY: value sections only; git tracks history." >&2
|
|
55
|
+
ERRORS=$((ERRORS + 1))
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
if grep -qiE '(^|[^[:alnum:]_])([FBR]-[0-9]{3}|T-[0-9]{3})(-[A-Z])?([^[:alnum:]_]|$)' "$CHECK_FILE" \
|
|
59
|
+
|| grep -qiE '^[[:space:]]*[-*]?[[:space:]]*((bug|feature|refactor|task)[ _-]?id|(session|run|pipeline|workflow)([ _-]?id)?)([[:space:]]*(:|=)|[[:space:]]+)' "$CHECK_FILE" \
|
|
60
|
+
|| grep -qiE '^[[:space:]]*[-*]?[[:space:]]*(bug|feature|refactor|task|session|run|pipeline|workflow)([ _-](bug|feature|refactor|task|session|run|pipeline|workflow|id))+([[:space:]]*(:|=)|[[:space:]]+)' "$CHECK_FILE"; then
|
|
61
|
+
echo "ERROR: $FILE contains workflow metadata. Translate IDs, branch names, worktree paths, and pipeline artifacts into durable product/domain language." >&2
|
|
62
|
+
ERRORS=$((ERRORS + 1))
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
if sed 's#\\#/#g' "$CHECK_FILE" | grep -qE '(^|[^[:alnum:]_.-])\.prizmkit/(specs|dev-pipeline)($|/|[^[:alnum:]_.-])'; then
|
|
66
|
+
echo "ERROR: $FILE contains PrizmKit artifact paths. Translate specs/dev-pipeline references into durable product/domain language." >&2
|
|
67
|
+
ERRORS=$((ERRORS + 1))
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
if sed 's#\\#/#g' "$CHECK_FILE" | grep -qE '(^|[^[:alnum:]_./:-])(/Users/|/home/|/tmp/|/private/tmp/|/var/folders/|/workspace/|/workspaces/|/opt/|/srv/|/root/|/var/tmp/|/Volumes/|/mnt/[A-Za-z]/|[A-Za-z]:/)'; then
|
|
71
|
+
echo "ERROR: $FILE contains absolute worktree paths. Use repository-relative source paths only." >&2
|
|
72
|
+
ERRORS=$((ERRORS + 1))
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
if grep -qE '^[[:space:]]*[-*]?[[:space:]]*(BRANCH|BRANCH_NAME|CURRENT_BRANCH|SOURCE_BRANCH|BASE_BRANCH|HEAD_BRANCH|GIT_BRANCH|TARGET_BRANCH)[[:space:]_-]*(:|=|[[:space:]])' "$CHECK_FILE" \
|
|
76
|
+
|| grep -qE '^[[:space:]]*[-*]?[[:space:]]*[A-Z][A-Z0-9_]*_BRANCH[[:space:]_-]*(:|=|[[:space:]])[[:space:]]*(main|master|develop|development|trunk|[A-Za-z0-9._-]+/[A-Za-z0-9._/-]+|(feature|fix|bugfix|hotfix|release|chore|refactor|task|dev)[/_-][A-Za-z0-9._/-]+)[[:space:]]*(#.*)?$' "$CHECK_FILE" \
|
|
77
|
+
|| grep -qiE '^[[:space:]]*[-*]?[[:space:]]*(branch[ _-]*name|current[ _-]*branch|source[ _-]*branch|base[ _-]*branch|head[ _-]*branch|git[ _-]*branch|target[ _-]*branch)[[:space:]_-]*(:|=|[[:space:]])' "$CHECK_FILE" \
|
|
78
|
+
|| grep -qiE '^[[:space:]]*[-*]?[[:space:]]*([[:alnum:]]+[ _-]+)+branch([[:space:]]*(:|=)|[[:space:]]+)[[:space:]]*(main|master|develop|development|trunk|[A-Za-z0-9._-]+/[A-Za-z0-9._/-]+|(feature|fix|bugfix|hotfix|release|chore|refactor|task|dev)[/_-][A-Za-z0-9._/-]+)[[:space:]]*(#.*)?$' "$CHECK_FILE" \
|
|
79
|
+
|| grep -qiE '^[[:space:]]*[-*]?[[:space:]]*branch[[:space:]_-]*(:|=|[[:space:]])[[:space:]]*(main|master|develop|development|trunk|[A-Za-z0-9._-]+/[A-Za-z0-9._/-]+|(feature|fix|bugfix|hotfix|release|chore|refactor|task|dev)[/_-][A-Za-z0-9._/-]+)[[:space:]]*(#.*)?$' "$CHECK_FILE"; then
|
|
80
|
+
echo "ERROR: $FILE contains branch names. Describe durable product/domain context instead." >&2
|
|
81
|
+
ERRORS=$((ERRORS + 1))
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
SIZE=$(wc -c < "$CHECK_FILE" | tr -d ' ')
|
|
36
85
|
case "$FILE" in
|
|
37
86
|
*root.prizm) LIMIT=4096 ;;
|
|
38
87
|
*)
|
|
@@ -4,6 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
MODE="${1:---staged}"
|
|
6
6
|
ERRORS=0
|
|
7
|
+
TEMP_FILES=""
|
|
8
|
+
|
|
9
|
+
cleanup() {
|
|
10
|
+
# shellcheck disable=SC2086
|
|
11
|
+
[ -z "$TEMP_FILES" ] || rm -f $TEMP_FILES
|
|
12
|
+
}
|
|
13
|
+
trap cleanup EXIT HUP INT TERM
|
|
7
14
|
|
|
8
15
|
# Not a prizm project — exit silently
|
|
9
16
|
[ -f ".prizmkit/prizm-docs/root.prizm" ] || exit 0
|
|
@@ -22,22 +29,70 @@ fi
|
|
|
22
29
|
[ -z "$FILES" ] && exit 0
|
|
23
30
|
|
|
24
31
|
for FILE in $FILES; do
|
|
25
|
-
|
|
32
|
+
CHECK_FILE="$FILE"
|
|
33
|
+
if [ "$MODE" = "--staged" ]; then
|
|
34
|
+
git cat-file -e ":$FILE" 2>/dev/null || continue
|
|
35
|
+
CHECK_FILE=$(mktemp "${TMPDIR:-/tmp}/prizm-doc.XXXXXX") || exit 1
|
|
36
|
+
TEMP_FILES="$TEMP_FILES $CHECK_FILE"
|
|
37
|
+
git show ":$FILE" > "$CHECK_FILE" 2>/dev/null || continue
|
|
38
|
+
else
|
|
39
|
+
[ -f "$FILE" ] || continue
|
|
40
|
+
fi
|
|
26
41
|
|
|
27
42
|
# Check markdown headers
|
|
28
|
-
if grep -qE '^#{1,6} ' "$
|
|
43
|
+
if grep -qE '^#{1,6} ' "$CHECK_FILE"; then
|
|
29
44
|
echo "ERROR: $FILE contains markdown headers (##). Use KEY: value format." >&2
|
|
30
45
|
ERRORS=$((ERRORS + 1))
|
|
31
46
|
fi
|
|
32
47
|
|
|
33
48
|
# Check code blocks
|
|
34
|
-
if grep -q '^```' "$
|
|
49
|
+
if grep -q '^```' "$CHECK_FILE"; then
|
|
35
50
|
echo "ERROR: $FILE contains code blocks. Use file_path:line_number reference." >&2
|
|
36
51
|
ERRORS=$((ERRORS + 1))
|
|
37
52
|
fi
|
|
38
53
|
|
|
54
|
+
# Check auxiliary history fields and files
|
|
55
|
+
BASE_NAME=$(basename "$FILE" | tr '[:upper:]' '[:lower:]')
|
|
56
|
+
case "$BASE_NAME" in
|
|
57
|
+
changelog.prizm|changelog-archive.prizm|*changelog*.prizm)
|
|
58
|
+
echo "ERROR: $FILE is auxiliary history. Use git history instead of changelog .prizm files." >&2
|
|
59
|
+
ERRORS=$((ERRORS + 1))
|
|
60
|
+
;;
|
|
61
|
+
esac
|
|
62
|
+
if grep -qiE '^[[:space:]]*[-*]?[[:space:]]*(CHANGELOG|CREATED([ _-]?(AT|ON|DATE))?|UPDATED([ _-]?(AT|ON|DATE))?|MODIFIED([ _-]?(AT|ON|DATE))?|LAST[ _-]?(UPDATED|MODIFIED)([ _-]?(AT|ON|DATE))?|DATE|TIMESTAMP):' "$CHECK_FILE"; then
|
|
63
|
+
echo "ERROR: $FILE contains auxiliary history metadata. Use durable KEY: value sections only; git tracks history." >&2
|
|
64
|
+
ERRORS=$((ERRORS + 1))
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
# Check workflow metadata leakage
|
|
68
|
+
if grep -qiE '(^|[^[:alnum:]_])([FBR]-[0-9]{3}|T-[0-9]{3})(-[A-Z])?([^[:alnum:]_]|$)' "$CHECK_FILE" \
|
|
69
|
+
|| grep -qiE '^[[:space:]]*[-*]?[[:space:]]*((bug|feature|refactor|task)[ _-]?id|(session|run|pipeline|workflow)([ _-]?id)?)([[:space:]]*(:|=)|[[:space:]]+)' "$CHECK_FILE" \
|
|
70
|
+
|| grep -qiE '^[[:space:]]*[-*]?[[:space:]]*(bug|feature|refactor|task|session|run|pipeline|workflow)([ _-](bug|feature|refactor|task|session|run|pipeline|workflow|id))+([[:space:]]*(:|=)|[[:space:]]+)' "$CHECK_FILE"; then
|
|
71
|
+
echo "ERROR: $FILE contains workflow metadata. Translate IDs, branch names, worktree paths, and pipeline artifacts into durable product/domain language." >&2
|
|
72
|
+
ERRORS=$((ERRORS + 1))
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
if sed 's#\\#/#g' "$CHECK_FILE" | grep -qE '(^|[^[:alnum:]_.-])\.prizmkit/(specs|dev-pipeline)($|/|[^[:alnum:]_.-])'; then
|
|
76
|
+
echo "ERROR: $FILE contains PrizmKit artifact paths. Translate specs/dev-pipeline references into durable product/domain language." >&2
|
|
77
|
+
ERRORS=$((ERRORS + 1))
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
if sed 's#\\#/#g' "$CHECK_FILE" | grep -qE '(^|[^[:alnum:]_./:-])(/Users/|/home/|/tmp/|/private/tmp/|/var/folders/|/workspace/|/workspaces/|/opt/|/srv/|/root/|/var/tmp/|/Volumes/|/mnt/[A-Za-z]/|[A-Za-z]:/)'; then
|
|
81
|
+
echo "ERROR: $FILE contains absolute worktree paths. Use repository-relative source paths only." >&2
|
|
82
|
+
ERRORS=$((ERRORS + 1))
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
if grep -qE '^[[:space:]]*[-*]?[[:space:]]*(BRANCH|BRANCH_NAME|CURRENT_BRANCH|SOURCE_BRANCH|BASE_BRANCH|HEAD_BRANCH|GIT_BRANCH|TARGET_BRANCH)[[:space:]_-]*(:|=|[[:space:]])' "$CHECK_FILE" \
|
|
86
|
+
|| grep -qE '^[[:space:]]*[-*]?[[:space:]]*[A-Z][A-Z0-9_]*_BRANCH[[:space:]_-]*(:|=|[[:space:]])[[:space:]]*(main|master|develop|development|trunk|[A-Za-z0-9._-]+/[A-Za-z0-9._/-]+|(feature|fix|bugfix|hotfix|release|chore|refactor|task|dev)[/_-][A-Za-z0-9._/-]+)[[:space:]]*(#.*)?$' "$CHECK_FILE" \
|
|
87
|
+
|| grep -qiE '^[[:space:]]*[-*]?[[:space:]]*(branch[ _-]*name|current[ _-]*branch|source[ _-]*branch|base[ _-]*branch|head[ _-]*branch|git[ _-]*branch|target[ _-]*branch)[[:space:]_-]*(:|=|[[:space:]])' "$CHECK_FILE" \
|
|
88
|
+
|| grep -qiE '^[[:space:]]*[-*]?[[:space:]]*([[:alnum:]]+[ _-]+)+branch([[:space:]]*(:|=)|[[:space:]]+)[[:space:]]*(main|master|develop|development|trunk|[A-Za-z0-9._-]+/[A-Za-z0-9._/-]+|(feature|fix|bugfix|hotfix|release|chore|refactor|task|dev)[/_-][A-Za-z0-9._/-]+)[[:space:]]*(#.*)?$' "$CHECK_FILE" \
|
|
89
|
+
|| grep -qiE '^[[:space:]]*[-*]?[[:space:]]*branch[[:space:]_-]*(:|=|[[:space:]])[[:space:]]*(main|master|develop|development|trunk|[A-Za-z0-9._-]+/[A-Za-z0-9._/-]+|(feature|fix|bugfix|hotfix|release|chore|refactor|task|dev)[/_-][A-Za-z0-9._/-]+)[[:space:]]*(#.*)?$' "$CHECK_FILE"; then
|
|
90
|
+
echo "ERROR: $FILE contains branch names. Describe durable product/domain context instead." >&2
|
|
91
|
+
ERRORS=$((ERRORS + 1))
|
|
92
|
+
fi
|
|
93
|
+
|
|
39
94
|
# Size limits — determine level by path depth
|
|
40
|
-
SIZE=$(wc -c < "$
|
|
95
|
+
SIZE=$(wc -c < "$CHECK_FILE" | tr -d ' ')
|
|
41
96
|
case "$FILE" in
|
|
42
97
|
*root.prizm)
|
|
43
98
|
LIMIT=4096; LEVEL="L0"
|
|
@@ -51,7 +106,7 @@ for FILE in $FILES; do
|
|
|
51
106
|
HINT="Move implementation details to L2."
|
|
52
107
|
else
|
|
53
108
|
LIMIT=5120; LEVEL="L2"
|
|
54
|
-
HINT="
|
|
109
|
+
HINT="Remove stale or trivially derivable entries."
|
|
55
110
|
fi
|
|
56
111
|
;;
|
|
57
112
|
esac
|
|
@@ -64,11 +119,11 @@ for FILE in $FILES; do
|
|
|
64
119
|
# Required fields in root.prizm
|
|
65
120
|
case "$FILE" in
|
|
66
121
|
*root.prizm)
|
|
67
|
-
if ! grep -q 'PRIZM_VERSION:' "$
|
|
122
|
+
if ! grep -q 'PRIZM_VERSION:' "$CHECK_FILE"; then
|
|
68
123
|
echo "ERROR: $FILE missing required field PRIZM_VERSION:" >&2
|
|
69
124
|
ERRORS=$((ERRORS + 1))
|
|
70
125
|
fi
|
|
71
|
-
if ! grep -q 'MODULE_INDEX:' "$
|
|
126
|
+
if ! grep -q 'MODULE_INDEX:' "$CHECK_FILE"; then
|
|
72
127
|
echo "ERROR: $FILE missing required field MODULE_INDEX:" >&2
|
|
73
128
|
ERRORS=$((ERRORS + 1))
|
|
74
129
|
fi
|
|
@@ -19,7 +19,8 @@ This project uses PrizmKit with the Prizm documentation system for AI-optimized
|
|
|
19
19
|
- All `.prizm` files use KEY: value format, not prose
|
|
20
20
|
- Size limits: L0 = 4KB, L1 = 4KB, L2 = 5KB
|
|
21
21
|
- Arrow notation (->) indicates load pointers to other .prizm docs
|
|
22
|
-
-
|
|
22
|
+
- Memory files must not contain CHANGELOG sections/files, UPDATED/date metadata, feature/bug/refactor/task/session/run/pipeline/workflow IDs, branch names, absolute worktree paths, or `.prizmkit/specs` / `.prizmkit/dev-pipeline` artifact paths
|
|
23
|
+
- Update durable sections in place; git history is the change log
|
|
23
24
|
- No date/time fields — git is the authoritative source for temporal info
|
|
24
25
|
|
|
25
26
|
### Creating New L2 Docs
|
package/package.json
CHANGED
package/src/config.js
CHANGED
|
@@ -53,7 +53,7 @@ import {
|
|
|
53
53
|
confirmTeamMode,
|
|
54
54
|
confirmPipeline,
|
|
55
55
|
} from './prompts.js';
|
|
56
|
-
import { expandPlatforms, platformLabel, projectMemoryFile } from './platforms.js';
|
|
56
|
+
import { expandPlatforms, isKnownPlatform, platformLabel, projectMemoryFile } from './platforms.js';
|
|
57
57
|
import { normalizeRuntime, runtimeLabel } from './runtimes.js';
|
|
58
58
|
|
|
59
59
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
@@ -362,6 +362,10 @@ export async function runConfig(directory, options = {}) {
|
|
|
362
362
|
aiCli: userConfig.ai_cli || oldManifest.options?.aiCli || '',
|
|
363
363
|
};
|
|
364
364
|
|
|
365
|
+
if (options.platform !== undefined && !isKnownPlatform(options.platform)) {
|
|
366
|
+
throw new Error(`Unknown platform "${options.platform}". Expected codebuddy, claude, codex, or all.`);
|
|
367
|
+
}
|
|
368
|
+
|
|
365
369
|
// Display current config
|
|
366
370
|
console.log(chalk.bold(' 当前配置:'));
|
|
367
371
|
console.log(` 平台: ${chalk.cyan(platformLabel(currentConfig.platform))}`);
|
|
@@ -431,6 +435,10 @@ export async function runConfig(directory, options = {}) {
|
|
|
431
435
|
}
|
|
432
436
|
}
|
|
433
437
|
|
|
438
|
+
if (!isKnownPlatform(newConfig.platform)) {
|
|
439
|
+
throw new Error(`Unknown platform "${newConfig.platform}". Expected codebuddy, claude, codex, or all.`);
|
|
440
|
+
}
|
|
441
|
+
|
|
434
442
|
// ── Phase 3: COMPUTE DIFF ────────────────────────────────────────────────
|
|
435
443
|
|
|
436
444
|
const changes = [];
|
package/src/detect-platform.js
CHANGED
|
@@ -44,8 +44,6 @@ export function detectPlatform() {
|
|
|
44
44
|
let suggested = 'codebuddy';
|
|
45
45
|
if (cbc && claude && codex) {
|
|
46
46
|
suggested = 'all';
|
|
47
|
-
} else if ((cbc) && (claude)) {
|
|
48
|
-
suggested = 'both';
|
|
49
47
|
} else if (codex && !cbc && !claude) {
|
|
50
48
|
suggested = 'codex';
|
|
51
49
|
} else if ((claude) && !cbc) {
|
package/src/external-skills.js
CHANGED
|
@@ -21,7 +21,7 @@ import { expandPlatforms } from './platforms.js';
|
|
|
21
21
|
* skill.repo {string} - GitHub short ref (e.g. "pbakaus/impeccable") or full URL
|
|
22
22
|
* skill.name {string} - Skill name (used for display / single-skill mode)
|
|
23
23
|
* skill.installAll {boolean} - If true, install all skills from the repo
|
|
24
|
-
* @param {string} platform - 'claude' | 'codebuddy' | 'codex' | 'both'
|
|
24
|
+
* @param {string} platform - 'claude' | 'codebuddy' | 'codex' | 'all' ('both' supported only for legacy manifests)
|
|
25
25
|
* @param {string} projectRoot - Target project root
|
|
26
26
|
* @param {boolean} dryRun
|
|
27
27
|
*/
|
|
@@ -105,7 +105,7 @@ export async function installExternalSkill(skill, platform, projectRoot, dryRun)
|
|
|
105
105
|
* Call this once after all external skills have been installed.
|
|
106
106
|
*
|
|
107
107
|
* @param {string} projectRoot
|
|
108
|
-
* @param {string} platform - 'claude' | 'codebuddy' | 'codex' | 'both'
|
|
108
|
+
* @param {string} platform - 'claude' | 'codebuddy' | 'codex' | 'all' ('both' supported only for legacy manifests)
|
|
109
109
|
*/
|
|
110
110
|
export async function cleanExternalSkillArtifacts(projectRoot, platform) {
|
|
111
111
|
const keepDirs = new Set(
|
package/src/index.js
CHANGED
|
@@ -106,10 +106,6 @@ export async function runScaffold(directory, options) {
|
|
|
106
106
|
name: `Codex (AGENTS.md + .agents/skills + .codex/)${detected.codex ? chalk.green(' ← 已检测到 codex') : ''}`,
|
|
107
107
|
value: 'codex',
|
|
108
108
|
},
|
|
109
|
-
{
|
|
110
|
-
name: '同时安装 CodeBuddy + Claude Code',
|
|
111
|
-
value: 'both',
|
|
112
|
-
},
|
|
113
109
|
{
|
|
114
110
|
name: '同时安装全部平台',
|
|
115
111
|
value: 'all',
|
package/src/manifest.js
CHANGED
|
@@ -47,7 +47,7 @@ export async function writeManifest(projectRoot, data) {
|
|
|
47
47
|
* Build a manifest object from installation config.
|
|
48
48
|
* @param {Object} params
|
|
49
49
|
* @param {string} params.version - PrizmKit version
|
|
50
|
-
* @param {string} params.platform - 'codebuddy' | 'claude' | 'codex' | 'both'
|
|
50
|
+
* @param {string} params.platform - 'codebuddy' | 'claude' | 'codex' | 'all' ('both' supported only for legacy manifests)
|
|
51
51
|
* @param {string} [params.runtime] - 'unix' | 'windows'
|
|
52
52
|
* @param {string} params.suite - skill suite name
|
|
53
53
|
* @param {string[]} params.skills - resolved skill name list
|
package/src/platforms.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
export const PLATFORM_IDS = ['codebuddy', 'claude', 'codex'];
|
|
2
2
|
export const PLATFORM_GROUPS = {
|
|
3
|
-
both: ['codebuddy', 'claude'],
|
|
4
3
|
all: PLATFORM_IDS,
|
|
5
4
|
};
|
|
5
|
+
const LEGACY_PLATFORM_GROUPS = {
|
|
6
|
+
both: ['codebuddy', 'claude'],
|
|
7
|
+
};
|
|
6
8
|
|
|
7
9
|
export function expandPlatforms(platform) {
|
|
8
|
-
return PLATFORM_GROUPS[platform] || [platform];
|
|
10
|
+
return PLATFORM_GROUPS[platform] || LEGACY_PLATFORM_GROUPS[platform] || [platform];
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
export function isKnownPlatform(platform) {
|
|
@@ -13,8 +15,8 @@ export function isKnownPlatform(platform) {
|
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
export function platformLabel(platform) {
|
|
16
|
-
if (platform === 'both') return '
|
|
17
|
-
if (platform === 'all') return 'CodeBuddy
|
|
18
|
+
if (platform === 'both') return 'legacy codebuddy/claude group';
|
|
19
|
+
if (platform === 'all') return 'All platforms (CodeBuddy, Claude Code, Codex)';
|
|
18
20
|
if (platform === 'codebuddy') return 'CodeBuddy';
|
|
19
21
|
if (platform === 'claude') return 'Claude Code';
|
|
20
22
|
if (platform === 'codex') return 'Codex';
|
package/src/prompts.js
CHANGED
|
@@ -8,6 +8,16 @@ import chalk from 'chalk';
|
|
|
8
8
|
import { platformLabel } from './platforms.js';
|
|
9
9
|
import { normalizeRuntime } from './runtimes.js';
|
|
10
10
|
|
|
11
|
+
let selectPlatformPrompt = select;
|
|
12
|
+
|
|
13
|
+
export function __setSelectPlatformPromptForTests(promptFn) {
|
|
14
|
+
selectPlatformPrompt = promptFn;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function __resetSelectPlatformPromptForTests() {
|
|
18
|
+
selectPlatformPrompt = select;
|
|
19
|
+
}
|
|
20
|
+
|
|
11
21
|
export async function selectRuntime(currentRuntime) {
|
|
12
22
|
return select({
|
|
13
23
|
message: '选择运行系统 (决定安装 macOS/Linux 或 Windows 版本的流水线与编排技能):',
|
|
@@ -20,13 +30,23 @@ export async function selectRuntime(currentRuntime) {
|
|
|
20
30
|
}
|
|
21
31
|
|
|
22
32
|
/**
|
|
23
|
-
* Select target platform (codebuddy, claude, codex,
|
|
33
|
+
* Select target platform (codebuddy, claude, codex, or all).
|
|
24
34
|
* @param {string} currentPlatform - current platform value
|
|
25
35
|
* @param {Object} detected - detected environment info (e.g., { cbc: true, claude: false })
|
|
26
36
|
* @returns {Promise<string>}
|
|
27
37
|
*/
|
|
28
38
|
export async function selectPlatform(currentPlatform, detected = {}) {
|
|
29
|
-
const
|
|
39
|
+
const selectablePlatforms = ['codebuddy', 'claude', 'codex', 'all'];
|
|
40
|
+
const detectedDefault = selectablePlatforms.includes(detected.suggested)
|
|
41
|
+
? detected.suggested
|
|
42
|
+
: 'claude';
|
|
43
|
+
let defaultPlatform = detectedDefault;
|
|
44
|
+
if (currentPlatform === 'both') {
|
|
45
|
+
defaultPlatform = 'all';
|
|
46
|
+
} else if (selectablePlatforms.includes(currentPlatform)) {
|
|
47
|
+
defaultPlatform = currentPlatform;
|
|
48
|
+
}
|
|
49
|
+
const platform = await selectPlatformPrompt({
|
|
30
50
|
message: '选择目标平台 (决定安装的目录结构):',
|
|
31
51
|
choices: [
|
|
32
52
|
{
|
|
@@ -41,16 +61,12 @@ export async function selectPlatform(currentPlatform, detected = {}) {
|
|
|
41
61
|
name: `Codex (AGENTS.md + .agents/skills + .codex/)${detected.codex ? chalk.green(' ← 已检测到 codex') : ''}`,
|
|
42
62
|
value: 'codex',
|
|
43
63
|
},
|
|
44
|
-
{
|
|
45
|
-
name: '同时安装 CodeBuddy + Claude Code',
|
|
46
|
-
value: 'both',
|
|
47
|
-
},
|
|
48
64
|
{
|
|
49
65
|
name: `同时安装全部平台 (${platformLabel('all')})`,
|
|
50
66
|
value: 'all',
|
|
51
67
|
},
|
|
52
68
|
],
|
|
53
|
-
default:
|
|
69
|
+
default: defaultPlatform,
|
|
54
70
|
});
|
|
55
71
|
return platform;
|
|
56
72
|
}
|
package/src/scaffold.js
CHANGED
|
@@ -574,6 +574,135 @@ max_depth = 1
|
|
|
574
574
|
/**
|
|
575
575
|
* 安装 git pre-commit hook(prizm 格式校验)
|
|
576
576
|
*/
|
|
577
|
+
const PRIZMKIT_HOOK_MARKER_START = '# PRIZMKIT_PRE_COMMIT_HOOK_START';
|
|
578
|
+
const PRIZMKIT_HOOK_MARKER_END = '# PRIZMKIT_PRE_COMMIT_HOOK_END';
|
|
579
|
+
|
|
580
|
+
function escapeRegExp(value) {
|
|
581
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
function ensureTrailingNewline(value) {
|
|
585
|
+
return value.endsWith('\n') ? value : `${value}\n`;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
function buildStandalonePrizmHook(templateContent) {
|
|
589
|
+
const content = templateContent.trimEnd();
|
|
590
|
+
const firstNewline = content.indexOf('\n');
|
|
591
|
+
|
|
592
|
+
if (content.startsWith('#!') && firstNewline !== -1) {
|
|
593
|
+
return [
|
|
594
|
+
content.slice(0, firstNewline),
|
|
595
|
+
PRIZMKIT_HOOK_MARKER_START,
|
|
596
|
+
content.slice(firstNewline + 1),
|
|
597
|
+
PRIZMKIT_HOOK_MARKER_END,
|
|
598
|
+
'',
|
|
599
|
+
].join('\n');
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
return [
|
|
603
|
+
PRIZMKIT_HOOK_MARKER_START,
|
|
604
|
+
content,
|
|
605
|
+
PRIZMKIT_HOOK_MARKER_END,
|
|
606
|
+
'',
|
|
607
|
+
].join('\n');
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
function buildAppendedPrizmHook(templateContent) {
|
|
611
|
+
return [
|
|
612
|
+
PRIZMKIT_HOOK_MARKER_START,
|
|
613
|
+
templateContent.trimEnd(),
|
|
614
|
+
PRIZMKIT_HOOK_MARKER_END,
|
|
615
|
+
'',
|
|
616
|
+
].join('\n');
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
function insertPrizmHookIntoUserHook(userHookContent, prizmHookBlock) {
|
|
620
|
+
const content = userHookContent.trimEnd();
|
|
621
|
+
const terminalSuccessExitPattern = /(^|\n)([ \t]*exit[ \t]+0[ \t]*(?:#.*)?)[ \t]*$/;
|
|
622
|
+
const match = content.match(terminalSuccessExitPattern);
|
|
623
|
+
|
|
624
|
+
if (!match) {
|
|
625
|
+
return `${content}\n\n${prizmHookBlock}`;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
const exitLineStart = match.index + match[1].length;
|
|
629
|
+
const beforeExit = content.slice(0, exitLineStart).trimEnd();
|
|
630
|
+
const exitLine = match[2];
|
|
631
|
+
|
|
632
|
+
return [
|
|
633
|
+
beforeExit,
|
|
634
|
+
prizmHookBlock.trimEnd(),
|
|
635
|
+
exitLine,
|
|
636
|
+
'',
|
|
637
|
+
].filter((part, index) => index > 0 || part.length > 0).join('\n\n');
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
function findLegacyPrizmHookEnd(content, markerIndex) {
|
|
641
|
+
const afterMarker = content.slice(markerIndex);
|
|
642
|
+
const exitMatch = afterMarker.match(/(^|\n)[ \t]*exit[ \t]+0[ \t]*(\r?\n|$)/);
|
|
643
|
+
if (exitMatch) {
|
|
644
|
+
return markerIndex + exitMatch.index + exitMatch[0].length;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
const markerLineEnd = content.indexOf('\n', markerIndex);
|
|
648
|
+
const searchStart = markerLineEnd === -1 ? content.length : markerLineEnd + 1;
|
|
649
|
+
const blankLineIndex = content.slice(searchStart).search(/\r?\n[ \t]*(\r?\n|$)/);
|
|
650
|
+
if (blankLineIndex !== -1) {
|
|
651
|
+
return searchStart + blankLineIndex + 1;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
return content.length;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
function stripLegacyPrizmHookBlocks(existing) {
|
|
658
|
+
const legacyMarker = '# prizm-pre-commit.sh';
|
|
659
|
+
let cleaned = '';
|
|
660
|
+
let cursor = 0;
|
|
661
|
+
|
|
662
|
+
while (cursor < existing.length) {
|
|
663
|
+
const markerIndex = existing.indexOf(legacyMarker, cursor);
|
|
664
|
+
if (markerIndex === -1) {
|
|
665
|
+
cleaned += existing.slice(cursor);
|
|
666
|
+
break;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
const markerLineStart = existing.lastIndexOf('\n', markerIndex) + 1;
|
|
670
|
+
let blockStart = markerLineStart;
|
|
671
|
+
if (markerLineStart > 0) {
|
|
672
|
+
const previousLineEnd = markerLineStart - 1;
|
|
673
|
+
const previousLineStart = existing.lastIndexOf('\n', previousLineEnd - 1) + 1;
|
|
674
|
+
const previousLine = existing.slice(previousLineStart, previousLineEnd).replace(/\r$/, '');
|
|
675
|
+
if (previousLine.startsWith('#!')) {
|
|
676
|
+
blockStart = previousLineStart;
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
cleaned += existing.slice(cursor, blockStart);
|
|
681
|
+
cursor = findLegacyPrizmHookEnd(existing, markerIndex);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
return cleaned;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
function stripManagedPrizmHook(existing) {
|
|
688
|
+
const markedBlockPattern = new RegExp(
|
|
689
|
+
`(^|\\n)${escapeRegExp(PRIZMKIT_HOOK_MARKER_START)}[\\s\\S]*?${escapeRegExp(PRIZMKIT_HOOK_MARKER_END)}\\n?`,
|
|
690
|
+
'g',
|
|
691
|
+
);
|
|
692
|
+
|
|
693
|
+
let cleaned = existing.replace(markedBlockPattern, '\n');
|
|
694
|
+
cleaned = stripLegacyPrizmHookBlocks(cleaned);
|
|
695
|
+
|
|
696
|
+
return cleaned.replace(/\n{3,}/g, '\n\n').trimEnd();
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
function hasUserHookContent(content) {
|
|
700
|
+
return content
|
|
701
|
+
.replace(/^#!.*(\r?\n|$)/, '')
|
|
702
|
+
.trim()
|
|
703
|
+
.length > 0;
|
|
704
|
+
}
|
|
705
|
+
|
|
577
706
|
export async function installGitHook(projectRoot, dryRun, runtime = 'unix') {
|
|
578
707
|
const gitDir = path.join(projectRoot, '.git');
|
|
579
708
|
const normalizedRuntime = normalizeRuntime(runtime);
|
|
@@ -591,21 +720,17 @@ export async function installGitHook(projectRoot, dryRun, runtime = 'unix') {
|
|
|
591
720
|
const templatePath = path.join(getTemplatesDir(), 'hooks', 'prizm-pre-commit.sh');
|
|
592
721
|
const hooksDir = path.join(gitDir, 'hooks');
|
|
593
722
|
const preCommitPath = path.join(hooksDir, 'pre-commit');
|
|
723
|
+
const hookContent = fs.readFileSync(templatePath, 'utf8');
|
|
594
724
|
|
|
595
725
|
if (normalizedRuntime === RUNTIME_WINDOWS) {
|
|
596
|
-
if (fs.existsSync(preCommitPath)
|
|
726
|
+
if (fs.existsSync(preCommitPath)) {
|
|
597
727
|
const existing = fs.readFileSync(preCommitPath, 'utf8');
|
|
598
|
-
const
|
|
599
|
-
if (
|
|
728
|
+
const cleaned = stripManagedPrizmHook(existing);
|
|
729
|
+
if (!hasUserHookContent(cleaned)) {
|
|
600
730
|
await fs.remove(preCommitPath);
|
|
601
731
|
console.log(chalk.gray(' • .git/hooks/pre-commit shell hook removed for Windows runtime'));
|
|
602
|
-
} else if (existing.
|
|
603
|
-
|
|
604
|
-
if (cleaned) {
|
|
605
|
-
fs.writeFileSync(preCommitPath, `${cleaned}\n`);
|
|
606
|
-
} else {
|
|
607
|
-
await fs.remove(preCommitPath);
|
|
608
|
-
}
|
|
732
|
+
} else if (cleaned !== existing.trimEnd()) {
|
|
733
|
+
fs.writeFileSync(preCommitPath, ensureTrailingNewline(cleaned));
|
|
609
734
|
console.log(chalk.gray(' • PrizmKit shell hook block removed for Windows runtime'));
|
|
610
735
|
}
|
|
611
736
|
}
|
|
@@ -617,11 +742,15 @@ export async function installGitHook(projectRoot, dryRun, runtime = 'unix') {
|
|
|
617
742
|
|
|
618
743
|
if (fs.existsSync(preCommitPath)) {
|
|
619
744
|
const existing = fs.readFileSync(preCommitPath, 'utf8');
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
745
|
+
const cleaned = stripManagedPrizmHook(existing);
|
|
746
|
+
if (hasUserHookContent(cleaned)) {
|
|
747
|
+
fs.writeFileSync(preCommitPath, insertPrizmHookIntoUserHook(cleaned, buildAppendedPrizmHook(hookContent)));
|
|
748
|
+
} else {
|
|
749
|
+
fs.writeFileSync(preCommitPath, buildStandalonePrizmHook(hookContent));
|
|
750
|
+
}
|
|
751
|
+
fs.chmodSync(preCommitPath, 0o755);
|
|
623
752
|
} else {
|
|
624
|
-
|
|
753
|
+
fs.writeFileSync(preCommitPath, buildStandalonePrizmHook(hookContent));
|
|
625
754
|
fs.chmodSync(preCommitPath, 0o755);
|
|
626
755
|
}
|
|
627
756
|
|
|
@@ -1153,7 +1282,7 @@ export const EXTRAS_REGISTRY = {
|
|
|
1153
1282
|
/**
|
|
1154
1283
|
* 执行纯净安装
|
|
1155
1284
|
* @param {Object} config
|
|
1156
|
-
* @param {string} config.platform - 'codebuddy' | 'claude' | 'codex' | '
|
|
1285
|
+
* @param {string} config.platform - 'codebuddy' | 'claude' | 'codex' | 'all'
|
|
1157
1286
|
* @param {string} [config.runtime] - 'unix' | 'windows'
|
|
1158
1287
|
* @param {string} config.skills - 'core' | 'minimal' | 'recommended:<type>'
|
|
1159
1288
|
* @param {boolean} config.team - 是否启用团队模式
|
|
@@ -1171,7 +1300,7 @@ export async function scaffold(config) {
|
|
|
1171
1300
|
const { platform, skills, team, pipeline, rules, aiCli, externalSkills, playwrightCli, openCli, openCliAutoDownload, projectRoot, dryRun } = config;
|
|
1172
1301
|
const runtime = normalizeRuntime(config.runtime);
|
|
1173
1302
|
if (!isKnownPlatform(platform)) {
|
|
1174
|
-
throw new Error(`Unknown platform "${platform}". Expected codebuddy, claude, codex,
|
|
1303
|
+
throw new Error(`Unknown platform "${platform}". Expected codebuddy, claude, codex, or all.`);
|
|
1175
1304
|
}
|
|
1176
1305
|
const platforms = expandPlatforms(platform);
|
|
1177
1306
|
|
package/src/upgrade.js
CHANGED
|
@@ -229,7 +229,7 @@ export async function runUpgrade(directory, options = {}) {
|
|
|
229
229
|
// (e.g. legacy installs before manifest tracked platform).
|
|
230
230
|
let platform;
|
|
231
231
|
if (oldManifest?.platform) {
|
|
232
|
-
platform = oldManifest.platform;
|
|
232
|
+
platform = oldManifest.platform === 'both' ? 'all' : oldManifest.platform;
|
|
233
233
|
} else {
|
|
234
234
|
// Fallback: detect from filesystem for legacy manifests without platform field
|
|
235
235
|
const hasPlatformFiles = async (dir) => {
|
|
@@ -247,11 +247,14 @@ export async function runUpgrade(directory, options = {}) {
|
|
|
247
247
|
const hasCodex = await hasPlatformFiles(path.join(projectRoot, '.agents', 'skills'))
|
|
248
248
|
|| await hasPlatformFiles(path.join(projectRoot, '.codex', 'agents'));
|
|
249
249
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
250
|
+
const detectedPlatforms = [
|
|
251
|
+
hasCodeBuddy && 'codebuddy',
|
|
252
|
+
hasClaude && 'claude',
|
|
253
|
+
hasCodex && 'codex',
|
|
254
|
+
].filter(Boolean);
|
|
255
|
+
|
|
256
|
+
if (detectedPlatforms.length > 1) platform = 'all';
|
|
257
|
+
else if (detectedPlatforms.length === 1) platform = detectedPlatforms[0];
|
|
255
258
|
else platform = 'claude'; // ultimate fallback
|
|
256
259
|
}
|
|
257
260
|
|