@i14ks/ccv 0.23.0 → 0.24.0
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 +10 -2
- package/bundle/ccv.mjs +1033 -139
- package/package.json +5 -2
- package/web/assets/{codemirror-BdKpW4CC.js → codemirror-BABguQzY.js} +1 -1
- package/web/assets/{index-B2BGvdag.js → index-BHEVBqv1.js} +1 -1
- package/web/assets/{index-D83he8x-.js → index-BJQdUP7a.js} +1 -1
- package/web/assets/{index-Dd7rh20x.js → index-BQiRpvdM.js} +1 -1
- package/web/assets/{index-BroMLvyS.js → index-BRzmWdWn.js} +1 -1
- package/web/assets/{index-Si6no75_.js → index-BWAAro79.js} +1 -1
- package/web/assets/{index-C59b0_Vk.js → index-BaKf7c69.js} +1 -1
- package/web/assets/{index-CRsndRFc.js → index-BmRYCxGv.js} +1 -1
- package/web/assets/{index-DqnCWDLh.js → index-BnqCpVA0.js} +1 -1
- package/web/assets/{index-yXtesgZ4.js → index-Bqjj9q2W.js} +1 -1
- package/web/assets/{index-UxKgaDrj.js → index-CIsgyM-R.js} +1 -1
- package/web/assets/{index-BrkwvvWk.js → index-CZppS1t2.js} +1 -1
- package/web/assets/{index-ChyP1fTD.js → index-Ck0zkLid.js} +1 -1
- package/web/assets/{index-YCUybqa_.js → index-CxF-ndAb.js} +1 -1
- package/web/assets/{index-DPrfFlZq.js → index-DW1Fnc9x.js} +1 -1
- package/web/assets/index-DXMZoXqv.js +136 -0
- package/web/assets/index-DafZE925.css +1 -0
- package/web/assets/{index-D6DYiY6f.js → index-Di0Nghq9.js} +1 -1
- package/web/assets/{index-CWTFMuFd.js → index-DnlEeQVW.js} +1 -1
- package/web/assets/{index-wsSNo9PM.js → index-DogVeywh.js} +1 -1
- package/web/assets/{index-CZuUjzhP.js → index-U9tL3Foh.js} +1 -1
- package/web/assets/{index-DXHZO0ym.js → index-dSYnVYDn.js} +1 -1
- package/web/index.html +2 -2
- package/web/assets/index-BCLbqlhA.js +0 -134
- package/web/assets/index-C6Y6TadO.css +0 -1
package/bundle/ccv.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// dist/ccv.js
|
|
4
|
-
import { spawn as
|
|
4
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
5
5
|
import { readFile as readFile17 } from "node:fs/promises";
|
|
6
|
-
import
|
|
6
|
+
import path25 from "node:path";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
8
|
import { parseArgs } from "node:util";
|
|
9
9
|
|
|
@@ -145,10 +145,10 @@ function envDefaults() {
|
|
|
145
145
|
|
|
146
146
|
// ../host/dist/server.js
|
|
147
147
|
import { createServer } from "node:http";
|
|
148
|
-
import { createReadStream, existsSync as
|
|
149
|
-
import
|
|
150
|
-
import { homedir as
|
|
151
|
-
import { randomUUID as
|
|
148
|
+
import { createReadStream, existsSync as existsSync5, statSync as statSync4 } from "node:fs";
|
|
149
|
+
import path24 from "node:path";
|
|
150
|
+
import { homedir as homedir7 } from "node:os";
|
|
151
|
+
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
152
152
|
import { WebSocketServer } from "ws";
|
|
153
153
|
import { renameSession as renameSession2 } from "@anthropic-ai/claude-agent-sdk";
|
|
154
154
|
|
|
@@ -187,12 +187,12 @@ function hashText(text) {
|
|
|
187
187
|
// ../host/dist/workspace-ids.js
|
|
188
188
|
function workspaceIdRemap(paths, sessionsOf) {
|
|
189
189
|
const byLegacy = /* @__PURE__ */ new Map();
|
|
190
|
-
for (const
|
|
191
|
-
const id = workspaceIdFromPath(
|
|
192
|
-
for (const legacy of formerWorkspaceIdsFromPath(
|
|
190
|
+
for (const path26 of paths) {
|
|
191
|
+
const id = workspaceIdFromPath(path26);
|
|
192
|
+
for (const legacy of formerWorkspaceIdsFromPath(path26)) {
|
|
193
193
|
const group = byLegacy.get(legacy) ?? [];
|
|
194
194
|
if (!group.some((target) => target.id === id))
|
|
195
|
-
group.push({ id, path:
|
|
195
|
+
group.push({ id, path: path26 });
|
|
196
196
|
byLegacy.set(legacy, group);
|
|
197
197
|
}
|
|
198
198
|
}
|
|
@@ -4217,18 +4217,865 @@ function describe2(error) {
|
|
|
4217
4217
|
return error instanceof Error ? error.message : String(error);
|
|
4218
4218
|
}
|
|
4219
4219
|
|
|
4220
|
+
// ../host/dist/codex-session.js
|
|
4221
|
+
import { EventEmitter as EventEmitter5 } from "node:events";
|
|
4222
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
4223
|
+
|
|
4224
|
+
// ../host/dist/codex-cli.js
|
|
4225
|
+
import { accessSync, constants as constants2, existsSync as existsSync2, readFileSync, statSync } from "node:fs";
|
|
4226
|
+
import { homedir as homedir4 } from "node:os";
|
|
4227
|
+
import path8 from "node:path";
|
|
4228
|
+
var CODEX_MISSING_HINT = "Codex CLI \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D. \u0423\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u0435: npm install -g @openai/codex, \u0437\u0430\u0442\u0435\u043C \u0432\u044B\u043F\u043E\u043B\u043D\u0438\u0442\u0435 codex login. \u0415\u0441\u043B\u0438 CLI \u0443\u0436\u0435 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D, \u0437\u0430\u0434\u0430\u0439\u0442\u0435 CCV_CODEX_PATH \u0438 \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u0435 ccv.";
|
|
4229
|
+
function codexLauncher() {
|
|
4230
|
+
const forced = process.env.CCV_CODEX_PATH;
|
|
4231
|
+
if (forced)
|
|
4232
|
+
return launcherFor(path8.resolve(forced));
|
|
4233
|
+
const dirs = (process.env.PATH ?? "").split(path8.delimiter).filter(Boolean);
|
|
4234
|
+
if (process.platform === "win32") {
|
|
4235
|
+
const local = process.env.LOCALAPPDATA ?? path8.join(homedir4(), "AppData", "Local");
|
|
4236
|
+
dirs.push(path8.join(local, "Programs", "OpenAI", "Codex", "bin"));
|
|
4237
|
+
dirs.push(path8.join(process.env.APPDATA ?? path8.join(homedir4(), "AppData", "Roaming"), "npm"));
|
|
4238
|
+
} else {
|
|
4239
|
+
dirs.push(path8.join(homedir4(), ".local", "bin"), "/usr/local/bin", "/opt/homebrew/bin");
|
|
4240
|
+
}
|
|
4241
|
+
for (const dir of dirs) {
|
|
4242
|
+
for (const name of process.platform === "win32" ? ["codex.exe", "codex.cmd", "codex"] : ["codex"]) {
|
|
4243
|
+
const found = launcherFor(path8.join(dir.replace(/^"|"$/g, ""), name));
|
|
4244
|
+
if (found)
|
|
4245
|
+
return found;
|
|
4246
|
+
}
|
|
4247
|
+
}
|
|
4248
|
+
return null;
|
|
4249
|
+
}
|
|
4250
|
+
function launcherFor(file) {
|
|
4251
|
+
try {
|
|
4252
|
+
if (!statSync(file).isFile())
|
|
4253
|
+
return null;
|
|
4254
|
+
if (/\.[cm]?js$/i.test(file))
|
|
4255
|
+
return { file: process.execPath, prefix: [file] };
|
|
4256
|
+
if (process.platform === "win32" && /\.(cmd|bat|ps1)$/i.test(file)) {
|
|
4257
|
+
const root = path8.dirname(file);
|
|
4258
|
+
const candidates = [path8.join(root, "node_modules", "@openai", "codex", "bin", "codex.js")];
|
|
4259
|
+
const shim = readFileSync(file, "utf8");
|
|
4260
|
+
for (const match of shim.matchAll(/(?:%dp0%|%~dp0|\$basedir)[\\/]([^"\r\n]+?\.[cm]?js)/gi)) {
|
|
4261
|
+
candidates.push(path8.resolve(root, match[1]));
|
|
4262
|
+
}
|
|
4263
|
+
const script = candidates.find((candidate) => existsSync2(candidate));
|
|
4264
|
+
return script ? { file: process.execPath, prefix: [script] } : null;
|
|
4265
|
+
}
|
|
4266
|
+
if (process.platform === "win32" && !/\.exe$/i.test(file))
|
|
4267
|
+
return null;
|
|
4268
|
+
accessSync(file, constants2.X_OK);
|
|
4269
|
+
return { file, prefix: [] };
|
|
4270
|
+
} catch {
|
|
4271
|
+
return null;
|
|
4272
|
+
}
|
|
4273
|
+
}
|
|
4274
|
+
|
|
4275
|
+
// ../host/dist/codex-rpc.js
|
|
4276
|
+
import { EventEmitter as EventEmitter4 } from "node:events";
|
|
4277
|
+
import { execFile as execFile4, spawn as spawn3 } from "node:child_process";
|
|
4278
|
+
import { createInterface as createInterface2 } from "node:readline";
|
|
4279
|
+
var CodexRpc = class extends EventEmitter4 {
|
|
4280
|
+
#child;
|
|
4281
|
+
#pending = /* @__PURE__ */ new Map();
|
|
4282
|
+
#nextId = 0;
|
|
4283
|
+
#closed = false;
|
|
4284
|
+
#stderr = "";
|
|
4285
|
+
constructor(launcher, cwd) {
|
|
4286
|
+
super();
|
|
4287
|
+
this.#child = spawn3(launcher.file, [...launcher.prefix, "app-server", "--listen", "stdio://"], {
|
|
4288
|
+
cwd,
|
|
4289
|
+
windowsHide: true,
|
|
4290
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
4291
|
+
env: { ...process.env, NO_COLOR: "1" }
|
|
4292
|
+
});
|
|
4293
|
+
createInterface2({ input: this.#child.stdout }).on("line", (line) => {
|
|
4294
|
+
let message;
|
|
4295
|
+
try {
|
|
4296
|
+
message = JSON.parse(line);
|
|
4297
|
+
} catch {
|
|
4298
|
+
return;
|
|
4299
|
+
}
|
|
4300
|
+
if (!message || typeof message !== "object")
|
|
4301
|
+
return;
|
|
4302
|
+
if (message.method) {
|
|
4303
|
+
this.emit("message", message);
|
|
4304
|
+
return;
|
|
4305
|
+
}
|
|
4306
|
+
const pending = typeof message.id === "number" ? this.#pending.get(message.id) : void 0;
|
|
4307
|
+
if (!pending)
|
|
4308
|
+
return;
|
|
4309
|
+
this.#pending.delete(message.id);
|
|
4310
|
+
clearTimeout(pending.timer);
|
|
4311
|
+
if (message.error)
|
|
4312
|
+
pending.reject(new Error(message.error.message));
|
|
4313
|
+
else
|
|
4314
|
+
pending.resolve(message.result);
|
|
4315
|
+
});
|
|
4316
|
+
this.#child.stderr.on("data", (chunk) => {
|
|
4317
|
+
this.#stderr = (this.#stderr + chunk.toString()).slice(-4e3);
|
|
4318
|
+
this.emit("stderr", chunk.toString());
|
|
4319
|
+
});
|
|
4320
|
+
this.#child.stdin.on("error", (error) => this.#finish(error));
|
|
4321
|
+
this.#child.on("error", (error) => this.#finish(error));
|
|
4322
|
+
this.#child.on("exit", (code) => this.#finish(new Error(`Codex \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043B\u0441\u044F (${code ?? "signal"}). ${this.#stderr.trim()}`)));
|
|
4323
|
+
}
|
|
4324
|
+
request(method, params = {}) {
|
|
4325
|
+
if (this.#closed)
|
|
4326
|
+
return Promise.reject(new Error("\u0421\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435 \u0441 Codex \u0437\u0430\u043A\u0440\u044B\u0442\u043E"));
|
|
4327
|
+
const id = ++this.#nextId;
|
|
4328
|
+
return new Promise((resolve, reject) => {
|
|
4329
|
+
const timer = setTimeout(() => {
|
|
4330
|
+
this.#pending.delete(id);
|
|
4331
|
+
reject(new Error(`Codex \u043D\u0435 \u043E\u0442\u0432\u0435\u0442\u0438\u043B \u043D\u0430 ${method} \u0437\u0430 60 \u0441\u0435\u043A\u0443\u043D\u0434`));
|
|
4332
|
+
}, 6e4);
|
|
4333
|
+
this.#pending.set(id, { resolve: (value) => resolve(value), reject, timer });
|
|
4334
|
+
this.write({ id, method, params });
|
|
4335
|
+
});
|
|
4336
|
+
}
|
|
4337
|
+
write(message) {
|
|
4338
|
+
if (!this.#closed)
|
|
4339
|
+
this.#child.stdin.write(JSON.stringify(message) + "\n");
|
|
4340
|
+
}
|
|
4341
|
+
close() {
|
|
4342
|
+
this.#finish(new Error("\u0421\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435 \u0441 Codex \u0437\u0430\u043A\u0440\u044B\u0442\u043E"), false);
|
|
4343
|
+
this.#child.stdin.end();
|
|
4344
|
+
const child = this.#child;
|
|
4345
|
+
if (child.exitCode !== null)
|
|
4346
|
+
return;
|
|
4347
|
+
if (process.platform === "win32" && child.pid) {
|
|
4348
|
+
execFile4("taskkill", ["/pid", String(child.pid), "/T", "/F"], { windowsHide: true }, () => {
|
|
4349
|
+
if (child.exitCode === null)
|
|
4350
|
+
child.kill();
|
|
4351
|
+
});
|
|
4352
|
+
} else
|
|
4353
|
+
child.kill("SIGTERM");
|
|
4354
|
+
}
|
|
4355
|
+
#finish(error, notify = true) {
|
|
4356
|
+
if (this.#closed)
|
|
4357
|
+
return;
|
|
4358
|
+
this.#closed = true;
|
|
4359
|
+
for (const pending of this.#pending.values()) {
|
|
4360
|
+
clearTimeout(pending.timer);
|
|
4361
|
+
pending.reject(error);
|
|
4362
|
+
}
|
|
4363
|
+
this.#pending.clear();
|
|
4364
|
+
if (notify)
|
|
4365
|
+
this.emit("exit", error);
|
|
4366
|
+
}
|
|
4367
|
+
};
|
|
4368
|
+
|
|
4369
|
+
// ../host/dist/codex-session.js
|
|
4370
|
+
function codexPolicy(mode) {
|
|
4371
|
+
switch (mode) {
|
|
4372
|
+
case "default":
|
|
4373
|
+
return { approvalPolicy: "untrusted", sandbox: "workspace-write" };
|
|
4374
|
+
case "acceptEdits":
|
|
4375
|
+
return { approvalPolicy: "on-request", sandbox: "workspace-write" };
|
|
4376
|
+
case "plan":
|
|
4377
|
+
return { approvalPolicy: "untrusted", sandbox: "read-only" };
|
|
4378
|
+
case "bypassPermissions":
|
|
4379
|
+
return { approvalPolicy: "never", sandbox: "danger-full-access" };
|
|
4380
|
+
default:
|
|
4381
|
+
throw new Error(`Codex \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0440\u0435\u0436\u0438\u043C \u043F\u0440\u0430\u0432 \xAB${mode}\xBB`);
|
|
4382
|
+
}
|
|
4383
|
+
}
|
|
4384
|
+
function codexUsage(limits) {
|
|
4385
|
+
const window = (value) => value ? {
|
|
4386
|
+
utilization: Math.min(100, Math.max(0, value.usedPercent)),
|
|
4387
|
+
resetsAt: value.resetsAt ? new Date(value.resetsAt * 1e3).toISOString() : ""
|
|
4388
|
+
} : null;
|
|
4389
|
+
return {
|
|
4390
|
+
available: !!(limits.primary || limits.secondary),
|
|
4391
|
+
plan: limits.planType ?? "",
|
|
4392
|
+
fiveHour: window(limits.primary),
|
|
4393
|
+
sevenDay: window(limits.secondary),
|
|
4394
|
+
sevenDayOpus: null,
|
|
4395
|
+
fetchedAt: Date.now()
|
|
4396
|
+
};
|
|
4397
|
+
}
|
|
4398
|
+
var CodexSession = class extends EventEmitter5 {
|
|
4399
|
+
provider = "codex";
|
|
4400
|
+
id;
|
|
4401
|
+
workspaceId;
|
|
4402
|
+
cwd;
|
|
4403
|
+
journal = new Journal();
|
|
4404
|
+
#store;
|
|
4405
|
+
#record;
|
|
4406
|
+
#history = Promise.resolve([]);
|
|
4407
|
+
#rpc = null;
|
|
4408
|
+
#ready = Promise.resolve();
|
|
4409
|
+
#state = "starting";
|
|
4410
|
+
#lastTurn = null;
|
|
4411
|
+
#capabilities = null;
|
|
4412
|
+
#usage = null;
|
|
4413
|
+
#context = null;
|
|
4414
|
+
#turnId = null;
|
|
4415
|
+
#turnStartedAt = 0;
|
|
4416
|
+
#turnUsage = null;
|
|
4417
|
+
#totalUsage = null;
|
|
4418
|
+
#turnUsageBaseline = null;
|
|
4419
|
+
#interruptRequested = false;
|
|
4420
|
+
#busy = false;
|
|
4421
|
+
#startingTurn = false;
|
|
4422
|
+
#generation = 0;
|
|
4423
|
+
#queue = [];
|
|
4424
|
+
#pending = /* @__PURE__ */ new Map();
|
|
4425
|
+
#texts = /* @__PURE__ */ new Map();
|
|
4426
|
+
#tools = /* @__PURE__ */ new Set();
|
|
4427
|
+
#items = /* @__PURE__ */ new Map();
|
|
4428
|
+
#titleIsDefault;
|
|
4429
|
+
#unsaved = [];
|
|
4430
|
+
#flushTimer = null;
|
|
4431
|
+
constructor(options2) {
|
|
4432
|
+
super();
|
|
4433
|
+
this.workspaceId = options2.workspaceId;
|
|
4434
|
+
this.cwd = options2.cwd;
|
|
4435
|
+
this.#store = options2.store;
|
|
4436
|
+
this.#record = options2.record ? { ...options2.record } : {
|
|
4437
|
+
id: randomUUID3(),
|
|
4438
|
+
conversationId: null,
|
|
4439
|
+
workspaceId: options2.workspaceId,
|
|
4440
|
+
cwd: options2.cwd,
|
|
4441
|
+
title: options2.defaultTitle ?? null,
|
|
4442
|
+
model: options2.model ?? null,
|
|
4443
|
+
permissionMode: options2.permissionMode ?? "default",
|
|
4444
|
+
effort: null,
|
|
4445
|
+
createdAt: Date.now(),
|
|
4446
|
+
updatedAt: Date.now()
|
|
4447
|
+
};
|
|
4448
|
+
if (options2.permissionMode)
|
|
4449
|
+
this.#record.permissionMode = options2.permissionMode;
|
|
4450
|
+
if (options2.model)
|
|
4451
|
+
this.#record.model = options2.model;
|
|
4452
|
+
this.id = this.#record.id;
|
|
4453
|
+
this.#context = this.#record.context ?? null;
|
|
4454
|
+
if (!options2.record?.conversationId) {
|
|
4455
|
+
this.#totalUsage = { inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheCreationTokens: 0 };
|
|
4456
|
+
}
|
|
4457
|
+
this.#titleIsDefault = !options2.record;
|
|
4458
|
+
}
|
|
4459
|
+
get state() {
|
|
4460
|
+
return this.#state;
|
|
4461
|
+
}
|
|
4462
|
+
get capabilities() {
|
|
4463
|
+
return this.#capabilities;
|
|
4464
|
+
}
|
|
4465
|
+
get claudeSessionId() {
|
|
4466
|
+
return this.id;
|
|
4467
|
+
}
|
|
4468
|
+
get parentSessionId() {
|
|
4469
|
+
return null;
|
|
4470
|
+
}
|
|
4471
|
+
get usage() {
|
|
4472
|
+
return this.#usage;
|
|
4473
|
+
}
|
|
4474
|
+
get context() {
|
|
4475
|
+
return this.#context;
|
|
4476
|
+
}
|
|
4477
|
+
history() {
|
|
4478
|
+
return this.#history;
|
|
4479
|
+
}
|
|
4480
|
+
summary() {
|
|
4481
|
+
return {
|
|
4482
|
+
id: this.id,
|
|
4483
|
+
provider: this.provider,
|
|
4484
|
+
claudeSessionId: this.id,
|
|
4485
|
+
workspaceId: this.workspaceId,
|
|
4486
|
+
cwd: this.cwd,
|
|
4487
|
+
parentSessionId: null,
|
|
4488
|
+
title: this.#record.title,
|
|
4489
|
+
state: this.#state,
|
|
4490
|
+
lastTurn: this.#lastTurn,
|
|
4491
|
+
backgroundWork: false,
|
|
4492
|
+
tasks: [],
|
|
4493
|
+
model: this.#record.model,
|
|
4494
|
+
permissionMode: this.#record.permissionMode,
|
|
4495
|
+
effort: this.#record.effort,
|
|
4496
|
+
ultracode: false,
|
|
4497
|
+
thinking: true,
|
|
4498
|
+
switchModelsOnFlag: false,
|
|
4499
|
+
createdAt: this.#record.createdAt,
|
|
4500
|
+
updatedAt: this.#record.updatedAt,
|
|
4501
|
+
lastSeq: this.journal.lastSeq,
|
|
4502
|
+
totalCostUsd: 0
|
|
4503
|
+
};
|
|
4504
|
+
}
|
|
4505
|
+
start() {
|
|
4506
|
+
this.#history = this.#store.readEvents(this.id).then((entries) => {
|
|
4507
|
+
const pending = /* @__PURE__ */ new Set();
|
|
4508
|
+
for (const { event } of entries) {
|
|
4509
|
+
if (event.kind === "permission.request")
|
|
4510
|
+
pending.add(event.requestId);
|
|
4511
|
+
if (event.kind === "permission.resolved")
|
|
4512
|
+
pending.delete(event.requestId);
|
|
4513
|
+
}
|
|
4514
|
+
for (const requestId of pending)
|
|
4515
|
+
entries.push({ seq: entries.length + 1, ts: Date.now(), event: {
|
|
4516
|
+
kind: "permission.resolved",
|
|
4517
|
+
requestId,
|
|
4518
|
+
decision: "deny",
|
|
4519
|
+
reason: "\u041F\u0440\u0435\u0434\u044B\u0434\u0443\u0449\u0438\u0439 \u043F\u0440\u043E\u0446\u0435\u0441\u0441 Codex \u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043D"
|
|
4520
|
+
} });
|
|
4521
|
+
return entries;
|
|
4522
|
+
});
|
|
4523
|
+
this.#launch();
|
|
4524
|
+
}
|
|
4525
|
+
#launch() {
|
|
4526
|
+
const generation = ++this.#generation;
|
|
4527
|
+
this.#ready = this.#connect(generation);
|
|
4528
|
+
void this.#ready.catch((error) => {
|
|
4529
|
+
if (generation === this.#generation)
|
|
4530
|
+
this.#fail(error);
|
|
4531
|
+
});
|
|
4532
|
+
}
|
|
4533
|
+
async #connect(generation) {
|
|
4534
|
+
await this.#history;
|
|
4535
|
+
await this.#store.save(this.#record);
|
|
4536
|
+
if (generation !== this.#generation)
|
|
4537
|
+
return;
|
|
4538
|
+
const reason = networkGuard.blockedReason();
|
|
4539
|
+
if (reason)
|
|
4540
|
+
throw new Error(reason);
|
|
4541
|
+
const launcher = codexLauncher();
|
|
4542
|
+
if (!launcher)
|
|
4543
|
+
throw new Error(CODEX_MISSING_HINT);
|
|
4544
|
+
const rpc = new CodexRpc(launcher, this.cwd);
|
|
4545
|
+
this.#rpc = rpc;
|
|
4546
|
+
rpc.on("message", (message) => {
|
|
4547
|
+
if (this.#rpc === rpc)
|
|
4548
|
+
this.#message(message);
|
|
4549
|
+
});
|
|
4550
|
+
rpc.on("stderr", (data) => this.emit("stderr", data));
|
|
4551
|
+
rpc.on("exit", (error) => {
|
|
4552
|
+
if (this.#rpc === rpc)
|
|
4553
|
+
this.#fail(error);
|
|
4554
|
+
});
|
|
4555
|
+
await rpc.request("initialize", { clientInfo: { name: "ccv", title: "Claude Code Visual", version: "0.1.0" } });
|
|
4556
|
+
if (this.#rpc !== rpc)
|
|
4557
|
+
return;
|
|
4558
|
+
rpc.write({ method: "initialized", params: {} });
|
|
4559
|
+
const policy = codexPolicy(this.#record.permissionMode);
|
|
4560
|
+
const result = await rpc.request(this.#record.conversationId ? "thread/resume" : "thread/start", {
|
|
4561
|
+
...this.#record.conversationId ? { threadId: this.#record.conversationId } : {},
|
|
4562
|
+
cwd: this.cwd,
|
|
4563
|
+
...this.#record.model ? { model: this.#record.model } : {},
|
|
4564
|
+
approvalPolicy: policy.approvalPolicy,
|
|
4565
|
+
sandbox: policy.sandbox
|
|
4566
|
+
});
|
|
4567
|
+
if (this.#rpc !== rpc)
|
|
4568
|
+
return;
|
|
4569
|
+
this.#record.conversationId = result.thread.id;
|
|
4570
|
+
this.#record.model = result.model;
|
|
4571
|
+
if (!this.#record.effort && result.reasoningEffort)
|
|
4572
|
+
this.#record.effort = result.reasoningEffort;
|
|
4573
|
+
await this.#store.save(this.#record);
|
|
4574
|
+
if (this.#rpc !== rpc)
|
|
4575
|
+
return;
|
|
4576
|
+
this.#capabilities = {
|
|
4577
|
+
cwd: this.cwd,
|
|
4578
|
+
model: result.model,
|
|
4579
|
+
permissionMode: this.#record.permissionMode,
|
|
4580
|
+
slashCommands: [],
|
|
4581
|
+
commands: [],
|
|
4582
|
+
models: [],
|
|
4583
|
+
tools: ["Bash", "apply_patch", "web_search"],
|
|
4584
|
+
agents: [],
|
|
4585
|
+
mcpServers: [],
|
|
4586
|
+
flags: []
|
|
4587
|
+
};
|
|
4588
|
+
this.emit("capabilities");
|
|
4589
|
+
this.#setState("idle");
|
|
4590
|
+
void this.#loadModels(rpc).catch((error) => {
|
|
4591
|
+
if (this.#rpc === rpc)
|
|
4592
|
+
this.#notice(error);
|
|
4593
|
+
});
|
|
4594
|
+
void this.refreshUsage();
|
|
4595
|
+
}
|
|
4596
|
+
async #loadModels(rpc) {
|
|
4597
|
+
const models = [];
|
|
4598
|
+
let cursor = null;
|
|
4599
|
+
do {
|
|
4600
|
+
const page = await rpc.request("model/list", { cursor, limit: 100 });
|
|
4601
|
+
for (const model of page.data) {
|
|
4602
|
+
const levels = (model.supportedReasoningEfforts ?? []).map((e) => e.reasoningEffort).filter((e) => ["low", "medium", "high", "xhigh", "max"].includes(e));
|
|
4603
|
+
models.push({
|
|
4604
|
+
value: model.model,
|
|
4605
|
+
resolvedModel: model.model,
|
|
4606
|
+
displayName: model.displayName,
|
|
4607
|
+
description: model.description,
|
|
4608
|
+
supportsEffort: levels.length > 0,
|
|
4609
|
+
effortLevels: levels,
|
|
4610
|
+
supportsThinking: false,
|
|
4611
|
+
supportsAutoMode: false
|
|
4612
|
+
});
|
|
4613
|
+
}
|
|
4614
|
+
cursor = page.nextCursor;
|
|
4615
|
+
} while (cursor && this.#rpc === rpc);
|
|
4616
|
+
if (this.#capabilities && this.#rpc === rpc) {
|
|
4617
|
+
this.#capabilities.models = models;
|
|
4618
|
+
this.emit("capabilities");
|
|
4619
|
+
}
|
|
4620
|
+
}
|
|
4621
|
+
sendPrompt(text, images) {
|
|
4622
|
+
const reason = networkGuard.blockedReason();
|
|
4623
|
+
if (reason) {
|
|
4624
|
+
this.#notice(new Error(reason));
|
|
4625
|
+
return;
|
|
4626
|
+
}
|
|
4627
|
+
if (this.#state === "closed" || this.#state === "error") {
|
|
4628
|
+
this.#notice(new Error("\u041F\u0435\u0440\u0435\u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0438\u0442\u0435 \u0441\u0435\u0441\u0441\u0438\u044E Codex \u043F\u0435\u0440\u0435\u0434 \u043E\u0442\u043F\u0440\u0430\u0432\u043A\u043E\u0439"));
|
|
4629
|
+
return;
|
|
4630
|
+
}
|
|
4631
|
+
if (!text.trim() && !images?.length)
|
|
4632
|
+
return;
|
|
4633
|
+
this.#append({ kind: "user.message", text, ...images?.length ? { images } : {} });
|
|
4634
|
+
if (this.#titleIsDefault) {
|
|
4635
|
+
this.#record.title = text.trim().split("\n")[0].slice(0, 100) || "Codex";
|
|
4636
|
+
this.#titleIsDefault = false;
|
|
4637
|
+
this.emit("summary", this.summary());
|
|
4638
|
+
}
|
|
4639
|
+
this.#queue.push({ text, images });
|
|
4640
|
+
void this.#drain();
|
|
4641
|
+
}
|
|
4642
|
+
async #drain() {
|
|
4643
|
+
if (this.#busy || this.#startingTurn || !this.#queue.length)
|
|
4644
|
+
return;
|
|
4645
|
+
const generation = this.#generation;
|
|
4646
|
+
this.#busy = true;
|
|
4647
|
+
this.#startingTurn = true;
|
|
4648
|
+
try {
|
|
4649
|
+
await this.#ready;
|
|
4650
|
+
if (generation !== this.#generation)
|
|
4651
|
+
return;
|
|
4652
|
+
const prompt = this.#queue.shift();
|
|
4653
|
+
if (!prompt || !this.#rpc || this.#state === "closed" || this.#state === "error") {
|
|
4654
|
+
this.#busy = false;
|
|
4655
|
+
return;
|
|
4656
|
+
}
|
|
4657
|
+
const reason = networkGuard.blockedReason();
|
|
4658
|
+
if (reason)
|
|
4659
|
+
throw new Error(reason);
|
|
4660
|
+
this.#turnStartedAt = Date.now();
|
|
4661
|
+
this.#turnUsage = null;
|
|
4662
|
+
this.#turnUsageBaseline = this.#totalUsage;
|
|
4663
|
+
this.#lastTurn = null;
|
|
4664
|
+
this.#setState("running");
|
|
4665
|
+
const policy = codexPolicy(this.#record.permissionMode);
|
|
4666
|
+
const sandboxPolicy = this.#record.permissionMode === "bypassPermissions" ? { type: "dangerFullAccess" } : this.#record.permissionMode === "plan" ? { type: "readOnly", networkAccess: false } : {
|
|
4667
|
+
type: "workspaceWrite",
|
|
4668
|
+
writableRoots: [this.cwd],
|
|
4669
|
+
networkAccess: false,
|
|
4670
|
+
excludeTmpdirEnvVar: false,
|
|
4671
|
+
excludeSlashTmp: false
|
|
4672
|
+
};
|
|
4673
|
+
const result = await this.#rpc.request("turn/start", {
|
|
4674
|
+
threadId: this.#record.conversationId,
|
|
4675
|
+
cwd: this.cwd,
|
|
4676
|
+
input: [{ type: "text", text: prompt.text, text_elements: [] }, ...(prompt.images ?? []).map((image) => ({
|
|
4677
|
+
type: "image",
|
|
4678
|
+
url: `data:${image.mediaType};base64,${image.data}`
|
|
4679
|
+
}))],
|
|
4680
|
+
model: this.#record.model,
|
|
4681
|
+
effort: this.#record.effort,
|
|
4682
|
+
approvalPolicy: policy.approvalPolicy,
|
|
4683
|
+
sandboxPolicy
|
|
4684
|
+
});
|
|
4685
|
+
if (this.#busy)
|
|
4686
|
+
this.#turnId = result.turn.id;
|
|
4687
|
+
if (this.#interruptRequested && this.#turnId)
|
|
4688
|
+
await this.interrupt();
|
|
4689
|
+
} catch (error) {
|
|
4690
|
+
if (generation === this.#generation)
|
|
4691
|
+
this.#fail(error);
|
|
4692
|
+
} finally {
|
|
4693
|
+
if (generation === this.#generation) {
|
|
4694
|
+
this.#startingTurn = false;
|
|
4695
|
+
if (!this.#busy)
|
|
4696
|
+
void this.#drain();
|
|
4697
|
+
}
|
|
4698
|
+
}
|
|
4699
|
+
}
|
|
4700
|
+
#message(message) {
|
|
4701
|
+
const p = message.params ?? {};
|
|
4702
|
+
if (message.id !== void 0 && message.method) {
|
|
4703
|
+
this.#request(message.id, message.method, p);
|
|
4704
|
+
return;
|
|
4705
|
+
}
|
|
4706
|
+
if (p.threadId && p.threadId !== this.#record.conversationId)
|
|
4707
|
+
return;
|
|
4708
|
+
switch (message.method) {
|
|
4709
|
+
case "turn/started": {
|
|
4710
|
+
const turn = p.turn;
|
|
4711
|
+
this.#turnId = turn.id;
|
|
4712
|
+
break;
|
|
4713
|
+
}
|
|
4714
|
+
case "item/agentMessage/delta":
|
|
4715
|
+
case "item/reasoning/summaryTextDelta": {
|
|
4716
|
+
const id = String(p.itemId);
|
|
4717
|
+
const thinking = message.method !== "item/agentMessage/delta";
|
|
4718
|
+
const key = `${id}:${thinking ? "thinking" : "text"}`;
|
|
4719
|
+
const delta = String(p.delta ?? "");
|
|
4720
|
+
const block = this.#texts.get(key) ?? { text: "", thinking };
|
|
4721
|
+
block.text += delta;
|
|
4722
|
+
this.#texts.set(key, block);
|
|
4723
|
+
this.#append({ kind: thinking ? "thinking.delta" : "assistant.delta", blockId: key, text: delta });
|
|
4724
|
+
break;
|
|
4725
|
+
}
|
|
4726
|
+
case "item/started":
|
|
4727
|
+
this.#item(p.item, false);
|
|
4728
|
+
break;
|
|
4729
|
+
case "item/completed":
|
|
4730
|
+
this.#item(p.item, true);
|
|
4731
|
+
break;
|
|
4732
|
+
case "thread/tokenUsage/updated": {
|
|
4733
|
+
const usage = p.tokenUsage;
|
|
4734
|
+
if (usage?.last && usage.modelContextWindow) {
|
|
4735
|
+
this.#context = { tokens: usage.last.totalTokens, maxTokens: usage.modelContextWindow, fetchedAt: Date.now() };
|
|
4736
|
+
this.#record.context = this.#context;
|
|
4737
|
+
this.emit("context", this.#context);
|
|
4738
|
+
}
|
|
4739
|
+
if (usage?.total) {
|
|
4740
|
+
const total = {
|
|
4741
|
+
inputTokens: usage.total.inputTokens,
|
|
4742
|
+
outputTokens: usage.total.outputTokens,
|
|
4743
|
+
cacheReadTokens: usage.total.cachedInputTokens ?? 0,
|
|
4744
|
+
cacheCreationTokens: usage.total.cacheWriteInputTokens ?? 0
|
|
4745
|
+
};
|
|
4746
|
+
if (this.#busy && this.#turnUsageBaseline) {
|
|
4747
|
+
const baseline = this.#turnUsageBaseline;
|
|
4748
|
+
this.#turnUsage = {
|
|
4749
|
+
inputTokens: Math.max(0, total.inputTokens - baseline.inputTokens),
|
|
4750
|
+
outputTokens: Math.max(0, total.outputTokens - baseline.outputTokens),
|
|
4751
|
+
cacheReadTokens: Math.max(0, total.cacheReadTokens - baseline.cacheReadTokens),
|
|
4752
|
+
cacheCreationTokens: Math.max(0, total.cacheCreationTokens - baseline.cacheCreationTokens)
|
|
4753
|
+
};
|
|
4754
|
+
}
|
|
4755
|
+
this.#totalUsage = total;
|
|
4756
|
+
}
|
|
4757
|
+
break;
|
|
4758
|
+
}
|
|
4759
|
+
case "account/rateLimits/updated":
|
|
4760
|
+
if (p.rateLimits)
|
|
4761
|
+
this.#setUsage(p.rateLimits);
|
|
4762
|
+
break;
|
|
4763
|
+
case "serverRequest/resolved": {
|
|
4764
|
+
const requestId = String(p.requestId);
|
|
4765
|
+
if (this.#pending.delete(requestId)) {
|
|
4766
|
+
this.#append({ kind: "permission.resolved", requestId, decision: "deny", reason: "\u0417\u0430\u043F\u0440\u043E\u0441 \u0437\u0430\u043A\u0440\u044B\u0442 Codex" });
|
|
4767
|
+
this.#setState(this.#pending.size ? "waiting_permission" : "running");
|
|
4768
|
+
}
|
|
4769
|
+
break;
|
|
4770
|
+
}
|
|
4771
|
+
case "turn/completed": {
|
|
4772
|
+
const turn = p.turn;
|
|
4773
|
+
this.#lastTurn = turn.status === "completed" ? "completed" : turn.status === "interrupted" ? "interrupted" : "failed";
|
|
4774
|
+
if (turn.error?.message)
|
|
4775
|
+
this.#notice(new Error(turn.error.message));
|
|
4776
|
+
this.#finishTurn(turn.status, turn.durationMs);
|
|
4777
|
+
void this.refreshUsage();
|
|
4778
|
+
break;
|
|
4779
|
+
}
|
|
4780
|
+
case "error": {
|
|
4781
|
+
const error = p.error;
|
|
4782
|
+
this.#notice(new Error(error?.message ?? "\u041E\u0448\u0438\u0431\u043A\u0430 Codex"));
|
|
4783
|
+
break;
|
|
4784
|
+
}
|
|
4785
|
+
}
|
|
4786
|
+
}
|
|
4787
|
+
#item(item, done) {
|
|
4788
|
+
if (!item)
|
|
4789
|
+
return;
|
|
4790
|
+
this.#items.set(item.id, item);
|
|
4791
|
+
if (item.type === "agentMessage" || item.type === "reasoning" || item.type === "plan") {
|
|
4792
|
+
if (!done)
|
|
4793
|
+
return;
|
|
4794
|
+
const thinking = item.type === "reasoning";
|
|
4795
|
+
const key = `${item.id}:${thinking ? "thinking" : "text"}`;
|
|
4796
|
+
const text = item.text ?? item.summary?.join("\n") ?? this.#texts.get(key)?.text ?? "";
|
|
4797
|
+
this.#texts.delete(key);
|
|
4798
|
+
if (text)
|
|
4799
|
+
this.#append({ kind: thinking ? "assistant.thinking" : "assistant.text", text, blockId: key });
|
|
4800
|
+
return;
|
|
4801
|
+
}
|
|
4802
|
+
if (!["commandExecution", "fileChange", "mcpToolCall", "webSearch", "imageView", "collabAgentToolCall"].includes(item.type))
|
|
4803
|
+
return;
|
|
4804
|
+
if (!this.#tools.has(item.id)) {
|
|
4805
|
+
this.#tools.add(item.id);
|
|
4806
|
+
const name = item.type === "commandExecution" ? "Bash" : item.type === "fileChange" ? "apply_patch" : item.type === "mcpToolCall" ? `mcp__${item.server}__${item.tool}` : item.type;
|
|
4807
|
+
const input = item.type === "commandExecution" ? { command: item.command, cwd: item.cwd } : item.type === "fileChange" ? { changes: item.changes, file_path: item.changes?.[0]?.path } : item.arguments ?? item.action ?? { query: item.query };
|
|
4808
|
+
this.#append({ kind: "tool.use", toolUseId: item.id, name, input });
|
|
4809
|
+
}
|
|
4810
|
+
if (done) {
|
|
4811
|
+
this.#tools.delete(item.id);
|
|
4812
|
+
const output = item.aggregatedOutput ?? (item.changes ? item.changes.map((c) => `${c.path}
|
|
4813
|
+
${c.diff}`).join("\n") : typeof item.result === "string" ? item.result : JSON.stringify(item.error ?? item.result ?? item.action ?? "\u0413\u043E\u0442\u043E\u0432\u043E"));
|
|
4814
|
+
this.#append({
|
|
4815
|
+
kind: "tool.result",
|
|
4816
|
+
toolUseId: item.id,
|
|
4817
|
+
content: output,
|
|
4818
|
+
isError: ["failed", "declined"].includes(item.status ?? "") || item.exitCode != null && item.exitCode !== 0 || !!item.error
|
|
4819
|
+
});
|
|
4820
|
+
}
|
|
4821
|
+
}
|
|
4822
|
+
#request(id, method, params) {
|
|
4823
|
+
const requestId = String(id);
|
|
4824
|
+
const questions = method === "item/tool/requestUserInput" ? params.questions.map((q) => ({ ...q, options: q.options ?? [], multiSelect: false })) : void 0;
|
|
4825
|
+
const known = [
|
|
4826
|
+
"item/commandExecution/requestApproval",
|
|
4827
|
+
"item/fileChange/requestApproval",
|
|
4828
|
+
"item/permissions/requestApproval",
|
|
4829
|
+
"item/tool/requestUserInput"
|
|
4830
|
+
];
|
|
4831
|
+
if (!known.includes(method)) {
|
|
4832
|
+
this.#rpc?.write({ id, error: { code: -32601, message: `CCV does not support ${method}` } });
|
|
4833
|
+
this.#notice(new Error(`Codex \u0437\u0430\u043F\u0440\u043E\u0441\u0438\u043B \u043D\u0435\u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043C\u043E\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435: ${method}`));
|
|
4834
|
+
return;
|
|
4835
|
+
}
|
|
4836
|
+
this.#pending.set(requestId, { id, method, params, questions });
|
|
4837
|
+
this.#append({
|
|
4838
|
+
kind: "permission.request",
|
|
4839
|
+
requestId,
|
|
4840
|
+
toolUseId: String(params.itemId ?? requestId),
|
|
4841
|
+
toolName: questions ? "AskUserQuestion" : method.includes("commandExecution") ? "Bash" : method.includes("fileChange") ? "apply_patch" : "Codex permissions",
|
|
4842
|
+
input: { ...params, ...this.#items.get(String(params.itemId))?.changes ? { changes: this.#items.get(String(params.itemId)).changes } : {} },
|
|
4843
|
+
...typeof params.reason === "string" ? { reason: params.reason } : {},
|
|
4844
|
+
...questions ? { questions } : {}
|
|
4845
|
+
});
|
|
4846
|
+
this.#setState("waiting_permission");
|
|
4847
|
+
}
|
|
4848
|
+
respondPermission(requestId, decision, reason, answers) {
|
|
4849
|
+
const request2 = this.#pending.get(requestId);
|
|
4850
|
+
if (!request2)
|
|
4851
|
+
return;
|
|
4852
|
+
let result = { decision: decision === "allow" ? "accept" : "decline" };
|
|
4853
|
+
if (request2.questions) {
|
|
4854
|
+
result = { answers: Object.fromEntries(request2.questions.map((q) => [q.id, {
|
|
4855
|
+
answers: decision === "allow" ? [answers?.[q.question] ?? ""] : []
|
|
4856
|
+
}])) };
|
|
4857
|
+
} else if (request2.method === "item/permissions/requestApproval") {
|
|
4858
|
+
result = { permissions: decision === "allow" ? request2.params.permissions : {}, scope: "turn" };
|
|
4859
|
+
}
|
|
4860
|
+
this.#rpc?.write({ id: request2.id, result });
|
|
4861
|
+
this.#pending.delete(requestId);
|
|
4862
|
+
this.#append({ kind: "permission.resolved", requestId, decision, reason, answers });
|
|
4863
|
+
this.#setState(this.#pending.size ? "waiting_permission" : "running");
|
|
4864
|
+
}
|
|
4865
|
+
async interrupt() {
|
|
4866
|
+
this.#queue = [];
|
|
4867
|
+
if (!this.#busy)
|
|
4868
|
+
return;
|
|
4869
|
+
this.#interruptRequested = true;
|
|
4870
|
+
if (this.#turnId && this.#rpc) {
|
|
4871
|
+
await this.#rpc.request("turn/interrupt", { threadId: this.#record.conversationId, turnId: this.#turnId });
|
|
4872
|
+
}
|
|
4873
|
+
}
|
|
4874
|
+
#finishTurn(subtype, durationMs) {
|
|
4875
|
+
for (const [blockId, block] of this.#texts) {
|
|
4876
|
+
this.#append({ kind: block.thinking ? "assistant.thinking" : "assistant.text", text: block.text, blockId });
|
|
4877
|
+
}
|
|
4878
|
+
this.#texts.clear();
|
|
4879
|
+
for (const toolUseId of this.#tools) {
|
|
4880
|
+
this.#append({ kind: "tool.result", toolUseId, content: "\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043F\u0440\u0435\u0440\u0432\u0430\u043D\u043E", isError: true });
|
|
4881
|
+
}
|
|
4882
|
+
this.#tools.clear();
|
|
4883
|
+
this.#items.clear();
|
|
4884
|
+
this.#clearApprovals();
|
|
4885
|
+
this.#append({
|
|
4886
|
+
kind: "result",
|
|
4887
|
+
subtype,
|
|
4888
|
+
isError: this.#lastTurn === "failed",
|
|
4889
|
+
durationMs: durationMs ?? Math.max(0, Date.now() - this.#turnStartedAt),
|
|
4890
|
+
costUsd: null,
|
|
4891
|
+
usage: this.#turnUsage,
|
|
4892
|
+
contextTokens: this.#context?.tokens ?? null,
|
|
4893
|
+
text: null
|
|
4894
|
+
});
|
|
4895
|
+
this.#busy = false;
|
|
4896
|
+
this.#turnId = null;
|
|
4897
|
+
this.#interruptRequested = false;
|
|
4898
|
+
this.#setState("idle");
|
|
4899
|
+
void this.#drain();
|
|
4900
|
+
}
|
|
4901
|
+
async setPermissionMode(mode) {
|
|
4902
|
+
codexPolicy(mode);
|
|
4903
|
+
this.#record.permissionMode = mode;
|
|
4904
|
+
this.#settingsChanged();
|
|
4905
|
+
}
|
|
4906
|
+
async setModel(model) {
|
|
4907
|
+
this.#record.model = model;
|
|
4908
|
+
this.#record.effort = null;
|
|
4909
|
+
this.#settingsChanged();
|
|
4910
|
+
}
|
|
4911
|
+
async setEffort(effort) {
|
|
4912
|
+
const model = this.#capabilities?.models.find((m) => m.value === this.#record.model);
|
|
4913
|
+
if (model && !model.effortLevels.includes(effort))
|
|
4914
|
+
throw new Error("\u041C\u043E\u0434\u0435\u043B\u044C Codex \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u044D\u0442\u043E \u0443\u0441\u0438\u043B\u0438\u0435");
|
|
4915
|
+
this.#record.effort = effort;
|
|
4916
|
+
this.#settingsChanged();
|
|
4917
|
+
}
|
|
4918
|
+
#settingsChanged() {
|
|
4919
|
+
if (this.#capabilities) {
|
|
4920
|
+
this.#capabilities.model = this.#record.model ?? "";
|
|
4921
|
+
this.#capabilities.permissionMode = this.#record.permissionMode;
|
|
4922
|
+
this.emit("capabilities");
|
|
4923
|
+
}
|
|
4924
|
+
void this.#store.save(this.#record);
|
|
4925
|
+
this.emit("summary", this.summary());
|
|
4926
|
+
}
|
|
4927
|
+
setTitle(title) {
|
|
4928
|
+
this.#record.title = title;
|
|
4929
|
+
this.#titleIsDefault = false;
|
|
4930
|
+
this.#settingsChanged();
|
|
4931
|
+
}
|
|
4932
|
+
async refreshUsage(_force = false) {
|
|
4933
|
+
if (!this.#rpc || networkGuard.blockedReason())
|
|
4934
|
+
return;
|
|
4935
|
+
try {
|
|
4936
|
+
const reply = await this.#rpc.request("account/rateLimits/read");
|
|
4937
|
+
this.#setUsage(reply.rateLimits);
|
|
4938
|
+
} catch {
|
|
4939
|
+
}
|
|
4940
|
+
}
|
|
4941
|
+
#setUsage(limits) {
|
|
4942
|
+
this.#usage = codexUsage(limits);
|
|
4943
|
+
this.emit("usage", this.#usage);
|
|
4944
|
+
}
|
|
4945
|
+
async refreshContext(_force = false) {
|
|
4946
|
+
if (this.#context)
|
|
4947
|
+
this.emit("context", this.#context);
|
|
4948
|
+
}
|
|
4949
|
+
reconnect(_reason) {
|
|
4950
|
+
this.#disconnect();
|
|
4951
|
+
this.#setState("starting");
|
|
4952
|
+
this.#launch();
|
|
4953
|
+
}
|
|
4954
|
+
suspend(reason) {
|
|
4955
|
+
this.#disconnect();
|
|
4956
|
+
this.#notice(new Error(reason));
|
|
4957
|
+
this.#setState("error");
|
|
4958
|
+
}
|
|
4959
|
+
async close(_reason = "closed by client") {
|
|
4960
|
+
this.#disconnect();
|
|
4961
|
+
this.#setState("closed");
|
|
4962
|
+
await this.#flush();
|
|
4963
|
+
}
|
|
4964
|
+
#disconnect() {
|
|
4965
|
+
this.#generation += 1;
|
|
4966
|
+
this.#startingTurn = false;
|
|
4967
|
+
const rpc = this.#rpc;
|
|
4968
|
+
this.#rpc = null;
|
|
4969
|
+
rpc?.close();
|
|
4970
|
+
this.#queue = [];
|
|
4971
|
+
if (this.#busy) {
|
|
4972
|
+
this.#lastTurn = "interrupted";
|
|
4973
|
+
this.#finishTurn("interrupted");
|
|
4974
|
+
}
|
|
4975
|
+
this.#clearApprovals();
|
|
4976
|
+
}
|
|
4977
|
+
#clearApprovals() {
|
|
4978
|
+
for (const requestId of this.#pending.keys()) {
|
|
4979
|
+
this.#append({ kind: "permission.resolved", requestId, decision: "deny", reason: "\u0425\u043E\u0434 \u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043D" });
|
|
4980
|
+
}
|
|
4981
|
+
this.#pending.clear();
|
|
4982
|
+
}
|
|
4983
|
+
#notice(error) {
|
|
4984
|
+
this.#append({ kind: "error", message: error instanceof Error ? error.message : String(error) });
|
|
4985
|
+
}
|
|
4986
|
+
#fail(error) {
|
|
4987
|
+
if (this.#state === "closed")
|
|
4988
|
+
return;
|
|
4989
|
+
this.#queue = [];
|
|
4990
|
+
if (this.#busy) {
|
|
4991
|
+
this.#lastTurn = "failed";
|
|
4992
|
+
this.#finishTurn("failed");
|
|
4993
|
+
}
|
|
4994
|
+
this.#notice(error);
|
|
4995
|
+
const rpc = this.#rpc;
|
|
4996
|
+
this.#rpc = null;
|
|
4997
|
+
rpc?.close();
|
|
4998
|
+
this.#setState("error");
|
|
4999
|
+
}
|
|
5000
|
+
#append(event) {
|
|
5001
|
+
this.#record.updatedAt = Date.now();
|
|
5002
|
+
const entry = this.journal.append(event);
|
|
5003
|
+
this.emit("event", entry);
|
|
5004
|
+
if (["assistant.delta", "thinking.delta", "state"].includes(event.kind))
|
|
5005
|
+
return;
|
|
5006
|
+
this.#unsaved.push({ ts: entry.ts, event });
|
|
5007
|
+
if (!this.#flushTimer) {
|
|
5008
|
+
this.#flushTimer = setTimeout(() => {
|
|
5009
|
+
void this.#flush();
|
|
5010
|
+
}, 500);
|
|
5011
|
+
this.#flushTimer.unref?.();
|
|
5012
|
+
}
|
|
5013
|
+
}
|
|
5014
|
+
async #flush() {
|
|
5015
|
+
if (this.#flushTimer)
|
|
5016
|
+
clearTimeout(this.#flushTimer);
|
|
5017
|
+
this.#flushTimer = null;
|
|
5018
|
+
const batch = this.#unsaved;
|
|
5019
|
+
this.#unsaved = [];
|
|
5020
|
+
await this.#store.appendEvents(this.id, batch);
|
|
5021
|
+
await this.#store.save(this.#record);
|
|
5022
|
+
}
|
|
5023
|
+
#setState(state) {
|
|
5024
|
+
this.#state = state;
|
|
5025
|
+
this.#append({ kind: "state", state });
|
|
5026
|
+
if (["idle", "error", "closed"].includes(state))
|
|
5027
|
+
void this.#flush();
|
|
5028
|
+
this.emit("summary", this.summary());
|
|
5029
|
+
}
|
|
5030
|
+
async editPrompt(_index, _text, _images) {
|
|
5031
|
+
throw new Error("\u0412 \u0441\u0435\u0441\u0441\u0438\u0438 Codex \u043F\u0440\u0430\u0432\u043A\u0430 \u043F\u0440\u043E\u0448\u043B\u044B\u0445 \u0440\u0435\u043F\u043B\u0438\u043A \u043F\u043E\u043A\u0430 \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F");
|
|
5032
|
+
}
|
|
5033
|
+
async setUltracode(_enabled) {
|
|
5034
|
+
}
|
|
5035
|
+
async setThinking(_enabled) {
|
|
5036
|
+
}
|
|
5037
|
+
async setSwitchModelsOnFlag(_enabled) {
|
|
5038
|
+
}
|
|
5039
|
+
async reloadPlugins() {
|
|
5040
|
+
}
|
|
5041
|
+
async mcpServerStatus() {
|
|
5042
|
+
return [];
|
|
5043
|
+
}
|
|
5044
|
+
async addMcpServer(_name, _config) {
|
|
5045
|
+
throw this.#mcpHint();
|
|
5046
|
+
}
|
|
5047
|
+
async removeMcpServer(_name) {
|
|
5048
|
+
throw this.#mcpHint();
|
|
5049
|
+
}
|
|
5050
|
+
async reconnectMcpServer(_name) {
|
|
5051
|
+
throw this.#mcpHint();
|
|
5052
|
+
}
|
|
5053
|
+
async toggleMcpServer(_name, _enabled) {
|
|
5054
|
+
throw this.#mcpHint();
|
|
5055
|
+
}
|
|
5056
|
+
async authenticateMcpServer(_name) {
|
|
5057
|
+
throw this.#mcpHint();
|
|
5058
|
+
}
|
|
5059
|
+
async submitMcpOAuthCallback(_name, _url) {
|
|
5060
|
+
throw this.#mcpHint();
|
|
5061
|
+
}
|
|
5062
|
+
#mcpHint() {
|
|
5063
|
+
return new Error("MCP Codex \u043D\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442\u0441\u044F \u0447\u0435\u0440\u0435\u0437 codex mcp \u0438\u043B\u0438 ~/.codex/config.toml");
|
|
5064
|
+
}
|
|
5065
|
+
};
|
|
5066
|
+
|
|
4220
5067
|
// ../host/dist/antigravity-store.js
|
|
4221
5068
|
import { appendFile, mkdir as mkdir3, readFile as readFile4, rm as rm2, writeFile as writeFile3 } from "node:fs/promises";
|
|
4222
|
-
import
|
|
5069
|
+
import path9 from "node:path";
|
|
4223
5070
|
var AntigravityStore = class {
|
|
4224
5071
|
#dir;
|
|
4225
5072
|
#file;
|
|
4226
5073
|
#records = /* @__PURE__ */ new Map();
|
|
4227
5074
|
#loaded = null;
|
|
4228
5075
|
#writing = Promise.resolve();
|
|
4229
|
-
constructor(dataDir) {
|
|
4230
|
-
this.#dir =
|
|
4231
|
-
this.#file =
|
|
5076
|
+
constructor(dataDir, provider = "antigravity") {
|
|
5077
|
+
this.#dir = path9.join(dataDir, provider);
|
|
5078
|
+
this.#file = path9.join(this.#dir, "sessions.json");
|
|
4232
5079
|
}
|
|
4233
5080
|
#load() {
|
|
4234
5081
|
this.#loaded ??= (async () => {
|
|
@@ -4325,7 +5172,7 @@ var AntigravityStore = class {
|
|
|
4325
5172
|
return entries;
|
|
4326
5173
|
}
|
|
4327
5174
|
#eventsFile(id) {
|
|
4328
|
-
return
|
|
5175
|
+
return path9.join(this.#dir, `${id.replace(/[^\w-]/g, "_")}.jsonl`);
|
|
4329
5176
|
}
|
|
4330
5177
|
#persist() {
|
|
4331
5178
|
const snapshot = JSON.stringify([...this.#records.values()], null, 2);
|
|
@@ -4345,10 +5192,10 @@ var AntigravityStore = class {
|
|
|
4345
5192
|
};
|
|
4346
5193
|
|
|
4347
5194
|
// ../host/dist/git.js
|
|
4348
|
-
import { execFile as
|
|
5195
|
+
import { execFile as execFile5 } from "node:child_process";
|
|
4349
5196
|
import { mkdtemp, readFile as readFile5, rm as rm3, writeFile as writeFile4 } from "node:fs/promises";
|
|
4350
5197
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
4351
|
-
import
|
|
5198
|
+
import path10 from "node:path";
|
|
4352
5199
|
var TIMEOUT_MS = 2e4;
|
|
4353
5200
|
var NET_TIMEOUT_MS = 5 * 6e4;
|
|
4354
5201
|
var MAX_BUFFER = 32 * 1024 * 1024;
|
|
@@ -4664,7 +5511,7 @@ var GitRepo = class {
|
|
|
4664
5511
|
* важнее всего (см. `checkIgnored`).
|
|
4665
5512
|
*/
|
|
4666
5513
|
async #withoutRepo(args) {
|
|
4667
|
-
const dir = await mkdtemp(
|
|
5514
|
+
const dir = await mkdtemp(path10.join(tmpdir2(), "ccv-git-"));
|
|
4668
5515
|
try {
|
|
4669
5516
|
await this.#run(["init", "--bare", "--quiet", dir]);
|
|
4670
5517
|
return await this.#soft([`--git-dir=${dir}`, `--work-tree=${this.cwd}`, ...args]);
|
|
@@ -4710,7 +5557,7 @@ var GitRepo = class {
|
|
|
4710
5557
|
* исключил. Повторы отсеиваются, чтобы файл не рос от каждой публикации.
|
|
4711
5558
|
*/
|
|
4712
5559
|
async #appendGitignore(paths) {
|
|
4713
|
-
const file =
|
|
5560
|
+
const file = path10.join(this.cwd, ".gitignore");
|
|
4714
5561
|
const existing = await readFile5(file, "utf8").catch(() => "");
|
|
4715
5562
|
const known = new Set(existing.split(/\r?\n/).map((line) => line.trim()));
|
|
4716
5563
|
const lines = paths.map(ignorePattern).filter((line) => !known.has(line));
|
|
@@ -4735,7 +5582,7 @@ var GitRepo = class {
|
|
|
4735
5582
|
#run(args, options2 = {}) {
|
|
4736
5583
|
const token = options2.token ?? "";
|
|
4737
5584
|
return new Promise((resolve, reject) => {
|
|
4738
|
-
const child =
|
|
5585
|
+
const child = execFile5(
|
|
4739
5586
|
"git",
|
|
4740
5587
|
// core.quotepath=false — иначе кириллические пути приезжают в виде
|
|
4741
5588
|
// «\320\277\321\200…» и в панели читаются как мусор.
|
|
@@ -4916,9 +5763,9 @@ function parsePatch(raw) {
|
|
|
4916
5763
|
body = "";
|
|
4917
5764
|
}
|
|
4918
5765
|
total += body.length;
|
|
4919
|
-
const
|
|
5766
|
+
const path26 = status === "deleted" ? oldPath : newPath || oldPath;
|
|
4920
5767
|
files.push({
|
|
4921
|
-
path:
|
|
5768
|
+
path: path26,
|
|
4922
5769
|
oldPath: status === "renamed" ? oldPath : "",
|
|
4923
5770
|
status,
|
|
4924
5771
|
added: count(body, "+"),
|
|
@@ -4930,10 +5777,10 @@ function parsePatch(raw) {
|
|
|
4930
5777
|
return { files, truncated };
|
|
4931
5778
|
}
|
|
4932
5779
|
function stripPrefix(value) {
|
|
4933
|
-
const
|
|
4934
|
-
if (
|
|
5780
|
+
const path26 = unquote(value.trim());
|
|
5781
|
+
if (path26 === "/dev/null")
|
|
4935
5782
|
return "";
|
|
4936
|
-
return
|
|
5783
|
+
return path26.replace(/^[ab]\//, "");
|
|
4937
5784
|
}
|
|
4938
5785
|
function count(body, mark) {
|
|
4939
5786
|
let n = 0;
|
|
@@ -4945,9 +5792,9 @@ function count(body, mark) {
|
|
|
4945
5792
|
}
|
|
4946
5793
|
|
|
4947
5794
|
// ../host/dist/github.js
|
|
4948
|
-
import { execFile as
|
|
5795
|
+
import { execFile as execFile6 } from "node:child_process";
|
|
4949
5796
|
import { mkdir as mkdir4, readFile as readFile6, writeFile as writeFile5 } from "node:fs/promises";
|
|
4950
|
-
import
|
|
5797
|
+
import path11 from "node:path";
|
|
4951
5798
|
var API = "https://api.github.com";
|
|
4952
5799
|
var API_VERSION = "2022-11-28";
|
|
4953
5800
|
var API_TIMEOUT_MS = 2e4;
|
|
@@ -4968,7 +5815,7 @@ var GitHubAccount = class {
|
|
|
4968
5815
|
*/
|
|
4969
5816
|
#ghInstalled = null;
|
|
4970
5817
|
constructor(dataDir) {
|
|
4971
|
-
this.#storePath =
|
|
5818
|
+
this.#storePath = path11.join(dataDir, "github.json");
|
|
4972
5819
|
}
|
|
4973
5820
|
async load() {
|
|
4974
5821
|
try {
|
|
@@ -4982,7 +5829,7 @@ var GitHubAccount = class {
|
|
|
4982
5829
|
/** Сохранить токен или стереть его пустой строкой. */
|
|
4983
5830
|
async setToken(token) {
|
|
4984
5831
|
this.#token = token.trim();
|
|
4985
|
-
await mkdir4(
|
|
5832
|
+
await mkdir4(path11.dirname(this.#storePath), { recursive: true });
|
|
4986
5833
|
await writeFile5(this.#storePath, JSON.stringify({ token: this.#token }, null, 2), {
|
|
4987
5834
|
encoding: "utf8",
|
|
4988
5835
|
mode: 384
|
|
@@ -5134,7 +5981,7 @@ var GitHubAccount = class {
|
|
|
5134
5981
|
};
|
|
5135
5982
|
function gh(args) {
|
|
5136
5983
|
return new Promise((resolve, reject) => {
|
|
5137
|
-
|
|
5984
|
+
execFile6("gh", args, { timeout: GH_TIMEOUT_MS, windowsHide: true, encoding: "utf8" }, (error, stdout, stderr) => {
|
|
5138
5985
|
if (error)
|
|
5139
5986
|
return reject(new Error(stderr.trim() || error.message));
|
|
5140
5987
|
resolve(stdout);
|
|
@@ -5175,10 +6022,10 @@ function describe4(error) {
|
|
|
5175
6022
|
}
|
|
5176
6023
|
|
|
5177
6024
|
// ../host/dist/finder.js
|
|
5178
|
-
import { existsSync as
|
|
6025
|
+
import { existsSync as existsSync3, statSync as statSync2 } from "node:fs";
|
|
5179
6026
|
import { readdir as readdir2 } from "node:fs/promises";
|
|
5180
6027
|
import os2 from "node:os";
|
|
5181
|
-
import
|
|
6028
|
+
import path12 from "node:path";
|
|
5182
6029
|
import { listSessions } from "@anthropic-ai/claude-agent-sdk";
|
|
5183
6030
|
var CACHE_TTL = 6e4;
|
|
5184
6031
|
var FIND_LIMIT = 50;
|
|
@@ -5217,7 +6064,7 @@ var ProjectFinder = class {
|
|
|
5217
6064
|
if (needles.length === 0)
|
|
5218
6065
|
return { candidates: [], truncated: false };
|
|
5219
6066
|
const open = new Map(this.registry.list().map((workspace) => [workspace.path.toLowerCase(), workspace]));
|
|
5220
|
-
const byName = this.#dirs.filter((dir) => matches(
|
|
6067
|
+
const byName = this.#dirs.filter((dir) => matches(path12.basename(dir.path), needles));
|
|
5221
6068
|
const matched = byName.length > 0 ? byName : this.#dirs.filter((dir) => matches(dir.path, needles));
|
|
5222
6069
|
const sorted = [...matched].sort((a, b) => {
|
|
5223
6070
|
const aOpen = open.has(a.path.toLowerCase());
|
|
@@ -5228,7 +6075,7 @@ var ProjectFinder = class {
|
|
|
5228
6075
|
return a.sessions > 0 ? -1 : 1;
|
|
5229
6076
|
if (a.lastUsedAt !== b.lastUsedAt)
|
|
5230
6077
|
return b.lastUsedAt - a.lastUsedAt;
|
|
5231
|
-
return
|
|
6078
|
+
return path12.basename(a.path).localeCompare(path12.basename(b.path), void 0, {
|
|
5232
6079
|
numeric: true,
|
|
5233
6080
|
sensitivity: "base"
|
|
5234
6081
|
});
|
|
@@ -5236,7 +6083,7 @@ var ProjectFinder = class {
|
|
|
5236
6083
|
return {
|
|
5237
6084
|
candidates: sorted.slice(0, FIND_LIMIT).map((dir) => ({
|
|
5238
6085
|
path: dir.path,
|
|
5239
|
-
name:
|
|
6086
|
+
name: path12.basename(dir.path) || dir.path,
|
|
5240
6087
|
sessions: dir.sessions,
|
|
5241
6088
|
lastUsedAt: dir.lastUsedAt || null,
|
|
5242
6089
|
open: open.has(dir.path.toLowerCase()),
|
|
@@ -5260,7 +6107,7 @@ var ProjectFinder = class {
|
|
|
5260
6107
|
const candidates = [];
|
|
5261
6108
|
for (const entry of named) {
|
|
5262
6109
|
const absolute = entry.path.trim();
|
|
5263
|
-
if (!absolute || !
|
|
6110
|
+
if (!absolute || !path12.isAbsolute(absolute))
|
|
5264
6111
|
continue;
|
|
5265
6112
|
const key = absolute.toLowerCase();
|
|
5266
6113
|
if (seen.has(key))
|
|
@@ -5271,7 +6118,7 @@ var ProjectFinder = class {
|
|
|
5271
6118
|
const record = known.get(key);
|
|
5272
6119
|
candidates.push({
|
|
5273
6120
|
path: record?.path ?? absolute,
|
|
5274
|
-
name:
|
|
6121
|
+
name: path12.basename(absolute) || absolute,
|
|
5275
6122
|
sessions: record?.sessions ?? 0,
|
|
5276
6123
|
lastUsedAt: record?.lastUsedAt || null,
|
|
5277
6124
|
open: open.has(key),
|
|
@@ -5328,7 +6175,7 @@ var ProjectFinder = class {
|
|
|
5328
6175
|
if (!dirent.isDirectory() || SKIP_NAMES.has(dirent.name) || dirent.name.startsWith(".")) {
|
|
5329
6176
|
continue;
|
|
5330
6177
|
}
|
|
5331
|
-
const full =
|
|
6178
|
+
const full = path12.join(parent, dirent.name);
|
|
5332
6179
|
const key = full.toLowerCase();
|
|
5333
6180
|
if (dirs.has(key))
|
|
5334
6181
|
continue;
|
|
@@ -5349,7 +6196,7 @@ var ProjectFinder = class {
|
|
|
5349
6196
|
#parents(dirs) {
|
|
5350
6197
|
const counted = /* @__PURE__ */ new Map();
|
|
5351
6198
|
for (const dir of dirs) {
|
|
5352
|
-
const parent =
|
|
6199
|
+
const parent = path12.dirname(dir.path);
|
|
5353
6200
|
if (parent === dir.path || !usable(parent))
|
|
5354
6201
|
continue;
|
|
5355
6202
|
const key = parent.toLowerCase();
|
|
@@ -5363,7 +6210,7 @@ var ProjectFinder = class {
|
|
|
5363
6210
|
}
|
|
5364
6211
|
};
|
|
5365
6212
|
function usable(dir) {
|
|
5366
|
-
return !contains(os2.tmpdir(), dir) &&
|
|
6213
|
+
return !contains(os2.tmpdir(), dir) && existsSync3(dir);
|
|
5367
6214
|
}
|
|
5368
6215
|
function tokens(query2) {
|
|
5369
6216
|
return query2.toLowerCase().split(/[^a-z0-9а-яё]+/i).filter(Boolean);
|
|
@@ -5374,7 +6221,7 @@ function matches(value, needles) {
|
|
|
5374
6221
|
}
|
|
5375
6222
|
function isDirectory(dir) {
|
|
5376
6223
|
try {
|
|
5377
|
-
return
|
|
6224
|
+
return statSync2(dir).isDirectory();
|
|
5378
6225
|
} catch {
|
|
5379
6226
|
return false;
|
|
5380
6227
|
}
|
|
@@ -5460,15 +6307,15 @@ function fromText(text) {
|
|
|
5460
6307
|
}
|
|
5461
6308
|
|
|
5462
6309
|
// ../host/dist/workspaces.js
|
|
5463
|
-
import { existsSync as
|
|
6310
|
+
import { existsSync as existsSync4, statSync as statSync3 } from "node:fs";
|
|
5464
6311
|
import { mkdir as mkdir5, readFile as readFile7, writeFile as writeFile6 } from "node:fs/promises";
|
|
5465
|
-
import
|
|
6312
|
+
import path13 from "node:path";
|
|
5466
6313
|
import { listSessions as listSessions2 } from "@anthropic-ai/claude-agent-sdk";
|
|
5467
6314
|
var WorkspaceRegistry = class {
|
|
5468
6315
|
#entries = [];
|
|
5469
6316
|
#storePath;
|
|
5470
6317
|
constructor(dataDir) {
|
|
5471
|
-
this.#storePath =
|
|
6318
|
+
this.#storePath = path13.join(dataDir, "workspaces.json");
|
|
5472
6319
|
}
|
|
5473
6320
|
async load() {
|
|
5474
6321
|
try {
|
|
@@ -5484,13 +6331,13 @@ var WorkspaceRegistry = class {
|
|
|
5484
6331
|
if (isEntry(item))
|
|
5485
6332
|
return item;
|
|
5486
6333
|
return null;
|
|
5487
|
-
}).filter((e) => e !== null &&
|
|
6334
|
+
}).filter((e) => e !== null && existsSync4(e.path));
|
|
5488
6335
|
} catch {
|
|
5489
6336
|
this.#entries = [];
|
|
5490
6337
|
}
|
|
5491
6338
|
}
|
|
5492
6339
|
async #persist() {
|
|
5493
|
-
await mkdir5(
|
|
6340
|
+
await mkdir5(path13.dirname(this.#storePath), { recursive: true });
|
|
5494
6341
|
await writeFile6(this.#storePath, JSON.stringify(this.#entries, null, 2), "utf8");
|
|
5495
6342
|
}
|
|
5496
6343
|
/** Активные проекты. */
|
|
@@ -5510,8 +6357,8 @@ var WorkspaceRegistry = class {
|
|
|
5510
6357
|
return entry ? toInfo(entry) : void 0;
|
|
5511
6358
|
}
|
|
5512
6359
|
async open(rawPath) {
|
|
5513
|
-
const absolute =
|
|
5514
|
-
if (!
|
|
6360
|
+
const absolute = path13.resolve(rawPath);
|
|
6361
|
+
if (!existsSync4(absolute)) {
|
|
5515
6362
|
throw new Error(`\u041A\u0430\u0442\u0430\u043B\u043E\u0433 \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D: ${absolute}`);
|
|
5516
6363
|
}
|
|
5517
6364
|
const existing = this.#entries.find((e) => e.path === absolute);
|
|
@@ -5577,24 +6424,24 @@ var WorkspaceRegistry = class {
|
|
|
5577
6424
|
async create(parentRaw, nameRaw, init) {
|
|
5578
6425
|
const name = nameRaw.trim();
|
|
5579
6426
|
requireName(name);
|
|
5580
|
-
const parent =
|
|
5581
|
-
if (!
|
|
6427
|
+
const parent = path13.resolve(parentRaw.trim());
|
|
6428
|
+
if (!existsSync4(parent)) {
|
|
5582
6429
|
throw new Error(`\u041A\u0430\u0442\u0430\u043B\u043E\u0433 \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D: ${parent}`);
|
|
5583
6430
|
}
|
|
5584
|
-
if (!
|
|
6431
|
+
if (!statSync3(parent).isDirectory()) {
|
|
5585
6432
|
throw new Error(`\u042D\u0442\u043E \u043D\u0435 \u043A\u0430\u0442\u0430\u043B\u043E\u0433: ${parent}`);
|
|
5586
6433
|
}
|
|
5587
|
-
const target =
|
|
5588
|
-
if (
|
|
6434
|
+
const target = path13.join(parent, name);
|
|
6435
|
+
if (existsSync4(target)) {
|
|
5589
6436
|
throw new Error(`\u0423\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442: ${target} \u2014 \u043E\u0442\u043A\u0440\u043E\u0439\u0442\u0435 \u0435\u0433\u043E \u043A\u0430\u043A \u043F\u0440\u043E\u0435\u043A\u0442`);
|
|
5590
6437
|
}
|
|
5591
6438
|
await mkdir5(target);
|
|
5592
6439
|
const warnings = [];
|
|
5593
6440
|
if (init.claudeMd) {
|
|
5594
|
-
await step(warnings, "CLAUDE.md", () => writeFile6(
|
|
6441
|
+
await step(warnings, "CLAUDE.md", () => writeFile6(path13.join(target, "CLAUDE.md"), claudeMdStub(name), "utf8"));
|
|
5595
6442
|
}
|
|
5596
6443
|
if (init.readme) {
|
|
5597
|
-
await step(warnings, "README.md", () => writeFile6(
|
|
6444
|
+
await step(warnings, "README.md", () => writeFile6(path13.join(target, "README.md"), readmeStub(name), "utf8"));
|
|
5598
6445
|
}
|
|
5599
6446
|
if (init.git) {
|
|
5600
6447
|
await step(warnings, "git init", () => new GitRepo(target).init());
|
|
@@ -5666,8 +6513,8 @@ function toInfo(entry) {
|
|
|
5666
6513
|
return {
|
|
5667
6514
|
id: workspaceIdFromPath(absolute),
|
|
5668
6515
|
path: absolute,
|
|
5669
|
-
name:
|
|
5670
|
-
hasClaudeMd:
|
|
6516
|
+
name: path13.basename(absolute) || absolute,
|
|
6517
|
+
hasClaudeMd: existsSync4(path13.join(absolute, "CLAUDE.md")),
|
|
5671
6518
|
...archivedAt ? { archivedAt } : {}
|
|
5672
6519
|
};
|
|
5673
6520
|
}
|
|
@@ -5677,13 +6524,13 @@ function isEntry(value) {
|
|
|
5677
6524
|
|
|
5678
6525
|
// ../host/dist/archive.js
|
|
5679
6526
|
import { mkdir as mkdir6, readFile as readFile8, writeFile as writeFile7 } from "node:fs/promises";
|
|
5680
|
-
import
|
|
6527
|
+
import path14 from "node:path";
|
|
5681
6528
|
var SessionArchive = class {
|
|
5682
6529
|
#archived = /* @__PURE__ */ new Map();
|
|
5683
6530
|
#restored = /* @__PURE__ */ new Map();
|
|
5684
6531
|
#storePath;
|
|
5685
6532
|
constructor(dataDir) {
|
|
5686
|
-
this.#storePath =
|
|
6533
|
+
this.#storePath = path14.join(dataDir, "session-archive.json");
|
|
5687
6534
|
}
|
|
5688
6535
|
async load() {
|
|
5689
6536
|
try {
|
|
@@ -5795,7 +6642,7 @@ var SessionArchive = class {
|
|
|
5795
6642
|
archived: Object.fromEntries(this.#archived),
|
|
5796
6643
|
restored: Object.fromEntries(this.#restored)
|
|
5797
6644
|
};
|
|
5798
|
-
await mkdir6(
|
|
6645
|
+
await mkdir6(path14.dirname(this.#storePath), { recursive: true });
|
|
5799
6646
|
await writeFile7(this.#storePath, JSON.stringify(file, null, 2), "utf8");
|
|
5800
6647
|
}
|
|
5801
6648
|
};
|
|
@@ -5805,7 +6652,7 @@ function isRecord(value) {
|
|
|
5805
6652
|
|
|
5806
6653
|
// ../host/dist/pins.js
|
|
5807
6654
|
import { mkdir as mkdir7, readFile as readFile9, writeFile as writeFile8 } from "node:fs/promises";
|
|
5808
|
-
import
|
|
6655
|
+
import path15 from "node:path";
|
|
5809
6656
|
var SessionPins = class {
|
|
5810
6657
|
#pinned = /* @__PURE__ */ new Map();
|
|
5811
6658
|
/**
|
|
@@ -5820,7 +6667,7 @@ var SessionPins = class {
|
|
|
5820
6667
|
#moved = /* @__PURE__ */ new Map();
|
|
5821
6668
|
#storePath;
|
|
5822
6669
|
constructor(dataDir) {
|
|
5823
|
-
this.#storePath =
|
|
6670
|
+
this.#storePath = path15.join(dataDir, "session-pins.json");
|
|
5824
6671
|
}
|
|
5825
6672
|
async load() {
|
|
5826
6673
|
try {
|
|
@@ -5977,7 +6824,7 @@ var SessionPins = class {
|
|
|
5977
6824
|
pinned: Object.fromEntries(this.#pinned),
|
|
5978
6825
|
...this.#moved.size > 0 ? { moved: Object.fromEntries(this.#moved) } : {}
|
|
5979
6826
|
};
|
|
5980
|
-
await mkdir7(
|
|
6827
|
+
await mkdir7(path15.dirname(this.#storePath), { recursive: true });
|
|
5981
6828
|
await writeFile8(this.#storePath, JSON.stringify(file, null, 2), "utf8");
|
|
5982
6829
|
}
|
|
5983
6830
|
};
|
|
@@ -5987,12 +6834,12 @@ function isRecord2(value) {
|
|
|
5987
6834
|
|
|
5988
6835
|
// ../host/dist/order.js
|
|
5989
6836
|
import { mkdir as mkdir8, readFile as readFile10, writeFile as writeFile9 } from "node:fs/promises";
|
|
5990
|
-
import
|
|
6837
|
+
import path16 from "node:path";
|
|
5991
6838
|
var ListOrderStore = class {
|
|
5992
6839
|
#order = emptyOrder();
|
|
5993
6840
|
#storePath;
|
|
5994
6841
|
constructor(dataDir) {
|
|
5995
|
-
this.#storePath =
|
|
6842
|
+
this.#storePath = path16.join(dataDir, "list-order.json");
|
|
5996
6843
|
}
|
|
5997
6844
|
async load() {
|
|
5998
6845
|
try {
|
|
@@ -6068,7 +6915,7 @@ var ListOrderStore = class {
|
|
|
6068
6915
|
return changed;
|
|
6069
6916
|
}
|
|
6070
6917
|
async #persist() {
|
|
6071
|
-
await mkdir8(
|
|
6918
|
+
await mkdir8(path16.dirname(this.#storePath), { recursive: true });
|
|
6072
6919
|
await writeFile9(this.#storePath, JSON.stringify(this.#order, null, 2), "utf8");
|
|
6073
6920
|
}
|
|
6074
6921
|
};
|
|
@@ -6099,8 +6946,8 @@ function sanitize(value) {
|
|
|
6099
6946
|
|
|
6100
6947
|
// ../host/dist/folders.js
|
|
6101
6948
|
import { mkdir as mkdir9, readFile as readFile11, writeFile as writeFile10 } from "node:fs/promises";
|
|
6102
|
-
import
|
|
6103
|
-
import { randomUUID as
|
|
6949
|
+
import path17 from "node:path";
|
|
6950
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
6104
6951
|
var COLOR_PATTERN = /^#[0-9a-f]{6}$/i;
|
|
6105
6952
|
var Folders = class {
|
|
6106
6953
|
#workspaceFolders = /* @__PURE__ */ new Map();
|
|
@@ -6111,7 +6958,7 @@ var Folders = class {
|
|
|
6111
6958
|
#pinnedAssignments = /* @__PURE__ */ new Map();
|
|
6112
6959
|
#storePath;
|
|
6113
6960
|
constructor(dataDir) {
|
|
6114
|
-
this.#storePath =
|
|
6961
|
+
this.#storePath = path17.join(dataDir, "folders.json");
|
|
6115
6962
|
}
|
|
6116
6963
|
async load() {
|
|
6117
6964
|
try {
|
|
@@ -6200,19 +7047,19 @@ var Folders = class {
|
|
|
6200
7047
|
};
|
|
6201
7048
|
}
|
|
6202
7049
|
async createWorkspaceFolder(name) {
|
|
6203
|
-
const id =
|
|
7050
|
+
const id = randomUUID4();
|
|
6204
7051
|
this.#workspaceFolders.set(id, { name });
|
|
6205
7052
|
await this.#persist();
|
|
6206
7053
|
return id;
|
|
6207
7054
|
}
|
|
6208
7055
|
async createSessionFolder(workspaceId, name) {
|
|
6209
|
-
const id =
|
|
7056
|
+
const id = randomUUID4();
|
|
6210
7057
|
this.#sessionFolders.set(id, { name, workspaceId });
|
|
6211
7058
|
await this.#persist();
|
|
6212
7059
|
return id;
|
|
6213
7060
|
}
|
|
6214
7061
|
async createPinnedFolder(name) {
|
|
6215
|
-
const id =
|
|
7062
|
+
const id = randomUUID4();
|
|
6216
7063
|
this.#pinnedFolders.set(id, { name });
|
|
6217
7064
|
await this.#persist();
|
|
6218
7065
|
return id;
|
|
@@ -6392,7 +7239,7 @@ var Folders = class {
|
|
|
6392
7239
|
sessionAssignments: Object.fromEntries(this.#sessionAssignments),
|
|
6393
7240
|
pinnedAssignments: Object.fromEntries(this.#pinnedAssignments)
|
|
6394
7241
|
};
|
|
6395
|
-
await mkdir9(
|
|
7242
|
+
await mkdir9(path17.dirname(this.#storePath), { recursive: true });
|
|
6396
7243
|
await writeFile10(this.#storePath, JSON.stringify(file, null, 2), "utf8");
|
|
6397
7244
|
}
|
|
6398
7245
|
};
|
|
@@ -6415,8 +7262,8 @@ function isPinnedFolder(value) {
|
|
|
6415
7262
|
|
|
6416
7263
|
// ../host/dist/app-settings.js
|
|
6417
7264
|
import { mkdir as mkdir10, readFile as readFile12, writeFile as writeFile11 } from "node:fs/promises";
|
|
6418
|
-
import { homedir as
|
|
6419
|
-
import
|
|
7265
|
+
import { homedir as homedir5 } from "node:os";
|
|
7266
|
+
import path18 from "node:path";
|
|
6420
7267
|
var DEFAULT_AUTO_ARCHIVE_AFTER_MS = 2 * 24 * 60 * 60 * 1e3;
|
|
6421
7268
|
var MIN_AUTO_ARCHIVE_AFTER_MS = 60 * 60 * 1e3;
|
|
6422
7269
|
var DEFAULT_AUTO_STOP_AFTER_MS = 10 * 60 * 1e3;
|
|
@@ -6424,7 +7271,7 @@ var MIN_AUTO_STOP_AFTER_MS = 60 * 1e3;
|
|
|
6424
7271
|
var MIN_AUTO_SAVE_AFTER_PAUSE_MS = 500;
|
|
6425
7272
|
var DEFAULT_BLOCKED_COUNTRIES = ["RU", "BY", "CN", "IR", "KP", "SY", "CU"];
|
|
6426
7273
|
var FOLDER_ACCESS = ["all", "projects", "project"];
|
|
6427
|
-
var PROVIDERS = ["claude", "antigravity"];
|
|
7274
|
+
var PROVIDERS = ["claude", "antigravity", "codex"];
|
|
6428
7275
|
var PERMISSION_MODES = [
|
|
6429
7276
|
"default",
|
|
6430
7277
|
"acceptEdits",
|
|
@@ -6459,7 +7306,7 @@ var DEFAULT_APP_SETTINGS = {
|
|
|
6459
7306
|
limitStopFiveHourPct: 95,
|
|
6460
7307
|
limitStopSevenDayPct: 99,
|
|
6461
7308
|
// Оба: до появления настройки приложение предлагало обоих агентов.
|
|
6462
|
-
enabledProviders: ["claude", "antigravity"],
|
|
7309
|
+
enabledProviders: ["claude", "antigravity", "codex"],
|
|
6463
7310
|
// Включено: запрос без VPN может стоить аккаунта, а тому, у кого маршрут и
|
|
6464
7311
|
// так из разрешённой страны, защита ничем не мешает.
|
|
6465
7312
|
networkGuardEnabled: true,
|
|
@@ -6469,7 +7316,7 @@ var AppSettingsStore = class {
|
|
|
6469
7316
|
#settings = { ...DEFAULT_APP_SETTINGS };
|
|
6470
7317
|
#storePath;
|
|
6471
7318
|
constructor(dataDir) {
|
|
6472
|
-
this.#storePath =
|
|
7319
|
+
this.#storePath = path18.join(dataDir, "app-settings.json");
|
|
6473
7320
|
}
|
|
6474
7321
|
async load() {
|
|
6475
7322
|
try {
|
|
@@ -6493,7 +7340,7 @@ var AppSettingsStore = class {
|
|
|
6493
7340
|
async update(patch) {
|
|
6494
7341
|
const next = sanitize2(patch, this.#settings);
|
|
6495
7342
|
this.#settings = next;
|
|
6496
|
-
await mkdir10(
|
|
7343
|
+
await mkdir10(path18.dirname(this.#storePath), { recursive: true });
|
|
6497
7344
|
await writeFile11(this.#storePath, JSON.stringify(next, null, 2), "utf8");
|
|
6498
7345
|
return this.current;
|
|
6499
7346
|
}
|
|
@@ -6560,7 +7407,7 @@ function sanitize2(value, fallback) {
|
|
|
6560
7407
|
return result;
|
|
6561
7408
|
}
|
|
6562
7409
|
function claudeHome() {
|
|
6563
|
-
return
|
|
7410
|
+
return path18.join(homedir5(), ".claude");
|
|
6564
7411
|
}
|
|
6565
7412
|
function writableRoots(mode, cwd, workspacePaths) {
|
|
6566
7413
|
if (mode === "all")
|
|
@@ -6570,7 +7417,7 @@ function writableRoots(mode, cwd, workspacePaths) {
|
|
|
6570
7417
|
return [...roots];
|
|
6571
7418
|
for (const workspace of [cwd, ...workspacePaths]) {
|
|
6572
7419
|
roots.add(workspace);
|
|
6573
|
-
const parent =
|
|
7420
|
+
const parent = path18.dirname(workspace);
|
|
6574
7421
|
if (parent !== workspace)
|
|
6575
7422
|
roots.add(parent);
|
|
6576
7423
|
}
|
|
@@ -6579,11 +7426,11 @@ function writableRoots(mode, cwd, workspacePaths) {
|
|
|
6579
7426
|
|
|
6580
7427
|
// ../host/dist/handoff-store.js
|
|
6581
7428
|
import { mkdir as mkdir11, readFile as readFile13, readdir as readdir3, rm as rm4, writeFile as writeFile12 } from "node:fs/promises";
|
|
6582
|
-
import
|
|
7429
|
+
import path19 from "node:path";
|
|
6583
7430
|
var HandoffStore = class {
|
|
6584
7431
|
#dir;
|
|
6585
7432
|
constructor(dataDir) {
|
|
6586
|
-
this.#dir =
|
|
7433
|
+
this.#dir = path19.join(dataDir, "handoffs");
|
|
6587
7434
|
}
|
|
6588
7435
|
async get(sessionId) {
|
|
6589
7436
|
const file = this.#file(sessionId);
|
|
@@ -6620,7 +7467,7 @@ var HandoffStore = class {
|
|
|
6620
7467
|
#file(sessionId) {
|
|
6621
7468
|
if (!/^[\w-]{1,128}$/.test(sessionId))
|
|
6622
7469
|
return null;
|
|
6623
|
-
return
|
|
7470
|
+
return path19.join(this.#dir, `${sessionId}.json`);
|
|
6624
7471
|
}
|
|
6625
7472
|
};
|
|
6626
7473
|
var SAME_WINDOW_MS = 5 * 6e4;
|
|
@@ -6628,7 +7475,7 @@ var LimitStopState = class {
|
|
|
6628
7475
|
#fired = {};
|
|
6629
7476
|
#storePath;
|
|
6630
7477
|
constructor(dataDir) {
|
|
6631
|
-
this.#storePath =
|
|
7478
|
+
this.#storePath = path19.join(dataDir, "limit-stop.json");
|
|
6632
7479
|
}
|
|
6633
7480
|
async load() {
|
|
6634
7481
|
try {
|
|
@@ -6664,7 +7511,7 @@ var LimitStopState = class {
|
|
|
6664
7511
|
/** Запомнить срабатывание до `until` (момент сброса окна). */
|
|
6665
7512
|
async mark(limit, until) {
|
|
6666
7513
|
this.#fired[limit] = until;
|
|
6667
|
-
await mkdir11(
|
|
7514
|
+
await mkdir11(path19.dirname(this.#storePath), { recursive: true });
|
|
6668
7515
|
await writeFile12(this.#storePath, JSON.stringify(this.#fired, null, 2), "utf8");
|
|
6669
7516
|
}
|
|
6670
7517
|
};
|
|
@@ -6770,8 +7617,8 @@ function capitalize(text) {
|
|
|
6770
7617
|
|
|
6771
7618
|
// ../host/dist/plugins.js
|
|
6772
7619
|
import { readFile as readFile14 } from "node:fs/promises";
|
|
6773
|
-
import { homedir as
|
|
6774
|
-
import
|
|
7620
|
+
import { homedir as homedir6 } from "node:os";
|
|
7621
|
+
import path20 from "node:path";
|
|
6775
7622
|
var TIMEOUT_MS2 = 12e4;
|
|
6776
7623
|
var SAFE_ARG = /^[A-Za-z0-9][A-Za-z0-9._@/-]*$/;
|
|
6777
7624
|
var PluginCli = class {
|
|
@@ -6870,10 +7717,10 @@ async function readCatalog(markets, installed) {
|
|
|
6870
7717
|
return lists.flat().sort((a, b) => a.name.localeCompare(b.name));
|
|
6871
7718
|
}
|
|
6872
7719
|
async function readMarketplace(market, installed) {
|
|
6873
|
-
const root = market.installLocation ||
|
|
7720
|
+
const root = market.installLocation || path20.join(homedir6(), ".claude", "plugins", "marketplaces", market.name);
|
|
6874
7721
|
let manifest;
|
|
6875
7722
|
try {
|
|
6876
|
-
const text = await readFile14(
|
|
7723
|
+
const text = await readFile14(path20.join(root, ".claude-plugin", "marketplace.json"), "utf8");
|
|
6877
7724
|
manifest = JSON.parse(text);
|
|
6878
7725
|
} catch {
|
|
6879
7726
|
return [];
|
|
@@ -6916,7 +7763,7 @@ function authorName(raw) {
|
|
|
6916
7763
|
}
|
|
6917
7764
|
|
|
6918
7765
|
// ../host/dist/auth.js
|
|
6919
|
-
import { EventEmitter as
|
|
7766
|
+
import { EventEmitter as EventEmitter6 } from "node:events";
|
|
6920
7767
|
var QUICK_TIMEOUT_MS = 3e4;
|
|
6921
7768
|
var LOGIN_TIMEOUT_MS = 10 * 6e4;
|
|
6922
7769
|
var URL_RE = /https:\/\/\S*\/oauth\/authorize\S*/;
|
|
@@ -6928,7 +7775,7 @@ var IDLE = {
|
|
|
6928
7775
|
output: "",
|
|
6929
7776
|
error: null
|
|
6930
7777
|
};
|
|
6931
|
-
var AuthCli = class extends
|
|
7778
|
+
var AuthCli = class extends EventEmitter6 {
|
|
6932
7779
|
#child = null;
|
|
6933
7780
|
#state = IDLE;
|
|
6934
7781
|
#timer = null;
|
|
@@ -7113,9 +7960,9 @@ function describe5(error) {
|
|
|
7113
7960
|
}
|
|
7114
7961
|
|
|
7115
7962
|
// ../host/dist/relay-link.js
|
|
7116
|
-
import { EventEmitter as
|
|
7963
|
+
import { EventEmitter as EventEmitter7 } from "node:events";
|
|
7117
7964
|
import { readFile as readFile15, writeFile as writeFile13, rm as rm5, mkdir as mkdir12 } from "node:fs/promises";
|
|
7118
|
-
import
|
|
7965
|
+
import path21 from "node:path";
|
|
7119
7966
|
import { hostname } from "node:os";
|
|
7120
7967
|
import WebSocket from "ws";
|
|
7121
7968
|
|
|
@@ -7132,7 +7979,7 @@ var SILENCE_TIMEOUT_MS = 95e3;
|
|
|
7132
7979
|
function jitter(delay2) {
|
|
7133
7980
|
return Math.round(delay2 * (0.8 + Math.random() * 0.4));
|
|
7134
7981
|
}
|
|
7135
|
-
var RelayLink = class extends
|
|
7982
|
+
var RelayLink = class extends EventEmitter7 {
|
|
7136
7983
|
#credentials = null;
|
|
7137
7984
|
#socket = null;
|
|
7138
7985
|
#retry = RETRY_MIN_MS;
|
|
@@ -7170,7 +8017,7 @@ var RelayLink = class extends EventEmitter5 {
|
|
|
7170
8017
|
#log;
|
|
7171
8018
|
constructor(options2) {
|
|
7172
8019
|
super();
|
|
7173
|
-
this.#file =
|
|
8020
|
+
this.#file = path21.join(options2.dataDir, "relay.json");
|
|
7174
8021
|
this.#defaultUrl = options2.defaultUrl.replace(/\/+$/, "");
|
|
7175
8022
|
this.#log = options2.log ?? ((msg) => console.log(`[relay] ${msg}`));
|
|
7176
8023
|
}
|
|
@@ -7264,7 +8111,7 @@ var RelayLink = class extends EventEmitter5 {
|
|
|
7264
8111
|
}
|
|
7265
8112
|
}
|
|
7266
8113
|
async #write(credentials) {
|
|
7267
|
-
await mkdir12(
|
|
8114
|
+
await mkdir12(path21.dirname(this.#file), { recursive: true });
|
|
7268
8115
|
await writeFile13(this.#file, `${JSON.stringify(credentials, null, 2)}
|
|
7269
8116
|
`, {
|
|
7270
8117
|
encoding: "utf8",
|
|
@@ -7520,14 +8367,14 @@ function humanize(error) {
|
|
|
7520
8367
|
}
|
|
7521
8368
|
|
|
7522
8369
|
// ../host/dist/terminal.js
|
|
7523
|
-
import { EventEmitter as
|
|
7524
|
-
import { access as access2, constants as
|
|
7525
|
-
import
|
|
7526
|
-
import { randomUUID as
|
|
8370
|
+
import { EventEmitter as EventEmitter8 } from "node:events";
|
|
8371
|
+
import { access as access2, constants as constants3 } from "node:fs/promises";
|
|
8372
|
+
import path22 from "node:path";
|
|
8373
|
+
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
7527
8374
|
var SCROLLBACK_BYTES = 256 * 1024;
|
|
7528
8375
|
var FLUSH_MS = 12;
|
|
7529
8376
|
var MAX_TERMINALS = 24;
|
|
7530
|
-
var TerminalHub = class extends
|
|
8377
|
+
var TerminalHub = class extends EventEmitter8 {
|
|
7531
8378
|
#terminals = /* @__PURE__ */ new Map();
|
|
7532
8379
|
#module = null;
|
|
7533
8380
|
list(workspaceId) {
|
|
@@ -7560,7 +8407,7 @@ var TerminalHub = class extends EventEmitter6 {
|
|
|
7560
8407
|
env: environment()
|
|
7561
8408
|
});
|
|
7562
8409
|
const info = {
|
|
7563
|
-
id:
|
|
8410
|
+
id: randomUUID5(),
|
|
7564
8411
|
workspaceId: options2.workspaceId,
|
|
7565
8412
|
title: shell.title,
|
|
7566
8413
|
shell: shell.file,
|
|
@@ -7692,36 +8539,36 @@ async function defaultShell() {
|
|
|
7692
8539
|
if (pwsh)
|
|
7693
8540
|
return { file: pwsh, args: [], title: "pwsh" };
|
|
7694
8541
|
const system = process.env.SystemRoot ?? "C:\\Windows";
|
|
7695
|
-
const powershell =
|
|
8542
|
+
const powershell = path22.join(system, "System32/WindowsPowerShell/v1.0/powershell.exe");
|
|
7696
8543
|
if (await exists2(powershell))
|
|
7697
8544
|
return { file: powershell, args: [], title: "powershell" };
|
|
7698
8545
|
return { file: process.env.COMSPEC ?? "cmd.exe", args: [], title: "cmd" };
|
|
7699
8546
|
}
|
|
7700
8547
|
const shell = process.env.SHELL;
|
|
7701
8548
|
if (shell && await exists2(shell))
|
|
7702
|
-
return { file: shell, args: [], title:
|
|
8549
|
+
return { file: shell, args: [], title: path22.basename(shell) };
|
|
7703
8550
|
if (await exists2("/bin/bash"))
|
|
7704
8551
|
return { file: "/bin/bash", args: [], title: "bash" };
|
|
7705
8552
|
return { file: "/bin/sh", args: [], title: "sh" };
|
|
7706
8553
|
}
|
|
7707
8554
|
async function findOnPath(name) {
|
|
7708
|
-
const dirs = (process.env.PATH ?? "").split(
|
|
8555
|
+
const dirs = (process.env.PATH ?? "").split(path22.delimiter).filter(Boolean);
|
|
7709
8556
|
for (const dir of dirs) {
|
|
7710
|
-
const candidate =
|
|
8557
|
+
const candidate = path22.join(dir, name);
|
|
7711
8558
|
if (await exists2(candidate))
|
|
7712
8559
|
return candidate;
|
|
7713
8560
|
}
|
|
7714
8561
|
return null;
|
|
7715
8562
|
}
|
|
7716
8563
|
function exists2(file) {
|
|
7717
|
-
return access2(file,
|
|
8564
|
+
return access2(file, constants3.X_OK).then(() => true, () => false);
|
|
7718
8565
|
}
|
|
7719
8566
|
|
|
7720
8567
|
// ../host/dist/mcp-config.js
|
|
7721
8568
|
import { readFile as readFile16, writeFile as writeFile14, mkdir as mkdir13 } from "node:fs/promises";
|
|
7722
|
-
import
|
|
8569
|
+
import path23 from "node:path";
|
|
7723
8570
|
var MCP_FILE = ".mcp.json";
|
|
7724
|
-
var LOCAL_SETTINGS2 =
|
|
8571
|
+
var LOCAL_SETTINGS2 = path23.join(".claude", "settings.local.json");
|
|
7725
8572
|
var queues = /* @__PURE__ */ new Map();
|
|
7726
8573
|
function serialize(cwd, work) {
|
|
7727
8574
|
const previous = queues.get(cwd) ?? Promise.resolve();
|
|
@@ -7730,7 +8577,7 @@ function serialize(cwd, work) {
|
|
|
7730
8577
|
return next;
|
|
7731
8578
|
}
|
|
7732
8579
|
async function readProjectServers(cwd) {
|
|
7733
|
-
const file = await readJson(
|
|
8580
|
+
const file = await readJson(path23.join(cwd, MCP_FILE));
|
|
7734
8581
|
const servers = file?.mcpServers;
|
|
7735
8582
|
if (!servers || typeof servers !== "object")
|
|
7736
8583
|
return {};
|
|
@@ -7738,23 +8585,23 @@ async function readProjectServers(cwd) {
|
|
|
7738
8585
|
}
|
|
7739
8586
|
function addProjectServer(cwd, name, config) {
|
|
7740
8587
|
return serialize(cwd, async () => {
|
|
7741
|
-
const file = await readJson(
|
|
8588
|
+
const file = await readJson(path23.join(cwd, MCP_FILE)) ?? {};
|
|
7742
8589
|
const servers = file.mcpServers ?? {};
|
|
7743
8590
|
servers[name] = config;
|
|
7744
8591
|
file.mcpServers = servers;
|
|
7745
|
-
await writeJson(
|
|
8592
|
+
await writeJson(path23.join(cwd, MCP_FILE), file);
|
|
7746
8593
|
await approve(cwd, name);
|
|
7747
8594
|
});
|
|
7748
8595
|
}
|
|
7749
8596
|
function removeProjectServer(cwd, name) {
|
|
7750
8597
|
return serialize(cwd, async () => {
|
|
7751
|
-
const file = await readJson(
|
|
8598
|
+
const file = await readJson(path23.join(cwd, MCP_FILE));
|
|
7752
8599
|
const servers = file?.mcpServers;
|
|
7753
8600
|
if (!servers || !(name in servers))
|
|
7754
8601
|
return false;
|
|
7755
8602
|
delete servers[name];
|
|
7756
|
-
await writeJson(
|
|
7757
|
-
const settingsPath =
|
|
8603
|
+
await writeJson(path23.join(cwd, MCP_FILE), file);
|
|
8604
|
+
const settingsPath = path23.join(cwd, LOCAL_SETTINGS2);
|
|
7758
8605
|
const settings = await readJson(settingsPath);
|
|
7759
8606
|
const enabled = settings?.enabledMcpjsonServers;
|
|
7760
8607
|
if (settings && Array.isArray(enabled) && enabled.includes(name)) {
|
|
@@ -7765,7 +8612,7 @@ function removeProjectServer(cwd, name) {
|
|
|
7765
8612
|
});
|
|
7766
8613
|
}
|
|
7767
8614
|
async function approve(cwd, name) {
|
|
7768
|
-
const file =
|
|
8615
|
+
const file = path23.join(cwd, LOCAL_SETTINGS2);
|
|
7769
8616
|
const settings = await readJson(file) ?? {};
|
|
7770
8617
|
const enabled = Array.isArray(settings.enabledMcpjsonServers) ? settings.enabledMcpjsonServers : [];
|
|
7771
8618
|
if (!enabled.includes(name))
|
|
@@ -7811,13 +8658,13 @@ async function readJson(file) {
|
|
|
7811
8658
|
if (error.code === "ENOENT")
|
|
7812
8659
|
return null;
|
|
7813
8660
|
if (error instanceof SyntaxError) {
|
|
7814
|
-
throw new Error(`\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0440\u0430\u0437\u043E\u0431\u0440\u0430\u0442\u044C ${
|
|
8661
|
+
throw new Error(`\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0440\u0430\u0437\u043E\u0431\u0440\u0430\u0442\u044C ${path23.basename(file)}: ${error.message}`);
|
|
7815
8662
|
}
|
|
7816
8663
|
throw error;
|
|
7817
8664
|
}
|
|
7818
8665
|
}
|
|
7819
8666
|
async function writeJson(file, data) {
|
|
7820
|
-
await mkdir13(
|
|
8667
|
+
await mkdir13(path23.dirname(file), { recursive: true });
|
|
7821
8668
|
await writeFile14(file, `${JSON.stringify(data, null, 2)}
|
|
7822
8669
|
`, "utf8");
|
|
7823
8670
|
}
|
|
@@ -7836,6 +8683,8 @@ var BUSY_STATES2 = /* @__PURE__ */ new Set([
|
|
|
7836
8683
|
"reconnecting"
|
|
7837
8684
|
]);
|
|
7838
8685
|
var HostServer = class {
|
|
8686
|
+
#httpServer = null;
|
|
8687
|
+
#webSockets = null;
|
|
7839
8688
|
#options;
|
|
7840
8689
|
#workspaces;
|
|
7841
8690
|
#archive;
|
|
@@ -7848,6 +8697,7 @@ var HostServer = class {
|
|
|
7848
8697
|
/** Опросы статуса для идущих OAuth-входов MCP, ключ — сессия и сервер. */
|
|
7849
8698
|
#mcpAuthWatch = /* @__PURE__ */ new Map();
|
|
7850
8699
|
#antigravity;
|
|
8700
|
+
#codex;
|
|
7851
8701
|
/** Боковые сессии («вопрос на полях») по id родителя — не больше одной на разговор. */
|
|
7852
8702
|
#sides = /* @__PURE__ */ new Map();
|
|
7853
8703
|
/**
|
|
@@ -7895,7 +8745,7 @@ var HostServer = class {
|
|
|
7895
8745
|
#limitHandoffBusy = /* @__PURE__ */ new Set();
|
|
7896
8746
|
/** Живые id сессий, у которых сейчас пишется ручной хэндофф. */
|
|
7897
8747
|
#handoffBusy = /* @__PURE__ */ new Set();
|
|
7898
|
-
#hostId =
|
|
8748
|
+
#hostId = randomUUID6();
|
|
7899
8749
|
#plugins = new PluginCli();
|
|
7900
8750
|
#auth = new AuthCli();
|
|
7901
8751
|
#relay;
|
|
@@ -7919,6 +8769,7 @@ var HostServer = class {
|
|
|
7919
8769
|
this.#folders = new Folders(options2.dataDir);
|
|
7920
8770
|
this.#settings = new AppSettingsStore(options2.dataDir);
|
|
7921
8771
|
this.#antigravity = new AntigravityStore(options2.dataDir);
|
|
8772
|
+
this.#codex = new AntigravityStore(options2.dataDir, "codex");
|
|
7922
8773
|
this.#handoffs = new HandoffStore(options2.dataDir);
|
|
7923
8774
|
this.#limitStop = new LimitStopState(options2.dataDir);
|
|
7924
8775
|
this.#finder = new ProjectFinder(this.#workspaces);
|
|
@@ -7945,9 +8796,11 @@ var HostServer = class {
|
|
|
7945
8796
|
const id = workspaceIdFromPath(dir);
|
|
7946
8797
|
const onDisk = await this.#workspaces.sessionsOnDisk(id);
|
|
7947
8798
|
const antigravity = await this.#antigravity.list(id);
|
|
7948
|
-
|
|
8799
|
+
const codex = await this.#codex.list(id);
|
|
8800
|
+
return [...onDisk.map((s) => s.sessionId), ...antigravity.map((r) => r.id), ...codex.map((r) => r.id)];
|
|
7949
8801
|
});
|
|
7950
8802
|
await this.#antigravity.remapWorkspaceIds(remap);
|
|
8803
|
+
await this.#codex.remapWorkspaceIds(remap);
|
|
7951
8804
|
await this.#archive.remapWorkspaceIds(remap);
|
|
7952
8805
|
await this.#pins.remapWorkspaceIds(remap);
|
|
7953
8806
|
await this.#order.remapWorkspaceIds(remap);
|
|
@@ -7982,6 +8835,8 @@ var HostServer = class {
|
|
|
7982
8835
|
resolve();
|
|
7983
8836
|
});
|
|
7984
8837
|
});
|
|
8838
|
+
this.#httpServer = httpServer;
|
|
8839
|
+
this.#webSockets = wss;
|
|
7985
8840
|
await this.#relay.start().catch((error) => {
|
|
7986
8841
|
console.error("[relay]", error instanceof Error ? error.message : String(error));
|
|
7987
8842
|
});
|
|
@@ -8020,6 +8875,16 @@ var HostServer = class {
|
|
|
8020
8875
|
await this.#relay.close();
|
|
8021
8876
|
await Promise.all([...this.#sessions.values()].map((s) => s.close("host shutdown")));
|
|
8022
8877
|
this.#sessions.clear();
|
|
8878
|
+
const wss = this.#webSockets;
|
|
8879
|
+
const http = this.#httpServer;
|
|
8880
|
+
this.#webSockets = null;
|
|
8881
|
+
this.#httpServer = null;
|
|
8882
|
+
for (const socket of wss?.clients ?? [])
|
|
8883
|
+
socket.terminate();
|
|
8884
|
+
await Promise.all([
|
|
8885
|
+
...wss ? [new Promise((resolve) => wss.close(() => resolve()))] : [],
|
|
8886
|
+
...http ? [new Promise((resolve) => http.close(() => resolve()))] : []
|
|
8887
|
+
]);
|
|
8023
8888
|
}
|
|
8024
8889
|
// -------------------------------------------------------------------------
|
|
8025
8890
|
// WebSocket
|
|
@@ -9419,7 +10284,31 @@ var HostServer = class {
|
|
|
9419
10284
|
throw new Error(`\u0412\u043E\u0440\u043A\u0441\u043F\u0435\u0439\u0441 \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D: ${frame.workspaceId}`);
|
|
9420
10285
|
const provider = frame.provider ?? "claude";
|
|
9421
10286
|
if (!frame.resume && !this.#settings.current.enabledProviders.includes(provider)) {
|
|
9422
|
-
throw new Error(`${provider === "antigravity" ? "Antigravity" : "Claude"} \u0432\u044B\u043A\u043B\u044E\u0447\u0435\u043D \u0432 \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0430\u0445`);
|
|
10287
|
+
throw new Error(`${provider === "antigravity" ? "Antigravity" : provider === "codex" ? "Codex" : "Claude"} \u0432\u044B\u043A\u043B\u044E\u0447\u0435\u043D \u0432 \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0430\u0445`);
|
|
10288
|
+
}
|
|
10289
|
+
const codexRecord = frame.resume ? await this.#codex.find(frame.resume) : null;
|
|
10290
|
+
if (codexRecord || !frame.resume && provider === "codex") {
|
|
10291
|
+
if (frame.fork)
|
|
10292
|
+
throw new Error("\u0412\u0435\u0442\u0432\u043B\u0435\u043D\u0438\u0435 \u0441\u0435\u0441\u0441\u0438\u0439 Codex \u043F\u043E\u043A\u0430 \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F");
|
|
10293
|
+
if (codexRecord && codexRecord.workspaceId !== workspace.id)
|
|
10294
|
+
throw new Error("\u0421\u0435\u0441\u0441\u0438\u044F Codex \u043F\u0440\u0438\u043D\u0430\u0434\u043B\u0435\u0436\u0438\u0442 \u0434\u0440\u0443\u0433\u043E\u043C\u0443 \u043F\u0440\u043E\u0435\u043A\u0442\u0443");
|
|
10295
|
+
if (codexRecord)
|
|
10296
|
+
await this.#archive.unarchive([codexRecord.id]);
|
|
10297
|
+
const session2 = new CodexSession({
|
|
10298
|
+
workspaceId: workspace.id,
|
|
10299
|
+
cwd: codexRecord?.cwd ?? workspace.path,
|
|
10300
|
+
store: this.#codex,
|
|
10301
|
+
...codexRecord ? { record: codexRecord } : {},
|
|
10302
|
+
...frame.permissionMode ? { permissionMode: frame.permissionMode } : {},
|
|
10303
|
+
...frame.model ? { model: frame.model } : {},
|
|
10304
|
+
defaultTitle: workspace.name
|
|
10305
|
+
});
|
|
10306
|
+
this.#wire(session2);
|
|
10307
|
+
this.#sessions.set(session2.id, session2);
|
|
10308
|
+
session2.start();
|
|
10309
|
+
this.#sendLive();
|
|
10310
|
+
this.#send(socket, { type: "session.summary", session: session2.summary() });
|
|
10311
|
+
return;
|
|
9423
10312
|
}
|
|
9424
10313
|
const agyRecord = frame.resume ? await this.#antigravity.find(frame.resume) : null;
|
|
9425
10314
|
if (agyRecord || !frame.resume && frame.provider === "antigravity") {
|
|
@@ -9583,7 +10472,7 @@ var HostServer = class {
|
|
|
9583
10472
|
this.#broadcast({ type: "context.state", sessionId: session.id, context });
|
|
9584
10473
|
});
|
|
9585
10474
|
session.on("stderr", (data) => {
|
|
9586
|
-
const tag = session instanceof AntigravitySession ? "agy" : "claude";
|
|
10475
|
+
const tag = session instanceof AntigravitySession ? "agy" : session instanceof CodexSession ? "codex" : "claude";
|
|
9587
10476
|
process.stderr.write(`[${tag} ${session.id.slice(0, 8)}] ${data}`);
|
|
9588
10477
|
});
|
|
9589
10478
|
}
|
|
@@ -9603,7 +10492,7 @@ var HostServer = class {
|
|
|
9603
10492
|
* разговора пока и не было.
|
|
9604
10493
|
*/
|
|
9605
10494
|
#ensureSide(parent) {
|
|
9606
|
-
if (parent instanceof
|
|
10495
|
+
if (!(parent instanceof ClaudeSession)) {
|
|
9607
10496
|
throw new Error("\u0412\u043E\u043F\u0440\u043E\u0441 \u043D\u0430 \u043F\u043E\u043B\u044F\u0445 \u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D \u0442\u043E\u043B\u044C\u043A\u043E \u0432 \u0441\u0435\u0441\u0441\u0438\u044F\u0445 Claude");
|
|
9608
10497
|
}
|
|
9609
10498
|
const existing = this.#sides.get(parent.id);
|
|
@@ -9661,7 +10550,7 @@ var HostServer = class {
|
|
|
9661
10550
|
*/
|
|
9662
10551
|
#roots() {
|
|
9663
10552
|
const roots = this.#finder.roots();
|
|
9664
|
-
return roots.length > 0 ? roots : [
|
|
10553
|
+
return roots.length > 0 ? roots : [homedir7()];
|
|
9665
10554
|
}
|
|
9666
10555
|
/**
|
|
9667
10556
|
* Где сессии этого каталога разрешено писать без вопроса.
|
|
@@ -9903,7 +10792,7 @@ var HostServer = class {
|
|
|
9903
10792
|
live.setTitle(title);
|
|
9904
10793
|
return;
|
|
9905
10794
|
}
|
|
9906
|
-
if (await this.#antigravity.rename(sessionId, title)) {
|
|
10795
|
+
if (await this.#antigravity.rename(sessionId, title) || await this.#codex.rename(sessionId, title)) {
|
|
9907
10796
|
if (workspaceId)
|
|
9908
10797
|
await this.#sendSessionList(workspaceId);
|
|
9909
10798
|
return;
|
|
@@ -9960,6 +10849,11 @@ var HostServer = class {
|
|
|
9960
10849
|
continue;
|
|
9961
10850
|
historical.push(antigravitySummary(record));
|
|
9962
10851
|
}
|
|
10852
|
+
for (const record of await this.#codex.list(workspaceId)) {
|
|
10853
|
+
if (liveIds.has(record.id))
|
|
10854
|
+
continue;
|
|
10855
|
+
historical.push({ ...antigravitySummary(record), provider: "codex", switchModelsOnFlag: false });
|
|
10856
|
+
}
|
|
9963
10857
|
const known = /* @__PURE__ */ new Set([...liveIds, ...historical.map((s) => s.id)]);
|
|
9964
10858
|
await this.#archive.sweep(workspaceId, historical.filter((s) => !this.#pins.has(s.id)).map((s) => ({ id: s.id, updatedAt: s.updatedAt })), known, this.#settings.current.autoArchiveAfterMs);
|
|
9965
10859
|
await this.#pins.sweep(workspaceId, known);
|
|
@@ -10006,15 +10900,15 @@ var HostServer = class {
|
|
|
10006
10900
|
}
|
|
10007
10901
|
#serveStatic(req, res) {
|
|
10008
10902
|
const webRoot = this.#options.webRoot;
|
|
10009
|
-
if (!webRoot || !
|
|
10903
|
+
if (!webRoot || !existsSync5(webRoot)) {
|
|
10010
10904
|
res.writeHead(200, { "content-type": "text/plain; charset=utf-8" });
|
|
10011
10905
|
res.end("CCV host is running. UI is served by the Vite dev server.\n");
|
|
10012
10906
|
return;
|
|
10013
10907
|
}
|
|
10014
10908
|
const url2 = new URL(req.url ?? "/", "http://localhost");
|
|
10015
|
-
const requested =
|
|
10016
|
-
const target = requested.startsWith(webRoot) &&
|
|
10017
|
-
if (!
|
|
10909
|
+
const requested = path24.join(webRoot, path24.normalize(url2.pathname));
|
|
10910
|
+
const target = requested.startsWith(webRoot) && existsSync5(requested) && statSync4(requested).isFile() ? requested : path24.join(webRoot, "index.html");
|
|
10911
|
+
if (!existsSync5(target)) {
|
|
10018
10912
|
res.writeHead(404).end("not found");
|
|
10019
10913
|
return;
|
|
10020
10914
|
}
|
|
@@ -10039,7 +10933,7 @@ function contentType(file) {
|
|
|
10039
10933
|
".svg": "image/svg+xml",
|
|
10040
10934
|
".woff2": "font/woff2"
|
|
10041
10935
|
};
|
|
10042
|
-
return types[
|
|
10936
|
+
return types[path24.extname(file)] ?? "application/octet-stream";
|
|
10043
10937
|
}
|
|
10044
10938
|
function antigravitySummary(record) {
|
|
10045
10939
|
return {
|
|
@@ -10068,9 +10962,9 @@ function antigravitySummary(record) {
|
|
|
10068
10962
|
}
|
|
10069
10963
|
|
|
10070
10964
|
// dist/ccv.js
|
|
10071
|
-
var HERE =
|
|
10072
|
-
var PACKAGE_ROOT =
|
|
10073
|
-
var USAGE = `ccv \u2014 Claude Code Visual: \
|
|
10965
|
+
var HERE = path25.dirname(fileURLToPath(import.meta.url));
|
|
10966
|
+
var PACKAGE_ROOT = path25.resolve(HERE, "..");
|
|
10967
|
+
var USAGE = `ccv \u2014 Claude Code Visual: \u0438\u043D\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043A Claude Code, Codex \u0438 Antigravity \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435.
|
|
10074
10968
|
|
|
10075
10969
|
\u0418\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u0438\u0435:
|
|
10076
10970
|
ccv [\u043E\u043F\u0446\u0438\u0438]
|
|
@@ -10079,12 +10973,12 @@ var USAGE = `ccv \u2014 Claude Code Visual: \u043B\u043E\u043A\u0430\u043B\u044C
|
|
|
10079
10973
|
-p, --port <\u043F\u043E\u0440\u0442> \u043F\u043E\u0440\u0442 \u0445\u043E\u0441\u0442\u0430 (\u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E 8787)
|
|
10080
10974
|
--host <\u0430\u0434\u0440\u0435\u0441> \u0430\u0434\u0440\u0435\u0441 \u043F\u0440\u043E\u0441\u043B\u0443\u0448\u0438\u0432\u0430\u043D\u0438\u044F (\u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E 127.0.0.1)
|
|
10081
10975
|
--no-open \u043D\u0435 \u043E\u0442\u043A\u0440\u044B\u0432\u0430\u0442\u044C \u0431\u0440\u0430\u0443\u0437\u0435\u0440
|
|
10082
|
-
--claude \u0447\u0435\u043C \u0431\u0443\u0434\u0443\u0442 \u043F\u043E\u0434\u043D\u0438\u043C\u0430\u0442\u044C\u0441\u044F \u0441\u0435\u0441\u0441\u0438\u0438, \u0438 \u0432\u044B\u0439\u0442\u0438
|
|
10976
|
+
--claude \u0447\u0435\u043C \u0431\u0443\u0434\u0443\u0442 \u043F\u043E\u0434\u043D\u0438\u043C\u0430\u0442\u044C\u0441\u044F \u0441\u0435\u0441\u0441\u0438\u0438 Claude, \u0438 \u0432\u044B\u0439\u0442\u0438
|
|
10083
10977
|
-v, --version \u0432\u0435\u0440\u0441\u0438\u044F
|
|
10084
10978
|
-h, --help \u044D\u0442\u0430 \u0441\u043F\u0440\u0430\u0432\u043A\u0430
|
|
10085
10979
|
|
|
10086
10980
|
\u041E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435: CCV_PORT, CCV_HOST, CCV_DATA_DIR, CCV_WEB_ROOT, CCV_RELAY_URL,
|
|
10087
|
-
CCV_CLAUDE_PATH, CCV_BUNDLED_CLAUDE.
|
|
10981
|
+
CCV_CLAUDE_PATH, CCV_BUNDLED_CLAUDE, CCV_CODEX_PATH, CCV_AGY_PATH.
|
|
10088
10982
|
\u0424\u043B\u0430\u0433 \u0432\u0430\u0436\u043D\u0435\u0435 \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u043E\u0439 \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u044F, \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u0430\u044F \u0432\u0430\u0436\u043D\u0435\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E.`;
|
|
10089
10983
|
var options = {
|
|
10090
10984
|
port: { type: "string", short: "p" },
|
|
@@ -10136,7 +11030,7 @@ var server = new HostServer({
|
|
|
10136
11030
|
dataDir: defaults.dataDir,
|
|
10137
11031
|
// UI лежит в пакете рядом с бандлом — это и есть разница между установленной
|
|
10138
11032
|
// утилитой и запуском из репозитория, где сборка живёт в `apps/web/dist`.
|
|
10139
|
-
webRoot: process.env.CCV_WEB_ROOT ??
|
|
11033
|
+
webRoot: process.env.CCV_WEB_ROOT ?? path25.join(PACKAGE_ROOT, "web"),
|
|
10140
11034
|
version,
|
|
10141
11035
|
relayUrl: defaults.relayUrl
|
|
10142
11036
|
});
|
|
@@ -10165,7 +11059,7 @@ for (const signal of ["SIGINT", "SIGTERM"]) {
|
|
|
10165
11059
|
}
|
|
10166
11060
|
async function packageVersion() {
|
|
10167
11061
|
try {
|
|
10168
|
-
const text = await readFile17(
|
|
11062
|
+
const text = await readFile17(path25.join(PACKAGE_ROOT, "package.json"), "utf8");
|
|
10169
11063
|
return JSON.parse(text).version ?? "0.0.0";
|
|
10170
11064
|
} catch {
|
|
10171
11065
|
return "0.0.0";
|
|
@@ -10209,7 +11103,7 @@ function openBrowser(target) {
|
|
|
10209
11103
|
return;
|
|
10210
11104
|
}
|
|
10211
11105
|
const command = process.platform === "win32" ? { file: "cmd", args: ["/c", "start", "", target] } : process.platform === "darwin" ? { file: "open", args: [target] } : { file: "xdg-open", args: [target] };
|
|
10212
|
-
const child =
|
|
11106
|
+
const child = spawn4(command.file, command.args, {
|
|
10213
11107
|
stdio: "ignore",
|
|
10214
11108
|
detached: true,
|
|
10215
11109
|
windowsHide: true
|