@covro/covro 0.2.0-beta.1 → 0.2.1-dev.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 +21 -9
- package/README.zh-CN.md +21 -9
- package/dist/cli/background.js +103 -0
- package/dist/cli/background.js.map +7 -0
- package/dist/cli/daemon.js +6 -1
- package/dist/cli/daemon.js.map +2 -2
- package/dist/cli/doctor.js +92 -0
- package/dist/cli/doctor.js.map +7 -0
- package/dist/cli/launch-environment.js +85 -0
- package/dist/cli/launch-environment.js.map +7 -0
- package/dist/cli/launchd.js +172 -0
- package/dist/cli/launchd.js.map +7 -0
- package/dist/cli/main.js +7 -35
- package/dist/cli/main.js.map +2 -2
- package/dist/cli/service.js +23 -49
- package/dist/cli/service.js.map +2 -2
- package/dist/codex/adapter.js +68 -1
- package/dist/codex/adapter.js.map +2 -2
- package/dist/server/auth.js +1 -1
- package/dist/server/auth.js.map +2 -2
- package/dist/server/http.js +21 -0
- package/dist/server/http.js.map +2 -2
- package/dist/server/service.js +17 -2
- package/dist/server/service.js.map +2 -2
- package/dist/update-worker.cjs +419 -168
- package/dist/updates/worker.js +7 -61
- package/dist/updates/worker.js.map +2 -2
- package/dist/web/assets/index-BmbPtei8.css +1 -0
- package/dist/web/assets/index-ycdL3pt0.js +140 -0
- package/dist/web/index.html +2 -2
- package/package.json +6 -4
- package/dist/web/assets/index-Dr0Qkixk.css +0 -1
- package/dist/web/assets/index-z5RGzL8u.js +0 -138
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { dirname, join } from "node:path";
|
|
6
|
+
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
7
|
+
import { environmentBridge, launchRunner } from "./launch-environment.js";
|
|
8
|
+
import { readJson, saveJson } from "../updates/files.js";
|
|
9
|
+
const exec = promisify(execFile);
|
|
10
|
+
const launchctl = (args) => exec("/bin/launchctl", args, { timeout: 5e3, maxBuffer: 2 * 1024 * 1024 });
|
|
11
|
+
const xml = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """);
|
|
12
|
+
function failureDetail(error) {
|
|
13
|
+
const failure = error;
|
|
14
|
+
if (failure.killed) return "launchctl \u8BF7\u6C42\u8D85\u65F6";
|
|
15
|
+
return (failure.stderr?.trim() || (error instanceof Error ? error.message : "\u672A\u77E5\u9519\u8BEF")).slice(
|
|
16
|
+
0,
|
|
17
|
+
1024
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
function launchdPaths(location, label = `dev.covro.${location.key}.${createHash("sha256").update(location.home).digest("hex").slice(0, 12)}`) {
|
|
21
|
+
const domain = `gui/${process.getuid()}`;
|
|
22
|
+
return {
|
|
23
|
+
label,
|
|
24
|
+
domain,
|
|
25
|
+
target: `${domain}/${label}`,
|
|
26
|
+
temporary: join(location.state, "launchd.plist"),
|
|
27
|
+
login: join(homedir(), "Library/LaunchAgents", `${label}.plist`)
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
async function loaded(target) {
|
|
31
|
+
try {
|
|
32
|
+
await launchctl(["print", target]);
|
|
33
|
+
return true;
|
|
34
|
+
} catch (error) {
|
|
35
|
+
const stderr = error.stderr ?? "";
|
|
36
|
+
if (/Could not find (?:domain|service|specified service)/i.test(stderr)) return false;
|
|
37
|
+
throw new Error(
|
|
38
|
+
`\u65E0\u6CD5\u67E5\u8BE2 launchd ${target}\uFF1A${failureDetail(error)}\uFF1B\u8BF7\u68C0\u67E5\u5F53\u524D\u7528\u6237\u7684 launchd \u6743\u9650`,
|
|
39
|
+
{ cause: error }
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
async function guiSessionAvailable(location) {
|
|
44
|
+
return loaded(launchdPaths(location).domain);
|
|
45
|
+
}
|
|
46
|
+
async function loginRegistration(location) {
|
|
47
|
+
const installed = await readJson(
|
|
48
|
+
join(location.state, "service.json")
|
|
49
|
+
);
|
|
50
|
+
if (installed?.platform !== "darwin") return void 0;
|
|
51
|
+
if (installed.label !== launchdPaths(location).label && installed.label !== `dev.covro.${location.key}`)
|
|
52
|
+
throw new Error("\u767B\u5F55\u670D\u52A1\u8EAB\u4EFD\u4E0E\u5F53\u524D\u914D\u7F6E\u4E0D\u5339\u914D");
|
|
53
|
+
return installed;
|
|
54
|
+
}
|
|
55
|
+
async function loginServiceInstalled(location) {
|
|
56
|
+
return Boolean(await loginRegistration(location));
|
|
57
|
+
}
|
|
58
|
+
function launchdPlist(location, args, login) {
|
|
59
|
+
const { label } = launchdPaths(location, login ? `dev.covro.${location.key}` : void 0);
|
|
60
|
+
const environment = {
|
|
61
|
+
PATH: process.env.PATH ?? "/usr/bin:/bin",
|
|
62
|
+
COVRO_HOME: location.home,
|
|
63
|
+
...process.env.CODEX_HOME ? { CODEX_HOME: process.env.CODEX_HOME } : {}
|
|
64
|
+
};
|
|
65
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
66
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
67
|
+
<plist version="1.0"><dict>
|
|
68
|
+
<key>Label</key><string>${label}</string>
|
|
69
|
+
<key>ProgramArguments</key><array>${args.map((arg) => `<string>${xml(arg)}</string>`).join("")}</array>
|
|
70
|
+
<key>LimitLoadToSessionType</key><string>Aqua</string>
|
|
71
|
+
<key>RunAtLoad</key><true/>
|
|
72
|
+
${login ? "<key>KeepAlive</key><dict><key>SuccessfulExit</key><false/></dict><key>ThrottleInterval</key><integer>30</integer>" : ""}
|
|
73
|
+
<key>EnvironmentVariables</key><dict>${Object.entries(environment).map(([key, value]) => `<key>${key}</key><string>${xml(value)}</string>`).join("")}</dict>
|
|
74
|
+
<key>StandardOutPath</key><string>${xml(location.log)}</string>
|
|
75
|
+
<key>StandardErrorPath</key><string>${xml(location.log)}</string>
|
|
76
|
+
</dict></plist>
|
|
77
|
+
`;
|
|
78
|
+
}
|
|
79
|
+
async function unloadLaunchd(location) {
|
|
80
|
+
const { target, temporary } = launchdPaths(location);
|
|
81
|
+
const installed = await loginRegistration(location);
|
|
82
|
+
const targets = /* @__PURE__ */ new Set([
|
|
83
|
+
target,
|
|
84
|
+
...installed ? [launchdPaths(location, installed.label).target] : []
|
|
85
|
+
]);
|
|
86
|
+
for (const serviceTarget of targets) {
|
|
87
|
+
if (await loaded(serviceTarget)) {
|
|
88
|
+
try {
|
|
89
|
+
await launchctl(["bootout", serviceTarget]);
|
|
90
|
+
} catch (error) {
|
|
91
|
+
if (await loaded(serviceTarget)) throw error;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
await rm(temporary, { force: true });
|
|
96
|
+
}
|
|
97
|
+
async function configureLaunchdLogin(location, entry, install) {
|
|
98
|
+
const { label, login } = launchdPaths(location, `dev.covro.${location.key}`);
|
|
99
|
+
const previous = await loginRegistration(location);
|
|
100
|
+
if (install) {
|
|
101
|
+
if (!await guiSessionAvailable(location))
|
|
102
|
+
throw new Error("\u542F\u7528\u767B\u5F55\u81EA\u542F\u9700\u8981\u5F53\u524D\u7528\u6237\u5DF2\u767B\u5F55 macOS \u684C\u9762");
|
|
103
|
+
await mkdir(dirname(login), { recursive: true });
|
|
104
|
+
await writeFile(
|
|
105
|
+
login,
|
|
106
|
+
launchdPlist(location, [process.execPath, entry, "run", "--config", location.config], true),
|
|
107
|
+
{ mode: 384 }
|
|
108
|
+
);
|
|
109
|
+
await saveJson(join(location.state, "service.json"), { platform: "darwin", label });
|
|
110
|
+
if (previous && previous.label !== label)
|
|
111
|
+
await rm(launchdPaths(location, previous.label).login, { force: true });
|
|
112
|
+
} else {
|
|
113
|
+
if (previous) await rm(launchdPaths(location, previous.label).login, { force: true });
|
|
114
|
+
await rm(login, { force: true });
|
|
115
|
+
await rm(join(location.state, "service.json"), { force: true });
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async function startLaunchd(location, entry) {
|
|
119
|
+
const installed = await loginRegistration(location);
|
|
120
|
+
const { domain, target, temporary, login } = launchdPaths(location, installed?.label);
|
|
121
|
+
if (!await guiSessionAvailable(location)) {
|
|
122
|
+
if (installed) throw new Error("\u5F53\u524D\u6CA1\u6709 macOS \u684C\u9762\u767B\u5F55\u4F1A\u8BDD\uFF0C\u65E0\u6CD5\u542F\u52A8 GUI \u767B\u5F55\u670D\u52A1");
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
await unloadLaunchd(location);
|
|
126
|
+
if (installed) {
|
|
127
|
+
await launchctl(["enable", target]);
|
|
128
|
+
await launchctl(["bootstrap", domain, login]);
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
const bridge = await environmentBridge(location.home);
|
|
132
|
+
try {
|
|
133
|
+
const runner = join(location.state, "launch-runner.mjs");
|
|
134
|
+
await writeFile(runner, launchRunner, { mode: 384 });
|
|
135
|
+
await writeFile(
|
|
136
|
+
temporary,
|
|
137
|
+
launchdPlist(
|
|
138
|
+
location,
|
|
139
|
+
[process.execPath, runner, bridge.path, entry, location.config],
|
|
140
|
+
false
|
|
141
|
+
),
|
|
142
|
+
{ mode: 384 }
|
|
143
|
+
);
|
|
144
|
+
await launchctl(["enable", target]);
|
|
145
|
+
await launchctl(["bootstrap", domain, temporary]);
|
|
146
|
+
await bridge.wait();
|
|
147
|
+
return true;
|
|
148
|
+
} catch (error) {
|
|
149
|
+
let cleanup = "";
|
|
150
|
+
try {
|
|
151
|
+
await unloadLaunchd(location);
|
|
152
|
+
} catch (cleanupError) {
|
|
153
|
+
cleanup = `\uFF1B\u6E05\u7406\u4EFB\u52A1\u5931\u8D25\uFF1A${failureDetail(cleanupError)}`;
|
|
154
|
+
}
|
|
155
|
+
throw new Error(
|
|
156
|
+
`Covro GUI \u540E\u53F0\u542F\u52A8\u5931\u8D25\uFF1A${failureDetail(error)}${cleanup}\uFF1B\u8FDB\u7A0B\u65E5\u5FD7\u4F4D\u4E8E ${location.log}`,
|
|
157
|
+
{ cause: error }
|
|
158
|
+
);
|
|
159
|
+
} finally {
|
|
160
|
+
await bridge.close();
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
export {
|
|
164
|
+
configureLaunchdLogin,
|
|
165
|
+
guiSessionAvailable,
|
|
166
|
+
launchdPaths,
|
|
167
|
+
launchdPlist,
|
|
168
|
+
loginServiceInstalled,
|
|
169
|
+
startLaunchd,
|
|
170
|
+
unloadLaunchd
|
|
171
|
+
};
|
|
172
|
+
//# sourceMappingURL=launchd.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/cli/launchd.ts"],
|
|
4
|
+
"sourcesContent": ["import { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { createHash } from 'node:crypto';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\nimport { mkdir, rm, writeFile } from 'node:fs/promises';\nimport type { CovroPaths } from './paths.js';\nimport { environmentBridge, launchRunner } from './launch-environment.js';\nimport { readJson, saveJson } from '../updates/files.js';\n\nconst exec = promisify(execFile);\nconst launchctl = (args: string[]) =>\n exec('/bin/launchctl', args, { timeout: 5000, maxBuffer: 2 * 1024 * 1024 });\nconst xml = (value: string) =>\n value\n .replaceAll('&', '&')\n .replaceAll('<', '<')\n .replaceAll('>', '>')\n .replaceAll('\"', '"');\n\nfunction failureDetail(error: unknown) {\n const failure = error as { killed?: boolean; stderr?: string };\n if (failure.killed) return 'launchctl \u8BF7\u6C42\u8D85\u65F6';\n return (failure.stderr?.trim() || (error instanceof Error ? error.message : '\u672A\u77E5\u9519\u8BEF')).slice(\n 0,\n 1024,\n );\n}\n\nexport function launchdPaths(\n location: CovroPaths,\n label = `dev.covro.${location.key}.${createHash('sha256').update(location.home).digest('hex').slice(0, 12)}`,\n) {\n const domain = `gui/${process.getuid!()}`;\n return {\n label,\n domain,\n target: `${domain}/${label}`,\n temporary: join(location.state, 'launchd.plist'),\n login: join(homedir(), 'Library/LaunchAgents', `${label}.plist`),\n };\n}\n\nasync function loaded(target: string) {\n try {\n await launchctl(['print', target]);\n return true;\n } catch (error) {\n const stderr = (error as { stderr?: string }).stderr ?? '';\n if (/Could not find (?:domain|service|specified service)/i.test(stderr)) return false;\n throw new Error(\n `\u65E0\u6CD5\u67E5\u8BE2 launchd ${target}\uFF1A${failureDetail(error)}\uFF1B\u8BF7\u68C0\u67E5\u5F53\u524D\u7528\u6237\u7684 launchd \u6743\u9650`,\n { cause: error },\n );\n }\n}\n\nexport async function guiSessionAvailable(location: CovroPaths) {\n return loaded(launchdPaths(location).domain);\n}\n\nasync function loginRegistration(location: CovroPaths) {\n const installed = await readJson<{ platform: string; label: string }>(\n join(location.state, 'service.json'),\n );\n if (installed?.platform !== 'darwin') return undefined;\n // Older releases used a config-only label; keep those installed login services operable.\n if (\n installed.label !== launchdPaths(location).label &&\n installed.label !== `dev.covro.${location.key}`\n )\n throw new Error('\u767B\u5F55\u670D\u52A1\u8EAB\u4EFD\u4E0E\u5F53\u524D\u914D\u7F6E\u4E0D\u5339\u914D');\n return installed;\n}\n\nexport async function loginServiceInstalled(location: CovroPaths) {\n return Boolean(await loginRegistration(location));\n}\n\nexport function launchdPlist(location: CovroPaths, args: string[], login: boolean) {\n const { label } = launchdPaths(location, login ? `dev.covro.${location.key}` : undefined);\n const environment = {\n PATH: process.env.PATH ?? '/usr/bin:/bin',\n COVRO_HOME: location.home,\n ...(process.env.CODEX_HOME ? { CODEX_HOME: process.env.CODEX_HOME } : {}),\n };\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\"><dict>\n<key>Label</key><string>${label}</string>\n<key>ProgramArguments</key><array>${args.map((arg) => `<string>${xml(arg)}</string>`).join('')}</array>\n<key>LimitLoadToSessionType</key><string>Aqua</string>\n<key>RunAtLoad</key><true/>\n${login ? '<key>KeepAlive</key><dict><key>SuccessfulExit</key><false/></dict><key>ThrottleInterval</key><integer>30</integer>' : ''}\n<key>EnvironmentVariables</key><dict>${Object.entries(environment)\n .map(([key, value]) => `<key>${key}</key><string>${xml(value)}</string>`)\n .join('')}</dict>\n<key>StandardOutPath</key><string>${xml(location.log)}</string>\n<key>StandardErrorPath</key><string>${xml(location.log)}</string>\n</dict></plist>\n`;\n}\n\nexport async function unloadLaunchd(location: CovroPaths) {\n const { target, temporary } = launchdPaths(location);\n const installed = await loginRegistration(location);\n const targets = new Set([\n target,\n ...(installed ? [launchdPaths(location, installed.label).target] : []),\n ]);\n for (const serviceTarget of targets) {\n if (await loaded(serviceTarget)) {\n try {\n await launchctl(['bootout', serviceTarget]);\n } catch (error) {\n if (await loaded(serviceTarget)) throw error;\n }\n }\n }\n await rm(temporary, { force: true });\n}\n\nexport async function configureLaunchdLogin(location: CovroPaths, entry: string, install: boolean) {\n // Preserve the installed label so older CLIs can still uninstall it after a rollback.\n const { label, login } = launchdPaths(location, `dev.covro.${location.key}`);\n const previous = await loginRegistration(location);\n if (install) {\n if (!(await guiSessionAvailable(location)))\n throw new Error('\u542F\u7528\u767B\u5F55\u81EA\u542F\u9700\u8981\u5F53\u524D\u7528\u6237\u5DF2\u767B\u5F55 macOS \u684C\u9762');\n await mkdir(dirname(login), { recursive: true });\n await writeFile(\n login,\n launchdPlist(location, [process.execPath, entry, 'run', '--config', location.config], true),\n { mode: 0o600 },\n );\n await saveJson(join(location.state, 'service.json'), { platform: 'darwin', label });\n if (previous && previous.label !== label)\n await rm(launchdPaths(location, previous.label).login, { force: true });\n } else {\n if (previous) await rm(launchdPaths(location, previous.label).login, { force: true });\n await rm(login, { force: true });\n await rm(join(location.state, 'service.json'), { force: true });\n }\n}\n\n/** Caller holds the per-instance lifecycle lock and has verified the daemon is stopped. */\nexport async function startLaunchd(location: CovroPaths, entry: string) {\n const installed = await loginRegistration(location);\n const { domain, target, temporary, login } = launchdPaths(location, installed?.label);\n if (!(await guiSessionAvailable(location))) {\n if (installed) throw new Error('\u5F53\u524D\u6CA1\u6709 macOS \u684C\u9762\u767B\u5F55\u4F1A\u8BDD\uFF0C\u65E0\u6CD5\u542F\u52A8 GUI \u767B\u5F55\u670D\u52A1');\n return false;\n }\n await unloadLaunchd(location);\n if (installed) {\n await launchctl(['enable', target]);\n await launchctl(['bootstrap', domain, login]);\n return true;\n }\n const bridge = await environmentBridge(location.home);\n try {\n const runner = join(location.state, 'launch-runner.mjs');\n await writeFile(runner, launchRunner, { mode: 0o600 });\n await writeFile(\n temporary,\n launchdPlist(\n location,\n [process.execPath, runner, bridge.path, entry, location.config],\n false,\n ),\n { mode: 0o600 },\n );\n await launchctl(['enable', target]);\n await launchctl(['bootstrap', domain, temporary]);\n await bridge.wait();\n return true;\n } catch (error) {\n let cleanup = '';\n try {\n await unloadLaunchd(location);\n } catch (cleanupError) {\n cleanup = `\uFF1B\u6E05\u7406\u4EFB\u52A1\u5931\u8D25\uFF1A${failureDetail(cleanupError)}`;\n }\n throw new Error(\n `Covro GUI \u540E\u53F0\u542F\u52A8\u5931\u8D25\uFF1A${failureDetail(error)}${cleanup}\uFF1B\u8FDB\u7A0B\u65E5\u5FD7\u4F4D\u4E8E ${location.log}`,\n { cause: error },\n );\n } finally {\n await bridge.close();\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/cli/main.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { mkdir, open } from "node:fs/promises";
|
|
1
|
+
import { open } from "node:fs/promises";
|
|
3
2
|
import { join } from "node:path";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { control, isNotRunning } from "./control.js";
|
|
4
|
+
import { startBackground as startManagedBackground, stopBackground } from "./background.js";
|
|
6
5
|
import { randomUUID } from "node:crypto";
|
|
7
6
|
import { ensureConfig, packageInfo, packageRoot, paths } from "./paths.js";
|
|
8
7
|
import { runDaemon } from "./daemon.js";
|
|
@@ -47,34 +46,7 @@ async function startBackground(location) {
|
|
|
47
46
|
if (!isNotRunning(error)) throw error;
|
|
48
47
|
}
|
|
49
48
|
await ensureConfig(location);
|
|
50
|
-
|
|
51
|
-
const log = await open(location.log, "a", 384);
|
|
52
|
-
const child = spawn(
|
|
53
|
-
process.execPath,
|
|
54
|
-
[join(packageRoot, "bin/covro.mjs"), "run", "--config", location.config],
|
|
55
|
-
{
|
|
56
|
-
detached: true,
|
|
57
|
-
stdio: ["ignore", log.fd, log.fd],
|
|
58
|
-
windowsHide: true
|
|
59
|
-
}
|
|
60
|
-
);
|
|
61
|
-
let failure;
|
|
62
|
-
child.once("error", (error) => {
|
|
63
|
-
failure = error;
|
|
64
|
-
});
|
|
65
|
-
child.unref();
|
|
66
|
-
await log.close();
|
|
67
|
-
for (let i = 0; i < 240; i++) {
|
|
68
|
-
if (failure) throw failure;
|
|
69
|
-
try {
|
|
70
|
-
return await control(location, "status");
|
|
71
|
-
} catch (error) {
|
|
72
|
-
if (!isNotRunning(error)) throw error;
|
|
73
|
-
}
|
|
74
|
-
if (child.exitCode !== null) throw new Error(`Covro \u542F\u52A8\u5931\u8D25\uFF0C\u8BF7\u67E5\u770B ${location.log}`);
|
|
75
|
-
await setTimeout(250);
|
|
76
|
-
}
|
|
77
|
-
throw new Error(`Covro \u5C1A\u672A\u786E\u8BA4\u542F\u52A8\uFF0C\u8BF7\u8FD0\u884C covro status \u5E76\u67E5\u770B ${location.log}`);
|
|
49
|
+
return startManagedBackground(location, join(packageRoot, "bin/covro.mjs"));
|
|
78
50
|
}
|
|
79
51
|
async function main(args = process.argv.slice(2)) {
|
|
80
52
|
const { command, subcommand, channel, allowDowngrade, allowUnverifiedCodex, location } = parseArguments(args);
|
|
@@ -84,7 +56,7 @@ async function main(args = process.argv.slice(2)) {
|
|
|
84
56
|
}
|
|
85
57
|
if (command === "--help" || command === "help") {
|
|
86
58
|
console.log(
|
|
87
|
-
"Covro\n\ncovro [start|run|stop|status|logs] [--config FILE]\ncovro update [status|repair] [--channel stable|beta|dev] [--allow-downgrade] [--allow-unverified-codex]\ncovro service install|uninstall [--config FILE]\n\n\u9ED8\u8BA4\u540E\u53F0\u8FD0\u884C\uFF1Bservice install \u5355\u72EC\u542F\u7528\u767B\u5F55\u81EA\u542F\u3002"
|
|
59
|
+
"Covro\n\ncovro [start|run|stop|status|doctor|logs] [--config FILE]\ncovro update [status|repair] [--channel stable|beta|dev] [--allow-downgrade] [--allow-unverified-codex]\ncovro service install|uninstall [--config FILE]\n\n\u9ED8\u8BA4\u540E\u53F0\u8FD0\u884C\uFF1Bservice install \u5355\u72EC\u542F\u7528\u767B\u5F55\u81EA\u542F\u3002doctor \u4ECE\u8FD0\u884C\u5B9E\u4F8B\u68C0\u67E5\u4F1A\u8BDD\u548C GitHub \u51ED\u8BC1\uFF0C\u4E0D\u663E\u793A\u4EE4\u724C\u3002"
|
|
88
60
|
);
|
|
89
61
|
return;
|
|
90
62
|
}
|
|
@@ -119,10 +91,10 @@ async function main(args = process.argv.slice(2)) {
|
|
|
119
91
|
2
|
|
120
92
|
)
|
|
121
93
|
);
|
|
122
|
-
} else if (command === "status" || command === "stop") {
|
|
94
|
+
} else if (command === "status" || command === "stop" || command === "doctor") {
|
|
123
95
|
try {
|
|
124
96
|
if (command === "stop") {
|
|
125
|
-
await
|
|
97
|
+
await stopBackground(location);
|
|
126
98
|
console.log("Covro \u5DF2\u505C\u6B62");
|
|
127
99
|
} else console.log(JSON.stringify(await control(location, command), null, 2));
|
|
128
100
|
} catch (error) {
|
package/dist/cli/main.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/cli/main.ts"],
|
|
4
|
-
"sourcesContent": ["import type { UpdateStatus } from '../shared/updates.js';\nimport {
|
|
5
|
-
"mappings": "AACA,SAAS,
|
|
4
|
+
"sourcesContent": ["import type { UpdateStatus } from '../shared/updates.js';\nimport { open } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { control, isNotRunning } from './control.js';\nimport { startBackground as startManagedBackground, stopBackground } from './background.js';\nimport { randomUUID } from 'node:crypto';\nimport { ensureConfig, packageInfo, packageRoot, paths, type CovroPaths } from './paths.js';\nimport { runDaemon } from './daemon.js';\nimport { service } from './service.js';\nimport { UpdateManager } from '../updates/manager.js';\nimport { loadConfig } from '../server/config.js';\n\nexport function parseArguments(args: string[]) {\n const positional: string[] = [];\n let configPath: string | undefined;\n let channel: 'stable' | 'beta' | 'dev' | undefined;\n let allowDowngrade = false;\n let allowUnverifiedCodex = false;\n for (let i = 0; i < args.length; i++) {\n const arg = args[i]!;\n if (arg === '--config' && args[i + 1]) configPath = args[++i];\n else if (arg === '--channel' && ['stable', 'beta', 'dev'].includes(args[i + 1] ?? ''))\n channel = args[++i] as typeof channel;\n else if (arg === '--allow-downgrade') allowDowngrade = true;\n else if (arg === '--allow-unverified-codex') allowUnverifiedCodex = true;\n else if (arg.startsWith('-') && arg !== '--help' && arg !== '--version')\n throw new Error(`Unknown argument: ${arg}`);\n else positional.push(arg);\n }\n const [command = 'start', subcommand] = positional;\n if (positional.length > (['service', 'update'].includes(command) ? 2 : 1))\n throw new Error('Too many arguments');\n if ((channel || allowDowngrade || allowUnverifiedCodex) && command !== 'update')\n throw new Error('\u5347\u7EA7\u9009\u9879\u4EC5\u7528\u4E8E update');\n return {\n command,\n subcommand,\n channel,\n allowDowngrade,\n allowUnverifiedCodex,\n location: paths(configPath),\n };\n}\n\nexport async function startBackground(location: CovroPaths) {\n try {\n return await control(location, 'status');\n } catch (error) {\n if (!isNotRunning(error)) throw error;\n }\n await ensureConfig(location);\n return startManagedBackground(location, join(packageRoot, 'bin/covro.mjs'));\n}\n\nexport async function main(args = process.argv.slice(2)) {\n const { command, subcommand, channel, allowDowngrade, allowUnverifiedCodex, location } =\n parseArguments(args);\n if (command === '--version') {\n console.log(packageInfo.version);\n return;\n }\n if (command === '--help' || command === 'help') {\n console.log(\n 'Covro\\n\\ncovro [start|run|stop|status|doctor|logs] [--config FILE]\\ncovro update [status|repair] [--channel stable|beta|dev] [--allow-downgrade] [--allow-unverified-codex]\\ncovro service install|uninstall [--config FILE]\\n\\n\u9ED8\u8BA4\u540E\u53F0\u8FD0\u884C\uFF1Bservice install \u5355\u72EC\u542F\u7528\u767B\u5F55\u81EA\u542F\u3002doctor \u4ECE\u8FD0\u884C\u5B9E\u4F8B\u68C0\u67E5\u4F1A\u8BDD\u548C GitHub \u51ED\u8BC1\uFF0C\u4E0D\u663E\u793A\u4EE4\u724C\u3002',\n );\n return;\n }\n if (command === 'start') console.log(JSON.stringify(await startBackground(location), null, 2));\n else if (command === 'run') {\n await ensureConfig(location);\n await runDaemon(location.config);\n } else if (command === 'update') {\n if (subcommand === 'repair') {\n const config = await loadConfig({ configPath: location.config, development: false });\n const manager = new UpdateManager(location, config.dataDir);\n console.log(JSON.stringify(await manager.repair(), null, 2));\n return;\n }\n if (subcommand && subcommand !== 'status') throw new Error('\u672A\u77E5\u5347\u7EA7\u547D\u4EE4');\n await startBackground(location);\n let codexConfirmation;\n if (allowUnverifiedCodex && !subcommand) {\n const checked = await control<UpdateStatus>(location, 'update-check', { channel });\n const candidate = checked.available;\n if (candidate?.codex.status === 'unverified' && candidate.codex.version)\n codexConfirmation = { version: candidate.codex.version, target: candidate.version };\n }\n console.log(\n JSON.stringify(\n await control(\n location,\n subcommand === 'status' ? 'update-check' : 'update',\n subcommand === 'status'\n ? { channel }\n : { clientOperationId: randomUUID(), channel, allowDowngrade, codexConfirmation },\n ),\n null,\n 2,\n ),\n );\n } else if (command === 'status' || command === 'stop' || command === 'doctor') {\n try {\n if (command === 'stop') {\n await stopBackground(location);\n console.log('Covro \u5DF2\u505C\u6B62');\n } else console.log(JSON.stringify(await control(location, command), null, 2));\n } catch (error) {\n if (!isNotRunning(error)) throw error;\n console.log('Covro \u672A\u8FD0\u884C');\n }\n } else if (command === 'logs') {\n const handle = await open(location.log, 'r');\n try {\n const { size } = await handle.stat();\n const buffer = Buffer.alloc(Math.min(size, 64 * 1024));\n await handle.read(buffer, 0, buffer.length, Math.max(0, size - buffer.length));\n console.log(buffer.toString('utf8'));\n } finally {\n await handle.close();\n }\n } else if (command === 'service' && ['install', 'uninstall'].includes(subcommand ?? '')) {\n await service(location, subcommand === 'install');\n console.log(subcommand === 'install' ? '\u5DF2\u542F\u7528 Covro \u767B\u5F55\u81EA\u542F' : '\u5DF2\u53D6\u6D88 Covro \u767B\u5F55\u81EA\u542F');\n } else throw new Error('\u672A\u77E5\u547D\u4EE4\uFF0C\u8FD0\u884C covro --help \u67E5\u770B\u7528\u6CD5');\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/cli/service.js
CHANGED
|
@@ -5,9 +5,9 @@ import { join } from "node:path";
|
|
|
5
5
|
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
6
6
|
import { stopAndWait } from "./control.js";
|
|
7
7
|
import { saveJson } from "../updates/files.js";
|
|
8
|
-
import { packageRoot } from "./paths.js";
|
|
8
|
+
import { ensureConfig, packageRoot } from "./paths.js";
|
|
9
|
+
import { macOSLoginService } from "./background.js";
|
|
9
10
|
const exec = promisify(execFile);
|
|
10
|
-
const xml = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """);
|
|
11
11
|
const unit = (value) => `"${value.replaceAll("\\", "\\\\").replaceAll('"', '\\"').replaceAll("%", "%%")}"`;
|
|
12
12
|
async function service(location, install) {
|
|
13
13
|
if (!["darwin", "linux"].includes(process.platform))
|
|
@@ -16,49 +16,24 @@ async function service(location, install) {
|
|
|
16
16
|
);
|
|
17
17
|
const label = `dev.covro.${location.key}`;
|
|
18
18
|
const entry = join(packageRoot, "bin/covro.mjs");
|
|
19
|
+
if (process.platform === "darwin") {
|
|
20
|
+
if (install) await ensureConfig(location);
|
|
21
|
+
await macOSLoginService(location, entry, install);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
19
24
|
if (install) {
|
|
20
25
|
await stopAndWait(location);
|
|
21
26
|
await mkdir(location.state, { recursive: true, mode: 448 });
|
|
22
27
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const domain = `gui/${process.getuid()}`;
|
|
27
|
-
if (!install) {
|
|
28
|
-
await exec("launchctl", ["bootout", domain, filename]);
|
|
29
|
-
await rm(filename);
|
|
30
|
-
await rm(join(location.state, "service.json"), { force: true });
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
28
|
+
const directory = join(homedir(), ".config/systemd/user");
|
|
29
|
+
const filename = join(directory, `${label}.service`);
|
|
30
|
+
if (install) {
|
|
33
31
|
await mkdir(directory, { recursive: true });
|
|
34
|
-
|
|
32
|
+
if (/[\r\n]/.test([entry, location.config, location.home, process.env.PATH].join("")))
|
|
33
|
+
throw new Error("\u670D\u52A1\u8DEF\u5F84\u548C PATH \u4E0D\u80FD\u5305\u542B\u6362\u884C");
|
|
35
34
|
await writeFile(
|
|
36
35
|
filename,
|
|
37
|
-
|
|
38
|
-
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
39
|
-
<plist version="1.0"><dict>
|
|
40
|
-
<key>Label</key><string>${label}</string>
|
|
41
|
-
<key>ProgramArguments</key><array>${args.map((arg) => `<string>${xml(arg)}</string>`).join("")}</array>
|
|
42
|
-
<key>RunAtLoad</key><true/><key>KeepAlive</key><dict><key>SuccessfulExit</key><false/></dict><key>ThrottleInterval</key><integer>30</integer>
|
|
43
|
-
<key>EnvironmentVariables</key><dict><key>PATH</key><string>${xml(process.env.PATH ?? "/usr/bin:/bin")}</string><key>COVRO_HOME</key><string>${xml(location.home)}</string></dict>
|
|
44
|
-
<key>StandardOutPath</key><string>${xml(location.log)}</string><key>StandardErrorPath</key><string>${xml(location.log)}</string>
|
|
45
|
-
</dict></plist>
|
|
46
|
-
`,
|
|
47
|
-
{ mode: 384 }
|
|
48
|
-
);
|
|
49
|
-
await exec("launchctl", ["enable", `${domain}/${label}`]);
|
|
50
|
-
await exec("launchctl", ["bootstrap", domain, filename]);
|
|
51
|
-
await saveJson(join(location.state, "service.json"), { platform: "darwin", label });
|
|
52
|
-
} else {
|
|
53
|
-
const directory = join(homedir(), ".config/systemd/user");
|
|
54
|
-
const filename = join(directory, `${label}.service`);
|
|
55
|
-
if (install) {
|
|
56
|
-
await mkdir(directory, { recursive: true });
|
|
57
|
-
if (/[\r\n]/.test([entry, location.config, location.home, process.env.PATH].join("")))
|
|
58
|
-
throw new Error("\u670D\u52A1\u8DEF\u5F84\u548C PATH \u4E0D\u80FD\u5305\u542B\u6362\u884C");
|
|
59
|
-
await writeFile(
|
|
60
|
-
filename,
|
|
61
|
-
`[Unit]
|
|
36
|
+
`[Unit]
|
|
62
37
|
Description=Covro
|
|
63
38
|
[Service]
|
|
64
39
|
ExecStart=${[process.execPath, entry, "run", "--config", location.config].map(unit).join(" ")}
|
|
@@ -68,17 +43,16 @@ RestartSec=30
|
|
|
68
43
|
[Install]
|
|
69
44
|
WantedBy=default.target
|
|
70
45
|
`,
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
46
|
+
{ mode: 384 }
|
|
47
|
+
);
|
|
48
|
+
await exec("systemctl", ["--user", "daemon-reload"]);
|
|
49
|
+
await exec("systemctl", ["--user", "enable", "--now", `${label}.service`]);
|
|
50
|
+
await saveJson(join(location.state, "service.json"), { platform: "linux", label });
|
|
51
|
+
} else {
|
|
52
|
+
await exec("systemctl", ["--user", "disable", "--now", `${label}.service`]);
|
|
53
|
+
await rm(filename);
|
|
54
|
+
await rm(join(location.state, "service.json"), { force: true });
|
|
55
|
+
await exec("systemctl", ["--user", "daemon-reload"]);
|
|
82
56
|
}
|
|
83
57
|
}
|
|
84
58
|
export {
|
package/dist/cli/service.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/cli/service.ts"],
|
|
4
|
-
"sourcesContent": ["import { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { mkdir, rm, writeFile } from 'node:fs/promises';\nimport { stopAndWait } from './control.js';\nimport { saveJson } from '../updates/files.js';\nimport { packageRoot, type CovroPaths } from './paths.js';\n\nconst exec = promisify(execFile);\nconst
|
|
5
|
-
"mappings": "AAAA,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAC1B,SAAS,eAAe;AACxB,SAAS,YAAY;AACrB,SAAS,OAAO,IAAI,iBAAiB;AACrC,SAAS,mBAAmB;AAC5B,SAAS,gBAAgB;AACzB,SAAS,mBAAoC;
|
|
4
|
+
"sourcesContent": ["import { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { mkdir, rm, writeFile } from 'node:fs/promises';\nimport { stopAndWait } from './control.js';\nimport { saveJson } from '../updates/files.js';\nimport { ensureConfig, packageRoot, type CovroPaths } from './paths.js';\nimport { macOSLoginService } from './background.js';\n\nconst exec = promisify(execFile);\nconst unit = (value: string) =>\n `\"${value.replaceAll('\\\\', '\\\\\\\\').replaceAll('\"', '\\\\\"').replaceAll('%', '%%')}\"`;\n\nexport async function service(location: CovroPaths, install: boolean) {\n if (!['darwin', 'linux'].includes(process.platform))\n throw new Error(\n '\u767B\u5F55\u81EA\u542F\u76EE\u524D\u652F\u6301 macOS launchd \u548C Linux systemd --user\uFF1B\u53EF\u4F7F\u7528 covro start \u540E\u53F0\u8FD0\u884C\u3002',\n );\n const label = `dev.covro.${location.key}`;\n const entry = join(packageRoot, 'bin/covro.mjs');\n if (process.platform === 'darwin') {\n if (install) await ensureConfig(location);\n await macOSLoginService(location, entry, install);\n return;\n }\n if (install) {\n await stopAndWait(location);\n await mkdir(location.state, { recursive: true, mode: 0o700 });\n }\n const directory = join(homedir(), '.config/systemd/user');\n const filename = join(directory, `${label}.service`);\n if (install) {\n await mkdir(directory, { recursive: true });\n if (/[\\r\\n]/.test([entry, location.config, location.home, process.env.PATH].join('')))\n throw new Error('\u670D\u52A1\u8DEF\u5F84\u548C PATH \u4E0D\u80FD\u5305\u542B\u6362\u884C');\n await writeFile(\n filename,\n `[Unit]\\nDescription=Covro\\n[Service]\\nExecStart=${[process.execPath, entry, 'run', '--config', location.config].map(unit).join(' ')}\\nEnvironment=${unit(`COVRO_HOME=${location.home}`)} ${unit(`PATH=${process.env.PATH ?? '/usr/bin:/bin'}`)}\\nRestart=on-failure\\nRestartSec=30\\n[Install]\\nWantedBy=default.target\\n`,\n { mode: 0o600 },\n );\n await exec('systemctl', ['--user', 'daemon-reload']);\n await exec('systemctl', ['--user', 'enable', '--now', `${label}.service`]);\n await saveJson(join(location.state, 'service.json'), { platform: 'linux', label });\n } else {\n await exec('systemctl', ['--user', 'disable', '--now', `${label}.service`]);\n await rm(filename);\n await rm(join(location.state, 'service.json'), { force: true });\n await exec('systemctl', ['--user', 'daemon-reload']);\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAC1B,SAAS,eAAe;AACxB,SAAS,YAAY;AACrB,SAAS,OAAO,IAAI,iBAAiB;AACrC,SAAS,mBAAmB;AAC5B,SAAS,gBAAgB;AACzB,SAAS,cAAc,mBAAoC;AAC3D,SAAS,yBAAyB;AAElC,MAAM,OAAO,UAAU,QAAQ;AAC/B,MAAM,OAAO,CAAC,UACZ,IAAI,MAAM,WAAW,MAAM,MAAM,EAAE,WAAW,KAAK,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;AAEjF,eAAsB,QAAQ,UAAsB,SAAkB;AACpE,MAAI,CAAC,CAAC,UAAU,OAAO,EAAE,SAAS,QAAQ,QAAQ;AAChD,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AACF,QAAM,QAAQ,aAAa,SAAS,GAAG;AACvC,QAAM,QAAQ,KAAK,aAAa,eAAe;AAC/C,MAAI,QAAQ,aAAa,UAAU;AACjC,QAAI,QAAS,OAAM,aAAa,QAAQ;AACxC,UAAM,kBAAkB,UAAU,OAAO,OAAO;AAChD;AAAA,EACF;AACA,MAAI,SAAS;AACX,UAAM,YAAY,QAAQ;AAC1B,UAAM,MAAM,SAAS,OAAO,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AAAA,EAC9D;AACA,QAAM,YAAY,KAAK,QAAQ,GAAG,sBAAsB;AACxD,QAAM,WAAW,KAAK,WAAW,GAAG,KAAK,UAAU;AACnD,MAAI,SAAS;AACX,UAAM,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAC1C,QAAI,SAAS,KAAK,CAAC,OAAO,SAAS,QAAQ,SAAS,MAAM,QAAQ,IAAI,IAAI,EAAE,KAAK,EAAE,CAAC;AAClF,YAAM,IAAI,MAAM,0EAAmB;AACrC,UAAM;AAAA,MACJ;AAAA,MACA;AAAA;AAAA;AAAA,YAAmD,CAAC,QAAQ,UAAU,OAAO,OAAO,YAAY,SAAS,MAAM,EAAE,IAAI,IAAI,EAAE,KAAK,GAAG,CAAC;AAAA,cAAiB,KAAK,cAAc,SAAS,IAAI,EAAE,CAAC,IAAI,KAAK,QAAQ,QAAQ,IAAI,QAAQ,eAAe,EAAE,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAC/O,EAAE,MAAM,IAAM;AAAA,IAChB;AACA,UAAM,KAAK,aAAa,CAAC,UAAU,eAAe,CAAC;AACnD,UAAM,KAAK,aAAa,CAAC,UAAU,UAAU,SAAS,GAAG,KAAK,UAAU,CAAC;AACzE,UAAM,SAAS,KAAK,SAAS,OAAO,cAAc,GAAG,EAAE,UAAU,SAAS,MAAM,CAAC;AAAA,EACnF,OAAO;AACL,UAAM,KAAK,aAAa,CAAC,UAAU,WAAW,SAAS,GAAG,KAAK,UAAU,CAAC;AAC1E,UAAM,GAAG,QAAQ;AACjB,UAAM,GAAG,KAAK,SAAS,OAAO,cAAc,GAAG,EAAE,OAAO,KAAK,CAAC;AAC9D,UAAM,KAAK,aAAa,CAAC,UAAU,eAAe,CAAC;AAAA,EACrD;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/codex/adapter.js
CHANGED
|
@@ -536,6 +536,73 @@ class CodexAdapter {
|
|
|
536
536
|
const sequence = ++this.archiveSequence;
|
|
537
537
|
return this.storedThread(await this.readThreadHeader(id), sequence);
|
|
538
538
|
}
|
|
539
|
+
async readThreadPage(id, continuation) {
|
|
540
|
+
const epoch = this.epoch;
|
|
541
|
+
let cursor = null;
|
|
542
|
+
if (continuation) {
|
|
543
|
+
try {
|
|
544
|
+
const decoded = JSON.parse(Buffer.from(continuation, "base64url").toString("utf8"));
|
|
545
|
+
if (decoded.threadId !== id || decoded.epoch !== epoch || typeof decoded.cursor !== "string")
|
|
546
|
+
throw new Error("Invalid cursor");
|
|
547
|
+
cursor = decoded.cursor;
|
|
548
|
+
} catch {
|
|
549
|
+
throw new AppError("HISTORY_CURSOR_EXPIRED", "\u5386\u53F2\u5206\u9875\u5DF2\u5931\u6548\uFF0C\u8BF7\u91CD\u65B0\u540C\u6B65\u4F1A\u8BDD\u3002", 409);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
const sequence = ++this.archiveSequence;
|
|
553
|
+
const header = await this.readThreadHeader(id);
|
|
554
|
+
if (header.historyMode !== "paginated") return this.readThread(id);
|
|
555
|
+
const page = await this.call("thread/turns/list", {
|
|
556
|
+
threadId: id,
|
|
557
|
+
cursor,
|
|
558
|
+
limit: 12,
|
|
559
|
+
sortDirection: "desc",
|
|
560
|
+
itemsView: "summary"
|
|
561
|
+
});
|
|
562
|
+
if (page.nextCursor && page.nextCursor === cursor)
|
|
563
|
+
throw new CodexError("PROTOCOL_INCOMPATIBLE", "Invalid turn pagination");
|
|
564
|
+
await this.hydrateTurns(id, page.data);
|
|
565
|
+
if (this.epoch !== epoch)
|
|
566
|
+
throw new AppError("HISTORY_CURSOR_EXPIRED", "\u8BFB\u53D6\u671F\u95F4 Codex \u5DF2\u91CD\u542F\uFF0C\u8BF7\u91CD\u65B0\u540C\u6B65\u4F1A\u8BDD\u3002", 409);
|
|
567
|
+
const view = await this.storedThread(
|
|
568
|
+
{ ...header, turns: page.data.slice().reverse() },
|
|
569
|
+
sequence
|
|
570
|
+
);
|
|
571
|
+
return {
|
|
572
|
+
...view,
|
|
573
|
+
history: {
|
|
574
|
+
olderCursor: page.nextCursor ? Buffer.from(
|
|
575
|
+
JSON.stringify({
|
|
576
|
+
threadId: id,
|
|
577
|
+
epoch,
|
|
578
|
+
cursor: page.nextCursor
|
|
579
|
+
})
|
|
580
|
+
).toString("base64url") : null
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
async hydrateTurns(id, turns) {
|
|
585
|
+
for (const turn of turns) {
|
|
586
|
+
if (turn.itemsView === "full") continue;
|
|
587
|
+
let cursor = null;
|
|
588
|
+
const seen = /* @__PURE__ */ new Set();
|
|
589
|
+
turn.items = [];
|
|
590
|
+
do {
|
|
591
|
+
const page = await this.call("thread/items/list", {
|
|
592
|
+
threadId: id,
|
|
593
|
+
turnId: turn.id,
|
|
594
|
+
cursor,
|
|
595
|
+
limit: 20,
|
|
596
|
+
sortDirection: "asc"
|
|
597
|
+
});
|
|
598
|
+
turn.items.push(...page.data.map((entry) => entry.item));
|
|
599
|
+
cursor = page.nextCursor;
|
|
600
|
+
if (cursor && (seen.has(cursor) || seen.size >= 1e3))
|
|
601
|
+
throw new CodexError("PROTOCOL_INCOMPATIBLE", "Invalid item pagination");
|
|
602
|
+
if (cursor) seen.add(cursor);
|
|
603
|
+
} while (cursor);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
539
606
|
async readThread(id) {
|
|
540
607
|
const sequence = ++this.archiveSequence;
|
|
541
608
|
const thread = await this.readThreadHeader(id);
|
|
@@ -726,7 +793,7 @@ class CodexAdapter {
|
|
|
726
793
|
throw error;
|
|
727
794
|
}
|
|
728
795
|
titles?.register(result);
|
|
729
|
-
const view = await this.
|
|
796
|
+
const view = await this.readThreadPage(result.thread.id);
|
|
730
797
|
return { ...view, runtimeSettings: await this.responseRuntimeSettings(result) };
|
|
731
798
|
}
|
|
732
799
|
async forkThread(id, cwd, settings) {
|