claude-prism 1.7.0 → 1.7.2

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-prism",
3
- "version": "1.7.0",
3
+ "version": "1.7.2",
4
4
  "description": "AI agent harness implementing the EUDEC methodology",
5
5
  "author": { "name": "lazysaturday91" },
6
6
  "repository": "https://github.com/lazysaturday91/claude-prism",
package/CHANGELOG.md CHANGED
@@ -5,6 +5,20 @@ 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.7.2] — 2026-03-06
9
+
10
+ ### Fixed
11
+ - **Plan template frontmatter** — EUDEC plan template now includes `status: draft` frontmatter, so plans created during DECOMPOSE phase participate in lifecycle management automatically
12
+
13
+ ## [1.7.1] — 2026-03-06
14
+
15
+ ### Fixed
16
+ - **Monorepo hook compatibility** — hooks now use `input.cwd` from Claude Code instead of `process.cwd()` to resolve the correct project root
17
+ - `findProjectRoot()` upward search for nearest `.prism/config.json` — prevents wrong config in monorepo setups
18
+ - `config.projectRoot` injection for all hook rules — existing `config.projectRoot || process.cwd()` fallbacks now receive the correct value
19
+ - All 4 template runners (`precompact`, `session-end`, `subagent-start`, `task-completed`) updated to use `findProjectRoot(input.cwd)`
20
+ - `pipeline.mjs` — `runPipeline()`, `runPipelineAsync()`, `loadCustomRules()` all resolve project root from hook input
21
+
8
22
  ## [1.7.0] — 2026-03-06
9
23
 
10
24
  ### Added
package/lib/config.mjs CHANGED
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { readFileSync, existsSync } from 'fs';
7
- import { join } from 'path';
7
+ import { join, dirname } from 'path';
8
8
 
9
9
  const DEFAULTS = {
10
10
  rulesMode: 'full',
@@ -23,6 +23,20 @@ const DEFAULTS = {
23
23
  }
24
24
  };
25
25
 
