dores-codex 4.0.0
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/.codex/bin/dores-hook-dispatch +43 -0
- package/.codex/hooks.json +62 -0
- package/INSTALL.md +37 -0
- package/README.md +231 -0
- package/codex-plugin-setup +14 -0
- package/codex-plugin-uninstall +14 -0
- package/install.sh +5 -0
- package/lib/client-event.js +144 -0
- package/lib/dores-client.js +76 -0
- package/lib/hook-runner.js +101 -0
- package/lib/hook-shared.js +362 -0
- package/lib/post-tool-use-hook.js +27 -0
- package/lib/pre-tool-use-hook.js +23 -0
- package/lib/setup-hooks.js +193 -0
- package/lib/startup-hook.js +21 -0
- package/lib/stop-hook.js +38 -0
- package/lib/uninstall-hooks.js +88 -0
- package/lib/user-prompt-submit-hook.js +20 -0
- package/package.json +39 -0
- package/uninstall.sh +5 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
buildHookPayload,
|
|
5
|
+
dispatchHookEvent,
|
|
6
|
+
readHookInput
|
|
7
|
+
} from "./hook-shared.js";
|
|
8
|
+
|
|
9
|
+
const label = "startup-hook";
|
|
10
|
+
const hookData = await readHookInput(label);
|
|
11
|
+
const source = String(hookData?.source ?? "").trim().toLowerCase();
|
|
12
|
+
const payload = buildHookPayload(hookData, {
|
|
13
|
+
start_source: source || null,
|
|
14
|
+
status: source === "resume" ? "resumed" : "in_progress"
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
process.exit(
|
|
18
|
+
await dispatchHookEvent(label, hookData, {
|
|
19
|
+
extraPayload: payload
|
|
20
|
+
})
|
|
21
|
+
);
|
package/lib/stop-hook.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
buildHookPayload,
|
|
5
|
+
dispatchHookEvent,
|
|
6
|
+
readHookInput
|
|
7
|
+
} from "./hook-shared.js";
|
|
8
|
+
|
|
9
|
+
const label = "stop-hook";
|
|
10
|
+
const hookData = await readHookInput(label);
|
|
11
|
+
const reasonText = String(
|
|
12
|
+
hookData?.reason ?? hookData?.message ?? hookData?.status ?? ""
|
|
13
|
+
).trim();
|
|
14
|
+
const normalizedReason = reasonText.toLowerCase();
|
|
15
|
+
const lastAssistantMessage =
|
|
16
|
+
String(hookData?.last_assistant_message ?? "").trim() || null;
|
|
17
|
+
const looksInterrupted =
|
|
18
|
+
normalizedReason.includes("interrupted") ||
|
|
19
|
+
normalizedReason.includes("cancelled") ||
|
|
20
|
+
normalizedReason.includes("canceled") ||
|
|
21
|
+
normalizedReason.includes("aborted");
|
|
22
|
+
const payload = buildHookPayload(hookData, {
|
|
23
|
+
last_assistant_message: lastAssistantMessage,
|
|
24
|
+
reason: reasonText || null,
|
|
25
|
+
status: looksInterrupted
|
|
26
|
+
? "interrupted"
|
|
27
|
+
: lastAssistantMessage
|
|
28
|
+
? "completed"
|
|
29
|
+
: "stopped",
|
|
30
|
+
stop_hook_active:
|
|
31
|
+
typeof hookData?.stop_hook_active === "boolean" ? hookData.stop_hook_active : null
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
process.exit(
|
|
35
|
+
await dispatchHookEvent(label, hookData, {
|
|
36
|
+
extraPayload: payload
|
|
37
|
+
})
|
|
38
|
+
);
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
|
|
7
|
+
const MANAGED_STATUS_PREFIX = "dores-codex:";
|
|
8
|
+
const DEFAULT_CODEX_HOME = path.join(os.homedir(), ".codex");
|
|
9
|
+
|
|
10
|
+
function resolveCodexHome() {
|
|
11
|
+
const explicit = (process.env.CODEX_PLUGIN_CODEX_HOME ?? "").trim();
|
|
12
|
+
return path.resolve(explicit || DEFAULT_CODEX_HOME);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function resolveHooksFile(codexHome) {
|
|
16
|
+
return path.join(codexHome, "hooks.json");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function readJsonFile(filePath) {
|
|
20
|
+
if (!fs.existsSync(filePath)) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const text = fs.readFileSync(filePath, "utf8");
|
|
25
|
+
if (!text.trim()) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return JSON.parse(text);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function isManagedGroup(group) {
|
|
33
|
+
return Array.isArray(group?.hooks) && group.hooks.some((hook) => {
|
|
34
|
+
const statusMessage = typeof hook?.statusMessage === "string" ? hook.statusMessage : "";
|
|
35
|
+
return statusMessage.startsWith(MANAGED_STATUS_PREFIX);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function main() {
|
|
40
|
+
const codexHome = resolveCodexHome();
|
|
41
|
+
const hooksFile = resolveHooksFile(codexHome);
|
|
42
|
+
const hooksDoc = readJsonFile(hooksFile);
|
|
43
|
+
|
|
44
|
+
if (!hooksDoc || typeof hooksDoc !== "object" || Array.isArray(hooksDoc)) {
|
|
45
|
+
console.log(`[codex-plugin-uninstall] no managed hooks found at ${hooksFile}`);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!hooksDoc.hooks || typeof hooksDoc.hooks !== "object" || Array.isArray(hooksDoc.hooks)) {
|
|
50
|
+
console.log(`[codex-plugin-uninstall] no managed hooks found at ${hooksFile}`);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
let removedGroups = 0;
|
|
55
|
+
for (const [eventName, groups] of Object.entries(hooksDoc.hooks)) {
|
|
56
|
+
if (!Array.isArray(groups)) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const filteredGroups = groups.filter((group) => !isManagedGroup(group));
|
|
61
|
+
removedGroups += groups.length - filteredGroups.length;
|
|
62
|
+
|
|
63
|
+
if (filteredGroups.length > 0) {
|
|
64
|
+
hooksDoc.hooks[eventName] = filteredGroups;
|
|
65
|
+
} else {
|
|
66
|
+
delete hooksDoc.hooks[eventName];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (removedGroups === 0) {
|
|
71
|
+
console.log(`[codex-plugin-uninstall] no managed hooks found at ${hooksFile}`);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (Object.keys(hooksDoc.hooks).length === 0) {
|
|
76
|
+
fs.unlinkSync(hooksFile);
|
|
77
|
+
} else {
|
|
78
|
+
fs.writeFileSync(hooksFile, `${JSON.stringify(hooksDoc, null, 2)}\n`, "utf8");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
console.log(`[codex-plugin-uninstall] removed ${removedGroups} managed hook group(s).`);
|
|
82
|
+
console.log(`[codex-plugin-uninstall] hooks file: ${hooksFile}`);
|
|
83
|
+
console.log(
|
|
84
|
+
"[codex-plugin-uninstall] codex_hooks in config.toml was left unchanged."
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
main();
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
buildHookPayload,
|
|
5
|
+
dispatchHookEvent,
|
|
6
|
+
readHookInput
|
|
7
|
+
} from "./hook-shared.js";
|
|
8
|
+
|
|
9
|
+
const label = "user-prompt-submit-hook";
|
|
10
|
+
const hookData = await readHookInput(label);
|
|
11
|
+
const payload = buildHookPayload(hookData, {
|
|
12
|
+
input_text: String(hookData?.prompt ?? hookData?.input_text ?? "").trim() || null,
|
|
13
|
+
status: "in_progress"
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
process.exit(
|
|
17
|
+
await dispatchHookEvent(label, hookData, {
|
|
18
|
+
extraPayload: payload
|
|
19
|
+
})
|
|
20
|
+
);
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dores-codex",
|
|
3
|
+
"version": "4.0.0",
|
|
4
|
+
"description": "Forward official Codex hook events to a websocket endpoint.",
|
|
5
|
+
"license": "UNLICENSED",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"codex-plugin-setup": "./codex-plugin-setup",
|
|
9
|
+
"codex-plugin-uninstall": "./codex-plugin-uninstall"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
".codex",
|
|
13
|
+
"lib",
|
|
14
|
+
"install.sh",
|
|
15
|
+
"uninstall.sh",
|
|
16
|
+
"codex-plugin-setup",
|
|
17
|
+
"codex-plugin-uninstall",
|
|
18
|
+
"README.md",
|
|
19
|
+
"INSTALL.md"
|
|
20
|
+
],
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=18"
|
|
23
|
+
},
|
|
24
|
+
"os": [
|
|
25
|
+
"darwin",
|
|
26
|
+
"linux"
|
|
27
|
+
],
|
|
28
|
+
"keywords": [
|
|
29
|
+
"codex",
|
|
30
|
+
"openai",
|
|
31
|
+
"cli",
|
|
32
|
+
"hooks"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"check": "node --check ./lib/client-event.js && node --check ./lib/dores-client.js && node --check ./lib/hook-shared.js && node --check ./lib/hook-runner.js && node --check ./lib/setup-hooks.js && node --check ./lib/uninstall-hooks.js && node --check ./lib/startup-hook.js && node --check ./lib/user-prompt-submit-hook.js && node --check ./lib/pre-tool-use-hook.js && node --check ./lib/post-tool-use-hook.js && node --check ./lib/stop-hook.js && bash -n ./install.sh ./uninstall.sh ./codex-plugin-setup ./codex-plugin-uninstall ./.codex/bin/dores-hook-dispatch",
|
|
36
|
+
"pack": "npm pack",
|
|
37
|
+
"pack:dry-run": "env npm_config_cache=${TMPDIR:-/tmp}/dores-codex-npm-cache npm pack --dry-run"
|
|
38
|
+
}
|
|
39
|
+
}
|