add-coder 0.3.31 → 0.3.32

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.
Files changed (74) hide show
  1. package/package.json +1 -1
  2. package/templates/.add-coder-src-hash.json +73 -1
  3. package/templates/adapters/claude/hooks/doc-format-guard.mjs +850 -0
  4. package/templates/adapters/claude/hooks/notification.mjs +256 -0
  5. package/templates/adapters/claude/hooks/permission-denied.mjs +167 -0
  6. package/templates/adapters/claude/hooks/permission-gate.mjs +150 -0
  7. package/templates/adapters/claude/hooks/post-tool-failure.mjs +3 -0
  8. package/templates/adapters/claude/hooks/post-tool-use.mjs +413 -0
  9. package/templates/adapters/claude/hooks/pre-compact.mjs +226 -0
  10. package/templates/adapters/claude/hooks/pre-tool-use.mjs +914 -0
  11. package/templates/adapters/claude/hooks/prompt-submit.mjs +847 -0
  12. package/templates/adapters/claude/hooks/review-checklist.mjs +3 -0
  13. package/templates/adapters/claude/hooks/session-end.mjs +287 -0
  14. package/templates/adapters/claude/hooks/session-start.mjs +566 -0
  15. package/templates/adapters/claude/hooks/stop-check.mjs +505 -0
  16. package/templates/adapters/claude/hooks/stop-failure.mjs +222 -0
  17. package/templates/adapters/claude/hooks/subagent-guard.mjs +224 -0
  18. package/templates/adapters/claude/hooks/subagent-stop.mjs +277 -0
  19. package/templates/adapters/codex/hooks/doc-format-guard.mjs +849 -0
  20. package/templates/adapters/codex/hooks/notification.mjs +254 -0
  21. package/templates/adapters/codex/hooks/permission-gate.mjs +169 -0
  22. package/templates/adapters/codex/hooks/post-tool-failure.mjs +176 -0
  23. package/templates/adapters/codex/hooks/post-tool-use.mjs +575 -0
  24. package/templates/adapters/codex/hooks/pre-compact.mjs +328 -0
  25. package/templates/adapters/codex/hooks/pre-tool-use.mjs +963 -0
  26. package/templates/adapters/codex/hooks/prompt-submit.mjs +623 -0
  27. package/templates/adapters/codex/hooks/review-checklist.mjs +3 -0
  28. package/templates/adapters/codex/hooks/session-end.mjs +389 -0
  29. package/templates/adapters/codex/hooks/session-start.mjs +583 -0
  30. package/templates/adapters/codex/hooks/stop-check.mjs +539 -0
  31. package/templates/adapters/codex/hooks/subagent-guard.mjs +218 -0
  32. package/templates/adapters/codex/hooks/subagent-stop.mjs +381 -0
  33. package/templates/adapters/qoder/hooks/doc-format-guard.mjs +858 -0
  34. package/templates/adapters/qoder/hooks/notification.mjs +269 -0
  35. package/templates/adapters/qoder/hooks/permission-gate.mjs +284 -0
  36. package/templates/adapters/qoder/hooks/post-tool-failure.mjs +294 -0
  37. package/templates/adapters/qoder/hooks/post-tool-use.mjs +535 -0
  38. package/templates/adapters/qoder/hooks/pre-compact.mjs +234 -0
  39. package/templates/adapters/qoder/hooks/pre-tool-use.mjs +948 -0
  40. package/templates/adapters/qoder/hooks/prompt-submit.mjs +789 -0
  41. package/templates/adapters/qoder/hooks/review-checklist.mjs +409 -0
  42. package/templates/adapters/qoder/hooks/session-end.mjs +301 -0
  43. package/templates/adapters/qoder/hooks/session-start.mjs +619 -0
  44. package/templates/adapters/qoder/hooks/stop-check.mjs +567 -0
  45. package/templates/adapters/qoder/hooks/subagent-guard.mjs +219 -0
  46. package/templates/adapters/qoder/hooks/subagent-stop.mjs +298 -0
  47. package/templates/adapters/trae/hooks/doc-format-guard.mjs +849 -0
  48. package/templates/adapters/trae/hooks/notification.mjs +251 -0
  49. package/templates/adapters/trae/hooks/permission-gate.mjs +169 -0
  50. package/templates/adapters/trae/hooks/post-tool-failure.mjs +176 -0
  51. package/templates/adapters/trae/hooks/post-tool-use.mjs +415 -0
  52. package/templates/adapters/trae/hooks/pre-compact.mjs +224 -0
  53. package/templates/adapters/trae/hooks/pre-tool-use.mjs +873 -0
  54. package/templates/adapters/trae/hooks/prompt-submit.mjs +614 -0
  55. package/templates/adapters/trae/hooks/review-checklist.mjs +3 -0
  56. package/templates/adapters/trae/hooks/session-end.mjs +285 -0
  57. package/templates/adapters/trae/hooks/session-start.mjs +555 -0
  58. package/templates/adapters/trae/hooks/stop-check.mjs +502 -0
  59. package/templates/adapters/trae/hooks/subagent-guard.mjs +218 -0
  60. package/templates/adapters/trae/hooks/subagent-stop.mjs +274 -0
  61. package/templates/adapters/vscode/hooks/doc-format-guard.mjs +847 -0
  62. package/templates/adapters/vscode/hooks/notification.mjs +251 -0
  63. package/templates/adapters/vscode/hooks/permission-gate.mjs +169 -0
  64. package/templates/adapters/vscode/hooks/post-tool-failure.mjs +192 -0
  65. package/templates/adapters/vscode/hooks/post-tool-use.mjs +415 -0
  66. package/templates/adapters/vscode/hooks/pre-compact.mjs +224 -0
  67. package/templates/adapters/vscode/hooks/pre-tool-use.mjs +906 -0
  68. package/templates/adapters/vscode/hooks/prompt-submit.mjs +838 -0
  69. package/templates/adapters/vscode/hooks/review-checklist.mjs +3 -0
  70. package/templates/adapters/vscode/hooks/session-end.mjs +285 -0
  71. package/templates/adapters/vscode/hooks/session-start.mjs +560 -0
  72. package/templates/adapters/vscode/hooks/stop-check.mjs +502 -0
  73. package/templates/adapters/vscode/hooks/subagent-guard.mjs +218 -0
  74. package/templates/adapters/vscode/hooks/subagent-stop.mjs +274 -0
