@zhuan-ai/zhuanspec 2.11.15 → 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,8 +251,23 @@ 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') {
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
+ }
241
265
  // Allow proposal file modifications
242
- if (filePath.includes('zhuanspec/changes/') || filePath.includes('zhuanspec/specs/')) {
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) {
243
271
  return {
244
272
  continue: true,
245
273
  systemMessage: '✓ Proposal file modification allowed in propose phase',
@@ -89,7 +89,6 @@ const proposalSteps = `**步骤**
89
89
  - **获取方式**:若用户提供链接(格式:\`https://zzcase.zhuanspirit.com/plan/taskDetail/module/{moduleId}/task/{taskId}\`),从 URL 路径中提取 \`moduleId\`,调用 MCP 工具 \`mcp__caseweb__GET_get2\` 读取数据;否则手动录入
90
90
  - **创建 test-cases.md**(路径:\`changes/<change-id>/test-cases.md\`),使用 \`getTestCasesTemplate\` 模板,每个 TC-XXX 包含:前置条件、测试步骤、预期结果、验收点
91
91
  - tasks.md 中使用 \`@test-case:TC-XXX\` 关联任务与测试 case,表格四列:Task、测试 Case ID、测试 Case 文件路径、覆盖场景
92
- - 任务实施顺序调整为:先写测试 → 再写实现 → 验证测试通过
93
92
 
94
93
  用户选择"暂不提供":跳过,按常规流程继续
95
94
  用户选择"其他":等待用户补充说明后继续
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhuan-ai/zhuanspec",
3
- "version": "2.11.15",
3
+ "version": "2.11.19",
4
4
  "description": "AI-native system for spec-driven development",
5
5
  "keywords": [
6
6
  "zhuanspec",