26
+ /**
27
+ * Search upward from startDir for nearest .prism/config.json
28
+ * @param {string} startDir - Directory to start searching from
29
+ * @returns {string} Project root with .prism/config.json, or startDir as fallback
30
+ */
31
+ export function findProjectRoot(startDir) {
32
+ let current = startDir;
33
+ while (current !== dirname(current)) {
34
+ if (existsSync(join(current, '.prism', 'config.json'))) return current;
35
+ current = dirname(current);
36
+ }
37
+ return startDir;
38
+ }
39
+
26
40
  export function loadConfig(projectRoot) {
27
41
  const configPath = join(projectRoot, '.prism', 'config.json');
28
42
 
package/lib/pipeline.mjs CHANGED
@@ -6,7 +6,7 @@
6
6
  import { readFileSync } from 'fs';
7
7
  import { join } from 'path';
8
8
  import { sanitizeId } from './utils.mjs';
9
- import { loadConfig } from './config.mjs';
9
+ import { loadConfig, findProjectRoot } from './config.mjs';
10
10
  import { getStateDir } from './state.mjs';
11
11
  import { logEvent } from './session.mjs';
12
12
 
@@ -68,8 +68,10 @@ export function runPipeline(rules, hookEventName) {
68
68
  const input = parseInput();
69
69
  if (!input) process.exit(0);
70
70
 
71
- // Read config ONCE
72
- const fullConfig = loadConfig(process.cwd());
71
+ // Resolve project root from hook input's cwd (monorepo-safe)
72
+ const projectRoot = findProjectRoot(input.cwd || process.cwd());
73
+ const fullConfig = loadConfig(projectRoot);
74
+ fullConfig.projectRoot = projectRoot;
73
75
 
74
76
  const ctx = toContext(input, hookEventName);
75
77
  const stateDir = getStateDir(ctx.sessionId, ctx.agentId);
@@ -128,13 +130,13 @@ export function runPipeline(rules, hookEventName) {
128
130
  * @param {string[]} customRulePaths - Paths relative to project root
129
131
  * @returns {Promise<Array<{name: string, rule: Object}>>}
130
132
  */
131
- export async function loadCustomRules(builtInRules, customRulePaths) {
133
+ export async function loadCustomRules(builtInRules, customRulePaths, projectRoot) {
132
134
  if (!customRulePaths || customRulePaths.length === 0) return builtInRules;
133
135
 
134
136
  const rules = [...builtInRules];
135
137
  for (const rulePath of customRulePaths) {
136
138
  try {
137
- const absPath = join(process.cwd(), rulePath);
139
+ const absPath = join(projectRoot || process.cwd(), rulePath);
138
140
  const mod = await import(absPath);
139
141
  const rule = mod.default || mod[Object.keys(mod)[0]];
140
142
  if (rule && typeof rule.evaluate === 'function') {
@@ -156,9 +158,11 @@ export async function runPipelineAsync(builtInRules, hookEventName) {
156
158
  const input = parseInput();
157
159
  if (!input) process.exit(0);
158
160
 
159
- const fullConfig = loadConfig(process.cwd());
161
+ const projectRoot = findProjectRoot(input.cwd || process.cwd());
162
+ const fullConfig = loadConfig(projectRoot);
163
+ fullConfig.projectRoot = projectRoot;
160
164
  const customRulePaths = fullConfig.customRules || [];
161
- const rules = await loadCustomRules(builtInRules, customRulePaths);
165
+ const rules = await loadCustomRules(builtInRules, customRulePaths, projectRoot);
162
166
 
163
167
  const ctx = toContext(input, hookEventName);
164
168
  const stateDir = getStateDir(ctx.sessionId, ctx.agentId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-prism",
3
- "version": "1.7.0",
3
+ "version": "1.7.2",
4
4
  "description": "AI agent harness implementing the EUDEC methodology — Essence, Understand, Decompose, Execute, Checkpoint.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -194,6 +194,11 @@ Save multi-step plans (6+ files) as markdown:
194
194
  - **Path**: `.prism/plans/YYYY-MM-DD-<topic>.md`
195
195
 
196
196
  ```markdown
197
+ ---
198
+ status: draft
199
+ created: YYYY-MM-DD
200
+ ---
201
+
197
202
  ## Goal
198
203
  One sentence: what we're building and why.
199
204
 
@@ -5,11 +5,13 @@
5
5
  */
6
6
  import { readFileSync } from 'fs';
7
7
  import { precompactHandler } from '../rules/precompact-handler.mjs';
8
- import { loadConfig } from '../lib/config.mjs';
8
+ import { loadConfig, findProjectRoot } from '../lib/config.mjs';
9
9
 
10
10
  try {
11
11
  const input = JSON.parse(readFileSync(0, 'utf8'));
12
- const config = loadConfig(process.cwd());
12
+ const projectRoot = findProjectRoot(input.cwd || process.cwd());
13
+ const config = loadConfig(projectRoot);
14
+ config.projectRoot = projectRoot;
13
15
  const result = precompactHandler.evaluate(input, config);
14
16
  if (result) {
15
17
  process.stdout.write(JSON.stringify(result));
@@ -5,11 +5,13 @@
5
5
  */
6
6
  import { readFileSync } from 'fs';
7
7
  import { sessionEndHandler } from '../rules/session-end-handler.mjs';
8
- import { loadConfig } from '../lib/config.mjs';
8
+ import { loadConfig, findProjectRoot } from '../lib/config.mjs';
9
9
 
10
10
  try {
11
11
  const input = JSON.parse(readFileSync(0, 'utf8'));
12
- const config = loadConfig(process.cwd());
12
+ const projectRoot = findProjectRoot(input.cwd || process.cwd());
13
+ const config = loadConfig(projectRoot);
14
+ config.projectRoot = projectRoot;
13
15
  const result = sessionEndHandler.evaluate(input, config);
14
16
  if (result) {
15
17
  process.stdout.write(JSON.stringify(result));
@@ -5,11 +5,13 @@
5
5
  */
6
6
  import { readFileSync } from 'fs';
7
7
  import { scopeInjector } from '../rules/subagent-scope-injector.mjs';
8
- import { loadConfig } from '../lib/config.mjs';
8
+ import { loadConfig, findProjectRoot } from '../lib/config.mjs';
9
9
 
10
10
  try {
11
11
  const input = JSON.parse(readFileSync(0, 'utf8'));
12
- const config = loadConfig(process.cwd());
12
+ const projectRoot = findProjectRoot(input.cwd || process.cwd());
13
+ const config = loadConfig(projectRoot);
14
+ config.projectRoot = projectRoot;
13
15
  const result = scopeInjector.evaluate(input, config);
14
16
  if (result) {
15
17
  process.stdout.write(JSON.stringify(result));
@@ -5,11 +5,13 @@
5
5
  */
6
6
  import { readFileSync } from 'fs';
7
7
  import { planSync } from '../rules/task-plan-sync.mjs';
8
- import { loadConfig } from '../lib/config.mjs';
8
+ import { loadConfig, findProjectRoot } from '../lib/config.mjs';
9
9
 
10
10
  try {
11
11
  const input = JSON.parse(readFileSync(0, 'utf8'));
12
- const config = loadConfig(process.cwd());
12
+ const projectRoot = findProjectRoot(input.cwd || process.cwd());
13
+ const config = loadConfig(projectRoot);
14
+ config.projectRoot = projectRoot;
13
15
  const result = planSync.evaluate(input, config);
14
16
  if (result) {
15
17
  process.stdout.write(JSON.stringify(result));