@zhuan-ai/zhuanspec 2.19.2 → 2.19.3
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.
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* user-input hook 的结构化调试日志(JSONL)。
|
|
3
|
+
*
|
|
4
|
+
* 历史实现直接 append 到 `<cwd>/.user-input-debug.log`,带来三个问题:
|
|
5
|
+
* 1. 污染业务仓库:detectActiveChange 只看 `<cwd>/zhuanspec/changes`,不向上查找。
|
|
6
|
+
* cwd 落在工作区下的业务子仓库时,每条 prompt 都只会写一行 no-active-change,
|
|
7
|
+
* 于是日志被创建在业务仓库根目录,且因为没有 .gitignore 兜底被提交进版本库。
|
|
8
|
+
* 2. 无上限:只 append 不轮转,单个文件可以无限增长。
|
|
9
|
+
* 3. 无开关:无法关闭。
|
|
10
|
+
*
|
|
11
|
+
* 现在的约定(与 `zhuanspec/.hook-debug.log`、`metrics/.accuracy-debug.log` 一致):
|
|
12
|
+
* - 只有 cwd 确实是 zhuanspec 项目(存在 `<cwd>/zhuanspec` 目录)时才落盘,
|
|
13
|
+
* 否则整体 no-op —— 业务仓库不会再出现这个文件。
|
|
14
|
+
* - 落盘到 `<cwd>/zhuanspec/.user-input-debug.log`,与其它过程产物同域。
|
|
15
|
+
* - 超过 DEBUG_LOG_MAX_BYTES 轮转一代(.1),旧代被覆盖,总占用有上限。
|
|
16
|
+
* - `ZHUANSPEC_DEBUG_LOG=0|false|off|no` 可完全关闭。
|
|
17
|
+
*/
|
|
18
|
+
/** 日志文件名(放在 zhuanspec 项目目录下,与 .hook-debug.log 同级) */
|
|
19
|
+
export declare const DEBUG_LOG_FILE_NAME = ".user-input-debug.log";
|
|
20
|
+
/** 单个日志文件上限:512KB。超过则轮转一代,最坏占用 ~1MB */
|
|
21
|
+
export declare const DEBUG_LOG_MAX_BYTES: number;
|
|
22
|
+
/**
|
|
23
|
+
* 调试日志是否启用。默认启用(保持“每次调用写一行”的排障契约),
|
|
24
|
+
* 显式把 ZHUANSPEC_DEBUG_LOG 设为 0/false/off/no 时关闭。
|
|
25
|
+
*/
|
|
26
|
+
export declare function isDebugLogEnabled(env?: NodeJS.ProcessEnv): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* 解析日志落盘路径。
|
|
29
|
+
* cwd 不是 zhuanspec 项目(没有 `<cwd>/zhuanspec` 目录)时返回 null,调用方据此跳过写入,
|
|
30
|
+
* 避免在业务仓库里凭空创建文件。
|
|
31
|
+
*/
|
|
32
|
+
export declare function resolveDebugLogPath(cwd: string): string | null;
|
|
33
|
+
/**
|
|
34
|
+
* 超过上限时轮转一代:当前文件重命名为 `<name>.1`(覆盖上一代),随后由调用方重新 append。
|
|
35
|
+
* 任何失败都静默返回,日志不能影响 hook 主流程。
|
|
36
|
+
*/
|
|
37
|
+
export declare function rotateDebugLogIfNeeded(logPath: string, maxBytes?: number): void;
|
|
38
|
+
/**
|
|
39
|
+
* 追加一行 JSONL 调试日志。禁用、非 zhuanspec 项目或任何 IO 异常都静默跳过。
|
|
40
|
+
* 返回实际写入的路径,便于测试与排障;未写入时返回 null。
|
|
41
|
+
*/
|
|
42
|
+
export declare function appendDebugLog(cwd: string, payload: Record<string, unknown>, env?: NodeJS.ProcessEnv): string | null;
|
|
43
|
+
//# sourceMappingURL=user-input-debug-log.d.ts.map
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* user-input hook 的结构化调试日志(JSONL)。
|
|
3
|
+
*
|
|
4
|
+
* 历史实现直接 append 到 `<cwd>/.user-input-debug.log`,带来三个问题:
|
|
5
|
+
* 1. 污染业务仓库:detectActiveChange 只看 `<cwd>/zhuanspec/changes`,不向上查找。
|
|
6
|
+
* cwd 落在工作区下的业务子仓库时,每条 prompt 都只会写一行 no-active-change,
|
|
7
|
+
* 于是日志被创建在业务仓库根目录,且因为没有 .gitignore 兜底被提交进版本库。
|
|
8
|
+
* 2. 无上限:只 append 不轮转,单个文件可以无限增长。
|
|
9
|
+
* 3. 无开关:无法关闭。
|
|
10
|
+
*
|
|
11
|
+
* 现在的约定(与 `zhuanspec/.hook-debug.log`、`metrics/.accuracy-debug.log` 一致):
|
|
12
|
+
* - 只有 cwd 确实是 zhuanspec 项目(存在 `<cwd>/zhuanspec` 目录)时才落盘,
|
|
13
|
+
* 否则整体 no-op —— 业务仓库不会再出现这个文件。
|
|
14
|
+
* - 落盘到 `<cwd>/zhuanspec/.user-input-debug.log`,与其它过程产物同域。
|
|
15
|
+
* - 超过 DEBUG_LOG_MAX_BYTES 轮转一代(.1),旧代被覆盖,总占用有上限。
|
|
16
|
+
* - `ZHUANSPEC_DEBUG_LOG=0|false|off|no` 可完全关闭。
|
|
17
|
+
*/
|
|
18
|
+
import path from 'path';
|
|
19
|
+
import fs from 'fs';
|
|
20
|
+
/** 日志文件名(放在 zhuanspec 项目目录下,与 .hook-debug.log 同级) */
|
|
21
|
+
export const DEBUG_LOG_FILE_NAME = '.user-input-debug.log';
|
|
22
|
+
/** 单个日志文件上限:512KB。超过则轮转一代,最坏占用 ~1MB */
|
|
23
|
+
export const DEBUG_LOG_MAX_BYTES = 512 * 1024;
|
|
24
|
+
/** 关闭调试日志的环境变量取值(大小写不敏感) */
|
|
25
|
+
const DISABLED_VALUES = new Set(['0', 'false', 'off', 'no']);
|
|
26
|
+
/**
|
|
27
|
+
* 调试日志是否启用。默认启用(保持“每次调用写一行”的排障契约),
|
|
28
|
+
* 显式把 ZHUANSPEC_DEBUG_LOG 设为 0/false/off/no 时关闭。
|
|
29
|
+
*/
|
|
30
|
+
export function isDebugLogEnabled(env = process.env) {
|
|
31
|
+
const raw = env.ZHUANSPEC_DEBUG_LOG;
|
|
32
|
+
if (raw === undefined || raw === '')
|
|
33
|
+
return true;
|
|
34
|
+
return !DISABLED_VALUES.has(raw.trim().toLowerCase());
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 解析日志落盘路径。
|
|
38
|
+
* cwd 不是 zhuanspec 项目(没有 `<cwd>/zhuanspec` 目录)时返回 null,调用方据此跳过写入,
|
|
39
|
+
* 避免在业务仓库里凭空创建文件。
|
|
40
|
+
*/
|
|
41
|
+
export function resolveDebugLogPath(cwd) {
|
|
42
|
+
const zhuanspecDir = path.join(cwd, 'zhuanspec');
|
|
43
|
+
try {
|
|
44
|
+
if (!fs.statSync(zhuanspecDir).isDirectory())
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
return path.join(zhuanspecDir, DEBUG_LOG_FILE_NAME);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* 超过上限时轮转一代:当前文件重命名为 `<name>.1`(覆盖上一代),随后由调用方重新 append。
|
|
54
|
+
* 任何失败都静默返回,日志不能影响 hook 主流程。
|
|
55
|
+
*/
|
|
56
|
+
export function rotateDebugLogIfNeeded(logPath, maxBytes = DEBUG_LOG_MAX_BYTES) {
|
|
57
|
+
try {
|
|
58
|
+
if (fs.statSync(logPath).size < maxBytes)
|
|
59
|
+
return;
|
|
60
|
+
fs.renameSync(logPath, `${logPath}.1`);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// 文件不存在或轮转失败都不阻塞写入
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* 追加一行 JSONL 调试日志。禁用、非 zhuanspec 项目或任何 IO 异常都静默跳过。
|
|
68
|
+
* 返回实际写入的路径,便于测试与排障;未写入时返回 null。
|
|
69
|
+
*/
|
|
70
|
+
export function appendDebugLog(cwd, payload, env = process.env) {
|
|
71
|
+
if (!isDebugLogEnabled(env))
|
|
72
|
+
return null;
|
|
73
|
+
const logPath = resolveDebugLogPath(cwd);
|
|
74
|
+
if (!logPath)
|
|
75
|
+
return null;
|
|
76
|
+
try {
|
|
77
|
+
rotateDebugLogIfNeeded(logPath);
|
|
78
|
+
fs.appendFileSync(logPath, `${JSON.stringify(payload)}\n`, 'utf-8');
|
|
79
|
+
return logPath;
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
// Logging must never block the hook
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=user-input-debug-log.js.map
|
|
@@ -22,22 +22,18 @@ import crypto from 'crypto';
|
|
|
22
22
|
import { FileSystemUtils } from '../../utils/file-system.js';
|
|
23
23
|
import { getBeijingTime, atomicWriteJson, detectActiveChange } from './record-progress.js';
|
|
24
24
|
import { detectHookHost, sanitizeCodexEnvelope } from '../../utils/hook-host.js';
|
|
25
|
+
import { appendDebugLog } from './user-input-debug-log.js';
|
|
25
26
|
import { USER_CORRECTION_KEYWORDS, REQUIREMENT_CHANGE_KEYWORDS, extractProposalSummary, buildCorrectionOptionsContext, buildRequirementChangeContext, isCodexInternalPrompt, } from './deviation-check.js';
|
|
26
27
|
/**
|
|
27
28
|
* Structured JSONL debug log for user-input hook.
|
|
28
|
-
* Writes to <cwd
|
|
29
|
-
* Every hook invocation MUST write exactly one line here, covering every
|
|
30
|
-
* (skip-*, record, baseline-miss, baseline-write) with positive reason codes.
|
|
29
|
+
* Writes to <cwd>/zhuanspec/.user-input-debug.log; failures are swallowed to keep
|
|
30
|
+
* main flow intact. Every hook invocation MUST write exactly one line here, covering every
|
|
31
|
+
* branch (skip-*, record, baseline-miss, baseline-write) with positive reason codes.
|
|
32
|
+
* cwd 不是 zhuanspec 项目时整体跳过,避免在业务仓库里凭空创建日志文件;
|
|
33
|
+
* 落盘策略(位置 / 上限轮转 / 开关)见 user-input-debug-log.ts。
|
|
31
34
|
*/
|
|
32
35
|
function logDebug(cwd, payload) {
|
|
33
|
-
|
|
34
|
-
const logPath = path.join(cwd, '.user-input-debug.log');
|
|
35
|
-
const line = JSON.stringify({ ts: getBeijingTime(), ...payload }) + '\n';
|
|
36
|
-
fs.appendFileSync(logPath, line, 'utf-8');
|
|
37
|
-
}
|
|
38
|
-
catch {
|
|
39
|
-
// Logging must never block the hook
|
|
40
|
-
}
|
|
36
|
+
appendDebugLog(cwd, { ts: getBeijingTime(), ...payload });
|
|
41
37
|
}
|
|
42
38
|
/** fullPrompt 截断长度:够写知识文件的"背景/问题/解决方案",又不会把 user_inputs.json 撑爆 */
|
|
43
39
|
const FULL_PROMPT_MAX_LEN = 2000;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhuan-ai/zhuanspec",
|
|
3
|
-
"version": "2.19.
|
|
3
|
+
"version": "2.19.3",
|
|
4
4
|
"description": "AI-native system for spec-driven development",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"zhuanspec",
|
|
@@ -39,26 +39,6 @@
|
|
|
39
39
|
"!dist/**/__tests__",
|
|
40
40
|
"!dist/**/*.map"
|
|
41
41
|
],
|
|
42
|
-
"scripts": {
|
|
43
|
-
"lint": "eslint src/",
|
|
44
|
-
"build": "node build.js",
|
|
45
|
-
"dev": "tsc --watch",
|
|
46
|
-
"dev:cli": "pnpm build && node bin/zhuanspec.js",
|
|
47
|
-
"test": "vitest run",
|
|
48
|
-
"test:watch": "vitest",
|
|
49
|
-
"test:ui": "vitest --ui",
|
|
50
|
-
"test:coverage": "vitest --coverage",
|
|
51
|
-
"test:postinstall": "node scripts/postinstall.js",
|
|
52
|
-
"prepare": "npm run build",
|
|
53
|
-
"prepublishOnly": "npm run build",
|
|
54
|
-
"postinstall": "node scripts/postinstall.js",
|
|
55
|
-
"check:pack-version": "node scripts/pack-version-check.mjs",
|
|
56
|
-
"diagnose:cursor": "node scripts/diagnose-cursor-commands.js",
|
|
57
|
-
"release": "pnpm run release:ci",
|
|
58
|
-
"release:ci": "pnpm run check:pack-version && pnpm exec changeset publish",
|
|
59
|
-
"release:local": "pnpm exec changeset version && pnpm run check:pack-version && pnpm exec changeset publish",
|
|
60
|
-
"changeset": "changeset"
|
|
61
|
-
},
|
|
62
42
|
"engines": {
|
|
63
43
|
"node": ">=20.19.0"
|
|
64
44
|
},
|
|
@@ -80,5 +60,23 @@
|
|
|
80
60
|
"ora": "^8.2.0",
|
|
81
61
|
"yaml": "^2.8.2",
|
|
82
62
|
"zod": "^4.0.17"
|
|
63
|
+
},
|
|
64
|
+
"scripts": {
|
|
65
|
+
"lint": "eslint src/",
|
|
66
|
+
"build": "node build.js",
|
|
67
|
+
"dev": "tsc --watch",
|
|
68
|
+
"dev:cli": "pnpm build && node bin/zhuanspec.js",
|
|
69
|
+
"test": "vitest run",
|
|
70
|
+
"test:watch": "vitest",
|
|
71
|
+
"test:ui": "vitest --ui",
|
|
72
|
+
"test:coverage": "vitest --coverage",
|
|
73
|
+
"test:postinstall": "node scripts/postinstall.js",
|
|
74
|
+
"postinstall": "node scripts/postinstall.js",
|
|
75
|
+
"check:pack-version": "node scripts/pack-version-check.mjs",
|
|
76
|
+
"diagnose:cursor": "node scripts/diagnose-cursor-commands.js",
|
|
77
|
+
"release": "pnpm run release:ci",
|
|
78
|
+
"release:ci": "pnpm run check:pack-version && pnpm exec changeset publish",
|
|
79
|
+
"release:local": "pnpm exec changeset version && pnpm run check:pack-version && pnpm exec changeset publish",
|
|
80
|
+
"changeset": "changeset"
|
|
83
81
|
}
|
|
84
|
-
}
|
|
82
|
+
}
|