@dev-anywhere/proxy 0.1.0 → 0.1.2
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 -13
- package/dist/chunk-CDKXSDAV.js +36 -0
- package/dist/chunk-CDKXSDAV.js.map +1 -0
- package/dist/{chunk-QWPI6YON.js → chunk-DFLQ3TFT.js} +137 -40
- package/dist/chunk-DFLQ3TFT.js.map +1 -0
- package/dist/{chunk-JPJMOVQ5.js → chunk-QXOARRC2.js} +2 -2
- package/dist/{chunk-WXWH6L7J.js → chunk-TG7JPHE5.js} +2 -2
- package/dist/index.js +46 -18
- package/dist/index.js.map +1 -1
- package/dist/serve.js +181 -127
- package/dist/serve.js.map +1 -1
- package/dist/session-worker.js +2 -2
- package/dist/{terminal-ZPPKNAL4.js → terminal-GIU6MXOR.js} +14 -6
- package/dist/terminal-GIU6MXOR.js.map +1 -0
- package/package.json +3 -3
- package/dist/chunk-7PXDRNLY.js +0 -34
- package/dist/chunk-7PXDRNLY.js.map +0 -1
- package/dist/chunk-QWPI6YON.js.map +0 -1
- package/dist/terminal-ZPPKNAL4.js.map +0 -1
- /package/dist/{chunk-JPJMOVQ5.js.map → chunk-QXOARRC2.js.map} +0 -0
- /package/dist/{chunk-WXWH6L7J.js.map → chunk-TG7JPHE5.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
} from "./chunk-
|
|
3
|
+
daemonRelayArgs,
|
|
4
|
+
setDesiredDaemonRelay
|
|
5
|
+
} from "./chunk-CDKXSDAV.js";
|
|
6
6
|
import {
|
|
7
7
|
spawnScript
|
|
8
8
|
} from "./chunk-ZUWAB67J.js";
|
|
9
9
|
import {
|
|
10
10
|
CONFIG_PATH,
|
|
11
11
|
PID_PATH,
|
|
12
|
+
PROFILE_NAME,
|
|
12
13
|
SERVICE_LOG_PATH,
|
|
13
14
|
SOCK_PATH,
|
|
14
15
|
STOPPED_PATH,
|
|
15
16
|
createIpcReader,
|
|
17
|
+
ensureProfileWorkspace,
|
|
16
18
|
initWorkspace,
|
|
17
19
|
isInitialized,
|
|
18
20
|
serializeIpc
|
|
19
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-DFLQ3TFT.js";
|
|
20
22
|
|
|
21
23
|
// src/index.ts
|
|
22
24
|
import { existsSync, readFileSync, unlinkSync, writeFileSync } from "fs";
|
|
@@ -34,6 +36,25 @@ function normalizeCliArgs(args) {
|
|
|
34
36
|
}
|
|
35
37
|
return normalized;
|
|
36
38
|
}
|
|
39
|
+
function stripProxyProfileArgs(args) {
|
|
40
|
+
const result = [];
|
|
41
|
+
for (let i = 0; i < args.length; i++) {
|
|
42
|
+
const arg = args[i];
|
|
43
|
+
if (arg === "claude" || arg === "codex") {
|
|
44
|
+
result.push(...args.slice(i));
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
if (arg === "--profile") {
|
|
48
|
+
i++;
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (arg.startsWith("--profile=")) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
result.push(arg);
|
|
55
|
+
}
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
37
58
|
function extractAgentInvocation(args) {
|
|
38
59
|
const [agent, ...providerArgs] = args;
|
|
39
60
|
if (agent !== "claude" && agent !== "codex") {
|
|
@@ -72,6 +93,7 @@ function showStatus() {
|
|
|
72
93
|
lines++;
|
|
73
94
|
};
|
|
74
95
|
if (!existsSync(PID_PATH)) {
|
|
96
|
+
log(`Profile: ${PROFILE_NAME}`);
|
|
75
97
|
log("Service: not running");
|
|
76
98
|
resolve(lines);
|
|
77
99
|
return;
|
|
@@ -88,19 +110,22 @@ function showStatus() {
|
|
|
88
110
|
resolve(lines);
|
|
89
111
|
return;
|
|
90
112
|
}
|
|
113
|
+
log(`Profile: ${PROFILE_NAME}`);
|
|
91
114
|
log(`Service: running (PID ${pid})`);
|
|
92
115
|
log(`Socket: ${SOCK_PATH}`);
|
|
93
116
|
log(`Log: ${SERVICE_LOG_PATH}`);
|
|
94
117
|
const sock = connect(SOCK_PATH);
|
|
95
118
|
sock.on("error", () => {
|
|
96
119
|
log("Sessions: unable to connect");
|
|
120
|
+
sock.destroy();
|
|
97
121
|
resolve(lines);
|
|
98
122
|
});
|
|
99
123
|
sock.on("connect", () => {
|
|
100
124
|
createIpcReader(sock, (msg) => {
|
|
101
125
|
if (msg.type === "service_status_response") {
|
|
102
126
|
const config = msg.config;
|
|
103
|
-
log(`
|
|
127
|
+
log(`Daemon: profile ${config.profile ?? PROFILE_NAME}`);
|
|
128
|
+
log(`Relay: ${config.relayName} (${config.relayNameSource})`);
|
|
104
129
|
log(`Config: relay ${config.relayUrl ?? "(unset)"} (${config.relayUrlSource})`);
|
|
105
130
|
const relay = msg.relay;
|
|
106
131
|
if (!relay) {
|
|
@@ -152,6 +177,7 @@ async function waitForServeReady(timeoutMs) {
|
|
|
152
177
|
return false;
|
|
153
178
|
}
|
|
154
179
|
async function startDaemon(options) {
|
|
180
|
+
ensureProfileWorkspace();
|
|
155
181
|
if (existsSync(PID_PATH)) {
|
|
156
182
|
const pid = parseInt(readFileSync(PID_PATH, "utf-8").trim(), 10);
|
|
157
183
|
try {
|
|
@@ -162,8 +188,9 @@ async function startDaemon(options) {
|
|
|
162
188
|
}
|
|
163
189
|
}
|
|
164
190
|
if (existsSync(STOPPED_PATH)) unlinkSync(STOPPED_PATH);
|
|
165
|
-
const serveArgs =
|
|
191
|
+
const serveArgs = ["--profile", PROFILE_NAME, ...daemonRelayArgs(options?.relayName)];
|
|
166
192
|
const child = spawnScript(new URL("./serve", import.meta.url), serveArgs, {
|
|
193
|
+
env: { ...process.env },
|
|
167
194
|
stdio: ["ignore", "ignore", "pipe"],
|
|
168
195
|
unref: false
|
|
169
196
|
});
|
|
@@ -205,15 +232,15 @@ async function startDaemon(options) {
|
|
|
205
232
|
}
|
|
206
233
|
process.exit(1);
|
|
207
234
|
}
|
|
208
|
-
var program = new Command("dev-anywhere").description("Dev Anywhere - transparent local AI CLI proxy with remote control").version(pkg.version).allowUnknownOption().allowExcessArguments().action(async () => {
|
|
235
|
+
var program = new Command("dev-anywhere").description("Dev Anywhere - transparent local AI CLI proxy with remote control").version(pkg.version).option("--profile <name>", "Use an isolated local proxy profile").allowUnknownOption().allowExcessArguments().action(async () => {
|
|
209
236
|
if (!isInitialized()) {
|
|
210
237
|
console.error(`Dev Anywhere is not initialized. Run "dev-anywhere init" first.`);
|
|
211
238
|
process.exit(1);
|
|
212
239
|
}
|
|
213
|
-
const { startTerminal } = await import("./terminal-
|
|
240
|
+
const { startTerminal } = await import("./terminal-GIU6MXOR.js");
|
|
214
241
|
let invocation;
|
|
215
242
|
try {
|
|
216
|
-
invocation = extractAgentInvocation(
|
|
243
|
+
invocation = extractAgentInvocation(cliArgsWithoutProfile);
|
|
217
244
|
} catch (err) {
|
|
218
245
|
console.error(err instanceof Error ? err.message : String(err));
|
|
219
246
|
process.exit(1);
|
|
@@ -221,26 +248,26 @@ var program = new Command("dev-anywhere").description("Dev Anywhere - transparen
|
|
|
221
248
|
const { provider, args } = invocation;
|
|
222
249
|
await startTerminal(args, provider);
|
|
223
250
|
});
|
|
224
|
-
var serve = new Command("serve").description("Manage the dev-anywhere background service").option("-d, --daemon", "Run in background").action(async (opts) => {
|
|
251
|
+
var serve = new Command("serve").description("Manage the dev-anywhere background service").option("--profile <name>", "Use an isolated local proxy profile").option("-d, --daemon", "Run in background").action(async (opts) => {
|
|
225
252
|
if (!isInitialized()) {
|
|
226
253
|
console.error(`Dev Anywhere is not initialized. Run "dev-anywhere init" first.`);
|
|
227
254
|
process.exit(1);
|
|
228
255
|
}
|
|
229
256
|
if (opts.daemon) {
|
|
230
|
-
|
|
257
|
+
setDesiredDaemonRelay(void 0);
|
|
231
258
|
await startDaemon();
|
|
232
259
|
} else {
|
|
233
260
|
const { startService } = await import("./serve.js");
|
|
234
261
|
await startService();
|
|
235
262
|
}
|
|
236
263
|
});
|
|
237
|
-
serve.command("start").description("Start the background service").option("--
|
|
264
|
+
serve.command("start").description("Start the background service").option("--relay <name>", "Use a named relay from config").action(async (opts) => {
|
|
238
265
|
if (!isInitialized()) {
|
|
239
266
|
console.error(`Dev Anywhere is not initialized. Run "dev-anywhere init" first.`);
|
|
240
267
|
process.exit(1);
|
|
241
268
|
}
|
|
242
|
-
|
|
243
|
-
await startDaemon({
|
|
269
|
+
setDesiredDaemonRelay(opts.relay);
|
|
270
|
+
await startDaemon({ relayName: opts.relay });
|
|
244
271
|
});
|
|
245
272
|
serve.command("status").description("Show service status and active sessions").option("-w, --watch", "Continuous monitoring mode").option("-n, --interval <seconds>", "Refresh interval in seconds", "2").action(async (opts) => {
|
|
246
273
|
if (opts.watch) {
|
|
@@ -259,10 +286,10 @@ serve.command("status").description("Show service status and active sessions").o
|
|
|
259
286
|
serve.command("stop").description("Stop the background service").action(() => {
|
|
260
287
|
stopService();
|
|
261
288
|
});
|
|
262
|
-
serve.command("restart").description("Restart the background service").option("--
|
|
263
|
-
|
|
289
|
+
serve.command("restart").description("Restart the background service").option("--relay <name>", "Use a named relay from config").action(async (opts) => {
|
|
290
|
+
setDesiredDaemonRelay(opts.relay);
|
|
264
291
|
stopService();
|
|
265
|
-
await startDaemon({
|
|
292
|
+
await startDaemon({ relayName: opts.relay });
|
|
266
293
|
});
|
|
267
294
|
program.addCommand(serve);
|
|
268
295
|
program.command("init").description("Initialize dev-anywhere workspace (~/.dev-anywhere)").action(() => {
|
|
@@ -275,5 +302,6 @@ program.command("init").description("Initialize dev-anywhere workspace (~/.dev-a
|
|
|
275
302
|
console.log(`Edit ${CONFIG_PATH} to configure relay server URL.`);
|
|
276
303
|
});
|
|
277
304
|
var cliArgs = normalizeCliArgs(process.argv.slice(2));
|
|
278
|
-
|
|
305
|
+
var cliArgsWithoutProfile = stripProxyProfileArgs(cliArgs);
|
|
306
|
+
program.parse(cliArgsWithoutProfile, { from: "user" });
|
|
279
307
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/cli-args.ts"],"sourcesContent":["import { existsSync, readFileSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport { connect } from \"node:net\";\nimport { setTimeout as sleep } from \"node:timers/promises\";\nimport { fileURLToPath } from \"node:url\";\nimport { dirname, join } from \"node:path\";\nimport { Command } from \"commander\";\nimport {\n PID_PATH,\n SOCK_PATH,\n STOPPED_PATH,\n SERVICE_LOG_PATH,\n CONFIG_PATH,\n isInitialized,\n initWorkspace,\n} from \"./common/paths.js\";\nimport { spawnScript } from \"./common/env.js\";\nimport { daemonEnvArgs, setDesiredDaemonEnv } from \"./common/daemon-env.js\";\nimport { createIpcReader, serializeIpc } from \"./ipc/ipc-protocol.js\";\nimport { extractAgentInvocation, normalizeCliArgs } from \"./cli-args.js\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst pkg = JSON.parse(readFileSync(join(__dirname, \"..\", \"package.json\"), \"utf-8\")) as {\n version: string;\n};\n\nfunction stopService(): boolean {\n if (!existsSync(PID_PATH)) {\n console.error(\"Service is not running (no PID file)\");\n return false;\n }\n const pid = parseInt(readFileSync(PID_PATH, \"utf-8\").trim(), 10);\n try {\n process.kill(pid, \"SIGTERM\");\n console.log(`Service stopped (PID ${pid})`);\n } catch {\n console.error(`Process ${pid} not found, cleaning up stale files`);\n }\n if (existsSync(PID_PATH)) unlinkSync(PID_PATH);\n if (existsSync(SOCK_PATH)) unlinkSync(SOCK_PATH);\n writeFileSync(STOPPED_PATH, String(Date.now()));\n return true;\n}\n\nfunction showStatus(): Promise<number> {\n return new Promise((resolve) => {\n let lines = 0;\n const log = (s: string) => {\n console.log(s);\n lines++;\n };\n\n if (!existsSync(PID_PATH)) {\n log(\"Service: not running\");\n resolve(lines);\n return;\n }\n const pid = parseInt(readFileSync(PID_PATH, \"utf-8\").trim(), 10);\n let alive = false;\n try {\n process.kill(pid, 0);\n alive = true;\n } catch {\n // process.kill(pid, 0) 抛错表示进程不存在\n }\n\n if (!alive) {\n log(\"Service: dead (stale PID file)\");\n resolve(lines);\n return;\n }\n\n log(`Service: running (PID ${pid})`);\n log(`Socket: ${SOCK_PATH}`);\n log(`Log: ${SERVICE_LOG_PATH}`);\n\n const sock = connect(SOCK_PATH);\n sock.on(\"error\", () => {\n log(\"Sessions: unable to connect\");\n resolve(lines);\n });\n sock.on(\"connect\", () => {\n createIpcReader(sock, (msg) => {\n if (msg.type === \"service_status_response\") {\n const config = msg.config;\n log(`Env: ${config.envName ?? \"single\"} (${config.envNameSource})`);\n log(`Config: relay ${config.relayUrl ?? \"(unset)\"} (${config.relayUrlSource})`);\n const relay = msg.relay;\n if (!relay) {\n log(\"Relay: not configured\");\n } else if (relay.connected) {\n log(`Relay: connected (proxy: ${relay.proxyId})`);\n log(\n ` queue depth: ${relay.queueDepth}, reconnect attempts: ${relay.reconnectAttempt}`,\n );\n } else {\n log(\n `Relay: disconnected (proxy: ${relay.proxyId}, reconnecting: attempt ${relay.reconnectAttempt}, queued: ${relay.queueDepth})`,\n );\n }\n log(\"\");\n\n // 显示会话列表\n const sessions = msg.sessions;\n if (sessions.length === 0) {\n log(\"Sessions: none\");\n } else {\n log(`Sessions: ${sessions.length}`);\n for (const s of sessions) {\n log(` ${s.id} ${s.mode} ${s.state} worker: ${s.hasWorker ? \"yes\" : \"no\"}`);\n }\n }\n sock.destroy();\n resolve(lines);\n }\n });\n sock.write(serializeIpc({ type: \"service_status_request\" }));\n });\n });\n}\n\nconst DAEMON_STARTUP_TIMEOUT_MS = 30_000;\nconst DAEMON_STARTUP_POLL_MS = 200;\n\n// 轮询 SOCK_PATH 直到可连接,作为 serve 的 readiness 信号。\n// serve.ts 里 server.listen(SOCK_PATH) 是启动序列的最后一步,连上即代表 ready。\nasync function waitForServeReady(timeoutMs: number): Promise<boolean> {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n const connected = await new Promise<boolean>((resolve) => {\n const sock = connect(SOCK_PATH);\n sock.once(\"connect\", () => {\n sock.destroy();\n resolve(true);\n });\n sock.once(\"error\", () => resolve(false));\n });\n if (connected) return true;\n await sleep(DAEMON_STARTUP_POLL_MS);\n }\n return false;\n}\n\nasync function startDaemon(options?: { envName?: string }): Promise<void> {\n if (existsSync(PID_PATH)) {\n const pid = parseInt(readFileSync(PID_PATH, \"utf-8\").trim(), 10);\n try {\n process.kill(pid, 0);\n console.error(`Service is already running (PID ${pid})`);\n return;\n } catch {\n // process.kill(pid, 0) 抛错表示进程不存在,继续启动\n }\n }\n if (existsSync(STOPPED_PATH)) unlinkSync(STOPPED_PATH);\n\n // stderr 走 pipe 由父 CLI 订阅:子进程 ready 前(pino logger 未接管)的启动错误\n // 会被捕获;ready 后父 detach,pino 接管所有输出到 service.log。\n // start 命令必须等 daemon socket 可连接后再退出;否则用户会看到“启动成功”,实际服务还没就绪。\n const serveArgs = daemonEnvArgs(options?.envName);\n const child = spawnScript(new URL(\"./serve\", import.meta.url), serveArgs, {\n stdio: [\"ignore\", \"ignore\", \"pipe\"],\n unref: false,\n });\n\n const stderrChunks: Buffer[] = [];\n child.stderr!.on(\"data\", (chunk: Buffer) => {\n stderrChunks.push(chunk);\n });\n\n // race: readiness handshake vs. 子进程先挂。子进程 ready 前就 exit 说明启动硬失败,\n // 不必再等到 30s 超时才报错。\n type Outcome =\n | { kind: \"ready\" }\n | { kind: \"timeout\" }\n | { kind: \"exited\"; code: number | null; signal: NodeJS.Signals | null };\n\n const readyOutcome: Promise<Outcome> = waitForServeReady(DAEMON_STARTUP_TIMEOUT_MS).then((ok) =>\n ok ? { kind: \"ready\" as const } : { kind: \"timeout\" as const },\n );\n const exitOutcome: Promise<Outcome> = new Promise((resolve) => {\n // 设 listener 前已经 exit 的边界:Node 记在 exitCode 上\n if (child.exitCode !== null) {\n resolve({ kind: \"exited\", code: child.exitCode, signal: child.signalCode });\n return;\n }\n child.once(\"exit\", (code, signal) => resolve({ kind: \"exited\", code, signal }));\n });\n\n const result = await Promise.race([readyOutcome, exitOutcome]);\n\n if (result.kind === \"ready\") {\n console.log(`Service started in background (PID ${child.pid})`);\n // ready 后 detach:摘 stderr 订阅 + destroy pipe + unref 子进程。\n // 单独 child.unref() 不够,父侧的 stderr pipe fd 还在事件循环里会让父 CLI 永不退出;\n // 必须 destroy 掉 pipe 才能真正释放 refcount。pino 已接管子进程的输出到 service.log。\n child.stderr!.removeAllListeners(\"data\");\n child.stderr!.destroy();\n child.unref();\n return;\n }\n\n // 失败路径:timeout 或 exited\n const stderrOutput = Buffer.concat(stderrChunks).toString(\"utf-8\").trim();\n if (result.kind === \"exited\") {\n console.error(`Service exited during startup (code=${result.code}, signal=${result.signal}).`);\n } else {\n console.error(`Service failed to become ready within ${DAEMON_STARTUP_TIMEOUT_MS / 1000}s.`);\n try {\n process.kill(child.pid!, \"SIGTERM\");\n } catch {\n // 子进程可能已自己退出,kill 失败不影响后续退出码\n }\n }\n if (stderrOutput) {\n console.error(\"--- child stderr ---\");\n console.error(stderrOutput);\n }\n process.exit(1);\n}\n\nconst program = new Command(\"dev-anywhere\")\n .description(\"Dev Anywhere - transparent local AI CLI proxy with remote control\")\n .version(pkg.version)\n .allowUnknownOption()\n .allowExcessArguments()\n .action(async () => {\n if (!isInitialized()) {\n console.error(`Dev Anywhere is not initialized. Run \"dev-anywhere init\" first.`);\n process.exit(1);\n }\n // 延迟导入 terminal: CLI 的其他子命令(init/stop/status)不需要 PTY + xterm 相关依赖,\n // tsup 基于 dynamic import 自动代码分裂,避免所有命令都为 terminal 付出 14KB 额外启动成本。\n const { startTerminal } = await import(\"./terminal.js\");\n let invocation: ReturnType<typeof extractAgentInvocation>;\n try {\n invocation = extractAgentInvocation(cliArgs);\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n const { provider, args } = invocation;\n await startTerminal(args, provider);\n });\n\n// serve 子命令组\nconst serve = new Command(\"serve\")\n .description(\"Manage the dev-anywhere background service\")\n .option(\"-d, --daemon\", \"Run in background\")\n .action(async (opts) => {\n if (!isInitialized()) {\n console.error(`Dev Anywhere is not initialized. Run \"dev-anywhere init\" first.`);\n process.exit(1);\n }\n if (opts.daemon) {\n setDesiredDaemonEnv(undefined);\n await startDaemon();\n } else {\n // 延迟导入 serve: daemon 模式只需要 startDaemon(纯 spawn),不需要加载 70KB 的 serve bundle\n const { startService } = await import(\"./serve.js\");\n await startService();\n }\n });\n\nserve\n .command(\"start\")\n .description(\"Start the background service\")\n .option(\"--env <name>\", \"Use a named config environment\")\n .action(async (opts) => {\n if (!isInitialized()) {\n console.error(`Dev Anywhere is not initialized. Run \"dev-anywhere init\" first.`);\n process.exit(1);\n }\n setDesiredDaemonEnv(opts.env);\n await startDaemon({ envName: opts.env });\n });\n\nserve\n .command(\"status\")\n .description(\"Show service status and active sessions\")\n .option(\"-w, --watch\", \"Continuous monitoring mode\")\n .option(\"-n, --interval <seconds>\", \"Refresh interval in seconds\", \"2\")\n .action(async (opts) => {\n if (opts.watch) {\n const intervalMs = Number(opts.interval) * 1000;\n let lastLines = await showStatus();\n setInterval(async () => {\n if (lastLines > 0) {\n process.stdout.write(`\\x1B[${lastLines}A\\x1B[J`);\n }\n lastLines = await showStatus();\n }, intervalMs);\n } else {\n await showStatus();\n }\n });\n\nserve\n .command(\"stop\")\n .description(\"Stop the background service\")\n .action(() => {\n stopService();\n });\n\nserve\n .command(\"restart\")\n .description(\"Restart the background service\")\n .option(\"--env <name>\", \"Use a named config environment\")\n .action(async (opts) => {\n setDesiredDaemonEnv(opts.env);\n stopService();\n await startDaemon({ envName: opts.env });\n });\n\nprogram.addCommand(serve);\n\nprogram\n .command(\"init\")\n .description(\"Initialize dev-anywhere workspace (~/.dev-anywhere)\")\n .action(() => {\n if (isInitialized()) {\n console.log(`Already initialized. Config at ${CONFIG_PATH}`);\n return;\n }\n initWorkspace();\n console.log(\"Initialized ~/.dev-anywhere/\");\n console.log(`Edit ${CONFIG_PATH} to configure relay server URL.`);\n });\n\n// pnpm run dev -- args 会在参数前插入 \"--\"。根脚本和用户命令都可能再加一层\n// 分隔符,所以这里过滤所有前导分隔符,再交给 Commander 和 provider 参数解析。\nconst cliArgs = normalizeCliArgs(process.argv.slice(2));\n\nprogram.parse(cliArgs, { from: \"user\" });\n","import type { ProviderId } from \"./providers/index.js\";\n\nexport function normalizeCliArgs(args: string[]): string[] {\n const normalized = [...args];\n while (normalized[0] === \"--\") {\n normalized.shift();\n }\n return normalized;\n}\n\nexport function extractAgentInvocation(args: string[]): { provider: ProviderId; args: string[] } {\n const [agent, ...providerArgs] = args;\n if (agent !== \"claude\" && agent !== \"codex\") {\n throw new Error(\n 'Missing Agent CLI. Use \"dev-anywhere claude ...\" or \"dev-anywhere codex ...\".',\n );\n }\n return { provider: agent, args: providerArgs };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/cli-args.ts"],"sourcesContent":["import { existsSync, readFileSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport { connect } from \"node:net\";\nimport { setTimeout as sleep } from \"node:timers/promises\";\nimport { fileURLToPath } from \"node:url\";\nimport { dirname, join } from \"node:path\";\nimport { Command } from \"commander\";\nimport {\n PID_PATH,\n SOCK_PATH,\n STOPPED_PATH,\n SERVICE_LOG_PATH,\n CONFIG_PATH,\n PROFILE_NAME,\n ensureProfileWorkspace,\n isInitialized,\n initWorkspace,\n} from \"./common/paths.js\";\nimport { spawnScript } from \"./common/env.js\";\nimport { daemonRelayArgs, setDesiredDaemonRelay } from \"./common/daemon-env.js\";\nimport { createIpcReader, serializeIpc } from \"./ipc/ipc-protocol.js\";\nimport { extractAgentInvocation, normalizeCliArgs, stripProxyProfileArgs } from \"./cli-args.js\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst pkg = JSON.parse(readFileSync(join(__dirname, \"..\", \"package.json\"), \"utf-8\")) as {\n version: string;\n};\n\nfunction stopService(): boolean {\n if (!existsSync(PID_PATH)) {\n console.error(\"Service is not running (no PID file)\");\n return false;\n }\n const pid = parseInt(readFileSync(PID_PATH, \"utf-8\").trim(), 10);\n try {\n process.kill(pid, \"SIGTERM\");\n console.log(`Service stopped (PID ${pid})`);\n } catch {\n console.error(`Process ${pid} not found, cleaning up stale files`);\n }\n if (existsSync(PID_PATH)) unlinkSync(PID_PATH);\n if (existsSync(SOCK_PATH)) unlinkSync(SOCK_PATH);\n writeFileSync(STOPPED_PATH, String(Date.now()));\n return true;\n}\n\nfunction showStatus(): Promise<number> {\n return new Promise((resolve) => {\n let lines = 0;\n const log = (s: string) => {\n console.log(s);\n lines++;\n };\n\n if (!existsSync(PID_PATH)) {\n log(`Profile: ${PROFILE_NAME}`);\n log(\"Service: not running\");\n resolve(lines);\n return;\n }\n const pid = parseInt(readFileSync(PID_PATH, \"utf-8\").trim(), 10);\n let alive = false;\n try {\n process.kill(pid, 0);\n alive = true;\n } catch {\n // process.kill(pid, 0) 抛错表示进程不存在\n }\n\n if (!alive) {\n log(\"Service: dead (stale PID file)\");\n resolve(lines);\n return;\n }\n\n log(`Profile: ${PROFILE_NAME}`);\n log(`Service: running (PID ${pid})`);\n log(`Socket: ${SOCK_PATH}`);\n log(`Log: ${SERVICE_LOG_PATH}`);\n\n const sock = connect(SOCK_PATH);\n sock.on(\"error\", () => {\n log(\"Sessions: unable to connect\");\n sock.destroy();\n resolve(lines);\n });\n sock.on(\"connect\", () => {\n createIpcReader(sock, (msg) => {\n if (msg.type === \"service_status_response\") {\n const config = msg.config;\n log(`Daemon: profile ${config.profile ?? PROFILE_NAME}`);\n log(`Relay: ${config.relayName} (${config.relayNameSource})`);\n log(`Config: relay ${config.relayUrl ?? \"(unset)\"} (${config.relayUrlSource})`);\n const relay = msg.relay;\n if (!relay) {\n log(\"Relay: not configured\");\n } else if (relay.connected) {\n log(`Relay: connected (proxy: ${relay.proxyId})`);\n log(\n ` queue depth: ${relay.queueDepth}, reconnect attempts: ${relay.reconnectAttempt}`,\n );\n } else {\n log(\n `Relay: disconnected (proxy: ${relay.proxyId}, reconnecting: attempt ${relay.reconnectAttempt}, queued: ${relay.queueDepth})`,\n );\n }\n log(\"\");\n\n // 显示会话列表\n const sessions = msg.sessions;\n if (sessions.length === 0) {\n log(\"Sessions: none\");\n } else {\n log(`Sessions: ${sessions.length}`);\n for (const s of sessions) {\n log(` ${s.id} ${s.mode} ${s.state} worker: ${s.hasWorker ? \"yes\" : \"no\"}`);\n }\n }\n sock.destroy();\n resolve(lines);\n }\n });\n sock.write(serializeIpc({ type: \"service_status_request\" }));\n });\n });\n}\n\nconst DAEMON_STARTUP_TIMEOUT_MS = 30_000;\nconst DAEMON_STARTUP_POLL_MS = 200;\n\n// 轮询 SOCK_PATH 直到可连接,作为 serve 的 readiness 信号。\n// serve.ts 里 server.listen(SOCK_PATH) 是启动序列的最后一步,连上即代表 ready。\nasync function waitForServeReady(timeoutMs: number): Promise<boolean> {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n const connected = await new Promise<boolean>((resolve) => {\n const sock = connect(SOCK_PATH);\n sock.once(\"connect\", () => {\n sock.destroy();\n resolve(true);\n });\n sock.once(\"error\", () => resolve(false));\n });\n if (connected) return true;\n await sleep(DAEMON_STARTUP_POLL_MS);\n }\n return false;\n}\n\nasync function startDaemon(options?: { relayName?: string }): Promise<void> {\n ensureProfileWorkspace();\n if (existsSync(PID_PATH)) {\n const pid = parseInt(readFileSync(PID_PATH, \"utf-8\").trim(), 10);\n try {\n process.kill(pid, 0);\n console.error(`Service is already running (PID ${pid})`);\n return;\n } catch {\n // process.kill(pid, 0) 抛错表示进程不存在,继续启动\n }\n }\n if (existsSync(STOPPED_PATH)) unlinkSync(STOPPED_PATH);\n\n // stderr 走 pipe 由父 CLI 订阅:子进程 ready 前(pino logger 未接管)的启动错误\n // 会被捕获;ready 后父 detach,pino 接管所有输出到 service.log。\n // start 命令必须等 daemon socket 可连接后再退出;否则用户会看到“启动成功”,实际服务还没就绪。\n const serveArgs = [\"--profile\", PROFILE_NAME, ...daemonRelayArgs(options?.relayName)];\n const child = spawnScript(new URL(\"./serve\", import.meta.url), serveArgs, {\n env: { ...process.env },\n stdio: [\"ignore\", \"ignore\", \"pipe\"],\n unref: false,\n });\n\n const stderrChunks: Buffer[] = [];\n child.stderr!.on(\"data\", (chunk: Buffer) => {\n stderrChunks.push(chunk);\n });\n\n // race: readiness handshake vs. 子进程先挂。子进程 ready 前就 exit 说明启动硬失败,\n // 不必再等到 30s 超时才报错。\n type Outcome =\n | { kind: \"ready\" }\n | { kind: \"timeout\" }\n | { kind: \"exited\"; code: number | null; signal: NodeJS.Signals | null };\n\n const readyOutcome: Promise<Outcome> = waitForServeReady(DAEMON_STARTUP_TIMEOUT_MS).then((ok) =>\n ok ? { kind: \"ready\" as const } : { kind: \"timeout\" as const },\n );\n const exitOutcome: Promise<Outcome> = new Promise((resolve) => {\n // 设 listener 前已经 exit 的边界:Node 记在 exitCode 上\n if (child.exitCode !== null) {\n resolve({ kind: \"exited\", code: child.exitCode, signal: child.signalCode });\n return;\n }\n child.once(\"exit\", (code, signal) => resolve({ kind: \"exited\", code, signal }));\n });\n\n const result = await Promise.race([readyOutcome, exitOutcome]);\n\n if (result.kind === \"ready\") {\n console.log(`Service started in background (PID ${child.pid})`);\n // ready 后 detach:摘 stderr 订阅 + destroy pipe + unref 子进程。\n // 单独 child.unref() 不够,父侧的 stderr pipe fd 还在事件循环里会让父 CLI 永不退出;\n // 必须 destroy 掉 pipe 才能真正释放 refcount。pino 已接管子进程的输出到 service.log。\n child.stderr!.removeAllListeners(\"data\");\n child.stderr!.destroy();\n child.unref();\n return;\n }\n\n // 失败路径:timeout 或 exited\n const stderrOutput = Buffer.concat(stderrChunks).toString(\"utf-8\").trim();\n if (result.kind === \"exited\") {\n console.error(`Service exited during startup (code=${result.code}, signal=${result.signal}).`);\n } else {\n console.error(`Service failed to become ready within ${DAEMON_STARTUP_TIMEOUT_MS / 1000}s.`);\n try {\n process.kill(child.pid!, \"SIGTERM\");\n } catch {\n // 子进程可能已自己退出,kill 失败不影响后续退出码\n }\n }\n if (stderrOutput) {\n console.error(\"--- child stderr ---\");\n console.error(stderrOutput);\n }\n process.exit(1);\n}\n\nconst program = new Command(\"dev-anywhere\")\n .description(\"Dev Anywhere - transparent local AI CLI proxy with remote control\")\n .version(pkg.version)\n .option(\"--profile <name>\", \"Use an isolated local proxy profile\")\n .allowUnknownOption()\n .allowExcessArguments()\n .action(async () => {\n if (!isInitialized()) {\n console.error(`Dev Anywhere is not initialized. Run \"dev-anywhere init\" first.`);\n process.exit(1);\n }\n // 延迟导入 terminal: CLI 的其他子命令(init/stop/status)不需要 PTY + xterm 相关依赖,\n // tsup 基于 dynamic import 自动代码分裂,避免所有命令都为 terminal 付出 14KB 额外启动成本。\n const { startTerminal } = await import(\"./terminal.js\");\n let invocation: ReturnType<typeof extractAgentInvocation>;\n try {\n invocation = extractAgentInvocation(cliArgsWithoutProfile);\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n const { provider, args } = invocation;\n await startTerminal(args, provider);\n });\n\n// serve 子命令组\nconst serve = new Command(\"serve\")\n .description(\"Manage the dev-anywhere background service\")\n .option(\"--profile <name>\", \"Use an isolated local proxy profile\")\n .option(\"-d, --daemon\", \"Run in background\")\n .action(async (opts) => {\n if (!isInitialized()) {\n console.error(`Dev Anywhere is not initialized. Run \"dev-anywhere init\" first.`);\n process.exit(1);\n }\n if (opts.daemon) {\n setDesiredDaemonRelay(undefined);\n await startDaemon();\n } else {\n // 延迟导入 serve: daemon 模式只需要 startDaemon(纯 spawn),不需要加载 70KB 的 serve bundle\n const { startService } = await import(\"./serve.js\");\n await startService();\n }\n });\n\nserve\n .command(\"start\")\n .description(\"Start the background service\")\n .option(\"--relay <name>\", \"Use a named relay from config\")\n .action(async (opts) => {\n if (!isInitialized()) {\n console.error(`Dev Anywhere is not initialized. Run \"dev-anywhere init\" first.`);\n process.exit(1);\n }\n setDesiredDaemonRelay(opts.relay);\n await startDaemon({ relayName: opts.relay });\n });\n\nserve\n .command(\"status\")\n .description(\"Show service status and active sessions\")\n .option(\"-w, --watch\", \"Continuous monitoring mode\")\n .option(\"-n, --interval <seconds>\", \"Refresh interval in seconds\", \"2\")\n .action(async (opts) => {\n if (opts.watch) {\n const intervalMs = Number(opts.interval) * 1000;\n let lastLines = await showStatus();\n setInterval(async () => {\n if (lastLines > 0) {\n process.stdout.write(`\\x1B[${lastLines}A\\x1B[J`);\n }\n lastLines = await showStatus();\n }, intervalMs);\n } else {\n await showStatus();\n }\n });\n\nserve\n .command(\"stop\")\n .description(\"Stop the background service\")\n .action(() => {\n stopService();\n });\n\nserve\n .command(\"restart\")\n .description(\"Restart the background service\")\n .option(\"--relay <name>\", \"Use a named relay from config\")\n .action(async (opts) => {\n setDesiredDaemonRelay(opts.relay);\n stopService();\n await startDaemon({ relayName: opts.relay });\n });\n\nprogram.addCommand(serve);\n\nprogram\n .command(\"init\")\n .description(\"Initialize dev-anywhere workspace (~/.dev-anywhere)\")\n .action(() => {\n if (isInitialized()) {\n console.log(`Already initialized. Config at ${CONFIG_PATH}`);\n return;\n }\n initWorkspace();\n console.log(\"Initialized ~/.dev-anywhere/\");\n console.log(`Edit ${CONFIG_PATH} to configure relay server URL.`);\n });\n\n// pnpm run dev -- args 会在参数前插入 \"--\"。根脚本和用户命令都可能再加一层\n// 分隔符,所以这里过滤所有前导分隔符,再交给 Commander 和 provider 参数解析。\nconst cliArgs = normalizeCliArgs(process.argv.slice(2));\nconst cliArgsWithoutProfile = stripProxyProfileArgs(cliArgs);\n\nprogram.parse(cliArgsWithoutProfile, { from: \"user\" });\n","import type { ProviderId } from \"./providers/index.js\";\n\nexport function normalizeCliArgs(args: string[]): string[] {\n const normalized = [...args];\n while (normalized[0] === \"--\") {\n normalized.shift();\n }\n return normalized;\n}\n\nexport function stripProxyProfileArgs(args: string[]): string[] {\n const result: string[] = [];\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n if (arg === \"claude\" || arg === \"codex\") {\n result.push(...args.slice(i));\n break;\n }\n if (arg === \"--profile\") {\n i++;\n continue;\n }\n if (arg.startsWith(\"--profile=\")) {\n continue;\n }\n result.push(arg);\n }\n return result;\n}\n\nexport function extractAgentInvocation(args: string[]): { provider: ProviderId; args: string[] } {\n const [agent, ...providerArgs] = args;\n if (agent !== \"claude\" && agent !== \"codex\") {\n throw new Error(\n 'Missing Agent CLI. Use \"dev-anywhere claude ...\" or \"dev-anywhere codex ...\".',\n );\n }\n return { provider: agent, args: providerArgs };\n}\n"],"mappings":"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","names":[]}
|