@michelj/context-guard 0.4.2 → 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 (36) hide show
  1. package/README.md +113 -150
  2. package/README.zh-CN.md +113 -150
  3. package/SKILL.md +46 -0
  4. package/agents/openai.yaml +4 -0
  5. package/bin/context-guard-skill.js +234 -46
  6. package/bin/postinstall.js +1 -1
  7. package/hooks.json +29 -5
  8. package/package.json +12 -5
  9. package/prototype/workbench.html +4933 -0
  10. package/references/bug-record-template.md +37 -0
  11. package/references/context-template.md +19 -0
  12. package/scripts/context_guard.py +806 -0
  13. package/scripts/context_guard_hook.py +302 -0
  14. package/scripts/map_owns.py +769 -0
  15. package/skills/context-guard/README.md +0 -234
  16. package/skills/context-guard/README.zh-CN.md +0 -234
  17. package/skills/context-guard/SKILL.md +0 -558
  18. package/skills/context-guard/agents/openai.yaml +0 -4
  19. package/skills/context-guard/references/context-template.md +0 -290
  20. package/skills/context-guard/references/register-template.md +0 -85
  21. package/skills/context-guard/references/task-case-template.md +0 -63
  22. package/skills/context-guard/scripts/context_guard.py +0 -4886
  23. package/skills/context-guard/scripts/context_guard_hook.py +0 -522
  24. package/skills/context-guard/tests/BC-20260618-063.sh +0 -116
  25. package/skills/context-guard/tests/BC-20260618-065.sh +0 -66
  26. package/skills/context-guard/tests/BC-20260626-080.sh +0 -48
  27. package/skills/context-guard/tests/BC-20260626-081.sh +0 -40
  28. package/skills/context-guard/tests/BC-20260626-082.sh +0 -32
  29. package/skills/context-guard/tests/BC-20260626-083.sh +0 -66
  30. package/skills/context-guard/tests/BC-20260627-084.sh +0 -74
  31. package/skills/context-guard/tests/BC-20260630-086.sh +0 -50
  32. package/skills/context-guard/tests/BC-20260630-087.sh +0 -103
  33. package/skills/context-guard/tests/BC-20260630-088.sh +0 -32
  34. package/skills/context-guard/tests/BC-20260630-089.sh +0 -63
  35. package/skills/context-guard/tests/BC-20260701-090.sh +0 -83
  36. package/skills/context-guard/tests/BC-20260702-096.sh +0 -45
@@ -7,22 +7,32 @@ const path = require("path");
7
7
  const { spawnSync } = require("child_process");
8
8
 
9
9
  const packageRoot = path.resolve(__dirname, "..");
10
- const sourceSkillDir = path.join(packageRoot, "skills", "context-guard");
10
+ const sourceSkillDir = packageRoot;
11
11
  const sourceHooksPath = path.join(packageRoot, "hooks.json");
12
12
  const pythonScript = path.join(sourceSkillDir, "scripts", "context_guard.py");
13
+ const skillInstallEntries = [
14
+ "SKILL.md",
15
+ "README.md",
16
+ "README.zh-CN.md",
17
+ "agents",
18
+ "prototype",
19
+ "references",
20
+ "scripts"
21
+ ];
13
22
 
14
23
  function usage() {
15
24
  console.log(`Context Guard Skill
16
25
 
17
26
  Usage:
18
- context-guard install [--target <dir>] [--with-hooks] [--hooks-target <file>]
27
+ context-guard install [--platform auto|all|codex|cursor|claude] [--no-hooks]
28
+ [--target <dir>] [--hooks-target <file>] [--config-target <file>]
19
29
  context-guard path
20
30
  context-guard <context_guard.py command> [args...]
21
31
 
22
32
  Examples:
23
33
  npx @michelj/context-guard install
24
- npx @michelj/context-guard install --with-hooks
25
- 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
26
36
  `);
27
37
  }
28
38
 
@@ -38,27 +48,54 @@ function expandHome(inputPath) {
38
48
  return inputPath;
39
49
  }
40
50
 
41
- function defaultSkillTarget() {
42
- if (process.env.CONTEXT_GUARD_SKILL_TARGET) {
43
- return path.resolve(expandHome(process.env.CONTEXT_GUARD_SKILL_TARGET));
44
- }
45
- const codexHome = process.env.CODEX_HOME || path.join(os.homedir(), ".codex");
46
- 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)));
47
60
  }
