agentroam 0.2.0-preview.46 → 0.2.0-preview.47
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/dist/args.js +10 -2
- package/dist/cli.js +2 -0
- package/dist/codex-desktop-command.js +8 -0
- package/dist/codex-desktop-setup.js +3 -0
- package/dist/codex-sharing.js +153 -0
- package/dist/runtime-manager.js +9 -0
- package/dist/service/service-command.js +9 -0
- package/install/codex-shared-watchdog.sh +16 -0
- package/package.json +5 -5
package/dist/args.js
CHANGED
|
@@ -81,8 +81,8 @@ export function parseArgs(argv) {
|
|
|
81
81
|
if (command === "desktop" && !["--data-dir", "--help", "-h"].includes(arg)) {
|
|
82
82
|
throw cliError("desktop accepts only --data-dir");
|
|
83
83
|
}
|
|
84
|
-
if (command === "codex-desktop" && !["--restart", "--dry-run", "--setup", "--data-dir", "--help", "-h"].includes(arg)) {
|
|
85
|
-
throw cliError("codex-desktop accepts only --setup, --restart, --dry-run and --data-dir");
|
|
84
|
+
if (command === "codex-desktop" && !["--restart", "--dry-run", "--setup", "--status", "--repair", "--data-dir", "--help", "-h"].includes(arg)) {
|
|
85
|
+
throw cliError("codex-desktop accepts only --setup, --restart, --dry-run, --status, --repair and --data-dir");
|
|
86
86
|
}
|
|
87
87
|
const next = () => {
|
|
88
88
|
const value = values[++index];
|
|
@@ -94,6 +94,10 @@ export function parseArgs(argv) {
|
|
|
94
94
|
options.desktopRestart = true;
|
|
95
95
|
else if (arg === "--dry-run" && command === "codex-desktop")
|
|
96
96
|
options.desktopDryRun = true;
|
|
97
|
+
else if (arg === "--status" && command === "codex-desktop")
|
|
98
|
+
options.desktopSharingStatus = true;
|
|
99
|
+
else if (arg === "--repair" && command === "codex-desktop")
|
|
100
|
+
options.desktopRepair = true;
|
|
97
101
|
else if (arg === "--setup" && command === "codex-desktop")
|
|
98
102
|
options.desktopSetup = true;
|
|
99
103
|
else if (arg === "--setup-codex-desktop" && command === "service" && serviceAction === "install")
|
|
@@ -137,6 +141,10 @@ export function parseArgs(argv) {
|
|
|
137
141
|
if (command === "codex-desktop" && options.desktopSetup && (options.desktopRestart || options.desktopDryRun)) {
|
|
138
142
|
throw cliError("--setup cannot be combined with --restart or --dry-run");
|
|
139
143
|
}
|
|
144
|
+
if (command === "codex-desktop" && (options.desktopSharingStatus || options.desktopRepair)
|
|
145
|
+
&& [options.desktopSharingStatus, options.desktopRepair, options.desktopSetup, options.desktopRestart, options.desktopDryRun].filter(Boolean).length !== 1) {
|
|
146
|
+
throw cliError("--status and --repair cannot be combined with other desktop actions");
|
|
147
|
+
}
|
|
140
148
|
if (command === "update" && updateVersion && !/^\d+\.\d+\.\d+$/.test(updateVersion)) {
|
|
141
149
|
throw cliError("update version must be an exact stable X.Y.Z version");
|
|
142
150
|
}
|
package/dist/cli.js
CHANGED
|
@@ -48,6 +48,8 @@ export async function main(argv) {
|
|
|
48
48
|
agentroam unlock-service install|uninstall|status 管理 Windows 远程解锁服务(安装时弹出 UAC)
|
|
49
49
|
agentroam codex-desktop [--dry-run] 通过共享后端启动官方 Codex 桌面端(macOS)
|
|
50
50
|
agentroam codex-desktop --restart 退出并重新连接官方桌面端,会中断它的全部运行会话
|
|
51
|
+
agentroam codex-desktop --status 输出实际共享连接状态(JSON)
|
|
52
|
+
agentroam codex-desktop --repair 修复默认共享和自动恢复,保留运行中的桌面任务
|
|
51
53
|
agentroam codex-desktop --setup 空闲桌面自动重新连接;有任务或状态未知时询问是否重启
|
|
52
54
|
agentroam service install --setup-codex-desktop 扫码前配置官方桌面共享连接(macOS)
|
|
53
55
|
设备命令支持 --data-dir PATH;配对码有效期 5 分钟,设备授权有效期 30 天。`);
|
|
@@ -4,6 +4,7 @@ import { promisify } from "node:util";
|
|
|
4
4
|
import { resolveCodexRuntime } from "./codex-runtime-manager.js";
|
|
5
5
|
import { readServiceConfig, resolveServicePaths } from "./service/service-files.js";
|
|
6
6
|
import { detectPlatform } from "./platform.js";
|
|
7
|
+
import { configureCodexSharing, inspectCodexSharing } from "./codex-sharing.js";
|
|
7
8
|
const execFileAsync = promisify(execFile);
|
|
8
9
|
const scriptPath = fileURLToPath(new URL("../install/start-codex-desktop-shared.sh", import.meta.url));
|
|
9
10
|
export async function runCodexDesktopCommand(options, context = {}) {
|
|
@@ -19,6 +20,12 @@ export async function runCodexDesktopCommand(options, context = {}) {
|
|
|
19
20
|
if (!environment.CODEX_HOME && service.codexHome)
|
|
20
21
|
environment.CODEX_HOME = service.codexHome;
|
|
21
22
|
}
|
|
23
|
+
if (options.desktopSharingStatus || options.desktopRepair) {
|
|
24
|
+
if (options.desktopRepair)
|
|
25
|
+
await (context.configureSharing ?? configureCodexSharing)(options, { platform, environment });
|
|
26
|
+
log(JSON.stringify(await (context.inspectSharing ?? inspectCodexSharing)({ platform, environment })));
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
22
29
|
// A dry run reads the installed configuration and never installs a runtime.
|
|
23
30
|
if (!options.desktopDryRun) {
|
|
24
31
|
const codex = await (context.codexResolver ?? resolveCodexRuntime)({
|
|
@@ -30,6 +37,7 @@ export async function runCodexDesktopCommand(options, context = {}) {
|
|
|
30
37
|
onProgress: (message) => log(`… ${message}`),
|
|
31
38
|
});
|
|
32
39
|
environment.AGENT_CODEX_BIN = codex.executable;
|
|
40
|
+
await (context.configureSharing ?? configureCodexSharing)(options, { platform, environment });
|
|
33
41
|
}
|
|
34
42
|
const args = [scriptPath];
|
|
35
43
|
if (!options.desktopDryRun) {
|
|
@@ -4,6 +4,7 @@ import { ReadStream, WriteStream } from "node:tty";
|
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { runCodexDesktopCommand } from "./codex-desktop-command.js";
|
|
6
6
|
import { inspectCodexDesktop } from "./codex-desktop-status.js";
|
|
7
|
+
import { configureCodexSharing } from "./codex-sharing.js";
|
|
7
8
|
import { withoutCliProgress } from "../bin/cli-progress.mjs";
|
|
8
9
|
export async function setupCodexDesktop(options, context = {}) {
|
|
9
10
|
if ((context.platform ?? process.platform) !== "darwin")
|
|
@@ -19,6 +20,8 @@ export async function setupCodexDesktop(options, context = {}) {
|
|
|
19
20
|
const inspect = context.inspect ?? inspectCodexDesktop;
|
|
20
21
|
const deferred = () => log("已保留当前 Codex 桌面端。扫码仍可连接 AgentRoam;原桌面会话暂未共享,可稍后执行 agentroam codex-desktop --setup。");
|
|
21
22
|
try {
|
|
23
|
+
await (context.configureSharing ?? configureCodexSharing)(options, { environment });
|
|
24
|
+
log("已保存默认共享启动与后台自动恢复配置。");
|
|
22
25
|
let snapshot = await inspect(environment);
|
|
23
26
|
if (snapshot.status === "not-installed") {
|
|
24
27
|
log("未安装官方 Codex 桌面端,继续生成扫码连接入口。");
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { access, chmod, mkdir, readFile, realpath, rename, rm } from "node:fs/promises";
|
|
3
|
+
import { constants } from "node:fs";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { dirname, resolve } from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { isDeepStrictEqual, promisify } from "node:util";
|
|
8
|
+
import { resolveCodexRuntime } from "./codex-runtime-manager.js";
|
|
9
|
+
import { inspectCodexDesktop } from "./codex-desktop-status.js";
|
|
10
|
+
import { withDesktopRpc } from "./codex-desktop-probe.js";
|
|
11
|
+
import { detectPlatform } from "./platform.js";
|
|
12
|
+
import { writePrivateText } from "./service/service-files.js";
|
|
13
|
+
const executeFile = promisify(execFile);
|
|
14
|
+
export const CODEX_SHARING_LABEL = "com.agentroam.codex-desktop-shared-env";
|
|
15
|
+
function locations(context) {
|
|
16
|
+
const home = resolve(context.homeDir ?? homedir());
|
|
17
|
+
const environment = context.environment ?? process.env;
|
|
18
|
+
const codexHome = resolve(environment.CODEX_HOME || resolve(home, ".codex"));
|
|
19
|
+
const socketPath = resolve(codexHome, "app-server-control/app-server-control.sock");
|
|
20
|
+
return { home, environment, codexHome, socketPath,
|
|
21
|
+
endpoint: `ws+unix://localhost${encodeURI(socketPath).replaceAll("#", "%23").replaceAll("?", "%3F").replaceAll(":", "%3A")}:/rpc`,
|
|
22
|
+
root: resolve(home, ".agentroam/codex-desktop"),
|
|
23
|
+
plist: resolve(home, "Library/LaunchAgents", `${CODEX_SHARING_LABEL}.plist`),
|
|
24
|
+
target: `gui/${context.uid ?? process.getuid?.() ?? 0}/${CODEX_SHARING_LABEL}`,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/** Save defaults and ensure the daemon; never quit Desktop or restart a live backend. */
|
|
28
|
+
export async function configureCodexSharing(options, context = {}) {
|
|
29
|
+
if ((context.platform ?? process.platform) !== "darwin")
|
|
30
|
+
return;
|
|
31
|
+
const paths = locations(context);
|
|
32
|
+
const environment = { ...paths.environment };
|
|
33
|
+
const executable = environment.AGENT_CODEX_BIN || (await resolveCodexRuntime({
|
|
34
|
+
dataDir: options.dataDir, target: detectPlatform(), environment,
|
|
35
|
+
})).executable;
|
|
36
|
+
if (!executable.startsWith("/"))
|
|
37
|
+
throw new Error("Codex 运行文件必须使用绝对路径");
|
|
38
|
+
await access(executable, constants.X_OK);
|
|
39
|
+
const execute = context.execute ?? executeFile;
|
|
40
|
+
const script = resolve(paths.root, "watchdog.sh");
|
|
41
|
+
await writePrivateText(script, await readFile(fileURLToPath(new URL("../install/codex-shared-watchdog.sh", import.meta.url)), "utf8"));
|
|
42
|
+
const args = [script, executable, paths.codexHome, paths.endpoint, environment.PATH || "/usr/bin:/bin:/usr/sbin:/sbin", paths.home];
|
|
43
|
+
const definition = {
|
|
44
|
+
Label: CODEX_SHARING_LABEL, ProgramArguments: ["/bin/bash", ...args],
|
|
45
|
+
RunAtLoad: true, StartInterval: 15, ProcessType: "Background", WorkingDirectory: paths.home,
|
|
46
|
+
StandardOutPath: resolve(paths.root, "watchdog.log"), StandardErrorPath: resolve(paths.root, "watchdog-error.log"),
|
|
47
|
+
};
|
|
48
|
+
const json = `${paths.root}/job.json`;
|
|
49
|
+
const temporary = `${paths.root}/job.plist`;
|
|
50
|
+
const commandOptions = { encoding: "utf8", timeout: 20_000, maxBuffer: 1024 * 1024 };
|
|
51
|
+
// Identical startup calls must not unload/reload an already healthy job.
|
|
52
|
+
let unchanged = false;
|
|
53
|
+
try {
|
|
54
|
+
const current = await execute("/usr/bin/plutil", ["-convert", "json", "-o", "-", paths.plist], commandOptions);
|
|
55
|
+
unchanged = isDeepStrictEqual(JSON.parse(String(current.stdout)), definition);
|
|
56
|
+
}
|
|
57
|
+
catch { /* First install or older definition. */ }
|
|
58
|
+
if (!unchanged) {
|
|
59
|
+
await writePrivateText(json, JSON.stringify(definition));
|
|
60
|
+
try {
|
|
61
|
+
await execute("/usr/bin/plutil", ["-convert", "xml1", "-o", temporary, json], commandOptions);
|
|
62
|
+
await chmod(temporary, 0o600);
|
|
63
|
+
await mkdir(dirname(paths.plist), { recursive: true });
|
|
64
|
+
let loaded = false;
|
|
65
|
+
try {
|
|
66
|
+
await execute("/bin/launchctl", ["print", paths.target], commandOptions);
|
|
67
|
+
loaded = true;
|
|
68
|
+
}
|
|
69
|
+
catch { /* Absent job. */ }
|
|
70
|
+
if (loaded)
|
|
71
|
+
await execute("/bin/launchctl", ["bootout", paths.target], commandOptions);
|
|
72
|
+
await rename(temporary, paths.plist);
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
await Promise.all([rm(json, { force: true }), rm(temporary, { force: true })]);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
await execute("/bin/launchctl", ["enable", paths.target], commandOptions);
|
|
79
|
+
let loaded = false;
|
|
80
|
+
try {
|
|
81
|
+
await execute("/bin/launchctl", ["print", paths.target], commandOptions);
|
|
82
|
+
loaded = true;
|
|
83
|
+
}
|
|
84
|
+
catch { /* bootstrap below */ }
|
|
85
|
+
if (!loaded)
|
|
86
|
+
await execute("/bin/launchctl", ["bootstrap", paths.target.slice(0, paths.target.lastIndexOf("/")), paths.plist], commandOptions);
|
|
87
|
+
// Make defaults effective now as well as on the next GUI login.
|
|
88
|
+
await execute("/bin/bash", args, { ...commandOptions, env: environment, cwd: paths.home });
|
|
89
|
+
}
|
|
90
|
+
/** Read process/socket evidence; configuration by itself never proves sharing. */
|
|
91
|
+
export async function inspectCodexSharing(context = {}) {
|
|
92
|
+
const result = { state: "failed", configured: false, autoStart: false, daemonReachable: false, message: "共享连接检查失败,请修复后重试。" };
|
|
93
|
+
if ((context.platform ?? process.platform) !== "darwin")
|
|
94
|
+
return { ...result, state: "unsupported", message: "当前系统暂不支持 Codex 桌面共享配置。" };
|
|
95
|
+
const paths = locations(context);
|
|
96
|
+
result.backendEndpoint = paths.endpoint;
|
|
97
|
+
const execute = context.execute ?? executeFile;
|
|
98
|
+
const commandOptions = { encoding: "utf8", timeout: 4_000, maxBuffer: 4 * 1024 * 1024 };
|
|
99
|
+
try {
|
|
100
|
+
const current = await execute("/bin/launchctl", ["getenv", "CODEX_APP_SERVER_WS_URL"], commandOptions).catch(() => ({ stdout: "" }));
|
|
101
|
+
const [force, home] = await Promise.all([
|
|
102
|
+
execute("/bin/launchctl", ["getenv", "CODEX_APP_SERVER_FORCE_CLI"], commandOptions).catch(() => ({ stdout: "" })),
|
|
103
|
+
execute("/bin/launchctl", ["getenv", "CODEX_HOME"], commandOptions).catch(() => ({ stdout: "" })),
|
|
104
|
+
]);
|
|
105
|
+
result.configured = String(current.stdout).trim() === paths.endpoint && String(force.stdout).trim() !== "1"
|
|
106
|
+
&& (String(home.stdout).trim() || resolve(paths.home, ".codex")) === paths.codexHome;
|
|
107
|
+
try {
|
|
108
|
+
const job = await execute("/bin/launchctl", ["print", paths.target], commandOptions);
|
|
109
|
+
const plist = await execute("/usr/bin/plutil", ["-convert", "json", "-o", "-", paths.plist], commandOptions);
|
|
110
|
+
const definition = JSON.parse(String(plist.stdout));
|
|
111
|
+
await access(resolve(paths.root, "watchdog.sh"), constants.R_OK);
|
|
112
|
+
await access(definition.ProgramArguments?.[2] ?? "", constants.X_OK);
|
|
113
|
+
result.autoStart = Boolean(job.stdout) && definition.RunAtLoad === true && definition.StartInterval === 15
|
|
114
|
+
&& definition.ProgramArguments?.[0] === "/bin/bash" && definition.ProgramArguments?.[1] === resolve(paths.root, "watchdog.sh")
|
|
115
|
+
&& definition.ProgramArguments?.[3] === paths.codexHome && definition.ProgramArguments?.[4] === paths.endpoint;
|
|
116
|
+
}
|
|
117
|
+
catch { /* Missing or outdated watchdog. */ }
|
|
118
|
+
try {
|
|
119
|
+
await (context.probe ?? (async (endpoint) => { await withDesktopRpc(endpoint, async (request) => { await request("config/read", { includeLayers: false }); }, 4_000); }))(paths.endpoint);
|
|
120
|
+
result.daemonReachable = true;
|
|
121
|
+
}
|
|
122
|
+
catch { /* Keep checking private Desktop evidence. */ }
|
|
123
|
+
const desktop = await (context.inspect ?? inspectCodexDesktop)(paths.environment);
|
|
124
|
+
if (desktop.status !== "running")
|
|
125
|
+
return { ...result, state: desktop.status, message: desktop.status === "stopped"
|
|
126
|
+
? result.configured && result.autoStart && result.daemonReachable ? "Codex 尚未启动;下次打开时使用共享后台。" : "Codex 尚未启动;请先修复共享配置。" : "尚未安装官方 Codex 桌面端。" };
|
|
127
|
+
const { stdout } = await execute("/bin/ps", ["-axo", "pid=,ppid=,args="], commandOptions);
|
|
128
|
+
const processes = String(stdout).split("\n").flatMap(line => {
|
|
129
|
+
const match = /^\s*(\d+)\s+(\d+)\s+(.+)$/.exec(line);
|
|
130
|
+
return match ? [{ pid: Number(match[1]), parent: Number(match[2]), command: match[3] }] : [];
|
|
131
|
+
});
|
|
132
|
+
if (processes.some(p => p.parent === desktop.pid && /\bapp-server\b/.test(p.command) && !/\b(?:proxy|daemon)\b/.test(p.command))) {
|
|
133
|
+
return { ...result, state: "independent", message: "Codex 正在使用独立后台。修复后,请在任务结束时退出并重新打开 Codex。" };
|
|
134
|
+
}
|
|
135
|
+
if (!result.daemonReachable)
|
|
136
|
+
return result;
|
|
137
|
+
const socket = await realpath(paths.socketPath);
|
|
138
|
+
const pids = [desktop.pid, ...processes.filter(p => /\bapp-server\b/.test(p.command) && /\bcodex\b/.test(p.command)).map(p => p.pid)];
|
|
139
|
+
const sockets = await execute("/usr/sbin/lsof", ["-nP", "-a", "-p", [...new Set(pids)].join(","), "-U"], commandOptions);
|
|
140
|
+
const rows = String(sockets.stdout).split("\n").flatMap(line => {
|
|
141
|
+
const match = /^\S+\s+(\d+)\s+\S+\s+\S+\s+unix\s+(0x[\da-f]+)\s+\S+\s+(.*)$/i.exec(line);
|
|
142
|
+
return match ? [{ pid: Number(match[1]), device: match[2], name: match[3].trim() }] : [];
|
|
143
|
+
});
|
|
144
|
+
const devices = new Set(rows.filter(row => row.pid !== desktop.pid && row.name === socket).map(row => row.device));
|
|
145
|
+
if (rows.some(row => row.pid === desktop.pid && row.name.startsWith("->") && devices.has(row.name.slice(2)))) {
|
|
146
|
+
return { ...result, state: "shared", message: "Codex 已连接共享后台。" };
|
|
147
|
+
}
|
|
148
|
+
return { ...result, message: "共享后台可用,但尚未确认 Codex 连接。请修复后,在任务结束时重新打开 Codex。" };
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
return result;
|
|
152
|
+
}
|
|
153
|
+
}
|
package/dist/runtime-manager.js
CHANGED
|
@@ -7,6 +7,7 @@ import { resolveOpenCodeRuntime, } from "./opencode-runtime-manager.js";
|
|
|
7
7
|
import { resolvePlatformRuntime } from "./platform-packages.js";
|
|
8
8
|
import { findAvailablePort } from "./port.js";
|
|
9
9
|
import { ProcessSupervisor } from "./process-supervisor.js";
|
|
10
|
+
import { configureCodexSharing } from "./codex-sharing.js";
|
|
10
11
|
import { withCliProgress } from "../bin/cli-progress.mjs";
|
|
11
12
|
export class RuntimeManager {
|
|
12
13
|
supervisor;
|
|
@@ -24,6 +25,14 @@ export class RuntimeManager {
|
|
|
24
25
|
const dataDir = resolve(options.dataDir);
|
|
25
26
|
await Promise.all(["data", "bin", "cache", "logs"].map((name) => mkdir(resolve(dataDir, name), { recursive: true })));
|
|
26
27
|
const codexEnvironment = await withCliProgress("正在准备 Codex 组件", () => prepareCodexRuntimeEnvironment(process.env, { dataDir, target }, this.codexResolver, this.report));
|
|
28
|
+
if (process.platform === "darwin" && codexEnvironment.AGENT_CODEX_BIN) {
|
|
29
|
+
try {
|
|
30
|
+
await configureCodexSharing(options, { environment: codexEnvironment });
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
this.report(`Codex 共享启动配置未完成,可在电脑菜单中修复:${error instanceof Error ? error.message : error}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
27
36
|
const childEnvironment = await withCliProgress("正在准备 OpenCode 组件", () => prepareOpenCodeRuntimeEnvironment(codexEnvironment, { dataDir, target }, this.opencodeResolver, this.report));
|
|
28
37
|
const { runtimeRoot } = resolvePlatformRuntime(target);
|
|
29
38
|
await repairNativeRuntimePermissions(runtimeRoot);
|
|
@@ -8,6 +8,7 @@ import { MacLaunchAgent } from "./macos-launch-agent.js";
|
|
|
8
8
|
import { WindowsTaskService } from "./windows-task-service.js";
|
|
9
9
|
import { assertSupportedNodeVersion } from "../../bin/runtime-policy.mjs";
|
|
10
10
|
import { cleanupOldLaunchers } from "./launcher-cleanup.js";
|
|
11
|
+
import { configureCodexSharing } from "../codex-sharing.js";
|
|
11
12
|
import { setupCodexDesktop } from "../codex-desktop-setup.js";
|
|
12
13
|
import { authorizeRemoteDesktop } from "../desktop-authorization.js";
|
|
13
14
|
import { withCliProgress } from "../../bin/cli-progress.mjs";
|
|
@@ -60,6 +61,14 @@ export async function runServiceCommand(options, context) {
|
|
|
60
61
|
dataDir: options.dataDir,
|
|
61
62
|
installedAt: now.toISOString(),
|
|
62
63
|
};
|
|
64
|
+
if (platform === "darwin" && codexPath) {
|
|
65
|
+
try {
|
|
66
|
+
await (context.configureSharing ?? configureCodexSharing)(options, { homeDir: context.homeDir, environment: { ...environment, PATH: environmentPath, AGENT_CODEX_BIN: codexPath } });
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
log(`Codex 默认共享配置未完成,可在电脑菜单中修复:${error instanceof Error ? error.message : error}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
63
72
|
const { definition, state } = await withCliProgress("正在安装后台服务,等待服务和手机访问连接就绪", () => controller.install(config));
|
|
64
73
|
log(`✓ AgentRoam service installed: ${definition}`);
|
|
65
74
|
if (state?.localUrl && state.status !== "stopped")
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Copied to a stable private directory: upgrades must not invalidate this job.
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
codex_bin="$1"
|
|
5
|
+
codex_home="$2"
|
|
6
|
+
shared_url="$3"
|
|
7
|
+
export CODEX_HOME="$codex_home"
|
|
8
|
+
export PATH="$4"
|
|
9
|
+
export CODEX_APP_SERVER_FORCE_CLI=0
|
|
10
|
+
export CODEX_APP_SERVER_WS_URL="$shared_url"
|
|
11
|
+
/bin/launchctl setenv CODEX_APP_SERVER_WS_URL "$shared_url"
|
|
12
|
+
/bin/launchctl setenv CODEX_APP_SERVER_FORCE_CLI 0
|
|
13
|
+
/bin/launchctl setenv CODEX_HOME "$codex_home"
|
|
14
|
+
# daemon start is idempotent; never stop or replace a live daemon.
|
|
15
|
+
cd "$5"
|
|
16
|
+
exec "$codex_bin" app-server daemon start
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentroam",
|
|
3
|
-
"version": "0.2.0-preview.
|
|
3
|
+
"version": "0.2.0-preview.47",
|
|
4
4
|
"description": "Zero-install mobile remote terminal and file console",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -27,12 +27,12 @@
|
|
|
27
27
|
"ws": "^8.21.3"
|
|
28
28
|
},
|
|
29
29
|
"optionalDependencies": {
|
|
30
|
-
"agentroam-runtime-darwin-arm64": "0.2.0-preview.
|
|
31
|
-
"agentroam-runtime-win32-x64": "0.2.0-preview.
|
|
30
|
+
"agentroam-runtime-darwin-arm64": "0.2.0-preview.47",
|
|
31
|
+
"agentroam-runtime-win32-x64": "0.2.0-preview.47",
|
|
32
32
|
"agentroam-cloudflared-darwin-arm64": "0.2.0-preview.39",
|
|
33
33
|
"agentroam-cloudflared-win32-x64": "0.2.0-preview.39",
|
|
34
|
-
"agentroam-tui-darwin-arm64": "0.2.0-preview.
|
|
35
|
-
"@caoqu/agentroam-tui-win32-x64": "0.2.0-preview.
|
|
34
|
+
"agentroam-tui-darwin-arm64": "0.2.0-preview.47",
|
|
35
|
+
"@caoqu/agentroam-tui-win32-x64": "0.2.0-preview.47"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@types/node": "^22.0.0",
|