prizmkit 1.0.15 → 1.0.16
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/skills/_metadata.json +1 -1
- package/bundled/skills/prizmkit-init/SKILL.md +28 -40
- package/bundled/templates/hooks/commit-intent-claude.json +11 -0
- package/bundled/templates/hooks/commit-intent-codebuddy.json +11 -0
- package/bundled/templates/hooks/diff-prizm-docs.sh +158 -0
- package/bundled/templates/hooks/prizm-pre-commit.sh +2 -1
- package/package.json +1 -1
- package/src/scaffold.js +23 -16
package/bundled/VERSION.json
CHANGED
|
@@ -39,44 +39,32 @@ BROWNFIELD WORKFLOW (existing project):
|
|
|
39
39
|
4. Catalog dependencies (external packages)
|
|
40
40
|
5. Count source files per directory
|
|
41
41
|
|
|
42
|
-
**Step 2:
|
|
43
|
-
2a.
|
|
44
|
-
- Count outdated dependencies (if lockfile exists)
|
|
45
|
-
- Note any known vulnerability patterns
|
|
46
|
-
|
|
47
|
-
2b. Scan for technical debt indicators:
|
|
48
|
-
- Count TODO/FIXME/HACK/XXX comments
|
|
49
|
-
- Identify large files (>500 lines)
|
|
50
|
-
- Check for test directories and coverage config
|
|
51
|
-
|
|
52
|
-
2c. Generate `ASSESSMENT.md` in project root with findings
|
|
53
|
-
|
|
54
|
-
**Step 3: Prizm Documentation Generation**
|
|
55
|
-
3a. Invoke prizmkit-prizm-docs `prizmkit.doc.init` algorithm:
|
|
42
|
+
**Step 2: Prizm Documentation Generation**
|
|
43
|
+
2a. Invoke prizmkit-prizm-docs `prizmkit.doc.init` algorithm:
|
|
56
44
|
- Create `.prizm-docs/` directory structure
|
|
57
45
|
- Generate `root.prizm` (L0) with project meta and module index
|
|
58
46
|
- Generate L1 docs for all discovered modules
|
|
59
47
|
- Create `changelog.prizm`
|
|
60
48
|
- Skip L2 (lazy generation)
|
|
61
49
|
|
|
62
|
-
|
|
50
|
+
2b. If project has existing `docs/AI_CONTEXT/`: suggest running `prizmkit.doc.migrate`
|
|
63
51
|
|
|
64
|
-
**Step
|
|
65
|
-
|
|
52
|
+
**Step 3: PrizmKit Workspace Initialization**
|
|
53
|
+
3a. Create `.prizmkit/` directory:
|
|
66
54
|
- `.prizmkit/config.json` (adoption_mode, speckit_hooks_enabled, platform)
|
|
67
55
|
- `.prizmkit/specs/` (empty)
|
|
68
56
|
|
|
69
|
-
**Step
|
|
57
|
+
**Step 4: Hook & Settings Configuration (Platform-Specific)**
|
|
70
58
|
|
|
71
59
|
**If platform is CodeBuddy (or both):**
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
60
|
+
4a-cb. Read or create `.codebuddy/settings.json`
|
|
61
|
+
4b-cb. Add UserPromptSubmit hook from `${SKILL_DIR}/../../../assets/hooks/prizm-commit-hook.json`
|
|
62
|
+
4c-cb. Preserve any existing hooks
|
|
75
63
|
|
|
76
64
|
**If platform is Claude Code (or both):**
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
65
|
+
4a-cl. Read or create `.claude/settings.json`
|
|
66
|
+
4b-cl. Add `permissions` and `allowedTools` entries if needed
|
|
67
|
+
4c-cl. Create `.claude/rules/prizm-documentation.md` with glob-scoped rules:
|
|
80
68
|
```yaml
|
|
81
69
|
---
|
|
82
70
|
description: PrizmKit documentation rules
|
|
@@ -91,7 +79,7 @@ BROWNFIELD WORKFLOW (existing project):
|
|
|
91
79
|
2. After changes, update affected `.prizm-docs/` files
|
|
92
80
|
3. Follow Prizm doc format (KEY: value, not prose)
|
|
93
81
|
```
|
|
94
|
-
|
|
82
|
+
4d-cl. Create `.claude/rules/prizm-commit-workflow.md` with commit-scoped rules:
|
|
95
83
|
```yaml
|
|
96
84
|
---
|
|
97
85
|
description: PrizmKit commit workflow enforcement
|
|
@@ -105,33 +93,33 @@ BROWNFIELD WORKFLOW (existing project):
|
|
|
105
93
|
4. Stage .prizm-docs/ changes
|
|
106
94
|
5. Use /prizmkit-committer for the complete workflow
|
|
107
95
|
```
|
|
108
|
-
|
|
96
|
+
4e-cl. Preserve any existing Claude settings and rules
|
|
109
97
|
|
|
110
|
-
**Step
|
|
98
|
+
**Step 5: Project Memory Update (Platform-Specific)**
|
|
111
99
|
|
|
112
100
|
**If platform is CodeBuddy (or both):**
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
101
|
+
5a-cb. Read existing `CODEBUDDY.md` (or create if missing)
|
|
102
|
+
5b-cb. Append PrizmKit section from `${SKILL_DIR}/../../../assets/codebuddy-md-template.md`
|
|
103
|
+
5c-cb. Do not duplicate if already present
|
|
116
104
|
|
|
117
105
|
**If platform is Claude Code (or both):**
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
106
|
+
5a-cl. Read existing `CLAUDE.md` (or create if missing)
|
|
107
|
+
5b-cl. Append PrizmKit section from `${SKILL_DIR}/../../../assets/claude-md-template.md`
|
|
108
|
+
5c-cl. Adjust command references to use `/command-name` format (not `prizmkit.xxx`)
|
|
109
|
+
5d-cl. Do not duplicate if already present
|
|
122
110
|
|
|
123
|
-
**Step
|
|
124
|
-
Output summary: platform detected, tech stack detected, modules discovered, L1 docs generated,
|
|
111
|
+
**Step 6: Report**
|
|
112
|
+
Output summary: platform detected, tech stack detected, modules discovered, L1 docs generated, platform-specific configuration applied, next recommended steps.
|
|
125
113
|
|
|
126
114
|
Include platform-specific guidance:
|
|
127
115
|
- CodeBuddy: "Use `prizmkit.specify` to start your first feature"
|
|
128
116
|
- Claude Code: "Use `/prizmkit-specify` to start your first feature"
|
|
129
117
|
|
|
130
118
|
GREENFIELD WORKFLOW (new project):
|
|
131
|
-
- Skip
|
|
132
|
-
- Step
|
|
133
|
-
- Steps
|
|
134
|
-
- Step
|
|
119
|
+
- Skip Step 1 (no code to scan)
|
|
120
|
+
- Step 2: Create minimal `.prizm-docs/` with just `root.prizm` skeleton
|
|
121
|
+
- Steps 3-5: Same as brownfield
|
|
122
|
+
- Step 6: Recommend starting with specify for first feature (platform-appropriate command format)
|
|
135
123
|
|
|
136
124
|
### Gradual Adoption Path
|
|
137
125
|
After init, PrizmKit operates in phases:
|
|
@@ -10,6 +10,17 @@
|
|
|
10
10
|
}
|
|
11
11
|
]
|
|
12
12
|
}
|
|
13
|
+
],
|
|
14
|
+
"PostToolUse": [
|
|
15
|
+
{
|
|
16
|
+
"matcher": "Bash",
|
|
17
|
+
"hooks": [
|
|
18
|
+
{
|
|
19
|
+
"type": "command",
|
|
20
|
+
"command": "if echo \"$CLAUDE_TOOL_INPUT\" 2>/dev/null | grep -qE 'git (commit|merge|rebase)' 2>/dev/null; then DRIFT=$(sh .prizmkit/scripts/diff-prizm-docs.sh 2>/dev/null); if [ -n \"$DRIFT\" ]; then echo \"PRIZMKIT_DRIFT_DETECTED: prizm-docs structural differences found after git operation:\"; echo \"$DRIFT\"; echo \"Please update affected .prizm-docs/ files using /prizmkit-prizm-docs.\"; fi; fi"
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
13
24
|
]
|
|
14
25
|
}
|
|
15
26
|
}
|
|
@@ -10,6 +10,17 @@
|
|
|
10
10
|
}
|
|
11
11
|
]
|
|
12
12
|
}
|
|
13
|
+
],
|
|
14
|
+
"PostToolUse": [
|
|
15
|
+
{
|
|
16
|
+
"matcher": "Bash",
|
|
17
|
+
"hooks": [
|
|
18
|
+
{
|
|
19
|
+
"type": "command",
|
|
20
|
+
"command": "TOOL_INPUT=\"${CLAUDE_TOOL_INPUT:-${CODEBUDDY_TOOL_INPUT:-}}\"; if echo \"$TOOL_INPUT\" | grep -qE 'git (commit|merge|rebase)' 2>/dev/null; then DRIFT=$(sh .prizmkit/scripts/diff-prizm-docs.sh 2>/dev/null); if [ -n \"$DRIFT\" ]; then echo \"PRIZMKIT_DRIFT_DETECTED: prizm-docs structural differences found:\"; echo \"$DRIFT\"; echo \"Please update affected .prizm-docs/ files.\"; fi; fi"
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
13
24
|
]
|
|
14
25
|
}
|
|
15
26
|
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# PrizmKit: diff-prizm-docs.sh
|
|
3
|
+
# Outputs structural differences between .prizm-docs/ and source code.
|
|
4
|
+
# Silent (exit 0) if no differences or if .prizm-docs doesn't exist.
|
|
5
|
+
# POSIX sh only — no arrays, no bashisms.
|
|
6
|
+
|
|
7
|
+
set -e
|
|
8
|
+
|
|
9
|
+
ROOT_PRIZM=".prizm-docs/root.prizm"
|
|
10
|
+
|
|
11
|
+
# 1. Exit silently if no root.prizm
|
|
12
|
+
[ -f "$ROOT_PRIZM" ] || exit 0
|
|
13
|
+
|
|
14
|
+
# 2. Detect language from LANG: field
|
|
15
|
+
LANG_VAL=$(grep '^LANG:' "$ROOT_PRIZM" | head -1 | sed 's/^LANG:[[:space:]]*//' | tr '[:upper:]' '[:lower:]')
|
|
16
|
+
|
|
17
|
+
case "$LANG_VAL" in
|
|
18
|
+
go)
|
|
19
|
+
FILE_PATTERN="*.go"
|
|
20
|
+
;;
|
|
21
|
+
javascript|typescript|javascript/typescript|typescript/javascript)
|
|
22
|
+
FILE_PATTERN="*.ts *.tsx *.js *.jsx"
|
|
23
|
+
;;
|
|
24
|
+
python)
|
|
25
|
+
FILE_PATTERN="*.py"
|
|
26
|
+
;;
|
|
27
|
+
rust)
|
|
28
|
+
FILE_PATTERN="*.rs"
|
|
29
|
+
;;
|
|
30
|
+
*)
|
|
31
|
+
FILE_PATTERN=""
|
|
32
|
+
;;
|
|
33
|
+
esac
|
|
34
|
+
|
|
35
|
+
# Helper: count source files in a directory (maxdepth 1) by language
|
|
36
|
+
count_source_files() {
|
|
37
|
+
_dir="$1"
|
|
38
|
+
[ -d "$_dir" ] || { echo 0; return; }
|
|
39
|
+
if [ -z "$FILE_PATTERN" ]; then
|
|
40
|
+
# All non-hidden files
|
|
41
|
+
find "$_dir" -maxdepth 1 -type f ! -name '.*' 2>/dev/null | wc -l | tr -d ' '
|
|
42
|
+
else
|
|
43
|
+
_count=0
|
|
44
|
+
for _pat in $FILE_PATTERN; do
|
|
45
|
+
_c=$(find "$_dir" -maxdepth 1 -type f -name "$_pat" 2>/dev/null | wc -l | tr -d ' ')
|
|
46
|
+
_count=$((_count + _c))
|
|
47
|
+
done
|
|
48
|
+
echo "$_count"
|
|
49
|
+
fi
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
# 3. Parse MODULE_INDEX from root.prizm
|
|
53
|
+
# Extract lines between MODULE_INDEX: and next ALL-CAPS header or EOF
|
|
54
|
+
# Each module line: "- src/auth: ..." -> source path is text before first ":" after "- "
|
|
55
|
+
REGISTERED_PATHS=""
|
|
56
|
+
_in_index=0
|
|
57
|
+
while IFS= read -r line; do
|
|
58
|
+
case "$line" in
|
|
59
|
+
MODULE_INDEX:*)
|
|
60
|
+
_in_index=1
|
|
61
|
+
continue
|
|
62
|
+
;;
|
|
63
|
+
esac
|
|
64
|
+
if [ "$_in_index" -eq 1 ]; then
|
|
65
|
+
# Check for next ALL-CAPS section header (word followed by colon, all uppercase letters)
|
|
66
|
+
_header=$(echo "$line" | grep '^[A-Z_][A-Z_]*:' || true)
|
|
67
|
+
if [ -n "$_header" ]; then
|
|
68
|
+
break
|
|
69
|
+
fi
|
|
70
|
+
# Extract source path from "- src/auth: ..."
|
|
71
|
+
case "$line" in
|
|
72
|
+
"- "*)
|
|
73
|
+
_path=$(echo "$line" | sed 's/^- //' | sed 's/:.*//')
|
|
74
|
+
if [ -n "$_path" ]; then
|
|
75
|
+
REGISTERED_PATHS="${REGISTERED_PATHS}${_path}
|
|
76
|
+
"
|
|
77
|
+
fi
|
|
78
|
+
;;
|
|
79
|
+
esac
|
|
80
|
+
fi
|
|
81
|
+
done < "$ROOT_PRIZM"
|
|
82
|
+
|
|
83
|
+
# 4. Check each registered module for drift
|
|
84
|
+
echo "$REGISTERED_PATHS" | while IFS= read -r source_path; do
|
|
85
|
+
[ -z "$source_path" ] && continue
|
|
86
|
+
|
|
87
|
+
# Derive L1 prizm file path
|
|
88
|
+
l1_file=".prizm-docs/${source_path}.prizm"
|
|
89
|
+
|
|
90
|
+
if [ ! -f "$l1_file" ]; then
|
|
91
|
+
continue
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
# Read declared FILES: count
|
|
95
|
+
declared=$(grep '^FILES:' "$l1_file" | head -1 | awk '{print $2}')
|
|
96
|
+
[ -z "$declared" ] && continue
|
|
97
|
+
|
|
98
|
+
# Count actual source files
|
|
99
|
+
actual=$(count_source_files "$source_path")
|
|
100
|
+
|
|
101
|
+
if [ "$actual" -gt 0 ] && [ "$declared" != "$actual" ]; then
|
|
102
|
+
echo "MODULE_DRIFT: $source_path | declared FILES: $declared | actual: $actual"
|
|
103
|
+
fi
|
|
104
|
+
done
|
|
105
|
+
|
|
106
|
+
# 5. Find orphan docs
|
|
107
|
+
find .prizm-docs -name '*.prizm' 2>/dev/null | while IFS= read -r prizm_file; do
|
|
108
|
+
_basename=$(basename "$prizm_file")
|
|
109
|
+
case "$_basename" in
|
|
110
|
+
root.prizm|changelog.prizm|changelog-archive.prizm)
|
|
111
|
+
continue
|
|
112
|
+
;;
|
|
113
|
+
esac
|
|
114
|
+
|
|
115
|
+
# Derive source path: remove .prizm-docs/ prefix and .prizm suffix
|
|
116
|
+
source_path=$(echo "$prizm_file" | sed 's|^\.prizm-docs/||' | sed 's|\.prizm$||')
|
|
117
|
+
|
|
118
|
+
if [ ! -d "$source_path" ]; then
|
|
119
|
+
echo "ORPHAN_DOC: $prizm_file | source dir missing"
|
|
120
|
+
fi
|
|
121
|
+
done
|
|
122
|
+
|
|
123
|
+
# 6. Find unregistered directories
|
|
124
|
+
find . -mindepth 1 -maxdepth 3 -type d \
|
|
125
|
+
! -path '*/.*' \
|
|
126
|
+
! -path '*/node_modules/*' ! -path './node_modules' \
|
|
127
|
+
! -path '*/vendor/*' ! -path './vendor' \
|
|
128
|
+
! -path '*/dist/*' ! -path './dist' \
|
|
129
|
+
! -path '*/build/*' ! -path './build' \
|
|
130
|
+
! -path '*/__pycache__/*' ! -path './__pycache__' \
|
|
131
|
+
! -path '*/target/*' ! -path './target' \
|
|
132
|
+
! -path '*/tests/*' ! -path './tests' \
|
|
133
|
+
! -path '*/__tests__/*' ! -path './__tests__' \
|
|
134
|
+
! -path '*/.prizm-docs/*' ! -path './.prizm-docs' \
|
|
135
|
+
! -path '*/.claude/*' ! -path './.claude' \
|
|
136
|
+
! -path '*/.codebuddy/*' ! -path './.codebuddy' \
|
|
137
|
+
! -path '*/dev-pipeline/*' ! -path './dev-pipeline' \
|
|
138
|
+
! -path '*/coverage/*' ! -path './coverage' \
|
|
139
|
+
! -path '*/.nyc_output/*' ! -path './.nyc_output' \
|
|
140
|
+
! -path '*/out/*' ! -path './out' \
|
|
141
|
+
! -path '*/tmp/*' ! -path './tmp' \
|
|
142
|
+
2>/dev/null | while IFS= read -r candidate; do
|
|
143
|
+
# Normalize: remove leading ./
|
|
144
|
+
candidate_clean=$(echo "$candidate" | sed 's|^\./||')
|
|
145
|
+
|
|
146
|
+
# Count source files
|
|
147
|
+
file_count=$(count_source_files "$candidate_clean")
|
|
148
|
+
|
|
149
|
+
if [ "$file_count" -ge 3 ]; then
|
|
150
|
+
# Check if registered in MODULE_INDEX
|
|
151
|
+
_match=$(echo "$REGISTERED_PATHS" | grep -Fx "$candidate_clean" || true)
|
|
152
|
+
if [ -z "$_match" ]; then
|
|
153
|
+
echo "UNREGISTERED: $candidate_clean | $file_count source files | not in MODULE_INDEX"
|
|
154
|
+
fi
|
|
155
|
+
fi
|
|
156
|
+
done
|
|
157
|
+
|
|
158
|
+
exit 0
|
|
@@ -6,7 +6,8 @@ PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null) || exit 0
|
|
|
6
6
|
# Only run in prizm projects
|
|
7
7
|
[ -f "$PROJECT_ROOT/.prizm-docs/root.prizm" ] || exit 0
|
|
8
8
|
|
|
9
|
-
VALIDATE_SCRIPT="$PROJECT_ROOT/
|
|
9
|
+
VALIDATE_SCRIPT="$PROJECT_ROOT/.prizmkit/scripts/validate-prizm-docs.sh"
|
|
10
|
+
[ -f "$VALIDATE_SCRIPT" ] || VALIDATE_SCRIPT="$PROJECT_ROOT/dev-pipeline/scripts/validate-prizm-docs.sh"
|
|
10
11
|
|
|
11
12
|
if [ -f "$VALIDATE_SCRIPT" ]; then
|
|
12
13
|
sh "$VALIDATE_SCRIPT" --staged
|
package/package.json
CHANGED
package/src/scaffold.js
CHANGED
|
@@ -472,25 +472,34 @@ async function installGitHook(projectRoot, dryRun) {
|
|
|
472
472
|
}
|
|
473
473
|
|
|
474
474
|
/**
|
|
475
|
-
* 安装
|
|
475
|
+
* 安装 PrizmKit 脚本到 .prizmkit/scripts/(始终安装)
|
|
476
476
|
*/
|
|
477
|
-
async function
|
|
478
|
-
const
|
|
479
|
-
|
|
477
|
+
async function installPrizmkitScripts(projectRoot, dryRun) {
|
|
478
|
+
const scriptsDir = path.join(projectRoot, '.prizmkit', 'scripts');
|
|
479
|
+
const templateHooksDir = path.join(getTemplatesDir(), 'hooks');
|
|
480
480
|
|
|
481
|
-
const
|
|
482
|
-
|
|
481
|
+
const scripts = [
|
|
482
|
+
'validate-prizm-docs.sh',
|
|
483
|
+
'diff-prizm-docs.sh',
|
|
484
|
+
];
|
|
483
485
|
|
|
484
486
|
if (dryRun) {
|
|
485
|
-
|
|
487
|
+
for (const s of scripts) {
|
|
488
|
+
console.log(chalk.gray(` [dry-run] .prizmkit/scripts/${s}`));
|
|
489
|
+
}
|
|
486
490
|
return;
|
|
487
491
|
}
|
|
488
492
|
|
|
489
|
-
await fs.ensureDir(
|
|
490
|
-
await fs.copy(sourcePath, targetPath);
|
|
491
|
-
fs.chmodSync(targetPath, 0o755);
|
|
493
|
+
await fs.ensureDir(scriptsDir);
|
|
492
494
|
|
|
493
|
-
|
|
495
|
+
for (const s of scripts) {
|
|
496
|
+
const src = path.join(templateHooksDir, s);
|
|
497
|
+
if (!fs.existsSync(src)) continue;
|
|
498
|
+
const tgt = path.join(scriptsDir, s);
|
|
499
|
+
await fs.copy(src, tgt);
|
|
500
|
+
fs.chmodSync(tgt, 0o755);
|
|
501
|
+
console.log(chalk.green(` ✓ .prizmkit/scripts/${s}`));
|
|
502
|
+
}
|
|
494
503
|
}
|
|
495
504
|
|
|
496
505
|
/**
|
|
@@ -711,11 +720,9 @@ export async function scaffold(config) {
|
|
|
711
720
|
console.log(chalk.blue(' Git Hook:'));
|
|
712
721
|
await installGitHook(projectRoot, dryRun);
|
|
713
722
|
|
|
714
|
-
// 11.
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
await installValidateScript(projectRoot, dryRun);
|
|
718
|
-
}
|
|
723
|
+
// 11. PrizmKit scripts (always installed)
|
|
724
|
+
console.log(chalk.blue(' PrizmKit 脚本:'));
|
|
725
|
+
await installPrizmkitScripts(projectRoot, dryRun);
|
|
719
726
|
|
|
720
727
|
// === 完成 ===
|
|
721
728
|
console.log('');
|