@agentrouter-top/relay-dsh-plugin-codex 0.2.2-agentrouter.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.
@@ -0,0 +1,16 @@
1
+ //#region typert.host.js
2
+ const TYPERT = {
3
+ package: "@agentrouter-top/relay-dsh-plugin-codex",
4
+ face: "host",
5
+ schemas: [],
6
+ invocations: [],
7
+ model: {
8
+ services: [],
9
+ events: [],
10
+ objects: []
11
+ }
12
+ };
13
+ //#endregion
14
+ export { TYPERT };
15
+
16
+ //# sourceMappingURL=typert.host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typert.host.js","names":[],"sources":["../typert.host.js"],"sourcesContent":["export const TYPERT = { package: \"@agentrouter-top/relay-dsh-plugin-codex\", face: \"host\", schemas: [], invocations: [], model: { services: [], events: [], objects: [] } };\n"],"mappings":";AAAA,MAAa,SAAS;CAAE,SAAS;CAA2C,MAAM;CAAQ,SAAS,CAAC;CAAG,aAAa,CAAC;CAAG,OAAO;EAAE,UAAU,CAAC;EAAG,QAAQ,CAAC;EAAG,SAAS,CAAC;CAAE;AAAE"}
package/package.json ADDED
@@ -0,0 +1,157 @@
1
+ {
2
+ "name": "@agentrouter-top/relay-dsh-plugin-codex",
3
+ "version": "0.2.2-agentrouter.1",
4
+ "description": "Codex conversation backend for DeepSeek Harness, powered by the Codex App Server with approvals and DSH tool support. AgentRouter fork: generic child-process launch configuration and pinned Codex runtime.",
5
+ "keywords": [
6
+ "dsh-plugin",
7
+ "deepseek-harness",
8
+ "dsh"
9
+ ],
10
+ "license": "MIT",
11
+ "type": "module",
12
+ "main": "lib/host-plugin.js",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/Maybank01/agentrouter-dsh-plugins.git",
16
+ "directory": "upstream/relay-codex"
17
+ },
18
+ "homepage": "https://github.com/Maybank01/agentrouter-dsh-plugins",
19
+ "bugs": {
20
+ "url": "https://github.com/Maybank01/agentrouter-dsh-plugins/issues"
21
+ },
22
+ "engines": {
23
+ "node": ">=22.13"
24
+ },
25
+ "publishConfig": {
26
+ "access": "public",
27
+ "tag": "next",
28
+ "registry": "https://registry.npmjs.org"
29
+ },
30
+ "scripts": {
31
+ "build": "tsdown --config tsdown.config.ts",
32
+ "postbuild": "node normalize-build.mjs",
33
+ "typecheck": "tsc -p tsconfig.json",
34
+ "test:unit": "node --test test/*.test.mjs",
35
+ "test:component": "vitest run test/*.spec.tsx",
36
+ "test": "npm run test:unit && npm run test:component",
37
+ "verify": "npm run typecheck && npm test && npm run build"
38
+ },
39
+ "exports": {
40
+ ".": "./lib/host-plugin.js",
41
+ "./client": "./lib/client.js",
42
+ "./typert": "./lib/typert.host.js",
43
+ "./package.json": "./package.json"
44
+ },
45
+ "files": [
46
+ "README.zh.md",
47
+ "docs/images",
48
+ "docs/reliability-spec.md",
49
+ "docs/reliability-acceptance.md",
50
+ "docs/spec/dsh-interaction-bridge.md",
51
+ "docs/spec/execution-presentation.md",
52
+ "scripts/repair-activity-history.mjs",
53
+ "codex-activity-wire.mjs",
54
+ "cordis.patch.yml",
55
+ "presets",
56
+ "lib/client.js",
57
+ "lib/client.js.map",
58
+ "lib/host-plugin.js",
59
+ "lib/host-plugin.js.map",
60
+ "lib/typert.host.js",
61
+ "lib/typert.host.js.map",
62
+ "docs/dsh-0.1.2-alpha.3.md",
63
+ "dsh-compat.mjs",
64
+ "dsh-client-compat.mjs",
65
+ "dsh-client-compat.d.mts",
66
+ "AGENTROUTER-FORK.md"
67
+ ],
68
+ "dsh": {
69
+ "client": {
70
+ "inject": [
71
+ "@deepseek-ai/dsh-client-connection",
72
+ "@deepseek-ai/dsh-client-locale",
73
+ "@deepseek-ai/dsh-client-ui-conversation",
74
+ "@deepseek-ai/dsh-client-ui-tool",
75
+ "@deepseek-ai/dsh-client-ui-primitives",
76
+ "@deepseek-ai/dsh-client-ui-settings",
77
+ "@deepseek-ai/dsh-client-ui-sidebar",
78
+ "@deepseek-ai/dsh-client-ui-slots",
79
+ "@deepseek-ai/dsh-client-ui-theme",
80
+ "relay-dsh-plugin-session-import",
81
+ "@deepseek-ai/dsh-client-ui-renderer",
82
+ "@deepseek-ai/dsh-client-ui-session",
83
+ "@deepseek-ai/dsh-api-session-controller",
84
+ "@deepseek-ai/dsh-api-workspace-controller",
85
+ "@deepseek-ai/dsh-client-ui-chat",
86
+ "@deepseek-ai/dsh-client-ui-model-selection"
87
+ ],
88
+ "platform": "web"
89
+ },
90
+ "bundle": {
91
+ "patch": "./cordis.patch.yml"
92
+ }
93
+ },
94
+ "peerDependencies": {
95
+ "@deepseek-ai/dsh-llm": ">=0.1.1-rc.2 <0.1.2-0 || >=0.1.2-alpha.2 <0.1.3-0",
96
+ "@deepseek-ai/dsh-session": ">=0.1.1-rc.2 <0.1.2-0 || >=0.1.2-alpha.2 <0.1.3-0",
97
+ "@deepseek-ai/dsh-typert-protocol": ">=0.1.1-rc.2 <0.1.2-0 || >=0.1.2-alpha.2 <0.1.3-0",
98
+ "react": "^18.2.0"
99
+ },
100
+ "peerDependenciesMeta": {
101
+ "@deepseek-ai/dsh-llm": {
102
+ "optional": true
103
+ },
104
+ "@deepseek-ai/dsh-session": {
105
+ "optional": true
106
+ },
107
+ "@deepseek-ai/dsh-typert-protocol": {
108
+ "optional": true
109
+ },
110
+ "react": {
111
+ "optional": true
112
+ }
113
+ },
114
+ "dependencies": {
115
+ "@openai/codex": "0.153.4",
116
+ "lucide-react": "^1.37.0",
117
+ "relay-dsh-plugin-session-import": "0.2.2"
118
+ },
119
+ "devDependencies": {
120
+ "@testing-library/dom": "^10.4.1",
121
+ "@testing-library/react": "^16.3.2",
122
+ "@types/react": "~18.3.1",
123
+ "@types/react-dom": "^18.3.7",
124
+ "jsdom": "^29.1.1",
125
+ "lightningcss": "1.32.0",
126
+ "react": "^18.2.0",
127
+ "react-dom": "^18.3.1",
128
+ "tsdown": "0.22.2",
129
+ "typescript": "6.0.3",
130
+ "vitest": "^4.1.8",
131
+ "@deepseek-ai/cordis": "4.0.2",
132
+ "@deepseek-ai/dsh-llm": "0.1.2-rc.1",
133
+ "@deepseek-ai/dsh-session": "0.1.2-rc.1",
134
+ "@deepseek-ai/dsh-typert-protocol": "0.1.2-rc.1",
135
+ "@deepseek-ai/dsh-client-connection": "0.1.2-rc.1",
136
+ "@deepseek-ai/dsh-client-locale": "0.1.2-rc.1",
137
+ "@deepseek-ai/dsh-client-ui-conversation": "0.1.2-rc.1",
138
+ "@deepseek-ai/dsh-client-ui-tool": "0.1.2-rc.1",
139
+ "@deepseek-ai/dsh-client-ui-primitives": "0.1.2-rc.1",
140
+ "@deepseek-ai/dsh-client-ui-settings": "0.1.2-rc.1",
141
+ "@deepseek-ai/dsh-client-ui-sidebar": "0.1.2-rc.1",
142
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.2-rc.1",
143
+ "@deepseek-ai/dsh-client-ui-theme": "0.1.2-rc.1",
144
+ "@deepseek-ai/dsh-client-ui-renderer": "0.1.2-rc.1",
145
+ "@deepseek-ai/dsh-client-ui-session": "0.1.2-rc.1",
146
+ "@deepseek-ai/dsh-api-session-controller": "0.1.2-rc.1",
147
+ "@deepseek-ai/dsh-api-workspace-controller": "0.1.2-rc.1",
148
+ "@deepseek-ai/dsh-client-ui-chat": "0.1.2-rc.1",
149
+ "@deepseek-ai/dsh-client-ui-model-selection": "0.1.2-rc.1"
150
+ },
151
+ "agentrouter": {
152
+ "upstream": "https://github.com/yangbobo2021/relay-dsh-plugin-codex.git",
153
+ "commit": "75918b3e06880df25375154321109f364124a544",
154
+ "launchConfigVersion": 1,
155
+ "codexRuntime": "0.153.4"
156
+ }
157
+ }
@@ -0,0 +1 @@
1
+ Managed by Relay's DSH integration.
@@ -0,0 +1,3 @@
1
+ # Codex owns the model context, tools, sandbox, and approvals. Relay's host
2
+ # adapter binds this otherwise-empty DSH presentation Session to App Server.
3
+ []
@@ -0,0 +1,3 @@
1
+ name: Codex
2
+ description: Run and resume a Codex thread in DSH. 在 DSH 中运行并继续 Codex thread。
3
+ order: 2
@@ -0,0 +1,123 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import { constants } from "node:fs";
3
+ import { copyFile, lstat, open, readFile, readdir, rename, rm } from "node:fs/promises";
4
+ import { dirname, join, resolve } from "node:path";
5
+ import { pathToFileURL } from "node:url";
6
+ import * as zlib from "node:zlib";
7
+ import { readActivityPayload } from "../codex-activity-wire.mjs";
8
+
9
+ const LEGACY_TYPE = "relay-codex/activity";
10
+ const hash = bytes => createHash("sha256").update(bytes).digest("hex");
11
+
12
+ function decodeFrames(bytes) {
13
+ const frames = [];
14
+ let offset = 0;
15
+ while (offset < bytes.length) {
16
+ const decoded = zlib.zstdDecompressSync(bytes.subarray(offset), { info: true });
17
+ const consumed = decoded.engine.bytesWritten;
18
+ if (consumed <= 0) throw new Error("Invalid zstd frame length");
19
+ frames.push(decoded.buffer);
20
+ offset += consumed;
21
+ }
22
+ return Buffer.concat(frames);
23
+ }
24
+
25
+ // Stop DSH before applying: the file hash check detects changes, not a live writer lock.
26
+ export async function repairActivityHistory(path, { write = false } = {}) {
27
+ const info = await lstat(path);
28
+ if (!info.isFile()) throw new Error("Expected a regular session log, not a symlink");
29
+ const compressed = path.endsWith(".jsonl.zstd");
30
+ if (!compressed && !path.endsWith(".jsonl")) throw new Error("Unsupported log suffix");
31
+ if (compressed && !zlib.zstdDecompressSync) throw new Error("Zstd repair requires Node with zstd support (22.15+)");
32
+ const original = await readFile(path);
33
+ const bytes = compressed ? decodeFrames(original) : original;
34
+ const plaintext = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
35
+ if (!plaintext.endsWith("\n")) throw new Error("Refusing a torn session log");
36
+ const lines = plaintext.slice(0, -1).split("\n");
37
+ const header = JSON.parse(lines[0]);
38
+ if (header.type !== "session" || header.version !== 0 || typeof header.id !== "string") {
39
+ throw new Error("Unsupported session header");
40
+ }
41
+ let changed = 0;
42
+ for (let i = 1; i < lines.length; i++) {
43
+ const event = JSON.parse(lines[i]);
44
+ if (event.type !== LEGACY_TYPE) continue;
45
+ if (!readActivityPayload(event.data) || !Number.isSafeInteger(event.seq) || event.seq < 0) {
46
+ throw new Error(`Refusing malformed legacy activity at record ${i}`);
47
+ }
48
+ if (event.ignorable === true) continue;
49
+ if (event.ignorable !== undefined) throw new Error(`Invalid ignorable marker at record ${i}`);
50
+ lines[i] = JSON.stringify({ ...event, ignorable: true });
51
+ changed++;
52
+ }
53
+ const result = { path, sessionId: header.id, changed, written: false, sha256: hash(original) };
54
+ if (!write || changed === 0) return result;
55
+ // DSH requires a standalone first zstd frame containing only the header.
56
+ const repaired = compressed
57
+ ? Buffer.concat([
58
+ zlib.zstdCompressSync(Buffer.from(`${lines[0]}\n`)),
59
+ zlib.zstdCompressSync(Buffer.from(`${lines.slice(1).join("\n")}\n`)),
60
+ ])
61
+ : Buffer.from(`${lines.join("\n")}\n`);
62
+ const backup = `${path}.before-codex-activity-${result.sha256}.bak`;
63
+ try { await copyFile(path, backup, constants.COPYFILE_EXCL) }
64
+ catch (error) { if (error.code !== "EEXIST") throw error }
65
+ if (hash(await readFile(backup)) !== result.sha256) throw new Error("Backup verification failed");
66
+ const temporary = `${path}.${randomUUID()}.tmp`;
67
+ try {
68
+ const handle = await open(temporary, "wx", info.mode & 0o777);
69
+ try { await handle.writeFile(repaired); await handle.sync() } finally { await handle.close() }
70
+ if (hash(await readFile(path)) !== result.sha256) throw new Error("Session changed during repair; refusing replacement");
71
+ await rename(temporary, path);
72
+ const directory = await open(dirname(path), "r");
73
+ try { await directory.sync() } finally { await directory.close() }
74
+ } finally {
75
+ await rm(temporary, { force: true });
76
+ }
77
+ return { ...result, written: true, backup };
78
+ }
79
+
80
+ export async function scanActivityHistories(root) {
81
+ const info = await lstat(root);
82
+ if (!info.isDirectory()) throw new Error("Expected a sessions directory, not a symlink");
83
+ const report = { scanned: 0, affected: [], errors: [] };
84
+ async function visit(directory) {
85
+ for (const entry of await readdir(directory, { withFileTypes: true })) {
86
+ const path = join(directory, entry.name);
87
+ if (entry.isDirectory()) await visit(path);
88
+ else if (entry.isFile() && ["session.jsonl", "session.jsonl.zstd"].includes(entry.name)) {
89
+ report.scanned++;
90
+ try {
91
+ const result = await repairActivityHistory(path);
92
+ if (result.changed > 0) report.affected.push(result);
93
+ } catch (error) {
94
+ report.errors.push({ path, error: error.message });
95
+ }
96
+ }
97
+ }
98
+ }
99
+ await visit(root);
100
+ return report;
101
+ }
102
+
103
+ if (process.argv[1] && import.meta.url === pathToFileURL(resolve(process.argv[1])).href) {
104
+ const args = process.argv.slice(2);
105
+ const write = args[0] === "--write";
106
+ const paths = write ? args.slice(1) : args;
107
+ if (!paths.length) throw new Error("Usage: repair-activity-history.mjs [--write] <session.jsonl[.zstd]> ... | [--write] --root <sessions-directory> (stop DSH before --write)");
108
+ if (paths[0] === "--root") {
109
+ if (paths.length !== 2) throw new Error("--root requires exactly one sessions directory");
110
+ const root = resolve(paths[1]);
111
+ const report = await scanActivityHistories(root);
112
+ console.log(JSON.stringify(report));
113
+ if (report.errors.length > 0) throw new Error("Session scan incomplete; no batch repairs applied");
114
+ if (write) {
115
+ for (const { path } of report.affected) console.log(JSON.stringify(await repairActivityHistory(path, { write: true })));
116
+ const remaining = await scanActivityHistories(root);
117
+ console.log(JSON.stringify({ verification: remaining }));
118
+ if (remaining.errors.length || remaining.affected.length) throw new Error("Session verification incomplete");
119
+ }
120
+ } else {
121
+ for (const path of paths) console.log(JSON.stringify(await repairActivityHistory(resolve(path), { write })));
122
+ }
123
+ }