@zhuan-ai/zhuanspec 2.11.16 → 2.11.19

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.
@@ -70,9 +70,11 @@ export async function deviationCheckHook(options) {
70
70
  const toolName = options.tool || 'Write';
71
71
  // Read stdin for Claude Code hook input
72
72
  let stdinData = {};
73
+ let rawStdin = '';
73
74
  try {
74
75
  const stdinContent = await readStdin();
75
76
  if (stdinContent) {
77
+ rawStdin = stdinContent;
76
78
  stdinData = JSON.parse(stdinContent);
77
79
  }
78
80
  }
@@ -80,9 +82,20 @@ export async function deviationCheckHook(options) {
80
82
  // Ignore parse errors
81
83
  }
82
84
  // Get file path from stdin or options
83
- const filePath = stdinData.tool_input?.file_path
85
+ // 兼容 Claude Code 两种输入形态:tool_input.file_path 或 tool_input.path
86
+ const toolInput = stdinData.tool_input || {};
87
+ const filePath = toolInput.file_path
88
+ || toolInput.path
89
+ || toolInput.notebook_path
84
90
  || options.file
85
91
  || '';
92
+ // DEBUG: 临时记录 stdin 与解析结果,定位路径传递问题后移除
93
+ try {
94
+ fs.appendFileSync('/tmp/zhuanspec-deviation-debug.log', `[${new Date().toISOString()}] phase=${process.env.ZHUANSPEC_PHASE} tool=${toolName} filePath="${filePath}"\n raw=${rawStdin.slice(0, 500)}\n`, 'utf-8');
95
+ }
96
+ catch {
97
+ // ignore
98
+ }
86
99
  const promptText = stdinData?.prompt
87
100
  || options.prompt
88
101
  || '';
@@ -238,13 +251,28 @@ async function runDeviationCheck(filePath, trigger, promptText, _options) {
238
251
  // Propose phase → block all code modifications (Iron Law 1: No Spec No Code)
239
252
  // But check if we can transition to Apply phase
240
253
  if (phase === 'propose') {
241
- // TODO: 路径匹配对相对路径不准,先注释掉放行分支(后续用正则+白名单修复)
242
- // if (filePath.includes('zhuanspec/changes/') || filePath.includes('zhuanspec/specs/')) {
243
- // return {
244
- // continue: true,
245
- // systemMessage: '✓ Proposal file modification allowed in propose phase',
246
- // };
247
- // }
254
+ // UserPromptSubmit(post-prompt) 和 resume 无 filePath 上下文,静默放行,仅 pre-tool 做拦截
255
+ if (trigger !== 'pre-tool') {
256
+ return { continue: true };
257
+ }
258
+ // 兼底:若 filePath 为空(stdin 未传 / 解析失败),不拦截,避免误伤用户修改提案文件
259
+ if (!filePath) {
260
+ return {
261
+ continue: true,
262
+ systemMessage: '⚠️ deviation-check: filePath empty, skip (see /tmp/zhuanspec-deviation-debug.log)',
263
+ };
264
+ }
265
+ // Allow proposal file modifications
266
+ // 修复:用正则匹配,同时兼容绝对路径和相对路径
267
+ // 匹配: changes/xxx / zhuanspec/changes/xxx / /abs/.../changes/xxx
268
+ const isProposalArtifact = /(?:^|\/)(?:zhuanspec\/)?changes\//.test(filePath) ||
269
+ /(?:^|\/)(?:zhuanspec\/)?specs\//.test(filePath);
270
+ if (isProposalArtifact) {
271
+ return {
272
+ continue: true,
273
+ systemMessage: '✓ Proposal file modification allowed in propose phase',
274
+ };
275
+ }
248
276
  // Check if this is a code file that might trigger Apply phase transition
249
277
  const isCodeFile = !filePath.includes('zhuanspec/') &&
250
278
  /\.(java|ts|tsx|js|jsx|py|go|rs|sql|kt|scala|c|cpp|cs)$/i.test(filePath);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhuan-ai/zhuanspec",
3
- "version": "2.11.16",
3
+ "version": "2.11.19",
4
4
  "description": "AI-native system for spec-driven development",
5
5
  "keywords": [
6
6
  "zhuanspec",