48
61
 
49
- function defaultHooksTarget() {
50
- if (process.env.CONTEXT_GUARD_HOOKS_TARGET) {
51
- return path.resolve(expandHome(process.env.CONTEXT_GUARD_HOOKS_TARGET));
52
- }
53
- const codexHome = process.env.CODEX_HOME || path.join(os.homedir(), ".codex");
54
- 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"];
80
+ }
81
+
82
+ function platformHomeBySpec(spec) {
83
+ return path.resolve(expandHome(process.env[spec.env] || path.join(os.homedir(), spec.folder)));
55
84
  }
56
85
 
57
86
  function parseInstallArgs(args) {
58
87
  const options = {
59
- target: defaultSkillTarget(),
60
- withHooks: false,
61
- hooksTarget: defaultHooksTarget(),
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),
62
99
  dryRun: false
63
100
  };
64
101
 
@@ -68,12 +105,26 @@ function parseInstallArgs(args) {
68
105
  const value = args[++i];
69
106
  if (!value) fail("--target requires a directory");
70
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;
71
115
  } else if (arg === "--with-hooks" || arg === "--hooks") {
72
116
  options.withHooks = true;
117
+ } else if (arg === "--no-hooks") {
118
+ options.withHooks = false;
73
119
  } else if (arg === "--hooks-target") {
74
120
  const value = args[++i];
75
121
  if (!value) fail("--hooks-target requires a file path");
76
122
  options.hooksTarget = path.resolve(expandHome(value));
123
+ options.hooksTargetExplicit = true;
124
+ } else if (arg === "--config-target") {
125
+ const value = args[++i];
126
+ if (!value) fail("--config-target requires a file path");
127
+ options.configTarget = path.resolve(expandHome(value));
77
128
  } else if (arg === "--dry-run") {
78
129
  options.dryRun = true;
79
130
  } else if (arg === "-h" || arg === "--help") {
@@ -83,9 +134,73 @@ function parseInstallArgs(args) {
83
134
  fail(`unknown install option: ${arg}`);
84
135
  }
85
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
+ }
86
147
  return options;
87
148
  }
88
149
 
