@michelj/context-guard 0.4.3 → 0.4.4

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/README.md +103 -208
  2. package/README.zh-CN.md +103 -208
  3. package/SKILL.md +27 -678
  4. package/agents/openai.yaml +2 -2
  5. package/bin/context-guard-skill.js +159 -56
  6. package/bin/postinstall.js +1 -1
  7. package/hooks.json +11 -11
  8. package/package.json +9 -6
  9. package/prototype/workbench.html +4933 -0
  10. package/references/bug-record-template.md +37 -0
  11. package/references/context-template.md +14 -336
  12. package/scripts/context_guard.py +577 -7655
  13. package/scripts/context_guard_hook.py +179 -731
  14. package/scripts/map_owns.py +769 -0
  15. package/references/feature-chain-methodology.md +0 -228
  16. package/references/register-template.md +0 -85
  17. package/references/task-case-template.md +0 -63
  18. package/tests/BC-20260618-063.sh +0 -116
  19. package/tests/BC-20260618-065.sh +0 -66
  20. package/tests/BC-20260626-080.sh +0 -48
  21. package/tests/BC-20260626-081.sh +0 -40
  22. package/tests/BC-20260626-082.sh +0 -32
  23. package/tests/BC-20260626-083.sh +0 -66
  24. package/tests/BC-20260627-084.sh +0 -74
  25. package/tests/BC-20260630-086.sh +0 -50
  26. package/tests/BC-20260630-087.sh +0 -103
  27. package/tests/BC-20260630-088.sh +0 -32
  28. package/tests/BC-20260630-089.sh +0 -63
  29. package/tests/BC-20260701-090.sh +0 -84
  30. package/tests/BC-20260702-096.sh +0 -48
  31. package/tests/BC-20260706-098.sh +0 -66
  32. package/tests/BC-20260707-099.sh +0 -47
  33. package/tests/BC-20260707-100.sh +0 -46
  34. package/tests/BC-20260707-101.sh +0 -47
  35. package/tests/BC-20260707-102.sh +0 -68
  36. package/tests/BC-20260707-103.sh +0 -59
  37. package/tests/BC-20260707-104.sh +0 -103
  38. package/tests/BC-20260707-105.sh +0 -109
  39. package/tests/BC-20260707-106.sh +0 -80
  40. package/tests/BC-20260707-107.sh +0 -74
  41. package/tests/BC-20260707-108.sh +0 -48
  42. package/tests/BC-20260707-109.sh +0 -56
  43. package/tests/BC-20260707-110.sh +0 -71
  44. package/tests/BC-20260707-111.sh +0 -70
  45. package/tests/BC-20260707-112.sh +0 -45
  46. package/tests/BC-20260707-113.sh +0 -73
  47. package/tests/BC-20260707-115.sh +0 -77
  48. package/tests/BC-20260707-116.sh +0 -77
  49. package/tests/BC-20260707-118.sh +0 -115
  50. package/tests/BC-20260707-119.sh +0 -47
  51. package/tests/BC-20260707-120.sh +0 -60
  52. package/tests/BC-20260707-121.sh +0 -66
  53. package/tests/BC-20260707-122.sh +0 -48
  54. package/tests/BC-20260707-123.sh +0 -43
  55. package/tests/BC-20260707-124.sh +0 -56
  56. package/tests/BC-20260707-125.sh +0 -64
  57. package/tests/BC-20260707-126.sh +0 -80
  58. package/tests/BC-20260707-127.sh +0 -88
  59. package/tests/BC-20260707-129.sh +0 -59
  60. package/tests/BC-20260707-130.sh +0 -69
  61. package/tests/BC-20260707-131.sh +0 -140
  62. package/tests/BC-20260707-132.sh +0 -150
  63. package/tests/BC-20260707-133.sh +0 -70
  64. package/tests/BC-20260708-136.sh +0 -210
  65. package/tests/BC-20260708-137.sh +0 -106
  66. package/tests/BC-20260708-138.sh +0 -168
  67. package/tests/BC-20260708-139.sh +0 -79
  68. package/tests/BC-20260709-002.sh +0 -63
  69. package/tests/BC-20260709-003.sh +0 -239
  70. package/tests/BC-20260709-006.sh +0 -76
  71. package/tests/BC-20260709-008.sh +0 -168
  72. package/tests/BC-20260710-001.sh +0 -61
  73. package/tests/BC-20260710-002.sh +0 -111
  74. package/tests/npm-install-smoke.sh +0 -53
