@usulpro/codex-bee 0.1.1
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 +535 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +5530 -0
- package/dist/cli.js.map +1 -0
- package/hooks/stop-hook.cjs +135 -0
- package/package.json +64 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require("node:fs");
|
|
4
|
+
const path = require("node:path");
|
|
5
|
+
|
|
6
|
+
let input = "";
|
|
7
|
+
|
|
8
|
+
process.stdin.setEncoding("utf8");
|
|
9
|
+
process.stdin.on("data", (chunk) => {
|
|
10
|
+
input += chunk;
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
function safeReadJson(value) {
|
|
14
|
+
try {
|
|
15
|
+
return JSON.parse(value);
|
|
16
|
+
} catch {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function readAncestorChain(startPid) {
|
|
22
|
+
const ancestors = [];
|
|
23
|
+
|
|
24
|
+
if (process.platform !== "linux") {
|
|
25
|
+
return ancestors;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let currentPid = startPid;
|
|
29
|
+
|
|
30
|
+
while (currentPid > 1) {
|
|
31
|
+
try {
|
|
32
|
+
const stat = fs.readFileSync(`/proc/${currentPid}/stat`, "utf8");
|
|
33
|
+
const command = fs.readFileSync(`/proc/${currentPid}/comm`, "utf8").trim();
|
|
34
|
+
const parentPid = Number.parseInt(stat.split(") ")[1].split(" ")[1], 10);
|
|
35
|
+
|
|
36
|
+
ancestors.push({
|
|
37
|
+
command,
|
|
38
|
+
parentPid,
|
|
39
|
+
pid: currentPid
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
if (!Number.isFinite(parentPid) || parentPid <= 1 || parentPid === currentPid) {
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
currentPid = parentPid;
|
|
47
|
+
} catch (error) {
|
|
48
|
+
ancestors.push({
|
|
49
|
+
error: error instanceof Error ? error.message : String(error),
|
|
50
|
+
pid: currentPid
|
|
51
|
+
});
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return ancestors;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function getTranscriptSummary(transcriptPath) {
|
|
60
|
+
if (!transcriptPath) {
|
|
61
|
+
return {
|
|
62
|
+
exists: false,
|
|
63
|
+
path: null
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
const stat = fs.statSync(transcriptPath);
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
exists: true,
|
|
72
|
+
mtimeMs: stat.mtimeMs,
|
|
73
|
+
path: transcriptPath,
|
|
74
|
+
size: stat.size
|
|
75
|
+
};
|
|
76
|
+
} catch (error) {
|
|
77
|
+
return {
|
|
78
|
+
error: error instanceof Error ? error.message : String(error),
|
|
79
|
+
exists: false,
|
|
80
|
+
path: transcriptPath
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function buildCapture(payload) {
|
|
86
|
+
const captureRoot = process.env.CODEX_BEE_CAPTURE_ROOT || process.cwd();
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
ancestors: readAncestorChain(process.ppid),
|
|
90
|
+
argv: process.argv,
|
|
91
|
+
capturedAt: new Date().toISOString(),
|
|
92
|
+
cwd: captureRoot,
|
|
93
|
+
env: process.env,
|
|
94
|
+
payload,
|
|
95
|
+
pid: process.pid,
|
|
96
|
+
ppid: process.ppid,
|
|
97
|
+
transcript: getTranscriptSummary(payload?.transcript_path ?? null)
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function writeCapture(capture) {
|
|
102
|
+
const captureRoot = process.env.CODEX_BEE_CAPTURE_ROOT || capture.cwd || process.cwd();
|
|
103
|
+
const tempDirectory = path.join(captureRoot, ".codex", "tmp");
|
|
104
|
+
const hookCapturesDirectory = path.join(tempDirectory, "hook-captures");
|
|
105
|
+
const capturesDirectory = path.join(tempDirectory, "stop-captures");
|
|
106
|
+
const eventName = capture.payload?.hook_event_name ?? "unknown";
|
|
107
|
+
const slug = [
|
|
108
|
+
eventName,
|
|
109
|
+
capture.payload?.turn_id ?? "no-turn",
|
|
110
|
+
capture.pid,
|
|
111
|
+
Date.now()
|
|
112
|
+
].join("-");
|
|
113
|
+
const hookCapturePath = path.join(hookCapturesDirectory, `${slug}.json`);
|
|
114
|
+
const capturePath = path.join(capturesDirectory, `${slug}.json`);
|
|
115
|
+
const latestHookPath = path.join(tempDirectory, "last-hook-capture.json");
|
|
116
|
+
const latestPath = path.join(tempDirectory, "last-stop-capture.json");
|
|
117
|
+
const serialized = JSON.stringify(capture, null, 2);
|
|
118
|
+
|
|
119
|
+
fs.mkdirSync(hookCapturesDirectory, { recursive: true });
|
|
120
|
+
fs.writeFileSync(hookCapturePath, serialized, "utf8");
|
|
121
|
+
fs.writeFileSync(latestHookPath, serialized, "utf8");
|
|
122
|
+
|
|
123
|
+
if (eventName === "Stop") {
|
|
124
|
+
fs.mkdirSync(capturesDirectory, { recursive: true });
|
|
125
|
+
fs.writeFileSync(capturePath, serialized, "utf8");
|
|
126
|
+
fs.writeFileSync(latestPath, serialized, "utf8");
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
process.stdin.on("end", () => {
|
|
131
|
+
const payload = safeReadJson(input);
|
|
132
|
+
const capture = buildCapture(payload);
|
|
133
|
+
|
|
134
|
+
writeCapture(capture);
|
|
135
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@usulpro/codex-bee",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Autonomous wrapper for Codex CLI with hook-driven continuation.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/usulpro/codex-bee.git"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/usulpro/codex-bee#readme",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/usulpro/codex-bee/issues"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"bin": {
|
|
15
|
+
"bee": "./dist/cli.js"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"hooks"
|
|
20
|
+
],
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=20"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"baseline:clear": "node scripts/clear-stop-captures.mjs",
|
|
26
|
+
"baseline:inspect": "node scripts/inspect-stop-capture.mjs",
|
|
27
|
+
"build": "tsup",
|
|
28
|
+
"dev": "tsup --watch",
|
|
29
|
+
"package:check": "node scripts/check-package.mjs",
|
|
30
|
+
"publish:local": "node scripts/publish-local.mjs",
|
|
31
|
+
"prepack": "pnpm build",
|
|
32
|
+
"sandbox:clean": "node scripts/clean-sandbox.mjs",
|
|
33
|
+
"sandbox:prepare": "node scripts/prepare-sandbox.mjs",
|
|
34
|
+
"test": "tsx --test tests/**/*.test.ts tests/**/*.test.tsx",
|
|
35
|
+
"typecheck": "tsc --noEmit",
|
|
36
|
+
"ui:demo": "tsx src/ui/dev-harness/main.tsx",
|
|
37
|
+
"ui:dev": "BEE_UI_ALLOW_QUIT=0 tsx watch src/ui/dev-harness/main.tsx",
|
|
38
|
+
"ui:test": "tsx --test tests/ui-*.test.ts tests/ui-*.test.tsx"
|
|
39
|
+
},
|
|
40
|
+
"keywords": [
|
|
41
|
+
"codex",
|
|
42
|
+
"cli",
|
|
43
|
+
"automation",
|
|
44
|
+
"hooks",
|
|
45
|
+
"pty"
|
|
46
|
+
],
|
|
47
|
+
"license": "UNLICENSED",
|
|
48
|
+
"packageManager": "pnpm@10.33.0",
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@types/node": "^24.5.2",
|
|
51
|
+
"@types/react": "19.2.14",
|
|
52
|
+
"ink-testing-library": "4.0.0",
|
|
53
|
+
"tsup": "^8.5.0",
|
|
54
|
+
"tsx": "^4.21.0",
|
|
55
|
+
"typescript": "^5.9.2"
|
|
56
|
+
},
|
|
57
|
+
"dependencies": {
|
|
58
|
+
"@inkjs/ui": "2.0.0",
|
|
59
|
+
"figlet": "^1.11.0",
|
|
60
|
+
"ink": "6.8.0",
|
|
61
|
+
"react": "19.2.4",
|
|
62
|
+
"string-width": "^8.2.0"
|
|
63
|
+
}
|
|
64
|
+
}
|