150
+ function migrateHooksFeatureConfig(configTarget, dryRun) {
151
+ const original = fs.existsSync(configTarget) ? fs.readFileSync(configTarget, "utf8") : "";
152
+ const lines = original ? original.replace(/\r\n/g, "\n").split("\n") : [];
153
+ const sectionStart = lines.findIndex((line) => /^\s*\[features\]\s*(?:#.*)?$/.test(line));
154
+ let nextLines = lines.slice();
155
+
156
+ if (sectionStart === -1) {
157
+ while (nextLines.length && nextLines[nextLines.length - 1] === "") nextLines.pop();
158
+ if (nextLines.length) nextLines.push("");
159
+ nextLines.push("[features]", "hooks = true", "");
160
+ } else {
161
+ let sectionEnd = nextLines.length;
162
+ for (let i = sectionStart + 1; i < nextLines.length; i += 1) {
163
+ if (/^\s*\[[^\]]+\]/.test(nextLines[i])) {
164
+ sectionEnd = i;
165
+ break;
166
+ }
167
+ }
168
+ const hooksIndex = nextLines.findIndex(
169
+ (line, index) => index > sectionStart && index < sectionEnd && /^\s*hooks\s*=/.test(line)
170
+ );
171
+ const legacyIndexes = [];
172
+ nextLines.forEach((line, index) => {
173
+ if (index > sectionStart && index < sectionEnd && /^\s*codex_hooks\s*=/.test(line)) legacyIndexes.push(index);
174
+ });
175
+
176
+ if (hooksIndex >= 0) {
177
+ nextLines[hooksIndex] = nextLines[hooksIndex].replace(/^\s*hooks\s*=.*$/, "hooks = true");
178
+ for (const index of legacyIndexes.reverse()) nextLines.splice(index, 1);
179
+ } else if (legacyIndexes.length) {
180
+ const first = legacyIndexes.shift();
181
+ nextLines[first] = nextLines[first].replace(/^\s*codex_hooks\s*=.*$/, "hooks = true");
182
+ for (const index of legacyIndexes.reverse()) nextLines.splice(index, 1);
183
+ } else {
184
+ nextLines.splice(sectionStart + 1, 0, "hooks = true");
185
+ }
186
+ }
187
+
188
+ const next = `${nextLines.join("\n").replace(/\n*$/, "")}\n`;
189
+ if (next === original.replace(/\r\n/g, "\n")) return;
190
+ if (dryRun) {
191
+ console.log(`[context-guard-skill] would enable hooks in ${configTarget}`);
192
+ return;
193
+ }
194
+ fs.mkdirSync(path.dirname(configTarget), { recursive: true });
195
+ if (fs.existsSync(configTarget)) {
196
+ const backupPath = `${configTarget}.bak-${new Date().toISOString().replace(/[:.]/g, "-")}`;
197
+ fs.copyFileSync(configTarget, backupPath);
198
+ console.log(`[context-guard-skill] backed up config: ${backupPath}`);
199
+ }
200
+ fs.writeFileSync(configTarget, next);
201
+ console.log(`[context-guard-skill] enabled hooks: ${configTarget}`);
202
+ }
203
+
89
204
  function copySkill(target, dryRun) {
90
205
  if (!fs.existsSync(path.join(sourceSkillDir, "SKILL.md"))) {
91
206
  fail(`source skill folder is missing: ${sourceSkillDir}`);
@@ -96,19 +211,32 @@ function copySkill(target, dryRun) {
96
211
  }
97
212
  fs.rmSync(target, { recursive: true, force: true });
98
213
  fs.mkdirSync(path.dirname(target), { recursive: true });
99
- fs.cpSync(sourceSkillDir, target, { recursive: true });
214
+ fs.mkdirSync(target, { recursive: true });
215
+ for (const entry of skillInstallEntries) {
216
+ const from = path.join(sourceSkillDir, entry);
217
+ if (!fs.existsSync(from)) continue;
218
+ const to = path.join(target, entry);
219
+ fs.cpSync(from, to, { recursive: true });
220
+ }
100
221
  console.log(`[context-guard-skill] installed skill: ${target}`);
101
222
  }
102
223
 
103
- function rewriteHookCommands(hooksConfig, skillTarget) {
224
+ function hookCommand(skillTarget, event, platform) {
104
225
  const hookScript = path.join(skillTarget, "scripts", "context_guard_hook.py");
105
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) {
106
232
  const next = JSON.parse(JSON.stringify(hooksConfig));
107
233
  for (const groups of Object.values(next.hooks || {})) {
108
234
  for (const group of groups || []) {
109
235
  for (const hook of group.hooks || []) {
110
236
  if (hook.type === "command" && typeof hook.command === "string" && hook.command.includes("context_guard_hook.py")) {
111
- 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);
112
240
  }
113
241
  }
114
242
  }
@@ -116,6 +244,25 @@ function rewriteHookCommands(hooksConfig, skillTarget) {
116
244
  return next;
117
245
  }
118
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
+
119
266
  function mergeHooks(existing, incoming) {
120
267
  const merged = existing && typeof existing === "object" ? existing : {};
121
268
  merged.hooks = merged.hooks && typeof merged.hooks === "object" ? merged.hooks : {};
@@ -130,36 +277,73 @@ function mergeHooks(existing, incoming) {
130
277
  return merged;
131
278
  }
132
279
 
133
- function installHooks(skillTarget, hooksTarget, dryRun) {
134
- if (!fs.existsSync(sourceHooksPath)) {
135
- fail(`source hooks file is missing: ${sourceHooksPath}`);
136
- }
137
- const rawIncoming = JSON.parse(fs.readFileSync(sourceHooksPath, "utf8"));
138
- const incoming = rewriteHookCommands(rawIncoming, skillTarget);
139
- let existing = {};
140
- if (fs.existsSync(hooksTarget)) {
141
- 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);
142
289
  }
143
- const merged = mergeHooks(existing, incoming);
290
+ return merged;
291
+ }
292
+
293
+ function writeConfigFile(target, value, label, dryRun) {
144
294
  if (dryRun) {
145
- console.log(`[context-guard-skill] would install hooks to ${hooksTarget}`);
295
+ console.log(`[context-guard-skill] would install ${label} to ${target}`);
146
296
  return;
147
297
  }
148
- fs.mkdirSync(path.dirname(hooksTarget), { recursive: true });
149
- if (fs.existsSync(hooksTarget)) {
150
- const backupPath = `${hooksTarget}.bak-${new Date().toISOString().replace(/[:.]/g, "-")}`;
151
- fs.copyFileSync(hooksTarget, backupPath);
152
- 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}`);
153
303
  }
154
- fs.writeFileSync(hooksTarget, `${JSON.stringify(merged, null, 2)}\n`);
155
- console.log(`[context-guard-skill] installed hooks: ${hooksTarget}`);
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;
322
+ }
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);
156
327
  }
157
328
 
158
329
  function install(args) {
159
330
  const options = parseInstallArgs(args);
160
- copySkill(options.target, options.dryRun);
161
- if (options.withHooks) {
162
- 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
+ }
163
347
  }
164
348
  }
165
349
 
@@ -167,9 +351,13 @@ function runPython(args) {
167
351
  if (!fs.existsSync(pythonScript)) {
168
352
  fail(`context_guard.py is missing: ${pythonScript}`);
169
353
  }
170
- const result = spawnSync("python3", [pythonScript, ...args], { stdio: "inherit" });
171
- if (result.error) fail(result.error.message);
172
- 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.");
173
361
  }
174
362
 
175
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,21 +6,45 @@
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
  }
13
13
  ]
14
14
  }
15
15
  ],
16
+ "SubagentStart": [
17
+ {
18
+ "hooks": [
19
+ {
20
+ "type": "command",
21
+ "command": "python3 ./scripts/context_guard_hook.py subagent-start --platform codex",
22
+ "timeout": 10,
23
+ "statusMessage": "Initializing folder context"
24
+ }
25
+ ]
26
+ }
27
+ ],
16
28
  "UserPromptSubmit": [
17
29
  {
18
30
  "hooks": [
19
31
  {
20
32
  "type": "command",
21
- "command": "python3 ./scripts/context_guard_hook.py user-prompt-submit",
33
+ "command": "python3 ./scripts/context_guard_hook.py user-prompt-submit --platform codex",
34
+ "timeout": 10,
35
+ "statusMessage": "Recording durable user wording"
36
+ }
37
+ ]
38
+ }
39
+ ],
40
+ "SubagentStop": [
41
+ {
42
+ "hooks": [
43
+ {
44
+ "type": "command",
45
+ "command": "python3 ./scripts/context_guard_hook.py subagent-stop --platform codex",
22
46
  "timeout": 10,
23
- "statusMessage": "Checking context intake"
47
+ "statusMessage": "Reminder: write sessions/bugs/tasks if this turn mattered"
24
48
  }
25
49
  ]
26
50
  }
@@ -30,9 +54,9 @@
30
54
  "hooks": [
31
55
  {
32
56
  "type": "command",
33
- "command": "python3 ./scripts/context_guard_hook.py stop",
57
+ "command": "python3 ./scripts/context_guard_hook.py stop --platform codex",
34
58
  "timeout": 10,
35
- "statusMessage": "Checking context checkpoint"
59
+ "statusMessage": "Reminder: write sessions/bugs/tasks if this turn mattered"
36
60
  }
37
61
  ]
38
62
  }
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@michelj/context-guard",
3
- "version": "0.4.2",
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",
@@ -17,13 +17,20 @@
17
17
  "files": [
18
18
  "README.md",
19
19
  "README.zh-CN.md",
20
+ "SKILL.md",
20
21
  "hooks.json",
22
+ "agents/",
21
23
  "bin/",
22
- "skills/context-guard/"
24
+ "prototype/",
25
+ "references/",
26
+ "scripts/context_guard.py",
27
+ "scripts/context_guard_hook.py",
28
+ "scripts/map_owns.py"
23
29
  ],
24
30
  "scripts": {
25
31
  "postinstall": "node bin/postinstall.js",
26
- "test": "bash tests/npm-install-smoke.sh && python3 -m py_compile skills/context-guard/scripts/context_guard.py skills/context-guard/scripts/context_guard_hook.py"
32
+ "test": "node tests/ci-smoke.mjs",
33
+ "test:cd": "node .github/scripts/rehearse-cd.mjs"
27
34
  },
28
35
  "engines": {
29
36
  "node": ">=18"