@@ -1,4 +1,4 @@
1
1
  interface:
2
2
  display_name: "Context Guard"
3
- short_description: "Keep context regressions from recurring"
4
- default_prompt: "Use $context-guard to show the current roadmap."
3
+ short_description: "Keep folder-scoped project memory"
4
+ default_prompt: "Use $context-guard. Four stores: sessions, bugs, tasks, map. Jump with FIND.md."
@@ -15,23 +15,24 @@ const skillInstallEntries = [
15
15
  "README.md",
16
16
  "README.zh-CN.md",
17
17
  "agents",
18
+ "prototype",
18
19
  "references",
19
- "scripts",
20
- "tests"
20
+ "scripts"
21
21
  ];
22
22
 
23
23
  function usage() {
24
24
  console.log(`Context Guard Skill
25
25
 
26
26
  Usage:
27
- context-guard install [--target <dir>] [--with-hooks] [--hooks-target <file>] [--config-target <file>]
27
+ context-guard install [--platform auto|all|codex|cursor|claude] [--no-hooks]
28
+ [--target <dir>] [--hooks-target <file>] [--config-target <file>]
28
29
  context-guard path
29
30
  context-guard <context_guard.py command> [args...]
30
31
 
31
32
  Examples:
32
33
  npx @michelj/context-guard install
33
- npx @michelj/context-guard install --with-hooks
34
- npx @michelj/context-guard show-roadmap --root /path/to/project
34
+ npx @michelj/context-guard install --platform all
35
+ npx @michelj/context-guard init --root /path/to/project
35
36
  `);
36
37
  }
37
38
 
@@ -47,34 +48,54 @@ function expandHome(inputPath) {
47
48
  return inputPath;
48
49
  }
49
50
 
