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,328 @@
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 { fileURLToPath as fileURLToPath3 } from "node:url";
5
+ import { spawnSync } from "node:child_process";
6
+ import { createHash } from "node:crypto";
7
+
8
+ // templates/core/governance/rules.ts
9
+ var protocol = {
10
+ "exit_codes": {
11
+ "pass": 0,
12
+ "block": 2,
13
+ "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"
14
+ },
15
+ "output": {
16
+ "stdout_json_only": true,
17
+ "stderr_human_text": true,
18
+ "field_separator": "::",
19
+ "magic_dir_resolution": "\u6CE8\u5165\u4F18\u5148 \u2192 \u7269\u7406\u4F4D\u7F6E\u63A8\u5BFC \u2192 failClosed\uFF08\u7981\u6B62\u731C\u6D4B adapter \u540D\uFF09"
20
+ },
21
+ "adapters": {
22
+ "claude": {
23
+ "stdout_form": "plain-text",
24
+ "project_dir_env": "CLAUDE_PROJECT_DIR",
25
+ "magic_dir": ".claude",
26
+ "handlerTypes": [
27
+ "command",
28
+ "mcp_tool"
29
+ ]
30
+ },
31
+ "qoder": {
32
+ "stdout_form": "json",
33
+ "project_dir_env": "QODER_PROJECT_DIR",
34
+ "magic_dir": ".qoder",
35
+ "handlerTypes": [
36
+ "command",
37
+ "http"
38
+ ]
39
+ },
40
+ "codex": {
41
+ "stdout_form": "systemMessage",
42
+ "project_dir_env": "git-toplevel",
43
+ "magic_dir": ".codex",
44
+ "handlerTypes": [
45
+ "command"
46
+ ]
47
+ },
48
+ "vscode": {
49
+ "stdout_form": "plain-text",
50
+ "project_dir_env": "PWD",
51
+ "magic_dir": ".vscode",
52
+ "handlerTypes": [
53
+ "command"
54
+ ]
55
+ },
56
+ "trae": {
57
+ "stdout_form": "plain-text",
58
+ "project_dir_env": "PWD",
59
+ "magic_dir": ".trae",
60
+ "handlerTypes": [
61
+ "command"
62
+ ]
63
+ }
64
+ },
65
+ "event_outputs": {
66
+ "qoder": {
67
+ "SessionStart": "additionalContext",
68
+ "UserPromptSubmit": "additionalContext",
69
+ "PreToolUse": "permissionDecision",
70
+ "Stop": "additionalContext",
71
+ "PostToolUse": "feedback",
72
+ "SubagentStart": "additionalContext",
73
+ "SubagentStop": "additionalContext",
74
+ "PostToolUseFailure": "text",
75
+ "PermissionRequest": "text",
76
+ "SessionEnd": "text",
77
+ "PreCompact": "text",
78
+ "Notification": "text"
79
+ },
80
+ "claude": {
81
+ "SessionStart": "additionalContext",
82
+ "UserPromptSubmit": "additionalContext",
83
+ "PreToolUse": "permissionDecision",
84
+ "Stop": "text",
85
+ "PostToolUse": "feedback",
86
+ "SubagentStart": "text",
87
+ "SubagentStop": "text",
88
+ "PostToolUseFailure": "text",
89
+ "PermissionRequest": "text",
90
+ "SessionEnd": "text",
91
+ "PreCompact": "text",
92
+ "Notification": "text"
93
+ },
94
+ "codex": {
95
+ "Stop": "systemMessage",
96
+ "PostToolUse": "text"
97
+ },
98
+ "vscode": {
99
+ "PostToolUse": "text"
100
+ },
101
+ "trae": {
102
+ "PostToolUse": "text"
103
+ }
104
+ },
105
+ "core": {
106
+ "stdout_form": "json",
107
+ "magic_dir": ".add",
108
+ "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"
109
+ },
110
+ "adapter_defaults": {
111
+ "magic_dir_fallback": ".qoder",
112
+ "probe_magic_dirs": [
113
+ ".claude",
114
+ ".qoder",
115
+ ".vscode",
116
+ ".add",
117
+ ".trae",
118
+ ".codex"
119
+ ]
120
+ }
121
+ };
122
+
123
+ // node_modules/.pnpm/find-up@8.0.0/node_modules/find-up/index.js
124
+ import path2 from "node:path";
125
+
126
+ // node_modules/.pnpm/locate-path@8.0.0/node_modules/locate-path/index.js
127
+ import process2 from "node:process";
128
+ import path from "node:path";
129
+ import fs, { promises as fsPromises } from "node:fs";
130
+ import { fileURLToPath } from "node:url";
131
+ var typeMappings = {
132
+ directory: "isDirectory",
133
+ file: "isFile"
134
+ };
135
+ function checkType(type) {
136
+ if (type === "both" || Object.hasOwn(typeMappings, type)) {
137
+ return;
138
+ }
139
+ throw new Error(`Invalid type specified: ${type}`);
140
+ }
141
+ var matchType = (type, stat) => type === "both" ? stat.isFile() || stat.isDirectory() : stat[typeMappings[type]]();
142
+ var toPath = (urlOrPath) => urlOrPath instanceof URL ? fileURLToPath(urlOrPath) : urlOrPath;
143
+ function locatePathSync(paths, {
144
+ cwd = process2.cwd(),
145
+ type = "file",
146
+ allowSymlinks = true
147
+ } = {}) {
148
+ checkType(type);
149
+ cwd = toPath(cwd);
150
+ const statFunction = allowSymlinks ? fs.statSync : fs.lstatSync;
151
+ for (const path_ of paths) {
152
+ try {
153
+ const stat = statFunction(path.resolve(cwd, path_), {
154
+ throwIfNoEntry: false
155
+ });
156
+ if (!stat) {
157
+ continue;
158
+ }
159
+ if (matchType(type, stat)) {
160
+ return path_;
161
+ }
162
+ } catch {
163
+ }
164
+ }
165
+ }
166
+
167
+ // node_modules/.pnpm/unicorn-magic@0.3.0/node_modules/unicorn-magic/node.js
168
+ import { promisify } from "node:util";
169
+ import { execFile as execFileCallback, execFileSync as execFileSyncOriginal } from "node:child_process";
170
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
171
+ var execFileOriginal = promisify(execFileCallback);
172
+ function toPath2(urlOrPath) {
173
+ return urlOrPath instanceof URL ? fileURLToPath2(urlOrPath) : urlOrPath;
174
+ }
175
+ var TEN_MEGABYTES_IN_BYTES = 10 * 1024 * 1024;
176
+
177
+ // node_modules/.pnpm/find-up@8.0.0/node_modules/find-up/index.js
178
+ var findUpStop = /* @__PURE__ */ Symbol("findUpStop");
179
+ function findUpMultipleSync(name, options = {}) {
180
+ let directory = path2.resolve(toPath2(options.cwd) ?? "");
181
+ const { root } = path2.parse(directory);
182
+ const stopAt = path2.resolve(directory, toPath2(options.stopAt) ?? root);
183
+ const limit = options.limit ?? Number.POSITIVE_INFINITY;
184
+ const paths = [name].flat();
185
+ const runMatcher = (locateOptions) => {
186
+ if (typeof name !== "function") {
187
+ return locatePathSync(paths, locateOptions);
188
+ }
189
+ const foundPath = name(locateOptions.cwd);
190
+ if (typeof foundPath === "string") {
191
+ return locatePathSync([foundPath], locateOptions);
192
+ }
193
+ return foundPath;
194
+ };
195
+ const matches = [];
196
+ while (true) {
197
+ const foundPath = runMatcher({ ...options, cwd: directory });
198
+ if (foundPath === findUpStop) {
199
+ break;
200
+ }
201
+ if (foundPath) {
202
+ matches.push(path2.resolve(directory, foundPath));
203
+ }
204
+ if (directory === stopAt || matches.length >= limit) {
205
+ break;
206
+ }
207
+ directory = path2.dirname(directory);
208
+ }
209
+ return matches;
210
+ }
211
+ function findUpSync(name, options = {}) {
212
+ const matches = findUpMultipleSync(name, { ...options, limit: 1 });
213
+ return matches[0];
214
+ }
215
+
216
+ // templates/core/governance/common.ts
217
+ var EXIT_PASS = protocol.exit_codes.pass;
218
+ var EXIT_BLOCK = protocol.exit_codes.block;
219
+ var STATE_SEP = protocol.output.field_separator;
220
+ function tryResolveMagicDir() {
221
+ const injected = process.env.MAGIC_DIR;
222
+ if (injected) return injected;
223
+ const startDir = dirname(fileURLToPath3(import.meta.url));
224
+ const hit = findUpSync((dir) => basename(dir).startsWith(".") ? dir : void 0, {
225
+ cwd: startDir,
226
+ type: "directory"
227
+ });
228
+ return hit ? basename(hit) : "";
229
+ }
230
+ function queryPlanStatus() {
231
+ const magicDir = process.env.MAGIC_DIR;
232
+ if (!magicDir) {
233
+ return {
234
+ stdout: '{"availability":"STATUS_UNAVAILABLE","source":"database","reason":"magicDir \u672A\u6CE8\u5165\u4E14\u65E0\u6CD5\u4ECE\u7269\u7406\u4F4D\u7F6E\u63A8\u5BFC"}',
235
+ exitCode: 3
236
+ };
237
+ }
238
+ const bridge = join(
239
+ process.env.PROJECT_DIR || process.cwd(),
240
+ magicDir,
241
+ "scripts",
242
+ "plan-status-bridge.ts"
243
+ );
244
+ if (!existsSync(bridge)) {
245
+ return {
246
+ stdout: '{"availability":"STATUS_UNAVAILABLE","source":"database","reason":"plan-status bridge missing"}',
247
+ exitCode: 3
248
+ };
249
+ }
250
+ const r = spawnSync("node", ["--import", "tsx", bridge], {
251
+ encoding: "utf-8",
252
+ timeout: 1e4
253
+ });
254
+ return { stdout: r.stdout ?? "", exitCode: r.status ?? -1 };
255
+ }
256
+ function detectActiveAdd() {
257
+ const r = queryPlanStatus();
258
+ if (r.exitCode !== 0) {
259
+ let reason = "database status unavailable";
260
+ try {
261
+ const parsed = JSON.parse(r.stdout);
262
+ if (parsed.reason) reason = parsed.reason;
263
+ } catch {
264
+ }
265
+ return `__STATUS_UNAVAILABLE__::${reason}::database::none::none`;
266
+ }
267
+ let snapshot;
268
+ try {
269
+ snapshot = JSON.parse(r.stdout);
270
+ } catch {
271
+ return null;
272
+ }
273
+ if (!(snapshot.availability === "READY" && snapshot.isActive === true)) return null;
274
+ const done = snapshot.progress?.doneTasks ?? 0;
275
+ const total = snapshot.progress?.totalTasks ?? 0;
276
+ const approval = snapshot.approvalStatus ?? "none";
277
+ return `${snapshot.planName}::${done}/${total}::${approval}::none::none`;
278
+ }
279
+ function projectHash() {
280
+ try {
281
+ return createHash("md5").update(`${process.env.PROJECT_DIR || process.cwd()}
282
+ `).digest("hex").slice(0, 8);
283
+ } catch {
284
+ return "default";
285
+ }
286
+ }
287
+ var DEV_FLAG = `/tmp/add_dev_${projectHash()}`;
288
+
289
+ // templates/core/governance/pre-compact-guard.ts
290
+ import { writeFileSync as writeFileSync2, unlinkSync as unlinkSync2 } from "node:fs";
291
+ var PreCompactGuard = class {
292
+ /** 主入口:返回 exit code(0) */
293
+ run() {
294
+ const hash = projectHash();
295
+ const state = detectActiveAdd();
296
+ if (state !== null) {
297
+ const [plan, step, rounds, handoff, addRoute] = state.split("::");
298
+ try {
299
+ writeFileSync2(
300
+ `/tmp/add_recovery_${hash}`,
301
+ `plan=${plan}
302
+ step=${step}
303
+ rounds=${rounds}
304
+ handoff=${handoff}
305
+ add_route=${addRoute}
306
+ `
307
+ );
308
+ } catch {
309
+ }
310
+ process.stderr.write(`[ADD PreCompact] ADD \u72B6\u6001\u5DF2\u4FDD\u5B58: Plan=${plan}, Step=${step}
311
+ `);
312
+ }
313
+ try {
314
+ unlinkSync2(`/tmp/add_tpl_${hash}`);
315
+ } catch {
316
+ }
317
+ return 0;
318
+ }
319
+ };
320
+
321
+ // templates/adapters/codex/hooks/pre-compact.ts
322
+ var CodexPreCompactGuard = class extends PreCompactGuard {
323
+ // 当前无 override(状态保存/恢复清单/tpl 清理与 core 基线一致);命名子类承载端身份 + 未来演进位
324
+ };
325
+ process.env.PROJECT_DIR = process.env.PROJECT_DIR || process.cwd();
326
+ var inferred = tryResolveMagicDir();
327
+ if (inferred && !process.env.MAGIC_DIR) process.env.MAGIC_DIR = inferred;
328
+ process.exit(new CodexPreCompactGuard().run());