@@ -0,0 +1,256 @@
1
+ // templates/core/governance/common.ts
2
+ import { existsSync, readFileSync, writeFileSync, unlinkSync } from "node:fs";
3
+ import { basename, dirname, join } from "node:path";
4
+ import { spawnSync } from "node:child_process";
5
+ import { createHash } from "node:crypto";
6
+
7
+ // templates/core/governance/rules.ts
8
+ var protocol = {
9
+ "exit_codes": {
10
+ "pass": 0,
11
+ "block": 2,
12
+ "note": "\u5192\u70DF\u6821\u9A8C: \u4EA7\u7269\u9000\u51FA\u7801 \u2208 {0,2}\uFF08\u5176\u4F59\u4E3A\u975E\u9884\u671F\uFF0C\u9700\u4FEE\u590D\uFF09"
13
+ },
14
+ "output": {
15
+ "stdout_json_only": true,
16
+ "stderr_human_text": true,
17
+ "field_separator": "::",
18
+ "magic_dir_resolution": "\u6CE8\u5165\u4F18\u5148 \u2192 \u7269\u7406\u4F4D\u7F6E\u63A8\u5BFC \u2192 failClosed\uFF08\u7981\u6B62\u731C\u6D4B adapter \u540D\uFF09"
19
+ },
20
+ "adapters": {
21
+ "claude": {
22
+ "stdout_form": "plain-text",
23
+ "project_dir_env": "CLAUDE_PROJECT_DIR",
24
+ "magic_dir": ".claude",
25
+ "handlerTypes": [
26
+ "command",
27
+ "mcp_tool"
28
+ ]
29
+ },
30
+ "qoder": {
31
+ "stdout_form": "json",
32
+ "project_dir_env": "QODER_PROJECT_DIR",
33
+ "magic_dir": ".qoder",
34
+ "handlerTypes": [
35
+ "command",
36
+ "http"
37
+ ]
38
+ },
39
+ "codex": {
40
+ "stdout_form": "systemMessage",
41
+ "project_dir_env": "git-toplevel",
42
+ "magic_dir": ".codex",
43
+ "handlerTypes": [
44
+ "command"
45
+ ]
46
+ },
47
+ "vscode": {
48
+ "stdout_form": "plain-text",
49
+ "project_dir_env": "PWD",
50
+ "magic_dir": ".vscode",
51
+ "handlerTypes": [
52
+ "command"
53
+ ]
54
+ },
55
+ "trae": {
56
+ "stdout_form": "plain-text",
57
+ "project_dir_env": "PWD",
58
+ "magic_dir": ".trae",
59
+ "handlerTypes": [
60
+ "command"
61
+ ]
62
+ }
63
+ },
64
+ "event_outputs": {
65
+ "qoder": {
66
+ "SessionStart": "additionalContext",
67
+ "UserPromptSubmit": "additionalContext",
68
+ "PreToolUse": "permissionDecision",
69
+ "Stop": "additionalContext",
70
+ "PostToolUse": "feedback",
71
+ "SubagentStart": "additionalContext",
72
+ "SubagentStop": "additionalContext",
73
+ "PostToolUseFailure": "text",
74
+ "PermissionRequest": "text",
75
+ "SessionEnd": "text",
76
+ "PreCompact": "text",
77
+ "Notification": "text"
78
+ },
79
+ "claude": {
80
+ "SessionStart": "additionalContext",
81
+ "UserPromptSubmit": "additionalContext",
82
+ "PreToolUse": "permissionDecision",
83
+ "Stop": "text",
84
+ "PostToolUse": "feedback",
85
+ "SubagentStart": "text",
86
+ "SubagentStop": "text",
87
+ "PostToolUseFailure": "text",
88
+ "PermissionRequest": "text",
89
+ "SessionEnd": "text",
90
+ "PreCompact": "text",
91
+ "Notification": "text"
92
+ },
93
+ "codex": {
94
+ "Stop": "systemMessage",
95
+ "PostToolUse": "text"
96
+ },
97
+ "vscode": {
98
+ "PostToolUse": "text"
99
+ },
100
+ "trae": {
101
+ "PostToolUse": "text"
102
+ }
103
+ },
104
+ "core": {
105
+ "stdout_form": "json",
106
+ "magic_dir": ".add",
107
+ "note": "core \u5165\u53E3\u534F\u8BAE = qoder \u540C\u6784\u53C2\u8003\u5B9E\u73B0\uFF1Badapter \u4EC5\u4FDD\u7559\u672C\u8868\u58F0\u660E\u7684\u79C1\u6709\u5DEE\u5F02"
108
+ },
109
+ "adapter_defaults": {
110
+ "magic_dir_fallback": ".qoder",
111
+ "probe_magic_dirs": [
112
+ ".claude",
113
+ ".qoder",
114
+ ".vscode",
115
+ ".add",
116
+ ".trae",
117
+ ".codex"
118
+ ]
119
+ }
120
+ };
121
+
122
+ // templates/core/governance/common.ts
123
+ var EXIT_PASS = protocol.exit_codes.pass;
124
+ var EXIT_BLOCK = protocol.exit_codes.block;
125
+ var STATE_SEP = protocol.output.field_separator;
126
+ function readHookInput() {
127
+ if (process.stdin.isTTY) return "{}";
128
+ return readFileSync(0, "utf-8");
129
+ }
130
+ function jsonGet(json, field) {
131
+ const re = new RegExp(`"${field}"\\s*:\\s*"([^"]*)"`);
132
+ const m = re.exec(json);
133
+ return m?.[1] ?? "";
134
+ }
135
+ function queryPlanStatus() {
136
+ const magicDir = process.env.MAGIC_DIR;
137
+ if (!magicDir) {
138
+ return {
139
+ stdout: '{"availability":"STATUS_UNAVAILABLE","source":"database","reason":"magicDir \u672A\u6CE8\u5165\u4E14\u65E0\u6CD5\u4ECE\u7269\u7406\u4F4D\u7F6E\u63A8\u5BFC"}',
140
+ exitCode: 3
141
+ };
142
+ }
143
+ const bridge = join(
144
+ process.env.PROJECT_DIR || process.cwd(),
145
+ magicDir,
146
+ "scripts",
147
+ "plan-status-bridge.ts"
148
+ );
149
+ if (!existsSync(bridge)) {
150
+ return {
151
+ stdout: '{"availability":"STATUS_UNAVAILABLE","source":"database","reason":"plan-status bridge missing"}',
152
+ exitCode: 3
153
+ };
154
+ }
155
+ const r = spawnSync("node", ["--import", "tsx", bridge], {
156
+ encoding: "utf-8",
157
+ timeout: 1e4
158
+ });
159
+ return { stdout: r.stdout ?? "", exitCode: r.status ?? -1 };
160
+ }
161
+ function detectActiveAdd() {
162
+ const r = queryPlanStatus();
163
+ if (r.exitCode !== 0) {
164
+ let reason = "database status unavailable";
165
+ try {
166
+ const parsed = JSON.parse(r.stdout);
167
+ if (parsed.reason) reason = parsed.reason;
168
+ } catch {
169
+ }
170
+ return `__STATUS_UNAVAILABLE__::${reason}::database::none::none`;
171
+ }
172
+ let snapshot;
173
+ try {
174
+ snapshot = JSON.parse(r.stdout);
175
+ } catch {
176
+ return null;
177
+ }
178
+ if (!(snapshot.availability === "READY" && snapshot.isActive === true)) return null;
179
+ const done = snapshot.progress?.doneTasks ?? 0;
180
+ const total = snapshot.progress?.totalTasks ?? 0;
181
+ const approval = snapshot.approvalStatus ?? "none";
182
+ return `${snapshot.planName}::${done}/${total}::${approval}::none::none`;
183
+ }
184
+ function projectHash() {
185
+ try {
186
+ return createHash("md5").update(`${process.env.PROJECT_DIR || process.cwd()}
187
+ `).digest("hex").slice(0, 8);
188
+ } catch {
189
+ return "default";
190
+ }
191
+ }
192
+ var DEV_FLAG = `/tmp/add_dev_${projectHash()}`;
193
+
194
+ // templates/core/governance/notification-router.ts
195
+ import { existsSync as existsSync2, readdirSync } from "node:fs";
196
+ import { join as join2 } from "node:path";
197
+ var NotificationRouter = class {
198
+ projectDir;
199
+ fallbackMagicDir;
200
+ constructor(projectDir, fallbackMagicDir) {
201
+ this.projectDir = projectDir;
202
+ this.fallbackMagicDir = fallbackMagicDir;
203
+ }
204
+ /** 提醒输出(core 默认: 含 Plan 前缀——bash 原文逐字;qoder 子类 override 无前缀) */
205
+ emitReminder(plan, reviewsDir) {
206
+ process.stdout.write(`[ADD Notification] Plan: ${plan} \u2014 \u8BF7\u68C0\u67E5 Review \u6587\u6863: ${reviewsDir}
207
+ `);
208
+ }
209
+ /**
210
+ * magicDir 解析(core 默认: env 优先 → 跨端探测循环 → fallback;bash 原文逐字):
211
+ * 扩展点: qoder 子类 override 为固定值(qoder bash 原文硬编码 ${PROJECT_DIR}/.qoder/reviews,无探测循环)。
212
+ * Task 9.4 中立化: 探测列表从 hook-protocol-rules.toml [protocol.adapter_defaults.probe_magic_dirs] 读取——
213
+ * 原硬编码 [".claude", ".qoder", ".vscode", ".add"] 缺 .trae/.codex(新增端需改代码);声明化后随端演进。
214
+ */
215
+ resolveMagicDir() {
216
+ const env = process.env.MAGIC_DIR;
217
+ if (env) return env;
218
+ const defaults = protocol.adapter_defaults;
219
+ const probeList = defaults?.probe_magic_dirs ?? [".claude", ".qoder", ".vscode", ".add"];
220
+ for (const m of probeList) {
221
+ if (existsSync2(join2(this.projectDir, m))) return m;
222
+ }
223
+ return this.fallbackMagicDir;
224
+ }
225
+ /** 主路由:返回 exit code(0) */
226
+ run(input2) {
227
+ const ntype = jsonGet(input2, "notification_type");
228
+ if (ntype !== "result") return 0;
229
+ const state = detectActiveAdd();
230
+ if (state === null) return 0;
231
+ const plan = state.split("::")[0] ?? "";
232
+ const magicDir = this.resolveMagicDir();
233
+ const reviewsDir = join2(this.projectDir, magicDir, "reviews");
234
+ if (existsSync2(reviewsDir) && readdirSync(reviewsDir).some((f) => f.endsWith(".md"))) {
235
+ this.emitReminder(plan, reviewsDir);
236
+ }
237
+ return 0;
238
+ }
239
+ };
240
+
241
+ // templates/adapters/claude/hooks/lib/claude-env.ts
242
+ function resolveClaudeProjectDir() {
243
+ return process.env.CLAUDE_PROJECT_DIR || process.cwd();
244
+ }
245
+
246
+ // templates/adapters/claude/hooks/notification.ts
247
+ var ClaudeNotificationRouter = class extends NotificationRouter {
248
+ /** 协议差异封装: fallbackMagicDir = ".claude"(claude 端兜底,bash 原文逐字) */
249
+ constructor(projectDir) {
250
+ super(projectDir, ".claude");
251
+ }
252
+ // 当前无 override(提醒文本与 core 基线一致);命名子类承载端身份 + 未来演进位
253
+ };
254
+ process.env.PROJECT_DIR = resolveClaudeProjectDir();
255
+ var input = readHookInput();
256
+ process.exit(new ClaudeNotificationRouter(process.env.PROJECT_DIR).run(input));
@@ -0,0 +1,167 @@
1
+ // templates/core/governance/common.ts
2
+ import { existsSync, readFileSync, writeFileSync, unlinkSync } from "node:fs";
3
+ import { createHash } from "node:crypto";
4
+
5
+ // templates/core/governance/rules.ts
6
+ var protocol = {
7
+ "exit_codes": {
8
+ "pass": 0,
9
+ "block": 2,
10
+ "note": "\u5192\u70DF\u6821\u9A8C: \u4EA7\u7269\u9000\u51FA\u7801 \u2208 {0,2}\uFF08\u5176\u4F59\u4E3A\u975E\u9884\u671F\uFF0C\u9700\u4FEE\u590D\uFF09"
11
+ },
12
+ "output": {
13
+ "stdout_json_only": true,
14
+ "stderr_human_text": true,
15
+ "field_separator": "::",
16
+ "magic_dir_resolution": "\u6CE8\u5165\u4F18\u5148 \u2192 \u7269\u7406\u4F4D\u7F6E\u63A8\u5BFC \u2192 failClosed\uFF08\u7981\u6B62\u731C\u6D4B adapter \u540D\uFF09"
17
+ },
18
+ "adapters": {
19
+ "claude": {
20
+ "stdout_form": "plain-text",
21
+ "project_dir_env": "CLAUDE_PROJECT_DIR",
22
+ "magic_dir": ".claude",
23
+ "handlerTypes": [
24
+ "command",
25
+ "mcp_tool"
26
+ ]
27
+ },
28
+ "qoder": {
29
+ "stdout_form": "json",
30
+ "project_dir_env": "QODER_PROJECT_DIR",
31
+ "magic_dir": ".qoder",
32
+ "handlerTypes": [
33
+ "command",
34
+ "http"
35
+ ]
36
+ },
37
+ "codex": {
38
+ "stdout_form": "systemMessage",
39
+ "project_dir_env": "git-toplevel",
40
+ "magic_dir": ".codex",
41
+ "handlerTypes": [
42
+ "command"
43
+ ]
44
+ },
45
+ "vscode": {
46
+ "stdout_form": "plain-text",
47
+ "project_dir_env": "PWD",
48
+ "magic_dir": ".vscode",
49
+ "handlerTypes": [
50
+ "command"
51
+ ]
52
+ },
53
+ "trae": {
54
+ "stdout_form": "plain-text",
55
+ "project_dir_env": "PWD",
56
+ "magic_dir": ".trae",
57
+ "handlerTypes": [
58
+ "command"
59
+ ]
60
+ }
61
+ },
62
+ "event_outputs": {
63
+ "qoder": {
64
+ "SessionStart": "additionalContext",
65
+ "UserPromptSubmit": "additionalContext",
66
+ "PreToolUse": "permissionDecision",
67
+ "Stop": "additionalContext",
68
+ "PostToolUse": "feedback",
69
+ "SubagentStart": "additionalContext",
70
+ "SubagentStop": "additionalContext",
71
+ "PostToolUseFailure": "text",
72
+ "PermissionRequest": "text",
73
+ "SessionEnd": "text",
74
+ "PreCompact": "text",
75
+ "Notification": "text"
76
+ },
77
+ "claude": {
78
+ "SessionStart": "additionalContext",
79
+ "UserPromptSubmit": "additionalContext",
80
+ "PreToolUse": "permissionDecision",
81
+ "Stop": "text",
82
+ "PostToolUse": "feedback",
83
+ "SubagentStart": "text",
84
+ "SubagentStop": "text",
85
+ "PostToolUseFailure": "text",
86
+ "PermissionRequest": "text",
87
+ "SessionEnd": "text",
88
+ "PreCompact": "text",
89
+ "Notification": "text"
90
+ },
91
+ "codex": {
92
+ "Stop": "systemMessage",
93
+ "PostToolUse": "text"
94
+ },
95
+ "vscode": {
96
+ "PostToolUse": "text"
97
+ },
98
+ "trae": {
99
+ "PostToolUse": "text"
100
+ }
101
+ },
102
+ "core": {
103
+ "stdout_form": "json",
104
+ "magic_dir": ".add",
105
+ "note": "core \u5165\u53E3\u534F\u8BAE = qoder \u540C\u6784\u53C2\u8003\u5B9E\u73B0\uFF1Badapter \u4EC5\u4FDD\u7559\u672C\u8868\u58F0\u660E\u7684\u79C1\u6709\u5DEE\u5F02"
106
+ },
107
+ "adapter_defaults": {
108
+ "magic_dir_fallback": ".qoder",
109
+ "probe_magic_dirs": [
110
+ ".claude",
111
+ ".qoder",
112
+ ".vscode",
113
+ ".add",
114
+ ".trae",
115
+ ".codex"
116
+ ]
117
+ }
118
+ };
119
+
120
+ // templates/core/governance/common.ts
121
+ var EXIT_PASS = protocol.exit_codes.pass;
122
+ var EXIT_BLOCK = protocol.exit_codes.block;
123
+ var STATE_SEP = protocol.output.field_separator;
124
+ function readHookInput() {
125
+ if (process.stdin.isTTY) return "{}";
126
+ return readFileSync(0, "utf-8");
127
+ }
128
+ function jsonGet(json, field) {
129
+ const re = new RegExp(`"${field}"\\s*:\\s*"([^"]*)"`);
130
+ const m = re.exec(json);
131
+ return m?.[1] ?? "";
132
+ }
133
+ function projectHash() {
134
+ try {
135
+ return createHash("md5").update(`${process.env.PROJECT_DIR || process.cwd()}
136
+ `).digest("hex").slice(0, 8);
137
+ } catch {
138
+ return "default";
139
+ }
140
+ }
141
+ var DEV_FLAG = `/tmp/add_dev_${projectHash()}`;
142
+
143
+ // templates/adapters/claude/hooks/permission-denied.ts
144
+ var input = readHookInput();
145
+ var toolName = jsonGet(input, "tool_name");
146
+ if (toolName === "") {
147
+ toolName = input.match(/"tool_name"\s*:\s*"([^"]*)"/)?.[1] ?? "unknown";
148
+ }
149
+ var reason = jsonGet(input, "reason");
150
+ if (reason === "") {
151
+ reason = input.match(/"reason"\s*:\s*"([^"]*)"/)?.[1] ?? "\u6743\u9650\u88AB\u62D2\u7EDD";
152
+ }
153
+ process.stderr.write(`[ADD PermissionDenied] ${toolName} \u88AB\u62D2\u7EDD: ${reason}
154
+ `);
155
+ switch (toolName) {
156
+ case "Bash":
157
+ process.stderr.write("[ADD PermissionDenied] \u5EFA\u8BAE: \u4F7F\u7528\u5B89\u5168\u7684\u7B49\u4EF7\u547D\u4EE4\uFF0C\u6216\u901A\u8FC7 permission-gate.sh \u767D\u540D\u5355\u653E\u884C\n");
158
+ break;
159
+ case "Write":
160
+ case "Edit":
161
+ process.stderr.write("[ADD PermissionDenied] \u5EFA\u8BAE: \u68C0\u67E5\u76EE\u6807\u8DEF\u5F84\u662F\u5426\u5728\u9879\u76EE\u8303\u56F4\u5185\uFF0C\u654F\u611F\u6587\u4EF6\uFF08.env\u7B49\uFF09\u4E0D\u53EF\u5199\u5165\n");
162
+ break;
163
+ case "Read":
164
+ process.stderr.write("[ADD PermissionDenied] \u5EFA\u8BAE: \u8BE5\u6587\u4EF6\u53EF\u80FD\u53D7\u8BFB\u4FDD\u62A4\uFF0C\u5C1D\u8BD5\u8BFB\u53D6\u9879\u76EE\u516C\u6709\u6587\u4EF6\u66FF\u4EE3\n");
165
+ break;
166
+ }
167
+ process.exit(0);
@@ -0,0 +1,150 @@
1
+ // templates/core/governance/common.ts
2
+ import { existsSync, readFileSync, writeFileSync, unlinkSync } from "node:fs";
3
+ import { createHash } from "node:crypto";
4
+
5
+ // templates/core/governance/rules.ts
6
+ var protocol = {
7
+ "exit_codes": {
8
+ "pass": 0,
9
+ "block": 2,
10
+ "note": "\u5192\u70DF\u6821\u9A8C: \u4EA7\u7269\u9000\u51FA\u7801 \u2208 {0,2}\uFF08\u5176\u4F59\u4E3A\u975E\u9884\u671F\uFF0C\u9700\u4FEE\u590D\uFF09"
11
+ },
12
+ "output": {
13
+ "stdout_json_only": true,
14
+ "stderr_human_text": true,
15
+ "field_separator": "::",
16
+ "magic_dir_resolution": "\u6CE8\u5165\u4F18\u5148 \u2192 \u7269\u7406\u4F4D\u7F6E\u63A8\u5BFC \u2192 failClosed\uFF08\u7981\u6B62\u731C\u6D4B adapter \u540D\uFF09"
17
+ },
18
+ "adapters": {
19
+ "claude": {
20
+ "stdout_form": "plain-text",
21
+ "project_dir_env": "CLAUDE_PROJECT_DIR",
22
+ "magic_dir": ".claude",
23
+ "handlerTypes": [
24
+ "command",
25
+ "mcp_tool"
26
+ ]
27
+ },
28
+ "qoder": {
29
+ "stdout_form": "json",
30
+ "project_dir_env": "QODER_PROJECT_DIR",
31
+ "magic_dir": ".qoder",
32
+ "handlerTypes": [
33
+ "command",
34
+ "http"
35
+ ]
36
+ },
37
+ "codex": {
38
+ "stdout_form": "systemMessage",
39
+ "project_dir_env": "git-toplevel",
40
+ "magic_dir": ".codex",
41
+ "handlerTypes": [
42
+ "command"
43
+ ]
44
+ },
45
+ "vscode": {
46
+ "stdout_form": "plain-text",
47
+ "project_dir_env": "PWD",
48
+ "magic_dir": ".vscode",
49
+ "handlerTypes": [
50
+ "command"
51
+ ]
52
+ },
53
+ "trae": {
54
+ "stdout_form": "plain-text",
55
+ "project_dir_env": "PWD",
56
+ "magic_dir": ".trae",
57
+ "handlerTypes": [
58
+ "command"
59
+ ]
60
+ }
61
+ },
62
+ "event_outputs": {
63
+ "qoder": {
64
+ "SessionStart": "additionalContext",
65
+ "UserPromptSubmit": "additionalContext",
66
+ "PreToolUse": "permissionDecision",
67
+ "Stop": "additionalContext",
68
+ "PostToolUse": "feedback",
69
+ "SubagentStart": "additionalContext",
70
+ "SubagentStop": "additionalContext",
71
+ "PostToolUseFailure": "text",
72
+ "PermissionRequest": "text",
73
+ "SessionEnd": "text",
74
+ "PreCompact": "text",
75
+ "Notification": "text"
76
+ },
77
+ "claude": {
78
+ "SessionStart": "additionalContext",
79
+ "UserPromptSubmit": "additionalContext",
80
+ "PreToolUse": "permissionDecision",
81
+ "Stop": "text",
82
+ "PostToolUse": "feedback",
83
+ "SubagentStart": "text",
84
+ "SubagentStop": "text",
85
+ "PostToolUseFailure": "text",
86
+ "PermissionRequest": "text",
87
+ "SessionEnd": "text",
88
+ "PreCompact": "text",
89
+ "Notification": "text"
90
+ },
91
+ "codex": {
92
+ "Stop": "systemMessage",
93
+ "PostToolUse": "text"
94
+ },
95
+ "vscode": {
96
+ "PostToolUse": "text"
97
+ },
98
+ "trae": {
99
+ "PostToolUse": "text"
100
+ }
101
+ },
102
+ "core": {
103
+ "stdout_form": "json",
104
+ "magic_dir": ".add",
105
+ "note": "core \u5165\u53E3\u534F\u8BAE = qoder \u540C\u6784\u53C2\u8003\u5B9E\u73B0\uFF1Badapter \u4EC5\u4FDD\u7559\u672C\u8868\u58F0\u660E\u7684\u79C1\u6709\u5DEE\u5F02"
106
+ },
107
+ "adapter_defaults": {
108
+ "magic_dir_fallback": ".qoder",
109
+ "probe_magic_dirs": [
110
+ ".claude",
111
+ ".qoder",
112
+ ".vscode",
113
+ ".add",
114
+ ".trae",
115
+ ".codex"
116
+ ]
117
+ }
118
+ };
119
+
120
+ // templates/core/governance/common.ts
121
+ var EXIT_PASS = protocol.exit_codes.pass;
122
+ var EXIT_BLOCK = protocol.exit_codes.block;
123
+ var STATE_SEP = protocol.output.field_separator;
124
+ function readHookInput() {
125
+ if (process.stdin.isTTY) return "{}";
126
+ return readFileSync(0, "utf-8");
127
+ }
128
+ function jsonGet(json, field) {
129
+ const re = new RegExp(`"${field}"\\s*:\\s*"([^"]*)"`);
130
+ const m = re.exec(json);
131
+ return m?.[1] ?? "";
132
+ }
133
+ function projectHash() {
134
+ try {
135
+ return createHash("md5").update(`${process.env.PROJECT_DIR || process.cwd()}
136
+ `).digest("hex").slice(0, 8);
137
+ } catch {
138
+ return "default";
139
+ }
140
+ }
141
+ var DEV_FLAG = `/tmp/add_dev_${projectHash()}`;
142
+
143
+ // templates/adapters/claude/hooks/permission-gate.ts
144
+ var input = readHookInput();
145
+ var toolName = jsonGet(input, "tool_name");
146
+ if (toolName === "Bash" || toolName === "Write" || toolName === "Edit") {
147
+ process.stdout.write(`[ADD PermissionGate] \u9AD8\u98CE\u9669\u5DE5\u5177: ${toolName}\uFF0C\u8BF7\u786E\u8BA4\u64CD\u4F5C\u3002
148
+ `);
149
+ }
150
+ process.exit(0);
@@ -0,0 +1,3 @@
1
+ // templates/adapters/claude/hooks/post-tool-failure.ts
2
+ process.stdout.write("[ADD PostToolFailure] \u5DE5\u5177\u8C03\u7528\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u9519\u8BEF\u4FE1\u606F\u5E76\u4FEE\u590D\u3002\n");
3
+ process.exit(0);