@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.
- package/README.md +113 -150
- package/README.zh-CN.md +113 -150
- package/SKILL.md +46 -0
- package/agents/openai.yaml +4 -0
- package/bin/context-guard-skill.js +234 -46
- package/bin/postinstall.js +1 -1
- package/hooks.json +29 -5
- package/package.json +12 -5
- package/prototype/workbench.html +4933 -0
- package/references/bug-record-template.md +37 -0
- package/references/context-template.md +19 -0
- package/scripts/context_guard.py +806 -0
- package/scripts/context_guard_hook.py +302 -0
- package/scripts/map_owns.py +769 -0
- package/skills/context-guard/README.md +0 -234
- package/skills/context-guard/README.zh-CN.md +0 -234
- package/skills/context-guard/SKILL.md +0 -558
- package/skills/context-guard/agents/openai.yaml +0 -4
- package/skills/context-guard/references/context-template.md +0 -290
- package/skills/context-guard/references/register-template.md +0 -85
- package/skills/context-guard/references/task-case-template.md +0 -63
- package/skills/context-guard/scripts/context_guard.py +0 -4886
- package/skills/context-guard/scripts/context_guard_hook.py +0 -522
- package/skills/context-guard/tests/BC-20260618-063.sh +0 -116
- package/skills/context-guard/tests/BC-20260618-065.sh +0 -66
- package/skills/context-guard/tests/BC-20260626-080.sh +0 -48
- package/skills/context-guard/tests/BC-20260626-081.sh +0 -40
- package/skills/context-guard/tests/BC-20260626-082.sh +0 -32
- package/skills/context-guard/tests/BC-20260626-083.sh +0 -66
- package/skills/context-guard/tests/BC-20260627-084.sh +0 -74
- package/skills/context-guard/tests/BC-20260630-086.sh +0 -50
- package/skills/context-guard/tests/BC-20260630-087.sh +0 -103
- package/skills/context-guard/tests/BC-20260630-088.sh +0 -32
- package/skills/context-guard/tests/BC-20260630-089.sh +0 -63
- package/skills/context-guard/tests/BC-20260701-090.sh +0 -83
- 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 =
|
|
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 [--
|
|
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 --
|
|
25
|
-
npx @michelj/context-guard
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
|
|
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
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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.
|
|
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
|
|
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
|
-
|
|
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
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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
|
-
|
|
290
|
+
return merged;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function writeConfigFile(target, value, label, dryRun) {
|
|
144
294
|
if (dryRun) {
|
|
145
|
-
console.log(`[context-guard-skill] would install
|
|
295
|
+
console.log(`[context-guard-skill] would install ${label} to ${target}`);
|
|
146
296
|
return;
|
|
147
297
|
}
|
|
148
|
-
fs.mkdirSync(path.dirname(
|
|
149
|
-
if (fs.existsSync(
|
|
150
|
-
const backupPath = `${
|
|
151
|
-
fs.copyFileSync(
|
|
152
|
-
console.log(`[context-guard-skill] backed up
|
|
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(
|
|
155
|
-
console.log(`[context-guard-skill] installed
|
|
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
|
-
|
|
161
|
-
if (options.
|
|
162
|
-
|
|
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
|
|
171
|
-
|
|
172
|
-
|
|
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);
|
package/bin/postinstall.js
CHANGED
|
@@ -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
|
|
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": "
|
|
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": "
|
|
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.
|
|
4
|
-
"description": "Install and run
|
|
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+
|
|
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
|
-
"
|
|
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": "
|
|
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"
|