claude-prism 1.5.0 → 1.6.0
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/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +32 -0
- package/README.md +25 -1
- package/bin/cli.mjs +10 -3
- package/lib/config.mjs +6 -0
- package/lib/handoff.mjs +93 -12
- package/lib/installer.mjs +124 -6
- package/package.json +1 -1
- package/templates/commands/claude-prism/plan.md +30 -4
- package/templates/commands/claude-prism/stats.md +3 -3
- package/templates/rules-lean.md +106 -0
- package/templates/rules.md +18 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,38 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.6.0] — 2026-03-05
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **Session Bootstrap** — `<!-- PRISM:BOOT -->` block auto-injected into CLAUDE.md; instructs agents to read `docs/PROJECT-MEMORY.md`, `docs/HANDOFF.md`, active plans, and `.prism/registry.json` on session start
|
|
12
|
+
- **Plan Frontmatter** — plans support YAML frontmatter (`status`, `created`, `depends_on`); `/plan list` shows status icons (📋 active, ✅ completed, 📦 archived, 🚫 blocked)
|
|
13
|
+
- **Plan Check** — `/plan check` subcommand detects file overlaps across active plans (cross-plan conflict detection)
|
|
14
|
+
- **Docs Scaffolding** — `prism init --docs` creates `docs/` structure with `PROJECT-MEMORY.md`, `HANDOFF.md` templates and `.prism/registry.json` (auto-scans existing docs)
|
|
15
|
+
- **Project Registry** — `.prism/registry.json` catalogs SSOT documents, session files, and reference/archive paths
|
|
16
|
+
- **Lightweight Recording** — lightweight tasks now record a 1-line summary to `docs/PROJECT-MEMORY.md`
|
|
17
|
+
- **HANDOFF Auto-triggers** — rules.md documents PreCompact/SessionEnd hook auto-generation of HANDOFF.md
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
- `getActivePlanInfo()` now filters by frontmatter `status: active` (backward-compatible: no frontmatter = active)
|
|
21
|
+
- `dryRun()` shows docs scaffolding actions when `--docs` is used
|
|
22
|
+
- `stats.md` plan list shows frontmatter status icons
|
|
23
|
+
- `rules-lean.md` Session Handoff section updated with auto-generation info
|
|
24
|
+
|
|
25
|
+
### New exports
|
|
26
|
+
- `parseFrontmatter(content)` — parse YAML-like frontmatter from markdown
|
|
27
|
+
- `getAllPlans(projectRoot)` — list all plans with frontmatter + progress info merged
|
|
28
|
+
- `detectPlanConflicts(projectRoot)` — find file overlaps across active plans
|
|
29
|
+
|
|
30
|
+
## [1.6.0-beta.1] — 2026-03-04
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
- **Lean Router** — `rulesMode: "lean"` in `.prism/config.json` injects ~80-line behavioral modifiers instead of the full ~500-line methodology
|
|
34
|
+
- Core principle, Adaptive Weight routing, Bugfix Fast Path, Scope Guard, Verification Fallback Ladder, Self-correction triggers, Rationalization Defense, Completion Declaration
|
|
35
|
+
- Standard/Full tasks routed to `/claude-prism:prism` slash command for full EUDEC guidance
|
|
36
|
+
- Fallback: if `rules-lean.md` missing, automatically uses `rules.md`
|
|
37
|
+
- `getRulesMode()` export in `lib/config.mjs`
|
|
38
|
+
- 5 new lean mode tests
|
|
39
|
+
|
|
8
40
|
## [1.5.0] — 2026-03-04
|
|
9
41
|
|
|
10
42
|
### Changed
|
package/README.md
CHANGED
|
@@ -90,6 +90,12 @@ Injected into `CLAUDE.md`, EUDEC is a behavioral framework that corrects how AI
|
|
|
90
90
|
- **Streamlined verification**: 3-level fallback ladder (Tests → Build → Diff)
|
|
91
91
|
- **Adaptive checkpoints**: no pause for small tasks, summary for medium, full for large
|
|
92
92
|
|
|
93
|
+
**New in v1.6.0:**
|
|
94
|
+
- **Session Bootstrap** — agents auto-read `PROJECT-MEMORY.md`, `HANDOFF.md`, active plans, and registry on session start
|
|
95
|
+
- **Plan Lifecycle** — frontmatter (`status`, `created`, `depends_on`), `/plan check` for cross-plan file conflict detection
|
|
96
|
+
- **Docs Scaffolding** — `prism init --docs` creates `docs/` with templates + `.prism/registry.json`
|
|
97
|
+
- **Lightweight Recording** — even small tasks append a 1-line summary to `docs/PROJECT-MEMORY.md`
|
|
98
|
+
|
|
93
99
|
**New in v1.4.0:**
|
|
94
100
|
- **Native Claude Code plugin** — `claude plugin install claude-prism` for zero-config setup
|
|
95
101
|
- **4 new hook events** — PreCompact (auto-HANDOFF), SessionEnd (session protection), SubagentStart (scope injection), TaskCompleted (plan auto-update)
|
|
@@ -187,6 +193,7 @@ Plugin mode auto-registers hooks and skills. Run `prism init` additionally if yo
|
|
|
187
193
|
|
|
188
194
|
```bash
|
|
189
195
|
npx claude-prism init # Install with hooks (prompts for HUD)
|
|
196
|
+
npx claude-prism init --docs # Install + docs scaffolding (PROJECT-MEMORY, HANDOFF, registry)
|
|
190
197
|
npx claude-prism init --hud # Install + auto-enable HUD
|
|
191
198
|
npx claude-prism init --no-hooks # Methodology only, no hooks
|
|
192
199
|
npx claude-prism init --global # Global skill (all projects)
|
|
@@ -246,15 +253,32 @@ Edit `.prism/config.json`:
|
|
|
246
253
|
| Setting | Default | Description |
|
|
247
254
|
|---------|---------|-------------|
|
|
248
255
|
| `version` | 1 | Config schema version (for future migrations) |
|
|
256
|
+
| `rulesMode` | `"full"` | `"full"` injects the complete ~500-line EUDEC methodology; `"lean"` injects ~80-line behavioral modifiers and routes to `/claude-prism:prism` for full guidance |
|
|
249
257
|
| `commit-guard.maxTestAge` | 300 | Seconds before test run is considered stale |
|
|
250
258
|
| `plan-enforcement.warnAt` | 6 | Unique source file count that triggers plan warning |
|
|
251
259
|
| `task-plan-sync.matchThreshold` | 0.3 | Keyword overlap ratio for fuzzy task matching |
|
|
252
260
|
| `webhooks` | `[]` | HTTP endpoints for event notifications |
|
|
253
261
|
|
|
262
|
+
### Lean Router (beta)
|
|
263
|
+
|
|
264
|
+
By default, Prism injects the full EUDEC methodology (~500 lines) into `CLAUDE.md`. This provides passive absorption — the agent always has the complete framework in context.
|
|
265
|
+
|
|
266
|
+
**Lean mode** injects only ~80 lines of behavioral modifiers (Scope Guard, Verification Ladder, Bugfix Fast Path, etc.) and routes Standard/Full tasks to the `/claude-prism:prism` slash command for on-demand full guidance. This saves context window for code.
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
# Switch to lean mode
|
|
270
|
+
echo '{"version":1,"rulesMode":"lean"}' > .prism/config.json
|
|
271
|
+
prism update
|
|
272
|
+
|
|
273
|
+
# Switch back to full mode
|
|
274
|
+
echo '{"version":1,"rulesMode":"full"}' > .prism/config.json
|
|
275
|
+
prism update
|
|
276
|
+
```
|
|
277
|
+
|
|
254
278
|
## CLI Commands
|
|
255
279
|
|
|
256
280
|
```bash
|
|
257
|
-
prism init [--no-hooks] [--global] [--dry-run]
|
|
281
|
+
prism init [--no-hooks] [--docs] [--global] [--dry-run] # Install
|
|
258
282
|
prism init --hud # Install + auto-enable HUD
|
|
259
283
|
prism check [--ci] # Verify installation
|
|
260
284
|
prism doctor # Diagnose issues
|
package/bin/cli.mjs
CHANGED
|
@@ -44,9 +44,11 @@ switch (command) {
|
|
|
44
44
|
|
|
45
45
|
const hooks = !hasFlag('no-hooks');
|
|
46
46
|
|
|
47
|
+
const docs = hasFlag('docs');
|
|
48
|
+
|
|
47
49
|
if (hasFlag('dry-run')) {
|
|
48
50
|
const { dryRun } = await import('../lib/installer.mjs');
|
|
49
|
-
const result = dryRun(cwd, { hooks });
|
|
51
|
+
const result = dryRun(cwd, { hooks, docs });
|
|
50
52
|
console.log('🌈 claude-prism init --dry-run\n');
|
|
51
53
|
console.log(' Files that would be created/updated:\n');
|
|
52
54
|
for (const action of result.actions) {
|
|
@@ -58,7 +60,7 @@ switch (command) {
|
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
console.log('🌈 claude-prism init\n');
|
|
61
|
-
await init(cwd, { hooks });
|
|
63
|
+
await init(cwd, { hooks, docs });
|
|
62
64
|
|
|
63
65
|
console.log('✅ EUDEC methodology → CLAUDE.md');
|
|
64
66
|
console.log('✅ Commands → /prism, /checkpoint, /plan');
|
|
@@ -67,6 +69,10 @@ switch (command) {
|
|
|
67
69
|
} else {
|
|
68
70
|
console.log('⏭️ Hooks skipped (--no-hooks)');
|
|
69
71
|
}
|
|
72
|
+
if (docs) {
|
|
73
|
+
console.log('✅ Docs scaffolding → docs/PROJECT-MEMORY.md, docs/HANDOFF.md');
|
|
74
|
+
console.log('✅ Registry → .prism/registry.json');
|
|
75
|
+
}
|
|
70
76
|
|
|
71
77
|
// HUD prompt — only ask interactively if not already installed and no flag given
|
|
72
78
|
if (!hasFlag('no-hud') && process.stdin.isTTY) {
|
|
@@ -308,7 +314,7 @@ switch (command) {
|
|
|
308
314
|
console.log(`🌈 claude-prism — EUDEC methodology framework for AI coding agents
|
|
309
315
|
|
|
310
316
|
Usage:
|
|
311
|
-
prism init [--no-hooks]
|
|
317
|
+
prism init [--no-hooks] [--docs] Install prism in current project
|
|
312
318
|
prism init --global Install globally (~/.claude/) + OMC skill
|
|
313
319
|
prism check [--ci] Verify installation
|
|
314
320
|
prism doctor Diagnose issues with fix suggestions
|
|
@@ -325,6 +331,7 @@ Usage:
|
|
|
325
331
|
|
|
326
332
|
Options:
|
|
327
333
|
--no-hooks Skip commit guard hook
|
|
334
|
+
--docs Create docs/ scaffolding (PROJECT-MEMORY.md, HANDOFF.md, registry.json)
|
|
328
335
|
--hud Auto-enable HUD during init (no prompt)
|
|
329
336
|
--no-hud Skip HUD prompt during init
|
|
330
337
|
--dry-run Show what init would do without making changes
|
package/lib/config.mjs
CHANGED
|
@@ -7,6 +7,7 @@ import { readFileSync, existsSync } from 'fs';
|
|
|
7
7
|
import { join } from 'path';
|
|
8
8
|
|
|
9
9
|
const DEFAULTS = {
|
|
10
|
+
rulesMode: 'full',
|
|
10
11
|
sourceExtensions: ['ts', 'tsx', 'js', 'jsx', 'py', 'go', 'rs', 'java', 'c', 'cpp', 'h', 'svelte', 'vue', 'rb', 'kt', 'swift', 'php', 'cs', 'scala', 'ex', 'clj', 'zig', 'lua', 'dart'],
|
|
11
12
|
testPatterns: ['test', 'spec', '_test'],
|
|
12
13
|
customRules: [],
|
|
@@ -70,4 +71,9 @@ export function buildTestPattern(patterns) {
|
|
|
70
71
|
return new RegExp(`\\.(${escaped.join('|')})\\.`);
|
|
71
72
|
}
|
|
72
73
|
|
|
74
|
+
export function getRulesMode(projectRoot) {
|
|
75
|
+
const config = loadConfig(projectRoot);
|
|
76
|
+
return config.rulesMode === 'lean' ? 'lean' : 'full';
|
|
77
|
+
}
|
|
78
|
+
|
|
73
79
|
export { DEFAULTS };
|
package/lib/handoff.mjs
CHANGED
|
@@ -70,23 +70,61 @@ export function generateHandoff(projectRoot) {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
/**
|
|
73
|
-
*
|
|
73
|
+
* Parse YAML-like frontmatter from markdown content
|
|
74
|
+
* @param {string} content - Markdown file content
|
|
75
|
+
* @returns {Object} Parsed frontmatter key-value pairs
|
|
74
76
|
*/
|
|
75
|
-
export function
|
|
76
|
-
const
|
|
77
|
-
if (!
|
|
77
|
+
export function parseFrontmatter(content) {
|
|
78
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
79
|
+
if (!match) return {};
|
|
80
|
+
const fm = {};
|
|
81
|
+
for (const line of match[1].split('\n')) {
|
|
82
|
+
const [key, ...rest] = line.split(':');
|
|
83
|
+
if (key && rest.length) {
|
|
84
|
+
const val = rest.join(':').trim();
|
|
85
|
+
if (val.startsWith('[')) {
|
|
86
|
+
try { fm[key.trim()] = JSON.parse(val); } catch { fm[key.trim()] = val; }
|
|
87
|
+
} else {
|
|
88
|
+
fm[key.trim()] = val;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return fm;
|
|
93
|
+
}
|
|
78
94
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
95
|
+
/**
|
|
96
|
+
* Get all plans with frontmatter and progress info
|
|
97
|
+
* @param {string} projectRoot - Project root directory
|
|
98
|
+
* @returns {Array<Object>} Array of plan objects
|
|
99
|
+
*/
|
|
100
|
+
export function getAllPlans(projectRoot) {
|
|
101
|
+
const plansDir = join(projectRoot, '.prism', 'plans');
|
|
102
|
+
if (!existsSync(plansDir)) return [];
|
|
103
|
+
const files = readdirSync(plansDir).filter(f => f.endsWith('.md')).sort().reverse();
|
|
104
|
+
return files.map(f => {
|
|
105
|
+
const content = readFileSync(join(plansDir, f), 'utf8');
|
|
106
|
+
const fm = parseFrontmatter(content);
|
|
107
|
+
const parsed = parsePlanContent(content, f);
|
|
108
|
+
return { file: f, content, ...fm, ...parsed };
|
|
109
|
+
});
|
|
110
|
+
}
|
|
83
111
|
|
|
84
|
-
|
|
112
|
+
/**
|
|
113
|
+
* Read active plan file and extract progress info
|
|
114
|
+
* Now uses frontmatter status to find active plans
|
|
115
|
+
*/
|
|
116
|
+
export function getActivePlanInfo(projectRoot) {
|
|
117
|
+
const plans = getAllPlans(projectRoot);
|
|
118
|
+
if (plans.length === 0) return null;
|
|
85
119
|
|
|
86
|
-
|
|
87
|
-
const
|
|
120
|
+
// Find the most recent plan with status: active (or no frontmatter = default active)
|
|
121
|
+
const activePlan = plans.find(p => (p.status || 'active') === 'active');
|
|
122
|
+
if (!activePlan) return null;
|
|
88
123
|
|
|
89
|
-
return parsePlanContent(
|
|
124
|
+
return parsePlanContent(
|
|
125
|
+
readFileSync(join(projectRoot, '.prism', 'plans', activePlan.file), 'utf8'),
|
|
126
|
+
activePlan.file
|
|
127
|
+
);
|
|
90
128
|
}
|
|
91
129
|
|
|
92
130
|
/**
|
|
@@ -170,6 +208,49 @@ export function parsePlanContent(content, planName) {
|
|
|
170
208
|
return { planName, total, done, nextBatch, nextTasks, currentBatchFiles };
|
|
171
209
|
}
|
|
172
210
|
|
|
211
|
+
/**
|
|
212
|
+
* Detect file overlaps across active plans
|
|
213
|
+
* @param {string} projectRoot - Project root directory
|
|
214
|
+
* @returns {Array<{file: string, plans: string[]}>} Conflicting files
|
|
215
|
+
*/
|
|
216
|
+
export function detectPlanConflicts(projectRoot) {
|
|
217
|
+
const plans = getAllPlans(projectRoot).filter(p => (p.status || 'active') === 'active');
|
|
218
|
+
const fileMap = new Map();
|
|
219
|
+
|
|
220
|
+
for (const plan of plans) {
|
|
221
|
+
const files = extractFilesInScope(plan.content || '');
|
|
222
|
+
for (const f of files) {
|
|
223
|
+
if (!fileMap.has(f)) fileMap.set(f, []);
|
|
224
|
+
fileMap.get(f).push(plan.file);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const conflicts = [];
|
|
229
|
+
for (const [file, planList] of fileMap) {
|
|
230
|
+
if (planList.length > 1) {
|
|
231
|
+
conflicts.push({ file, plans: planList });
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return conflicts;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Extract file paths from "Files in Scope" section
|
|
239
|
+
* @param {string} content - Plan markdown content
|
|
240
|
+
* @returns {string[]} File paths found
|
|
241
|
+
*/
|
|
242
|
+
function extractFilesInScope(content) {
|
|
243
|
+
const scopeMatch = content.match(/##\s+Files\s+in\s+Scope\s*\n([\s\S]*?)(?=\n##|\n---|\s*$)/i);
|
|
244
|
+
if (!scopeMatch) return [];
|
|
245
|
+
const paths = [];
|
|
246
|
+
const backtickRegex = /`([^`]+\.[a-z]+)`/g;
|
|
247
|
+
let m;
|
|
248
|
+
while ((m = backtickRegex.exec(scopeMatch[1])) !== null) {
|
|
249
|
+
paths.push(m[1]);
|
|
250
|
+
}
|
|
251
|
+
return paths;
|
|
252
|
+
}
|
|
253
|
+
|
|
173
254
|
/**
|
|
174
255
|
* Get git status info
|
|
175
256
|
*/
|
package/lib/installer.mjs
CHANGED
|
@@ -8,6 +8,7 @@ import { join, dirname } from 'path';
|
|
|
8
8
|
import { fileURLToPath } from 'url';
|
|
9
9
|
import { tmpdir, homedir } from 'os';
|
|
10
10
|
import { detectOmc } from './omc.mjs';
|
|
11
|
+
import { getRulesMode } from './config.mjs';
|
|
11
12
|
|
|
12
13
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
13
14
|
const TEMPLATES_DIR = join(__dirname, '..', 'templates');
|
|
@@ -19,7 +20,7 @@ const TEMPLATES_DIR = join(__dirname, '..', 'templates');
|
|
|
19
20
|
* @param {boolean} options.hooks - Install commit-guard hook
|
|
20
21
|
*/
|
|
21
22
|
export async function init(projectDir, options = {}) {
|
|
22
|
-
const { hooks = true } = options;
|
|
23
|
+
const { hooks = true, docs = false } = options;
|
|
23
24
|
|
|
24
25
|
// 1. Create directories
|
|
25
26
|
const claudeDir = join(projectDir, '.claude');
|
|
@@ -107,6 +108,26 @@ export async function init(projectDir, options = {}) {
|
|
|
107
108
|
if (!existsSync(prismGitignore)) {
|
|
108
109
|
writeFileSync(prismGitignore, '.version\n');
|
|
109
110
|
}
|
|
111
|
+
|
|
112
|
+
// 7. Docs scaffolding (optional)
|
|
113
|
+
if (docs) {
|
|
114
|
+
const docsDir = join(projectDir, 'docs');
|
|
115
|
+
mkdirSync(docsDir, { recursive: true });
|
|
116
|
+
mkdirSync(join(docsDir, 'reference'), { recursive: true });
|
|
117
|
+
mkdirSync(join(docsDir, 'archive'), { recursive: true });
|
|
118
|
+
|
|
119
|
+
const memoryPath = join(docsDir, 'PROJECT-MEMORY.md');
|
|
120
|
+
if (!existsSync(memoryPath)) {
|
|
121
|
+
writeFileSync(memoryPath, PROJECT_MEMORY_TEMPLATE);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const handoffPath = join(docsDir, 'HANDOFF.md');
|
|
125
|
+
if (!existsSync(handoffPath)) {
|
|
126
|
+
writeFileSync(handoffPath, HANDOFF_TEMPLATE);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
createRegistry(projectDir);
|
|
130
|
+
}
|
|
110
131
|
}
|
|
111
132
|
|
|
112
133
|
/**
|
|
@@ -371,10 +392,12 @@ export async function update(projectDir) {
|
|
|
371
392
|
}
|
|
372
393
|
}
|
|
373
394
|
|
|
374
|
-
// Migrate config: add version field if missing
|
|
395
|
+
// Migrate config: add version field if missing, preserve rulesMode
|
|
396
|
+
let preservedRulesMode;
|
|
375
397
|
if (existsSync(configPath)) {
|
|
376
398
|
try {
|
|
377
399
|
const existingConfig = JSON.parse(readFileSync(configPath, 'utf8'));
|
|
400
|
+
preservedRulesMode = existingConfig.rulesMode;
|
|
378
401
|
if (!existingConfig.version) {
|
|
379
402
|
existingConfig.version = 1;
|
|
380
403
|
writeFileSync(configPath, JSON.stringify(existingConfig, null, 2) + '\n');
|
|
@@ -385,10 +408,23 @@ export async function update(projectDir) {
|
|
|
385
408
|
|
|
386
409
|
await init(projectDir, { hooks });
|
|
387
410
|
|
|
411
|
+
// Restore rulesMode if it was set before migration
|
|
412
|
+
if (preservedRulesMode && preservedRulesMode !== 'full') {
|
|
413
|
+
const newConfig = JSON.parse(readFileSync(configPath, 'utf8'));
|
|
414
|
+
newConfig.rulesMode = preservedRulesMode;
|
|
415
|
+
writeFileSync(configPath, JSON.stringify(newConfig, null, 2) + '\n');
|
|
416
|
+
// Re-inject rules with restored mode
|
|
417
|
+
injectRules(projectDir);
|
|
418
|
+
}
|
|
419
|
+
|
|
388
420
|
// Source repo: re-inject rules from local templates (overrides the npx version)
|
|
389
421
|
if (sourceRepo) {
|
|
390
|
-
const
|
|
391
|
-
|
|
422
|
+
const mode = getRulesMode(projectDir);
|
|
423
|
+
const fileName = mode === 'lean' ? 'rules-lean.md' : 'rules.md';
|
|
424
|
+
const localRulesPath = join(projectDir, 'templates', fileName);
|
|
425
|
+
if (existsSync(localRulesPath)) {
|
|
426
|
+
injectRules(projectDir, localRulesPath);
|
|
427
|
+
}
|
|
392
428
|
}
|
|
393
429
|
|
|
394
430
|
return sourceRepo ? { sourceRepo: true } : undefined;
|
|
@@ -598,7 +634,7 @@ export function uninstallGlobal(options = {}) {
|
|
|
598
634
|
* @returns {{ actions: Array<{type: string, path: string, status: string}> }}
|
|
599
635
|
*/
|
|
600
636
|
export function dryRun(projectDir, options = {}) {
|
|
601
|
-
const { hooks = true } = options;
|
|
637
|
+
const { hooks = true, docs = false } = options;
|
|
602
638
|
const claudeDir = join(projectDir, '.claude');
|
|
603
639
|
const actions = [];
|
|
604
640
|
|
|
@@ -658,6 +694,19 @@ export function dryRun(projectDir, options = {}) {
|
|
|
658
694
|
actions.push({ type: 'config', path: '.prism/config.json', status: 'create' });
|
|
659
695
|
}
|
|
660
696
|
|
|
697
|
+
// Docs scaffolding
|
|
698
|
+
if (docs) {
|
|
699
|
+
const docsDir = join(projectDir, 'docs');
|
|
700
|
+
for (const sub of ['', 'reference/', 'archive/']) {
|
|
701
|
+
actions.push({ type: 'docs', path: `docs/${sub}`, status: existsSync(join(docsDir, sub)) ? 'exists' : 'create' });
|
|
702
|
+
}
|
|
703
|
+
const memoryPath = join(docsDir, 'PROJECT-MEMORY.md');
|
|
704
|
+
actions.push({ type: 'docs', path: 'docs/PROJECT-MEMORY.md', status: existsSync(memoryPath) ? 'exists' : 'create' });
|
|
705
|
+
const handoffPath = join(docsDir, 'HANDOFF.md');
|
|
706
|
+
actions.push({ type: 'docs', path: 'docs/HANDOFF.md', status: existsSync(handoffPath) ? 'exists' : 'create' });
|
|
707
|
+
actions.push({ type: 'docs', path: '.prism/registry.json', status: 'create' });
|
|
708
|
+
}
|
|
709
|
+
|
|
661
710
|
return { actions };
|
|
662
711
|
}
|
|
663
712
|
|
|
@@ -743,11 +792,80 @@ export function hudStatus(options = {}) {
|
|
|
743
792
|
return { enabled, scriptExists: existsSync(scriptPath), command: cmd };
|
|
744
793
|
}
|
|
745
794
|
|
|
795
|
+
// ─── templates ───
|
|
796
|
+
|
|
797
|
+
const PROJECT_MEMORY_TEMPLATE = `# Project Memory
|
|
798
|
+
|
|
799
|
+
Cumulative knowledge that survives session transitions.
|
|
800
|
+
|
|
801
|
+
## Architectural Decisions
|
|
802
|
+
<!-- [date] [decision] — [rationale] -->
|
|
803
|
+
|
|
804
|
+
## Conventions
|
|
805
|
+
<!-- [naming, patterns, file structure rules] -->
|
|
806
|
+
|
|
807
|
+
## Environment Gotchas
|
|
808
|
+
<!-- [quirks, workarounds, version constraints] -->
|
|
809
|
+
|
|
810
|
+
## Package Constraints
|
|
811
|
+
<!-- [package@version — why pinned] -->
|
|
812
|
+
`;
|
|
813
|
+
|
|
814
|
+
const HANDOFF_TEMPLATE = `# Handoff
|
|
815
|
+
|
|
816
|
+
## Status
|
|
817
|
+
[What's done, what's remaining]
|
|
818
|
+
|
|
819
|
+
## Current State
|
|
820
|
+
[Branch name, last commit, any uncommitted changes]
|
|
821
|
+
|
|
822
|
+
## Next Steps
|
|
823
|
+
[Exact next action to take, with file paths]
|
|
824
|
+
|
|
825
|
+
## Decisions Made
|
|
826
|
+
[Key choices and why]
|
|
827
|
+
|
|
828
|
+
## Known Issues
|
|
829
|
+
[Anything broken or incomplete]
|
|
830
|
+
`;
|
|
831
|
+
|
|
832
|
+
function createRegistry(projectDir) {
|
|
833
|
+
const registryPath = join(projectDir, '.prism', 'registry.json');
|
|
834
|
+
const registry = {
|
|
835
|
+
ssot: [],
|
|
836
|
+
session: {
|
|
837
|
+
handoff: 'docs/HANDOFF.md',
|
|
838
|
+
memory: 'docs/PROJECT-MEMORY.md'
|
|
839
|
+
},
|
|
840
|
+
reference: [],
|
|
841
|
+
archive: 'docs/archive/'
|
|
842
|
+
};
|
|
843
|
+
|
|
844
|
+
const docsDir = join(projectDir, 'docs');
|
|
845
|
+
if (existsSync(docsDir)) {
|
|
846
|
+
const files = readdirSync(docsDir).filter(f => f.endsWith('.md'));
|
|
847
|
+
for (const f of files) {
|
|
848
|
+
if (f === 'HANDOFF.md' || f === 'PROJECT-MEMORY.md') continue;
|
|
849
|
+
registry.ssot.push({ path: `docs/${f}`, role: 'unknown' });
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
writeFileSync(registryPath, JSON.stringify(registry, null, 2) + '\n');
|
|
854
|
+
}
|
|
855
|
+
|
|
746
856
|
// ─── internal helpers ───
|
|
747
857
|
|
|
748
858
|
function injectRules(projectDir, overrideRulesPath) {
|
|
749
859
|
const claudeMdPath = join(projectDir, 'CLAUDE.md');
|
|
750
|
-
|
|
860
|
+
let rulesPath;
|
|
861
|
+
if (overrideRulesPath) {
|
|
862
|
+
rulesPath = overrideRulesPath;
|
|
863
|
+
} else {
|
|
864
|
+
const mode = getRulesMode(projectDir);
|
|
865
|
+
const fileName = mode === 'lean' ? 'rules-lean.md' : 'rules.md';
|
|
866
|
+
rulesPath = join(TEMPLATES_DIR, fileName);
|
|
867
|
+
if (!existsSync(rulesPath)) rulesPath = join(TEMPLATES_DIR, 'rules.md');
|
|
868
|
+
}
|
|
751
869
|
if (!existsSync(rulesPath)) return;
|
|
752
870
|
|
|
753
871
|
const rules = readFileSync(rulesPath, 'utf8');
|
package/package.json
CHANGED
|
@@ -6,11 +6,17 @@ When this command is invoked:
|
|
|
6
6
|
|
|
7
7
|
1. **Check** if `.prism/plans/` exists. If not, report "No plans directory found. Create one with `/claude-prism:plan create <topic>`."
|
|
8
8
|
2. **Scan** `.prism/plans/` for all `.md` files
|
|
9
|
-
3. **
|
|
10
|
-
-
|
|
9
|
+
3. **Parse frontmatter** for each plan (between `---` markers at file start):
|
|
10
|
+
- `status: active` → 📋
|
|
11
|
+
- `status: completed` → ✅
|
|
12
|
+
- `status: archived` → 📦
|
|
13
|
+
- `status: blocked` → 🚫
|
|
14
|
+
- No frontmatter → 📋 (default: active)
|
|
15
|
+
4. **Show each plan** with:
|
|
16
|
+
- Status icon, filename and date
|
|
11
17
|
- Goal (first line after `## Goal`)
|
|
12
18
|
- Progress: count [x] vs [ ] tasks
|
|
13
|
-
-
|
|
19
|
+
- Frontmatter status + task-based progress
|
|
14
20
|
|
|
15
21
|
## Create New Plan
|
|
16
22
|
|
|
@@ -18,9 +24,15 @@ If user requests a new plan:
|
|
|
18
24
|
|
|
19
25
|
1. **Determine topic** from user's description
|
|
20
26
|
2. **Create file** at `.prism/plans/YYYY-MM-DD-<topic>.md`
|
|
21
|
-
3. **Use EUDEC template
|
|
27
|
+
3. **Use EUDEC template** (with frontmatter):
|
|
22
28
|
|
|
23
29
|
```
|
|
30
|
+
---
|
|
31
|
+
status: active
|
|
32
|
+
created: YYYY-MM-DD
|
|
33
|
+
depends_on: []
|
|
34
|
+
---
|
|
35
|
+
|
|
24
36
|
## Goal
|
|
25
37
|
One sentence: what we're building and why.
|
|
26
38
|
|
|
@@ -53,6 +65,20 @@ Tech stack, key decisions, 2-3 sentences max.
|
|
|
53
65
|
|
|
54
66
|
4. **Announce**: "Plan file created. Use /claude-prism:prism to start execution."
|
|
55
67
|
|
|
68
|
+
## Check (file overlap detection)
|
|
69
|
+
|
|
70
|
+
If user requests a conflict check:
|
|
71
|
+
|
|
72
|
+
1. **Read all active plans** from `.prism/plans/` (frontmatter `status: active` or no frontmatter)
|
|
73
|
+
2. **Parse "Files in Scope"** section from each plan — extract backtick-wrapped file paths
|
|
74
|
+
3. **Detect file overlaps** across plans
|
|
75
|
+
4. **Report**:
|
|
76
|
+
- ⚠️ File overlap: `path/to/file`
|
|
77
|
+
← plan-a.md (active)
|
|
78
|
+
← plan-b.md (active)
|
|
79
|
+
- Recommendation: check dependency order or merge plans
|
|
80
|
+
5. If no overlaps found: "✅ No file conflicts across active plans."
|
|
81
|
+
|
|
56
82
|
## View Specific Plan
|
|
57
83
|
|
|
58
84
|
If user specifies a plan file:
|
|
@@ -30,7 +30,7 @@ When this command is invoked:
|
|
|
30
30
|
✅ scope-guard (warn: 4/8, block: 7/12)
|
|
31
31
|
|
|
32
32
|
Plans:
|
|
33
|
-
📋 2026-02-15-p3-inspector.md [3/5] 60%
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
📋 2026-02-15-p3-inspector.md [3/5] 60% (active)
|
|
34
|
+
✅ 2026-02-15-p8-templates.md [5/5] 100% (completed)
|
|
35
|
+
🚫 2026-02-16-p4-token.md [0/4] 0% (blocked)
|
|
36
36
|
```
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
|
|
2
|
+
<!-- PRISM:START -->
|
|
3
|
+
<!-- PRISM:BOOT -->
|
|
4
|
+
## Session Bootstrap (auto-generated by Prism)
|
|
5
|
+
|
|
6
|
+
On session start, read in order:
|
|
7
|
+
1. `docs/PROJECT-MEMORY.md` (if exists) — persistent architectural decisions and conventions
|
|
8
|
+
2. `docs/HANDOFF.md` (if exists) — previous session's state and next steps
|
|
9
|
+
3. `.prism/plans/` — scan for active plans (frontmatter `status: active`)
|
|
10
|
+
4. `.prism/registry.json` (if exists) — project document registry
|
|
11
|
+
|
|
12
|
+
After reading, verify described state matches reality (git status, file contents).
|
|
13
|
+
<!-- PRISM:BOOT:END -->
|
|
14
|
+
|
|
15
|
+
# Prism — EUDEC Methodology (Lean Mode)
|
|
16
|
+
|
|
17
|
+
**EUDEC = Essence, Understand, Decompose, Execute, Checkpoint** — the core cycle.
|
|
18
|
+
|
|
19
|
+
> **Never implement what you haven't understood. Never understand what you haven't distilled to its essence.**
|
|
20
|
+
|
|
21
|
+
For the full methodology, run `/claude-prism:prism`.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Adaptive Weight (Task Size Routing)
|
|
26
|
+
|
|
27
|
+
| Weight | Criteria | Path |
|
|
28
|
+
|--------|----------|------|
|
|
29
|
+
| **Lightweight** | 1-2 files, <50 LOC, clear scope | Essence (1 line) → Execute → Verify → Record (1-line to `docs/PROJECT-MEMORY.md`) → Done |
|
|
30
|
+
| **Standard** | 3-5 files, 50-200 LOC | Run `/claude-prism:prism` for full EUDEC guidance |
|
|
31
|
+
| **Full** | 6+ files, 200+ LOC, or unclear scope | Run `/claude-prism:prism` for full EUDEC with plan file |
|
|
32
|
+
|
|
33
|
+
## Task Type Derivation
|
|
34
|
+
|
|
35
|
+
| Essence Character | Type | Path |
|
|
36
|
+
|-------------------|------|------|
|
|
37
|
+
| "X is broken" | Bugfix | Fast Path (below) |
|
|
38
|
+
| "X should be possible" | Feature | `/claude-prism:prism` |
|
|
39
|
+
| "All X must become Y" | Migration | Pattern → batch apply → verify |
|
|
40
|
+
| "X's structure must change" | Refactor | `/claude-prism:prism` |
|
|
41
|
+
|
|
42
|
+
## Bugfix Fast Path
|
|
43
|
+
|
|
44
|
+
1. Reproduce the symptom
|
|
45
|
+
2. Trace to root cause
|
|
46
|
+
3. Minimal fix (smallest change that resolves the cause)
|
|
47
|
+
4. Verify (test/build/diff)
|
|
48
|
+
|
|
49
|
+
After 3 failed fixes: STOP. Discuss with user.
|
|
50
|
+
|
|
51
|
+
## Scope Guard
|
|
52
|
+
|
|
53
|
+
**Only change what was requested. Nothing more, nothing less.**
|
|
54
|
+
|
|
55
|
+
1. Was this change explicitly requested? → proceed
|
|
56
|
+
2. Is it required to make the requested change work? → proceed
|
|
57
|
+
3. Is it an improvement I noticed while working? → STOP. Note it, don't do it.
|
|
58
|
+
4. Is it "while I'm here" cleanup? → STOP. Not your job right now.
|
|
59
|
+
|
|
60
|
+
## Verification & Fallback Ladder
|
|
61
|
+
|
|
62
|
+
| Level | Method | When |
|
|
63
|
+
|-------|--------|------|
|
|
64
|
+
| 1. Tests | Automated tests | Test infrastructure exists |
|
|
65
|
+
| 2. Build | Compiles + lint without new errors | No tests for this area |
|
|
66
|
+
| 3. Diff | `git diff` reviewed for regressions | No build tooling |
|
|
67
|
+
|
|
68
|
+
**Every change must have SOME verification.** Never claim completion without evidence.
|
|
69
|
+
|
|
70
|
+
## Self-Correction Triggers
|
|
71
|
+
|
|
72
|
+
- Same file edited 3+ times → investigate root cause
|
|
73
|
+
- Editing file not in plan → scope change needed?
|
|
74
|
+
- 3 consecutive test failures → back to essence
|
|
75
|
+
- 5 turns autonomous → report progress before continuing
|
|
76
|
+
- Adding workarounds to fix workarounds → design problem, step back
|
|
77
|
+
|
|
78
|
+
## Rationalization Defense
|
|
79
|
+
|
|
80
|
+
| Excuse | Reality |
|
|
81
|
+
|--------|---------|
|
|
82
|
+
| "I know what they mean" | Verify. Assumption is the root of all bugs |
|
|
83
|
+
| "While I'm here, let me also..." | Scope creep. Note it for later |
|
|
84
|
+
| "Too simple to decompose" | Check file count and coupling |
|
|
85
|
+
| "I'll add tests later" | High-risk: tests come first |
|
|
86
|
+
|
|
87
|
+
## Checkpoint Frequency
|
|
88
|
+
|
|
89
|
+
- **Lightweight**: report completion with evidence, no pause
|
|
90
|
+
- **Standard/Full**: run `/claude-prism:prism` for guided checkpoints
|
|
91
|
+
- **Blocker encountered**: always stop
|
|
92
|
+
|
|
93
|
+
## Session Handoff
|
|
94
|
+
|
|
95
|
+
Prism hooks auto-generate `docs/HANDOFF.md` on compaction and session end.
|
|
96
|
+
`docs/PROJECT-MEMORY.md` is auto-appended on session end.
|
|
97
|
+
For manual handoff: Status, Current State, Next Steps, Decisions Made, Known Issues.
|
|
98
|
+
|
|
99
|
+
## Completion Declaration
|
|
100
|
+
|
|
101
|
+
Before declaring completion:
|
|
102
|
+
1. **IDENTIFY** — What proves completion?
|
|
103
|
+
2. **RUN** — Execute the relevant test/build
|
|
104
|
+
3. **READ** — Check the output directly
|
|
105
|
+
4. **CLAIM** — Only declare based on evidence
|
|
106
|
+
<!-- PRISM:END -->
|
package/templates/rules.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
|
|
2
2
|
<!-- PRISM:START -->
|
|
3
|
+
<!-- PRISM:BOOT -->
|
|
4
|
+
## Session Bootstrap (auto-generated by Prism)
|
|
5
|
+
|
|
6
|
+
On session start, read in order:
|
|
7
|
+
1. `docs/PROJECT-MEMORY.md` (if exists) — persistent architectural decisions and conventions
|
|
8
|
+
2. `docs/HANDOFF.md` (if exists) — previous session's state and next steps
|
|
9
|
+
3. `.prism/plans/` — scan for active plans (frontmatter `status: active`)
|
|
10
|
+
4. `.prism/registry.json` (if exists) — project document registry
|
|
11
|
+
|
|
12
|
+
After reading, verify described state matches reality (git status, file contents).
|
|
13
|
+
<!-- PRISM:BOOT:END -->
|
|
14
|
+
|
|
3
15
|
# Prism — EUDEC Methodology Framework
|
|
4
16
|
|
|
5
17
|
**EUDEC = Essence, Understand, Decompose, Execute, Checkpoint** — the core cycle.
|
|
@@ -76,7 +88,7 @@ After extracting essence and task type, assess task weight to select the appropr
|
|
|
76
88
|
| **Standard** | 3-5 files, 50-200 LOC | Full EUDEC, summary checkpoints |
|
|
77
89
|
| **Full** | 6+ files, 200+ LOC, or unclear scope | Full EUDEC with plan file + full checkpoints |
|
|
78
90
|
|
|
79
|
-
**Lightweight path** skips formal UNDERSTAND (sufficiency assessment, question rounds, alignment confirmation) and DECOMPOSE. The essence statement still grounds the work but takes one line, not a full section.
|
|
91
|
+
**Lightweight path** skips formal UNDERSTAND (sufficiency assessment, question rounds, alignment confirmation) and DECOMPOSE. The essence statement still grounds the work but takes one line, not a full section. Record: append 1-line summary to `docs/PROJECT-MEMORY.md` (what was changed and why).
|
|
80
92
|
|
|
81
93
|
**Bugfix fast path** (regardless of file count):
|
|
82
94
|
1. Reproduce the symptom
|
|
@@ -419,6 +431,11 @@ User says "stop here" → clean exit
|
|
|
419
431
|
- Task is multi-session by nature (multi-day refactor, large migration)
|
|
420
432
|
- Switching to a different task mid-session
|
|
421
433
|
|
|
434
|
+
**Auto-triggers (via Prism hooks):**
|
|
435
|
+
- PreCompact hook → auto-generates `docs/HANDOFF.md`
|
|
436
|
+
- SessionEnd hook → auto-generates `docs/HANDOFF.md` + appends to `docs/PROJECT-MEMORY.md`
|
|
437
|
+
- `/compact` 실행 전 → HANDOFF 자동 저장 (hook으로 처리됨)
|
|
438
|
+
|
|
422
439
|
### 6-2. Handoff Document
|
|
423
440
|
|
|
424
441
|
Create `docs/HANDOFF.md` with:
|