50
- function defaultSkillTarget() {
51
- if (process.env.CONTEXT_GUARD_SKILL_TARGET) {
52
- return path.resolve(expandHome(process.env.CONTEXT_GUARD_SKILL_TARGET));
53
- }
54
- const codexHome = process.env.CODEX_HOME || path.join(os.homedir(), ".codex");
55
- return path.join(codexHome, "skills", "context-guard");
51
+ const PLATFORM_SPECS = {
52
+ codex: { env: "CODEX_HOME", folder: ".codex", hooksFile: "hooks.json", configFile: "config.toml" },
53
+ cursor: { env: "CURSOR_HOME", folder: ".cursor", hooksFile: "hooks.json" },
54
+ claude: { env: "CLAUDE_HOME", folder: ".claude", hooksFile: "settings.json" }
55
+ };
56
+
57
+ function platformHome(platform) {
58
+ const spec = PLATFORM_SPECS[platform];
59
+ return path.resolve(expandHome(process.env[spec.env] || path.join(os.homedir(), spec.folder)));
56
60
  }
57
61
 
58
- function defaultHooksTarget() {
59
- if (process.env.CONTEXT_GUARD_HOOKS_TARGET) {
60
- return path.resolve(expandHome(process.env.CONTEXT_GUARD_HOOKS_TARGET));
61
- }
62
- const codexHome = process.env.CODEX_HOME || path.join(os.homedir(), ".codex");
63
- return path.join(codexHome, "hooks.json");
62
+ function platformTargets(platform) {
63
+ const home = platformHome(platform);
64
+ return {
65
+ target: path.join(home, "skills", "context-guard"),
66
+ hooksTarget: path.join(home, PLATFORM_SPECS[platform].hooksFile),
67
+ configTarget: PLATFORM_SPECS[platform].configFile
68
+ ? path.join(home, PLATFORM_SPECS[platform].configFile)
69
+ : null
70
+ };
71
+ }
72
+
73
+ function selectedPlatforms(requested) {
74
+ if (requested === "all") return Object.keys(PLATFORM_SPECS);
75
+ if (requested !== "auto") return [requested];
76
+ const detected = Object.entries(PLATFORM_SPECS)
77
+ .filter(([, spec]) => Boolean(process.env[spec.env]) || fs.existsSync(platformHomeBySpec(spec)))
78
+ .map(([name]) => name);
79
+ return detected.length ? detected : ["codex"];
64
80
  }
65
81
 
66
- function defaultConfigTarget() {
67
- const codexHome = process.env.CODEX_HOME || path.join(os.homedir(), ".codex");
68
- return path.join(codexHome, "config.toml");
82
+ function platformHomeBySpec(spec) {
83
+ return path.resolve(expandHome(process.env[spec.env] || path.join(os.homedir(), spec.folder)));
69
84
  }
70
85
 
71
86
  function parseInstallArgs(args) {
72
87
  const options = {
73
- target: defaultSkillTarget(),
74
- withHooks: false,
75
- hooksTarget: defaultHooksTarget(),
76
- configTarget: defaultConfigTarget(),
77
- configTargetExplicit: false,
88
+ platform: "auto",
89
+ target: process.env.CONTEXT_GUARD_SKILL_TARGET
90
+ ? path.resolve(expandHome(process.env.CONTEXT_GUARD_SKILL_TARGET))
91
+ : null,
92
+ withHooks: true,
93
+ hooksTarget: process.env.CONTEXT_GUARD_HOOKS_TARGET
94
+ ? path.resolve(expandHome(process.env.CONTEXT_GUARD_HOOKS_TARGET))
95
+ : null,
96
+ configTarget: null,
97
+ targetExplicit: Boolean(process.env.CONTEXT_GUARD_SKILL_TARGET),
98
+ hooksTargetExplicit: Boolean(process.env.CONTEXT_GUARD_HOOKS_TARGET),
78
99
  dryRun: false
79
100
  };
80
101
 
@@ -84,20 +105,26 @@ function parseInstallArgs(args) {
84
105
  const value = args[++i];
85
106
  if (!value) fail("--target requires a directory");
86
107
  options.target = path.resolve(expandHome(value));
108
+ options.targetExplicit = true;
109
+ } else if (arg === "--platform") {
110
+ const value = String(args[++i] || "").toLowerCase();
111
+ if (!["auto", "all", ...Object.keys(PLATFORM_SPECS)].includes(value)) {
112
+ fail("--platform must be auto, all, codex, cursor, or claude");
113
+ }
114
+ options.platform = value;
87
115
  } else if (arg === "--with-hooks" || arg === "--hooks") {
88
116
  options.withHooks = true;
117
+ } else if (arg === "--no-hooks") {
118
+ options.withHooks = false;
89
119
  } else if (arg === "--hooks-target") {
90
120
  const value = args[++i];
91
121
  if (!value) fail("--hooks-target requires a file path");
92
122
  options.hooksTarget = path.resolve(expandHome(value));
93
- if (!options.configTargetExplicit) {
94
- options.configTarget = path.join(path.dirname(options.hooksTarget), "config.toml");
95
- }
123
+ options.hooksTargetExplicit = true;
96
124
  } else if (arg === "--config-target") {
97
125
  const value = args[++i];
98
126
  if (!value) fail("--config-target requires a file path");
99
127
  options.configTarget = path.resolve(expandHome(value));
100
- options.configTargetExplicit = true;
101
128
  } else if (arg === "--dry-run") {
102
129
  options.dryRun = true;
103
130
  } else if (arg === "-h" || arg === "--help") {
@@ -107,6 +134,16 @@ function parseInstallArgs(args) {
107
134
  fail(`unknown install option: ${arg}`);
108
135
  }
109
136
  }
137
+ if ((options.target || options.hooksTarget || options.configTarget) && options.platform === "all") {
138
+ fail("custom targets can only be used with one platform");
139
+ }
140
+ if (options.targetExplicit && !options.hooksTargetExplicit) {
141
+ const platform = options.platform === "auto" ? "codex" : options.platform;
142
+ options.hooksTarget = path.join(path.dirname(options.target), PLATFORM_SPECS[platform].hooksFile);
143
+ }
144
+ if (!options.configTarget && options.hooksTarget && (options.platform === "auto" || options.platform === "codex")) {
145
+ options.configTarget = path.join(path.dirname(options.hooksTarget), "config.toml");
146
+ }
110
147
  return options;
111
148
  }
112
149
 
@@ -184,15 +221,22 @@ function copySkill(target, dryRun) {
184
221
  console.log(`[context-guard-skill] installed skill: ${target}`);
185
222
  }
186
223
 
187
- function rewriteHookCommands(hooksConfig, skillTarget) {
224
+ function hookCommand(skillTarget, event, platform) {
188
225
  const hookScript = path.join(skillTarget, "scripts", "context_guard_hook.py");
189
226
  const encodedHookScript = JSON.stringify(hookScript);
227
+ const pythonCommand = process.platform === "win32" ? "python" : "python3";
228
+ return `${pythonCommand} ${encodedHookScript} ${event} --platform ${platform}`;
229
+ }
230
+
231
+ function rewriteGroupedHookCommands(hooksConfig, skillTarget, platform) {
190
232
  const next = JSON.parse(JSON.stringify(hooksConfig));
191
233
  for (const groups of Object.values(next.hooks || {})) {
192
234
  for (const group of groups || []) {
193
235
  for (const hook of group.hooks || []) {
194
236
  if (hook.type === "command" && typeof hook.command === "string" && hook.command.includes("context_guard_hook.py")) {
195
- hook.command = `python3 ${encodedHookScript} ${hook.command.split(" ").pop()}`;
237
+ const match = hook.command.match(/context_guard_hook\.py["']?\s+([a-z-]+)/);
238
+ const event = match ? match[1] : "session-start";
239
+ hook.command = hookCommand(skillTarget, event, platform);
196
240
  }
197
241
  }
198
242
  }
@@ -200,6 +244,25 @@ function rewriteHookCommands(hooksConfig, skillTarget) {
200
244
  return next;
201
245
  }
202
246
 
247
+ function cursorHooks(skillTarget) {
248
+ const events = {
249
+ sessionStart: "session-start",
250
+ subagentStart: "subagent-start",
251
+ beforeSubmitPrompt: "user-prompt-submit",
252
+ subagentStop: "subagent-stop",
253
+ stop: "stop"
254
+ };
255
+ const hooks = {};
256
+ for (const [cursorEvent, normalizedEvent] of Object.entries(events)) {
257
+ hooks[cursorEvent] = [{
258
+ type: "command",
259
+ command: hookCommand(skillTarget, normalizedEvent, "cursor"),
260
+ timeout: 10
261
+ }];
262
+ }
263
+ return { version: 1, hooks };
264
+ }
265
+
203
266
  function mergeHooks(existing, incoming) {
204
267
  const merged = existing && typeof existing === "object" ? existing : {};
205
268
  merged.hooks = merged.hooks && typeof merged.hooks === "object" ? merged.hooks : {};
@@ -214,37 +277,73 @@ function mergeHooks(existing, incoming) {
214
277
  return merged;
215
278
  }
216
279
 
217
- function installHooks(skillTarget, hooksTarget, dryRun) {
218
- if (!fs.existsSync(sourceHooksPath)) {
219
- fail(`source hooks file is missing: ${sourceHooksPath}`);
220
- }
221
- const rawIncoming = JSON.parse(fs.readFileSync(sourceHooksPath, "utf8"));
222
- const incoming = rewriteHookCommands(rawIncoming, skillTarget);
223
- let existing = {};
224
- if (fs.existsSync(hooksTarget)) {
225
- existing = JSON.parse(fs.readFileSync(hooksTarget, "utf8"));
280
+ function mergeCursorHooks(existing, incoming) {
281
+ const merged = existing && typeof existing === "object" ? existing : {};
282
+ merged.version = merged.version || 1;
283
+ merged.hooks = merged.hooks && typeof merged.hooks === "object" ? merged.hooks : {};
284
+ for (const [event, hooks] of Object.entries(incoming.hooks || {})) {
285
+ const current = Array.isArray(merged.hooks[event]) ? merged.hooks[event] : [];
286
+ merged.hooks[event] = current
287
+ .filter((hook) => !String(hook && hook.command || "").includes("context_guard_hook.py"))
288
+ .concat(hooks);
226
289
  }
227
- const merged = mergeHooks(existing, incoming);
290
+ return merged;
291
+ }
292
+
293
+ function writeConfigFile(target, value, label, dryRun) {
228
294
  if (dryRun) {
229
- console.log(`[context-guard-skill] would install hooks to ${hooksTarget}`);
295
+ console.log(`[context-guard-skill] would install ${label} to ${target}`);
230
296
  return;
231
297
  }
232
- fs.mkdirSync(path.dirname(hooksTarget), { recursive: true });
233
- if (fs.existsSync(hooksTarget)) {
234
- const backupPath = `${hooksTarget}.bak-${new Date().toISOString().replace(/[:.]/g, "-")}`;
235
- fs.copyFileSync(hooksTarget, backupPath);
236
- console.log(`[context-guard-skill] backed up hooks: ${backupPath}`);
298
+ fs.mkdirSync(path.dirname(target), { recursive: true });
299
+ if (fs.existsSync(target)) {
300
+ const backupPath = `${target}.bak-${new Date().toISOString().replace(/[:.]/g, "-")}`;
301
+ fs.copyFileSync(target, backupPath);
302
+ console.log(`[context-guard-skill] backed up ${label}: ${backupPath}`);
303
+ }
304
+ fs.writeFileSync(target, `${JSON.stringify(value, null, 2)}\n`);
305
+ console.log(`[context-guard-skill] installed ${label}: ${target}`);
306
+ }
307
+
308
+ function readObject(target) {
309
+ if (!fs.existsSync(target)) return {};
310
+ const value = JSON.parse(fs.readFileSync(target, "utf8"));
311
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
312
+ }
313
+
314
+ function installHooks(platform, skillTarget, hooksTarget, dryRun) {
315
+ if (!fs.existsSync(sourceHooksPath)) {
316
+ fail(`source hooks file is missing: ${sourceHooksPath}`);
317
+ }
318
+ const existing = readObject(hooksTarget);
319
+ if (platform === "cursor") {
320
+ writeConfigFile(hooksTarget, mergeCursorHooks(existing, cursorHooks(skillTarget)), "hooks", dryRun);
321
+ return;
237
322
  }
238
- fs.writeFileSync(hooksTarget, `${JSON.stringify(merged, null, 2)}\n`);
239
- console.log(`[context-guard-skill] installed hooks: ${hooksTarget}`);
323
+ const rawIncoming = JSON.parse(fs.readFileSync(sourceHooksPath, "utf8"));
324
+ const incoming = rewriteGroupedHookCommands(rawIncoming, skillTarget, platform);
325
+ const merged = mergeHooks(existing, incoming);
326
+ writeConfigFile(hooksTarget, merged, platform === "claude" ? "settings hooks" : "hooks", dryRun);
240
327
  }
241
328
 
242
329
  function install(args) {
243
330
  const options = parseInstallArgs(args);
244
- copySkill(options.target, options.dryRun);
245
- if (options.withHooks) {
246
- migrateHooksFeatureConfig(options.configTarget, options.dryRun);
247
- installHooks(options.target, options.hooksTarget, options.dryRun);
331
+ let platforms = selectedPlatforms(options.platform);
332
+ if ((options.target || options.hooksTarget || options.configTarget) && options.platform === "auto") {
333
+ platforms = ["codex"];
334
+ }
335
+ for (const platform of platforms) {
336
+ const defaults = platformTargets(platform);
337
+ const skillTarget = options.target || defaults.target;
338
+ const hooksTarget = options.hooksTarget || defaults.hooksTarget;
339
+ const configTarget = options.configTarget || defaults.configTarget;
340
+ copySkill(skillTarget, options.dryRun);
341
+ if (options.withHooks) {
342
+ if (platform === "codex" && configTarget) {
343
+ migrateHooksFeatureConfig(configTarget, options.dryRun);
344
+ }
345
+ installHooks(platform, skillTarget, hooksTarget, options.dryRun);
346
+ }
248
347
  }
249
348
  }
250
349
 
@@ -252,9 +351,13 @@ function runPython(args) {
252
351
  if (!fs.existsSync(pythonScript)) {
253
352
  fail(`context_guard.py is missing: ${pythonScript}`);
254
353
  }
255
- const result = spawnSync("python3", [pythonScript, ...args], { stdio: "inherit" });
256
- if (result.error) fail(result.error.message);
257
- process.exit(result.status === null ? 1 : result.status);
354
+ for (const command of ["python3", "python"]) {
355
+ const result = spawnSync(command, [pythonScript, ...args], { stdio: "inherit" });
356
+ if (result.error && result.error.code === "ENOENT") continue;
357
+ if (result.error) fail(result.error.message);
358
+ process.exit(result.status === null ? 1 : result.status);
359
+ }
360
+ fail("Python 3 is required; neither `python3` nor `python` was found.");
258
361
  }
259
362
 
260
363
  const [command, ...rest] = process.argv.slice(2);
@@ -13,7 +13,7 @@ if (skipInstall) {
13
13
  }
14
14
 
15
15
  if (!isGlobalInstall && !autoInstall) {
16
- console.log("[context-guard-skill] package installed. Run `npx @michelj/context-guard install` to install the Codex skill.");
16
+ console.log("[context-guard-skill] package installed. Run `npx @michelj/context-guard install` to install the skill and hooks for detected clients.");
17
17
  process.exit(0);
18
18
  }
19
19
 
package/hooks.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "hooks": [
7
7
  {
8
8
  "type": "command",
9
- "command": "python3 ./scripts/context_guard_hook.py session-start",
9
+ "command": "python3 ./scripts/context_guard_hook.py session-start --platform codex",
10
10
  "timeout": 10,
11
11
  "statusMessage": "Initializing context folder"
12
12
  }
@@ -18,9 +18,9 @@
18
18
  "hooks": [
19
19
  {
20
20
  "type": "command",
21
- "command": "python3 ./scripts/context_guard_hook.py subagent-start",
21
+ "command": "python3 ./scripts/context_guard_hook.py subagent-start --platform codex",
22
22
  "timeout": 10,
23
- "statusMessage": "Initializing subagent context"
23
+ "statusMessage": "Initializing folder context"
24
24
  }
25
25
  ]
26
26
  }
@@ -30,9 +30,9 @@
30
30
  "hooks": [
31
31
  {
32
32
  "type": "command",
33
- "command": "python3 ./scripts/context_guard_hook.py user-prompt-submit",
33
+ "command": "python3 ./scripts/context_guard_hook.py user-prompt-submit --platform codex",
34
34
  "timeout": 10,
35
- "statusMessage": "Checking context intake"
35
+ "statusMessage": "Recording durable user wording"
36
36
  }
37
37
  ]
38
38
  }
@@ -42,9 +42,9 @@
42
42
  "hooks": [
43
43
  {
44
44
  "type": "command",
45
- "command": "python3 ./scripts/context_guard_hook.py subagent-stop",
46
- "timeout": 900,
47
- "statusMessage": "Checking subagent context and Test Hub"
45
+ "command": "python3 ./scripts/context_guard_hook.py subagent-stop --platform codex",
46
+ "timeout": 10,
47
+ "statusMessage": "Reminder: write sessions/bugs/tasks if this turn mattered"
48
48
  }
49
49
  ]
50
50
  }
@@ -54,9 +54,9 @@
54
54
  "hooks": [
55
55
  {
56
56
  "type": "command",
57
- "command": "python3 ./scripts/context_guard_hook.py stop",
58
- "timeout": 900,
59
- "statusMessage": "Checking context checkpoint"
57
+ "command": "python3 ./scripts/context_guard_hook.py stop --platform codex",
58
+ "timeout": 10,
59
+ "statusMessage": "Reminder: write sessions/bugs/tasks if this turn mattered"
60
60
  }
61
61
  ]
62
62
  }
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@michelj/context-guard",
3
- "version": "0.4.3",
4
- "description": "Install and run the Context Guard Codex skill.",
3
+ "version": "0.4.4",
4
+ "description": "Install and run Context Guard for Codex, Cursor, and Claude.",
5
5
  "repository": {
6
6
  "type": "git",
7
- "url": "git+ssh://git@github.com/Michel-Johnson/Context-Guard-Skill.git"
7
+ "url": "git+https://github.com/Michel-Johnson/Context-Guard-Skill.git"
8
8
  },
9
9
  "publishConfig": {
10
10
  "access": "public",
@@ -21,13 +21,16 @@
21
21
  "hooks.json",
22
22
  "agents/",
23
23
  "bin/",
24
+ "prototype/",
24
25
  "references/",
25
- "scripts/",
26
- "tests/"
26
+ "scripts/context_guard.py",
27
+ "scripts/context_guard_hook.py",
28
+ "scripts/map_owns.py"
27
29
  ],
28
30
  "scripts": {
29
31
  "postinstall": "node bin/postinstall.js",
30
- "test": "bash tests/npm-install-smoke.sh && python3 -m py_compile scripts/context_guard.py scripts/context_guard_hook.py"
32
+ "test": "node tests/ci-smoke.mjs",
33
+ "test:cd": "node .github/scripts/rehearse-cd.mjs"
31
34
  },
32
35
  "engines": {
33
36
  "node": ">=18"