@4pm/cli 1.3.2 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +262 -64
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -28794,6 +28794,7 @@ var WORKER_TOOL_CATALOG = [
|
|
|
28794
28794
|
var WORKER_TOOL_PREREQUISITE_IDS = WORKER_TOOL_CATALOG.filter(
|
|
28795
28795
|
(t) => t.installPackage === null
|
|
28796
28796
|
).map((t) => t.id);
|
|
28797
|
+
var WORKER_TOOL_BUNDLED_GLOBALS = ["npm", "corepack"];
|
|
28797
28798
|
|
|
28798
28799
|
// vendor/@4pm/constants/ws.ts
|
|
28799
28800
|
var WsChannel = {
|
|
@@ -32954,7 +32955,11 @@ var issueProvisioningTokenRequestSchema = external_exports.object({
|
|
|
32954
32955
|
ttlSec: external_exports.number().int().min(0).max(2592e3).optional()
|
|
32955
32956
|
});
|
|
32956
32957
|
var listWorkersQuerySchema = baseRequestSchema.extend({
|
|
32957
|
-
status: external_exports.enum(["online", "offline"]).optional()
|
|
32958
|
+
status: external_exports.enum(["online", "offline"]).optional(),
|
|
32959
|
+
/** Only workers whose live CPU/memory/disk usage % ≥ the given threshold (0–100). */
|
|
32960
|
+
minCpuPct: external_exports.coerce.number().min(0).max(100).optional(),
|
|
32961
|
+
minMemPct: external_exports.coerce.number().min(0).max(100).optional(),
|
|
32962
|
+
minDiskPct: external_exports.coerce.number().min(0).max(100).optional()
|
|
32958
32963
|
});
|
|
32959
32964
|
var updateWorkerRequestSchema = external_exports.object({
|
|
32960
32965
|
name: external_exports.string().min(1).max(100).optional()
|
|
@@ -33290,6 +33295,118 @@ var activityHeartbeatSchema = external_exports.object({
|
|
|
33290
33295
|
projectId: external_exports.string().uuid().optional()
|
|
33291
33296
|
});
|
|
33292
33297
|
|
|
33298
|
+
// src/core/worker-metrics.ts
|
|
33299
|
+
import { statfs, readFile } from "fs/promises";
|
|
33300
|
+
import { existsSync as existsSync4 } from "fs";
|
|
33301
|
+
import { totalmem, freemem, cpus, platform, arch } from "os";
|
|
33302
|
+
var CGROUP = "/sys/fs/cgroup";
|
|
33303
|
+
var MB = 1024 * 1024;
|
|
33304
|
+
var GB = 1024 * 1024 * 1024;
|
|
33305
|
+
async function readCgroup(file) {
|
|
33306
|
+
try {
|
|
33307
|
+
return (await readFile(`${CGROUP}/${file}`, "utf8")).trim();
|
|
33308
|
+
} catch {
|
|
33309
|
+
return null;
|
|
33310
|
+
}
|
|
33311
|
+
}
|
|
33312
|
+
function createWorkerMetricsSampler(diskPath) {
|
|
33313
|
+
const cgroupV2 = existsSync4(`${CGROUP}/cpu.stat`) && existsSync4(`${CGROUP}/memory.current`);
|
|
33314
|
+
let prev = null;
|
|
33315
|
+
async function cgroupCpuCount() {
|
|
33316
|
+
const raw = await readCgroup("cpu.max");
|
|
33317
|
+
if (raw) {
|
|
33318
|
+
const [quota, period] = raw.split(/\s+/);
|
|
33319
|
+
if (quota && quota !== "max" && period) {
|
|
33320
|
+
const n = Number(quota) / Number(period);
|
|
33321
|
+
if (n > 0) return Math.max(1, Math.round(n * 10) / 10);
|
|
33322
|
+
}
|
|
33323
|
+
}
|
|
33324
|
+
return cpus().length;
|
|
33325
|
+
}
|
|
33326
|
+
async function cgroupCpuPct(cpuCount) {
|
|
33327
|
+
const stat2 = await readCgroup("cpu.stat");
|
|
33328
|
+
const m = stat2?.match(/usage_usec\s+(\d+)/);
|
|
33329
|
+
const usageUsec = m ? Number(m[1]) : NaN;
|
|
33330
|
+
const now = Date.now();
|
|
33331
|
+
if (!Number.isFinite(usageUsec)) return 0;
|
|
33332
|
+
if (!prev) {
|
|
33333
|
+
prev = { busy: usageUsec, ref: now };
|
|
33334
|
+
return 0;
|
|
33335
|
+
}
|
|
33336
|
+
const dUsage = usageUsec - prev.busy;
|
|
33337
|
+
const dWall = (now - prev.ref) * 1e3;
|
|
33338
|
+
prev = { busy: usageUsec, ref: now };
|
|
33339
|
+
if (dWall <= 0) return 0;
|
|
33340
|
+
return clampPct(dUsage / (dWall * cpuCount) * 100);
|
|
33341
|
+
}
|
|
33342
|
+
function osCpuPct() {
|
|
33343
|
+
let busy = 0;
|
|
33344
|
+
let total = 0;
|
|
33345
|
+
for (const c of cpus()) {
|
|
33346
|
+
const t = c.times;
|
|
33347
|
+
busy += t.user + t.nice + t.sys + t.irq;
|
|
33348
|
+
total += t.user + t.nice + t.sys + t.irq + t.idle;
|
|
33349
|
+
}
|
|
33350
|
+
if (!prev) {
|
|
33351
|
+
prev = { busy, ref: total };
|
|
33352
|
+
return 0;
|
|
33353
|
+
}
|
|
33354
|
+
const dBusy = busy - prev.busy;
|
|
33355
|
+
const dTotal = total - prev.ref;
|
|
33356
|
+
prev = { busy, ref: total };
|
|
33357
|
+
if (dTotal <= 0) return 0;
|
|
33358
|
+
return clampPct(dBusy / dTotal * 100);
|
|
33359
|
+
}
|
|
33360
|
+
async function disk() {
|
|
33361
|
+
try {
|
|
33362
|
+
const fs2 = await statfs(diskPath);
|
|
33363
|
+
const total = fs2.blocks * fs2.bsize;
|
|
33364
|
+
const free = fs2.bavail * fs2.bsize;
|
|
33365
|
+
return { usedGb: round1((total - free) / GB), totalGb: round1(total / GB) };
|
|
33366
|
+
} catch {
|
|
33367
|
+
return { usedGb: 0, totalGb: 0 };
|
|
33368
|
+
}
|
|
33369
|
+
}
|
|
33370
|
+
return {
|
|
33371
|
+
async sample() {
|
|
33372
|
+
const at = (/* @__PURE__ */ new Date()).toISOString();
|
|
33373
|
+
const { usedGb: diskUsedGb, totalGb: diskTotalGb } = await disk();
|
|
33374
|
+
const base = { platform: platform(), arch: arch(), diskUsedGb, diskTotalGb, at };
|
|
33375
|
+
if (cgroupV2) {
|
|
33376
|
+
const memMaxRaw = await readCgroup("memory.max");
|
|
33377
|
+
const memCurRaw = await readCgroup("memory.current");
|
|
33378
|
+
const memTotalBytes = memMaxRaw && memMaxRaw !== "max" ? Number(memMaxRaw) : totalmem();
|
|
33379
|
+
const memUsedBytes = memCurRaw ? Number(memCurRaw) : totalmem() - freemem();
|
|
33380
|
+
const cpuCount = await cgroupCpuCount();
|
|
33381
|
+
const cpuPct = await cgroupCpuPct(cpuCount);
|
|
33382
|
+
return {
|
|
33383
|
+
...base,
|
|
33384
|
+
source: "cgroup",
|
|
33385
|
+
cpuCount,
|
|
33386
|
+
cpuPct,
|
|
33387
|
+
memUsedMb: Math.round(memUsedBytes / MB),
|
|
33388
|
+
memTotalMb: Math.round(memTotalBytes / MB)
|
|
33389
|
+
};
|
|
33390
|
+
}
|
|
33391
|
+
const total = totalmem();
|
|
33392
|
+
return {
|
|
33393
|
+
...base,
|
|
33394
|
+
source: "os",
|
|
33395
|
+
cpuCount: cpus().length,
|
|
33396
|
+
cpuPct: osCpuPct(),
|
|
33397
|
+
memUsedMb: Math.round((total - freemem()) / MB),
|
|
33398
|
+
memTotalMb: Math.round(total / MB)
|
|
33399
|
+
};
|
|
33400
|
+
}
|
|
33401
|
+
};
|
|
33402
|
+
}
|
|
33403
|
+
function clampPct(n) {
|
|
33404
|
+
return round1(Math.min(100, Math.max(0, n)));
|
|
33405
|
+
}
|
|
33406
|
+
function round1(n) {
|
|
33407
|
+
return Math.round(n * 10) / 10;
|
|
33408
|
+
}
|
|
33409
|
+
|
|
33293
33410
|
// vendor/@4pm/ws/batcher.ts
|
|
33294
33411
|
var OutputBatcher = class {
|
|
33295
33412
|
opts;
|
|
@@ -33432,6 +33549,12 @@ var WsChannels = {
|
|
|
33432
33549
|
// whether a web viewer is attached) so an unwatched cli syncs nothing.
|
|
33433
33550
|
CONSOLE_SYNC: "console.sync",
|
|
33434
33551
|
CONSOLE_WATCH: "console.watch",
|
|
33552
|
+
// worker resource live-metrics (ADR-0214): the cli streams live CPU/RAM/disk (cgroup-accurate)
|
|
33553
|
+
// only while `metrics.watch` (server → cli: whether a web viewer has the Workers tab open) is on,
|
|
33554
|
+
// so an unwatched cli samples nothing. Buffered ephemerally in Redis (never the DB), separate from
|
|
33555
|
+
// the low-frequency, DB-authoritative `machine.status`.
|
|
33556
|
+
METRICS_WATCH: "metrics.watch",
|
|
33557
|
+
MACHINE_METRICS: "machine.metrics",
|
|
33435
33558
|
// AI spec-assist (suggest/review/compose) moved off dedicated ai.* channels to
|
|
33436
33559
|
// command.dispatch({ ai:true }) → the profile-failover AI path (ADR-0100).
|
|
33437
33560
|
// quota & usage (ADR-0020)
|
|
@@ -33449,6 +33572,10 @@ var WsChannels = {
|
|
|
33449
33572
|
// server → cli (reply): read a finished command's captured output on demand (ADR-0115) —
|
|
33450
33573
|
// cli stores command-output/{commandId}.log; returns null when pruned/unavailable.
|
|
33451
33574
|
COMMAND_OUTPUT_READ: "command.output-read",
|
|
33575
|
+
// server → cli (reply): flush pending data before a rented machine is scrubbed (ADR-0210) —
|
|
33576
|
+
// the worker uploads its pending log tail (+ any queued history) then acks, so the release
|
|
33577
|
+
// sweep can finalise without waiting the full 5-minute timeout when the worker is online.
|
|
33578
|
+
RENTAL_FLUSH: "rental.flush",
|
|
33452
33579
|
// outbound review (ADR-0082): machine→server request, server→outbound evaluate, result back
|
|
33453
33580
|
REVIEW_REQUEST: "review.request",
|
|
33454
33581
|
REVIEW_EVALUATE: "review.evaluate",
|
|
@@ -33514,7 +33641,7 @@ function decryptPayload(key, payloadBase64, nonceBase64) {
|
|
|
33514
33641
|
}
|
|
33515
33642
|
|
|
33516
33643
|
// src/core/ws-client.ts
|
|
33517
|
-
import { existsSync as
|
|
33644
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync5, rmSync as rmSync5 } from "fs";
|
|
33518
33645
|
import { randomUUID as randomCommandId } from "crypto";
|
|
33519
33646
|
|
|
33520
33647
|
// src/core/update-scheduler.ts
|
|
@@ -33920,14 +34047,14 @@ async function runAiFailover(plan, commandId, cwd2, handlers) {
|
|
|
33920
34047
|
}
|
|
33921
34048
|
|
|
33922
34049
|
// src/core/ai-profile-state.ts
|
|
33923
|
-
import { existsSync as
|
|
34050
|
+
import { existsSync as existsSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
33924
34051
|
import { join as join7 } from "path";
|
|
33925
34052
|
function statePath(profileDir2) {
|
|
33926
34053
|
return join7(profileDir2, "ai-profiles.json");
|
|
33927
34054
|
}
|
|
33928
34055
|
function readState(profileDir2) {
|
|
33929
34056
|
const path = statePath(profileDir2);
|
|
33930
|
-
if (!
|
|
34057
|
+
if (!existsSync5(path)) return {};
|
|
33931
34058
|
try {
|
|
33932
34059
|
return JSON.parse(readFileSync7(path, "utf8"));
|
|
33933
34060
|
} catch {
|
|
@@ -34393,7 +34520,7 @@ async function evaluateReview(payload) {
|
|
|
34393
34520
|
}
|
|
34394
34521
|
|
|
34395
34522
|
// src/core/command-history.ts
|
|
34396
|
-
import { existsSync as
|
|
34523
|
+
import { existsSync as existsSync6, readFileSync as readFileSync10, writeFileSync as writeFileSync5 } from "fs";
|
|
34397
34524
|
import { join as join10 } from "path";
|
|
34398
34525
|
var MAX_ENTRIES = 1e3;
|
|
34399
34526
|
var filePath = null;
|
|
@@ -34457,7 +34584,7 @@ async function uploadHistory(cfg) {
|
|
|
34457
34584
|
}
|
|
34458
34585
|
function initCommandHistory(profileDir2, profileName, uploadMinutes = 10) {
|
|
34459
34586
|
filePath = join10(profileDir2, "command-history.json");
|
|
34460
|
-
if (
|
|
34587
|
+
if (existsSync6(filePath)) {
|
|
34461
34588
|
try {
|
|
34462
34589
|
entries = JSON.parse(readFileSync10(filePath, "utf8"));
|
|
34463
34590
|
} catch {
|
|
@@ -34515,7 +34642,7 @@ function finishCommand(commandId, exitCode, usage) {
|
|
|
34515
34642
|
// src/core/command-output-store.ts
|
|
34516
34643
|
import {
|
|
34517
34644
|
appendFileSync,
|
|
34518
|
-
existsSync as
|
|
34645
|
+
existsSync as existsSync7,
|
|
34519
34646
|
mkdirSync as mkdirSync3,
|
|
34520
34647
|
readFileSync as readFileSync11,
|
|
34521
34648
|
readdirSync as readdirSync3,
|
|
@@ -34543,7 +34670,7 @@ function appendCommandOutput(commandId, text) {
|
|
|
34543
34670
|
function readCommandOutput(commandId) {
|
|
34544
34671
|
if (!dir) return null;
|
|
34545
34672
|
const path = join11(dir, `${commandId}.log`);
|
|
34546
|
-
if (!
|
|
34673
|
+
if (!existsSync7(path)) return null;
|
|
34547
34674
|
try {
|
|
34548
34675
|
return readFileSync11(path, "utf8");
|
|
34549
34676
|
} catch {
|
|
@@ -34594,13 +34721,13 @@ async function listDir(path, root) {
|
|
|
34594
34721
|
}
|
|
34595
34722
|
|
|
34596
34723
|
// src/core/fs-read.ts
|
|
34597
|
-
import { readFile } from "fs/promises";
|
|
34724
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
34598
34725
|
import { resolve as resolve2 } from "path";
|
|
34599
34726
|
var MAX_BYTES = 256 * 1024;
|
|
34600
34727
|
async function readWorkerFile(path) {
|
|
34601
34728
|
const target = resolve2(path);
|
|
34602
34729
|
try {
|
|
34603
|
-
const buf = await
|
|
34730
|
+
const buf = await readFile2(target);
|
|
34604
34731
|
const truncated = buf.byteLength > MAX_BYTES;
|
|
34605
34732
|
const content = buf.subarray(0, MAX_BYTES).toString("utf8");
|
|
34606
34733
|
return { path: target, content, truncated };
|
|
@@ -34641,7 +34768,7 @@ async function writeWorkerFile(root, relPath, content) {
|
|
|
34641
34768
|
import { spawn as spawn4 } from "child_process";
|
|
34642
34769
|
import { execFile as execFile2 } from "child_process";
|
|
34643
34770
|
import { createHash as createHash3 } from "crypto";
|
|
34644
|
-
import { existsSync as
|
|
34771
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync4, readdirSync as readdirSync4, readFileSync as readFileSync12, statSync as statSync3 } from "fs";
|
|
34645
34772
|
import { join as join12 } from "path";
|
|
34646
34773
|
import { promisify as promisify2 } from "util";
|
|
34647
34774
|
var execFileAsync = promisify2(execFile2);
|
|
@@ -34662,7 +34789,7 @@ function authedUrl(url, token) {
|
|
|
34662
34789
|
}
|
|
34663
34790
|
async function ensureRepo(profileDir2, repo) {
|
|
34664
34791
|
const dir2 = repoDir(profileDir2, repo.url, repo.branch);
|
|
34665
|
-
if (
|
|
34792
|
+
if (existsSync8(join12(dir2, ".git"))) return dir2;
|
|
34666
34793
|
const url = authedUrl(repo.url, repo.token);
|
|
34667
34794
|
const gitEnv = { ...process.env, GIT_TERMINAL_PROMPT: "0" };
|
|
34668
34795
|
mkdirSync4(kbRoot(profileDir2), { recursive: true });
|
|
@@ -34673,11 +34800,11 @@ async function ensureRepo(profileDir2, repo) {
|
|
|
34673
34800
|
}
|
|
34674
34801
|
async function refreshSupportKb(profileDir2) {
|
|
34675
34802
|
const root = kbRoot(profileDir2);
|
|
34676
|
-
if (!
|
|
34803
|
+
if (!existsSync8(root)) return;
|
|
34677
34804
|
const gitEnv = { ...process.env, GIT_TERMINAL_PROMPT: "0" };
|
|
34678
34805
|
for (const entry of readdirSync4(root)) {
|
|
34679
34806
|
const dir2 = join12(root, entry);
|
|
34680
|
-
if (!
|
|
34807
|
+
if (!existsSync8(join12(dir2, ".git"))) continue;
|
|
34681
34808
|
try {
|
|
34682
34809
|
await execFileAsync("git", ["-C", dir2, "pull", "--ff-only"], { env: gitEnv });
|
|
34683
34810
|
} catch (err) {
|
|
@@ -34853,7 +34980,7 @@ async function runKnowledgeCompose(req, ai, physicRoot) {
|
|
|
34853
34980
|
}
|
|
34854
34981
|
|
|
34855
34982
|
// src/core/autonomous.ts
|
|
34856
|
-
import { readFile as
|
|
34983
|
+
import { readFile as readFile3, writeFile as writeFile2, chmod } from "fs/promises";
|
|
34857
34984
|
import { readFileSync as readFileSync13 } from "fs";
|
|
34858
34985
|
import { execFile as execFile3, spawn as spawn6 } from "child_process";
|
|
34859
34986
|
import { join as join13 } from "path";
|
|
@@ -34874,7 +35001,7 @@ var BOOK_FILES = {
|
|
|
34874
35001
|
var DEFAULT_CRON = "*/10 * * * *";
|
|
34875
35002
|
async function readText(path, fallback = "") {
|
|
34876
35003
|
try {
|
|
34877
|
-
return await
|
|
35004
|
+
return await readFile3(path, "utf8");
|
|
34878
35005
|
} catch {
|
|
34879
35006
|
return fallback;
|
|
34880
35007
|
}
|
|
@@ -35011,7 +35138,7 @@ ${req.content.trim()}
|
|
|
35011
35138
|
}
|
|
35012
35139
|
|
|
35013
35140
|
// src/core/agents.ts
|
|
35014
|
-
import { readFile as
|
|
35141
|
+
import { readFile as readFile4, writeFile as writeFile3, mkdir as mkdir3, readdir as readdir3, rm } from "fs/promises";
|
|
35015
35142
|
import { join as join14 } from "path";
|
|
35016
35143
|
var AGENTS_REL = ".claude/agents";
|
|
35017
35144
|
var SKILLS_REL = ".claude/skills";
|
|
@@ -35021,7 +35148,7 @@ function safeName(name) {
|
|
|
35021
35148
|
}
|
|
35022
35149
|
async function readText2(path, fallback = "") {
|
|
35023
35150
|
try {
|
|
35024
|
-
return await
|
|
35151
|
+
return await readFile4(path, "utf8");
|
|
35025
35152
|
} catch {
|
|
35026
35153
|
return fallback;
|
|
35027
35154
|
}
|
|
@@ -35090,7 +35217,7 @@ async function writeAgent(root, req) {
|
|
|
35090
35217
|
|
|
35091
35218
|
// src/core/packages.ts
|
|
35092
35219
|
import { createHash as createHash4 } from "crypto";
|
|
35093
|
-
import { readFile as
|
|
35220
|
+
import { readFile as readFile5, writeFile as writeFile4, mkdir as mkdir4, readdir as readdir4, rm as rm2, stat } from "fs/promises";
|
|
35094
35221
|
import { dirname as dirname4, join as join15, relative } from "path";
|
|
35095
35222
|
var AGENTS_REL2 = ".claude/agents";
|
|
35096
35223
|
var SKILLS_REL2 = ".claude/skills";
|
|
@@ -35100,7 +35227,7 @@ function safeName2(name) {
|
|
|
35100
35227
|
}
|
|
35101
35228
|
async function readMaybe(path) {
|
|
35102
35229
|
try {
|
|
35103
|
-
return await
|
|
35230
|
+
return await readFile5(path);
|
|
35104
35231
|
} catch {
|
|
35105
35232
|
return null;
|
|
35106
35233
|
}
|
|
@@ -35324,21 +35451,21 @@ function applyGitAuth(method) {
|
|
|
35324
35451
|
}
|
|
35325
35452
|
|
|
35326
35453
|
// src/core/secrets.ts
|
|
35327
|
-
import { readFile as
|
|
35454
|
+
import { readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
|
|
35328
35455
|
import { join as join18 } from "path";
|
|
35329
35456
|
var SECURITY_REL = "AI_SECURITY.md";
|
|
35330
35457
|
var PLACEHOLDER_REL = "AI_PLACEHOLDER.md";
|
|
35331
35458
|
var SECRETS_REL = "project.secrets.json";
|
|
35332
35459
|
async function readText3(path, fallback = "") {
|
|
35333
35460
|
try {
|
|
35334
|
-
return await
|
|
35461
|
+
return await readFile6(path, "utf8");
|
|
35335
35462
|
} catch {
|
|
35336
35463
|
return fallback;
|
|
35337
35464
|
}
|
|
35338
35465
|
}
|
|
35339
35466
|
async function readSecretsObject(root) {
|
|
35340
35467
|
try {
|
|
35341
|
-
const v = JSON.parse(await
|
|
35468
|
+
const v = JSON.parse(await readFile6(join18(root, SECRETS_REL), "utf8"));
|
|
35342
35469
|
return v && typeof v === "object" ? v : {};
|
|
35343
35470
|
} catch {
|
|
35344
35471
|
return {};
|
|
@@ -35387,7 +35514,7 @@ async function writeSecrets(root, req) {
|
|
|
35387
35514
|
}
|
|
35388
35515
|
|
|
35389
35516
|
// src/core/agent-tools.ts
|
|
35390
|
-
import { readFile as
|
|
35517
|
+
import { readFile as readFile7, writeFile as writeFile6, mkdir as mkdir5 } from "fs/promises";
|
|
35391
35518
|
import { dirname as dirname5, join as join19 } from "path";
|
|
35392
35519
|
var SHARED_REL = ".claude/settings.json";
|
|
35393
35520
|
var LOCAL_REL = ".claude/settings.local.json";
|
|
@@ -35398,7 +35525,7 @@ function fileFor(root, scope) {
|
|
|
35398
35525
|
}
|
|
35399
35526
|
async function readSettingsObject(path) {
|
|
35400
35527
|
try {
|
|
35401
|
-
const v = JSON.parse(await
|
|
35528
|
+
const v = JSON.parse(await readFile7(path, "utf8"));
|
|
35402
35529
|
return v && typeof v === "object" ? v : {};
|
|
35403
35530
|
} catch {
|
|
35404
35531
|
return {};
|
|
@@ -35430,7 +35557,7 @@ async function writeAgentTools(root, scope, permissions) {
|
|
|
35430
35557
|
}
|
|
35431
35558
|
|
|
35432
35559
|
// src/core/graph.ts
|
|
35433
|
-
import { readFile as
|
|
35560
|
+
import { readFile as readFile8, readdir as readdir5 } from "fs/promises";
|
|
35434
35561
|
import { join as join20, relative as relative2, dirname as dirname6, resolve as resolve4, extname, basename as basename2 } from "path";
|
|
35435
35562
|
var MAX_FILES = 2e3;
|
|
35436
35563
|
var MAX_NODES = 3e3;
|
|
@@ -35479,7 +35606,7 @@ async function buildDocs(root) {
|
|
|
35479
35606
|
const rel = relative2(root, f).split("\\").join("/");
|
|
35480
35607
|
let text = "";
|
|
35481
35608
|
try {
|
|
35482
|
-
text = await
|
|
35609
|
+
text = await readFile8(f, "utf8");
|
|
35483
35610
|
} catch {
|
|
35484
35611
|
continue;
|
|
35485
35612
|
}
|
|
@@ -35518,7 +35645,7 @@ async function buildCode(root) {
|
|
|
35518
35645
|
const rel = relative2(root, f).split("\\").join("/");
|
|
35519
35646
|
let text = "";
|
|
35520
35647
|
try {
|
|
35521
|
-
text = await
|
|
35648
|
+
text = await readFile8(f, "utf8");
|
|
35522
35649
|
} catch {
|
|
35523
35650
|
continue;
|
|
35524
35651
|
}
|
|
@@ -35570,10 +35697,10 @@ async function buildGraph(root, mode) {
|
|
|
35570
35697
|
}
|
|
35571
35698
|
|
|
35572
35699
|
// src/core/rag.ts
|
|
35573
|
-
import { readFile as
|
|
35574
|
-
import { existsSync as
|
|
35700
|
+
import { readFile as readFile9, writeFile as writeFile7, statfs as statfs2, mkdir as mkdir6 } from "fs/promises";
|
|
35701
|
+
import { existsSync as existsSync9 } from "fs";
|
|
35575
35702
|
import { execFile as execFile4, spawn as spawn7 } from "child_process";
|
|
35576
|
-
import { totalmem, cpus } from "os";
|
|
35703
|
+
import { totalmem as totalmem2, cpus as cpus2 } from "os";
|
|
35577
35704
|
import { join as join21 } from "path";
|
|
35578
35705
|
import { promisify as promisify4 } from "util";
|
|
35579
35706
|
var run3 = promisify4(execFile4);
|
|
@@ -35595,7 +35722,7 @@ async function detectPython() {
|
|
|
35595
35722
|
}
|
|
35596
35723
|
async function installLog(root) {
|
|
35597
35724
|
try {
|
|
35598
|
-
const text = await
|
|
35725
|
+
const text = await readFile9(join21(root, RAG_REL, "install.log"), "utf8");
|
|
35599
35726
|
return text.split("\n").filter((l) => l.length > 0).slice(-200);
|
|
35600
35727
|
} catch {
|
|
35601
35728
|
return [];
|
|
@@ -35643,28 +35770,28 @@ async function ragStatus(root) {
|
|
|
35643
35770
|
]) : [false, false, false];
|
|
35644
35771
|
let diskFreeGB = 0;
|
|
35645
35772
|
try {
|
|
35646
|
-
const s = await
|
|
35773
|
+
const s = await statfs2(root);
|
|
35647
35774
|
diskFreeGB = Math.round(s.bavail * s.bsize / 1e9 * 10) / 10;
|
|
35648
35775
|
} catch {
|
|
35649
35776
|
diskFreeGB = 0;
|
|
35650
35777
|
}
|
|
35651
35778
|
const gpu = (await tryRun("nvidia-smi", ["-L"])).ok;
|
|
35652
35779
|
const machine = {
|
|
35653
|
-
ramGB: Math.round(
|
|
35654
|
-
cpus:
|
|
35780
|
+
ramGB: Math.round(totalmem2() / 1e9 * 10) / 10,
|
|
35781
|
+
cpus: cpus2().length,
|
|
35655
35782
|
diskFreeGB,
|
|
35656
35783
|
gpu
|
|
35657
35784
|
};
|
|
35658
35785
|
let modelName = "";
|
|
35659
35786
|
try {
|
|
35660
|
-
modelName = (await
|
|
35787
|
+
modelName = (await readFile9(join21(root, RAG_REL, ".installed"), "utf8")).trim();
|
|
35661
35788
|
} catch {
|
|
35662
35789
|
modelName = "";
|
|
35663
35790
|
}
|
|
35664
35791
|
const modelPresent = modelName.length > 0;
|
|
35665
35792
|
return {
|
|
35666
35793
|
installed: fastembed && sqliteVec && modelPresent,
|
|
35667
|
-
installing:
|
|
35794
|
+
installing: existsSync9(join21(root, RAG_REL, ".installing")),
|
|
35668
35795
|
python: { found: py.found, version: py.version },
|
|
35669
35796
|
deps: { pip, fastembed, sqliteVec },
|
|
35670
35797
|
model: { present: modelPresent, name: modelName },
|
|
@@ -35675,9 +35802,9 @@ async function ragStatus(root) {
|
|
|
35675
35802
|
};
|
|
35676
35803
|
}
|
|
35677
35804
|
async function readIndexMeta(root) {
|
|
35678
|
-
const indexing =
|
|
35805
|
+
const indexing = existsSync9(join21(root, RAG_REL, ".indexing"));
|
|
35679
35806
|
try {
|
|
35680
|
-
const m = JSON.parse(await
|
|
35807
|
+
const m = JSON.parse(await readFile9(join21(root, RAG_REL, ".index.json"), "utf8"));
|
|
35681
35808
|
return {
|
|
35682
35809
|
present: true,
|
|
35683
35810
|
indexing,
|
|
@@ -35750,8 +35877,8 @@ async function ensureEngine(root) {
|
|
|
35750
35877
|
async function ragReindex(root) {
|
|
35751
35878
|
const py = await detectPython();
|
|
35752
35879
|
if (!py.found) return { ok: false, started: false, error: "python3 not found" };
|
|
35753
|
-
if (!
|
|
35754
|
-
if (
|
|
35880
|
+
if (!existsSync9(join21(root, RAG_REL, ".installed"))) return { ok: false, started: false, error: "RAG is not installed" };
|
|
35881
|
+
if (existsSync9(join21(root, RAG_REL, ".indexing"))) return { ok: true, started: true };
|
|
35755
35882
|
await ensureEngine(root);
|
|
35756
35883
|
const script = `
|
|
35757
35884
|
set +e
|
|
@@ -35771,7 +35898,7 @@ rm -f "${RAG_REL}/.indexing"
|
|
|
35771
35898
|
async function ragQuery(root, queryText, k = 8) {
|
|
35772
35899
|
const py = await detectPython();
|
|
35773
35900
|
if (!py.found) return { results: [], error: "python3 not found" };
|
|
35774
|
-
if (!
|
|
35901
|
+
if (!existsSync9(join21(root, RAG_REL, "index.db"))) return { results: [], error: "no index \u2014 reindex first" };
|
|
35775
35902
|
await ensureEngine(root);
|
|
35776
35903
|
try {
|
|
35777
35904
|
const { stdout } = await run3(
|
|
@@ -35788,7 +35915,7 @@ async function ragQuery(root, queryText, k = 8) {
|
|
|
35788
35915
|
async function ragInstall(root, model) {
|
|
35789
35916
|
const py = await detectPython();
|
|
35790
35917
|
if (!py.found) return { ok: false, started: false, error: "python3 not found on the worker" };
|
|
35791
|
-
if (
|
|
35918
|
+
if (existsSync9(join21(root, RAG_REL, ".installing"))) return { ok: true, started: true };
|
|
35792
35919
|
try {
|
|
35793
35920
|
await mkdir6(join21(root, RAG_REL), { recursive: true });
|
|
35794
35921
|
} catch {
|
|
@@ -35817,7 +35944,7 @@ rm -f "${RAG_REL}/.installing"
|
|
|
35817
35944
|
}
|
|
35818
35945
|
|
|
35819
35946
|
// src/core/git-diff.ts
|
|
35820
|
-
import { readFile as
|
|
35947
|
+
import { readFile as readFile10 } from "fs/promises";
|
|
35821
35948
|
import { execFile as execFile5 } from "child_process";
|
|
35822
35949
|
import { basename as basename3, dirname as dirname7, resolve as resolve5 } from "path";
|
|
35823
35950
|
import { promisify as promisify5 } from "util";
|
|
@@ -35828,7 +35955,7 @@ async function gitDiff(path) {
|
|
|
35828
35955
|
const base = basename3(target);
|
|
35829
35956
|
let newContent = "";
|
|
35830
35957
|
try {
|
|
35831
|
-
newContent = await
|
|
35958
|
+
newContent = await readFile10(target, "utf8");
|
|
35832
35959
|
} catch {
|
|
35833
35960
|
}
|
|
35834
35961
|
let oldContent = "";
|
|
@@ -35877,7 +36004,7 @@ ${stderr}`;
|
|
|
35877
36004
|
|
|
35878
36005
|
// src/core/git-ssh-key.ts
|
|
35879
36006
|
import { execFile as execFile7 } from "child_process";
|
|
35880
|
-
import { readFile as
|
|
36007
|
+
import { readFile as readFile11, rm as rm3, mkdir as mkdir7 } from "fs/promises";
|
|
35881
36008
|
import { join as join22 } from "path";
|
|
35882
36009
|
import { promisify as promisify7 } from "util";
|
|
35883
36010
|
var run6 = promisify7(execFile7);
|
|
@@ -35888,7 +36015,7 @@ function keyPaths(profileDir2) {
|
|
|
35888
36015
|
}
|
|
35889
36016
|
async function readPublicKey(pub) {
|
|
35890
36017
|
try {
|
|
35891
|
-
return (await
|
|
36018
|
+
return (await readFile11(pub, "utf8")).trim();
|
|
35892
36019
|
} catch {
|
|
35893
36020
|
return null;
|
|
35894
36021
|
}
|
|
@@ -36197,12 +36324,12 @@ async function addProject(payload, profileDir2, onProgress) {
|
|
|
36197
36324
|
}
|
|
36198
36325
|
|
|
36199
36326
|
// src/core/config-sync.ts
|
|
36200
|
-
import { existsSync as
|
|
36327
|
+
import { existsSync as existsSync10, readFileSync as readFileSync14 } from "fs";
|
|
36201
36328
|
import { join as join24 } from "path";
|
|
36202
36329
|
var SERVER_MANAGED_KEYS = ["physicPath", "sessionSwitchPct", "perPromptTokenLimit"];
|
|
36203
36330
|
function readConfigText(profileDir2) {
|
|
36204
36331
|
const path = join24(profileDir2, "config.json");
|
|
36205
|
-
if (
|
|
36332
|
+
if (existsSync10(path)) {
|
|
36206
36333
|
try {
|
|
36207
36334
|
return readFileSync14(path, "utf8");
|
|
36208
36335
|
} catch {
|
|
@@ -36287,9 +36414,11 @@ async function listExtras() {
|
|
|
36287
36414
|
} catch {
|
|
36288
36415
|
return [];
|
|
36289
36416
|
}
|
|
36290
|
-
const catalogPkgs = new Set(
|
|
36291
|
-
|
|
36292
|
-
|
|
36417
|
+
const catalogPkgs = new Set(WORKER_TOOL_BUNDLED_GLOBALS);
|
|
36418
|
+
for (const t of WORKER_TOOL_CATALOG) {
|
|
36419
|
+
catalogPkgs.add(t.id);
|
|
36420
|
+
if (t.installPackage) catalogPkgs.add(t.installPackage);
|
|
36421
|
+
}
|
|
36293
36422
|
return Object.entries(deps).filter(([name]) => !catalogPkgs.has(name)).map(([name, info]) => ({
|
|
36294
36423
|
id: name,
|
|
36295
36424
|
label: name,
|
|
@@ -36327,6 +36456,9 @@ function resolvePackage(name, op) {
|
|
|
36327
36456
|
if (WORKER_TOOL_PREREQUISITE_IDS.includes(name)) {
|
|
36328
36457
|
return { error: `"${name}" is a prerequisite and cannot be ${op}ed from here.` };
|
|
36329
36458
|
}
|
|
36459
|
+
if (WORKER_TOOL_BUNDLED_GLOBALS.includes(name)) {
|
|
36460
|
+
return { error: `"${name}" ships with Node and cannot be ${op}ed from here.` };
|
|
36461
|
+
}
|
|
36330
36462
|
if (!NPM_NAME.test(name)) return { error: `Invalid package name: "${name}".` };
|
|
36331
36463
|
return { pkg: name };
|
|
36332
36464
|
}
|
|
@@ -36363,6 +36495,8 @@ var CLOSE_DRAINING = 4001;
|
|
|
36363
36495
|
var OFFLINE_BUFFER_MAX_BYTES = 512 * 1024;
|
|
36364
36496
|
var CONSOLE_SNAPSHOT_INTERVAL_MS = 3e4;
|
|
36365
36497
|
var CONSOLE_WATCH_LEASE_MS = 45e3;
|
|
36498
|
+
var METRICS_SAMPLE_INTERVAL_MS = 5e3;
|
|
36499
|
+
var METRICS_WATCH_LEASE_MS = 45e3;
|
|
36366
36500
|
function toDtoEntry(e) {
|
|
36367
36501
|
return { id: e.id, source: e.source, kind: e.kind, text: e.text, level: e.level, resultKind: e.resultKind };
|
|
36368
36502
|
}
|
|
@@ -36455,6 +36589,16 @@ var WsClient = class {
|
|
|
36455
36589
|
consoleSnapshotTimer = null;
|
|
36456
36590
|
/** Lease expiry: stop syncing if the server does not renew `console.watch` in time. */
|
|
36457
36591
|
consoleWatchExpiry = null;
|
|
36592
|
+
/**
|
|
36593
|
+
* Worker-metrics state (ADR-0214). `metricsWatching` is set by `metrics.watch` (a viewer has the
|
|
36594
|
+
* Workers tab open); only then does the cli sample + emit `machine.metrics`. The sampler holds the
|
|
36595
|
+
* CPU-delta baseline; both timers are lease-driven like console-sync and reset on reconnect.
|
|
36596
|
+
*/
|
|
36597
|
+
metricsWatching = false;
|
|
36598
|
+
metricsTimer = null;
|
|
36599
|
+
metricsWatchExpiry = null;
|
|
36600
|
+
/** Lazily created on the first `metrics.watch` (keeps the CPU-delta baseline across samples). */
|
|
36601
|
+
metricsSampler = null;
|
|
36458
36602
|
/** cli → server requests awaiting a reply (quota.check — ADR-0020). */
|
|
36459
36603
|
pending = /* @__PURE__ */ new Map();
|
|
36460
36604
|
/** Daily scheduled cli auto-update (ADR-0074); policy fed from each ws_token. */
|
|
@@ -36690,6 +36834,7 @@ var WsClient = class {
|
|
|
36690
36834
|
}
|
|
36691
36835
|
logger.info("ws.connected", { version: CLI_VERSION });
|
|
36692
36836
|
this.stopConsoleSync();
|
|
36837
|
+
this.stopMetricsSync();
|
|
36693
36838
|
this.bus.setStatus("connected");
|
|
36694
36839
|
this.finishReconnect();
|
|
36695
36840
|
this.sendMachineStatus();
|
|
@@ -37152,6 +37297,11 @@ var WsClient = class {
|
|
|
37152
37297
|
this.send(WsChannels.COMMAND_OUTPUT_READ, { output }, message.id);
|
|
37153
37298
|
break;
|
|
37154
37299
|
}
|
|
37300
|
+
case WsChannels.RENTAL_FLUSH: {
|
|
37301
|
+
this.uploadLog();
|
|
37302
|
+
this.send(WsChannels.RENTAL_FLUSH, { ok: true }, message.id);
|
|
37303
|
+
break;
|
|
37304
|
+
}
|
|
37155
37305
|
case WsChannels.PROJECT_CREATE:
|
|
37156
37306
|
void scaffoldProject(
|
|
37157
37307
|
payload,
|
|
@@ -37176,6 +37326,9 @@ var WsClient = class {
|
|
|
37176
37326
|
case WsChannels.CONSOLE_WATCH:
|
|
37177
37327
|
this.setConsoleWatching(payload.on);
|
|
37178
37328
|
break;
|
|
37329
|
+
case WsChannels.METRICS_WATCH:
|
|
37330
|
+
this.setMetricsWatching(payload.on);
|
|
37331
|
+
break;
|
|
37179
37332
|
default:
|
|
37180
37333
|
this.bus.log(`Unsupported channel: ${message.channel}`, "warn");
|
|
37181
37334
|
}
|
|
@@ -37605,6 +37758,50 @@ var WsClient = class {
|
|
|
37605
37758
|
this.consoleWatchExpiry = null;
|
|
37606
37759
|
}
|
|
37607
37760
|
}
|
|
37761
|
+
/**
|
|
37762
|
+
* Handle `metrics.watch` (ADR-0214) — a renewable lease mirroring `console.watch`. `on` renews it:
|
|
37763
|
+
* on the first assertion the cli samples immediately + starts the ~5s sampler; later renewals just
|
|
37764
|
+
* extend the lease. No renewal within `METRICS_WATCH_LEASE_MS` (or an explicit `on:false`) ⇒ stop.
|
|
37765
|
+
*/
|
|
37766
|
+
setMetricsWatching(on) {
|
|
37767
|
+
if (!on) {
|
|
37768
|
+
this.stopMetricsSync();
|
|
37769
|
+
return;
|
|
37770
|
+
}
|
|
37771
|
+
if (this.metricsWatchExpiry) clearTimeout(this.metricsWatchExpiry);
|
|
37772
|
+
this.metricsWatchExpiry = setTimeout(() => this.stopMetricsSync(), METRICS_WATCH_LEASE_MS);
|
|
37773
|
+
this.metricsWatchExpiry.unref?.();
|
|
37774
|
+
if (this.metricsWatching) return;
|
|
37775
|
+
this.metricsWatching = true;
|
|
37776
|
+
void this.sendMachineMetrics();
|
|
37777
|
+
this.metricsTimer = setInterval(() => void this.sendMachineMetrics(), METRICS_SAMPLE_INTERVAL_MS);
|
|
37778
|
+
this.metricsTimer.unref?.();
|
|
37779
|
+
}
|
|
37780
|
+
/** Stop sampling worker resources (lease expired / viewer left / reconnect) — clears both timers. */
|
|
37781
|
+
stopMetricsSync() {
|
|
37782
|
+
this.metricsWatching = false;
|
|
37783
|
+
if (this.metricsTimer) {
|
|
37784
|
+
clearInterval(this.metricsTimer);
|
|
37785
|
+
this.metricsTimer = null;
|
|
37786
|
+
}
|
|
37787
|
+
if (this.metricsWatchExpiry) {
|
|
37788
|
+
clearTimeout(this.metricsWatchExpiry);
|
|
37789
|
+
this.metricsWatchExpiry = null;
|
|
37790
|
+
}
|
|
37791
|
+
}
|
|
37792
|
+
/** Sample the worker's live CPU/RAM/disk and push a `machine.metrics` frame (ADR-0214). */
|
|
37793
|
+
async sendMachineMetrics() {
|
|
37794
|
+
if (!this.sessionKey) return;
|
|
37795
|
+
try {
|
|
37796
|
+
if (!this.metricsSampler) this.metricsSampler = createWorkerMetricsSampler(this.context.profileDir);
|
|
37797
|
+
const resources = await this.metricsSampler.sample();
|
|
37798
|
+
this.send(WsChannels.MACHINE_METRICS, {
|
|
37799
|
+
fingerprint: this.context.machine.fingerprint,
|
|
37800
|
+
resources
|
|
37801
|
+
});
|
|
37802
|
+
} catch {
|
|
37803
|
+
}
|
|
37804
|
+
}
|
|
37608
37805
|
/**
|
|
37609
37806
|
* Send a cli → server request and await the reply by envelope id (15s timeout).
|
|
37610
37807
|
* Used for quota.check before spawning an AI cli (ADR-0020).
|
|
@@ -37677,7 +37874,7 @@ var WsClient = class {
|
|
|
37677
37874
|
/** Create the physic folder at an absolute path if missing (best-effort). */
|
|
37678
37875
|
ensurePhysicFolderPath(folder) {
|
|
37679
37876
|
try {
|
|
37680
|
-
if (!
|
|
37877
|
+
if (!existsSync11(folder)) {
|
|
37681
37878
|
mkdirSync5(folder, { recursive: true });
|
|
37682
37879
|
this.bus.log(`Created physic project folder: ${folder}`);
|
|
37683
37880
|
}
|
|
@@ -37706,7 +37903,7 @@ var WsClient = class {
|
|
|
37706
37903
|
projects: [],
|
|
37707
37904
|
version: CLI_VERSION,
|
|
37708
37905
|
physicPath,
|
|
37709
|
-
physicPathExists: physicPath ?
|
|
37906
|
+
physicPathExists: physicPath ? existsSync11(physicPath) : void 0,
|
|
37710
37907
|
// Real coarse state (ADR-0152): !paused and a recent tick (was hard-coded false).
|
|
37711
37908
|
autonomousRunning: physicPath ? isAutonomousRunning(physicPath) : false
|
|
37712
37909
|
});
|
|
@@ -37729,6 +37926,7 @@ var WsClient = class {
|
|
|
37729
37926
|
this.logUploadTimer = null;
|
|
37730
37927
|
if (this.kbRefreshTimer) clearInterval(this.kbRefreshTimer);
|
|
37731
37928
|
this.kbRefreshTimer = null;
|
|
37929
|
+
this.stopMetricsSync();
|
|
37732
37930
|
}
|
|
37733
37931
|
/**
|
|
37734
37932
|
* Poll the Claude subscription usage API and push a `machine.usage` snapshot (ADR-0072).
|
|
@@ -38415,12 +38613,12 @@ var isWebWorker = typeof WorkerGlobalScope !== "undefined" && globalThis instanc
|
|
|
38415
38613
|
var isDedicatedWorker = typeof DedicatedWorkerGlobalScope !== "undefined" && globalThis instanceof DedicatedWorkerGlobalScope;
|
|
38416
38614
|
var isSharedWorker = typeof SharedWorkerGlobalScope !== "undefined" && globalThis instanceof SharedWorkerGlobalScope;
|
|
38417
38615
|
var isServiceWorker = typeof ServiceWorkerGlobalScope !== "undefined" && globalThis instanceof ServiceWorkerGlobalScope;
|
|
38418
|
-
var
|
|
38419
|
-
var isMacOs =
|
|
38420
|
-
var isWindows =
|
|
38421
|
-
var isLinux =
|
|
38422
|
-
var isIos =
|
|
38423
|
-
var isAndroid =
|
|
38616
|
+
var platform2 = globalThis.navigator?.userAgentData?.platform;
|
|
38617
|
+
var isMacOs = platform2 === "macOS" || globalThis.navigator?.platform === "MacIntel" || globalThis.navigator?.userAgent?.includes(" Mac ") === true || globalThis.process?.platform === "darwin";
|
|
38618
|
+
var isWindows = platform2 === "Windows" || globalThis.navigator?.platform === "Win32" || globalThis.process?.platform === "win32";
|
|
38619
|
+
var isLinux = platform2 === "Linux" || globalThis.navigator?.platform?.startsWith("Linux") === true || globalThis.navigator?.userAgent?.includes(" Linux ") === true || globalThis.process?.platform === "linux";
|
|
38620
|
+
var isIos = platform2 === "iOS" || globalThis.navigator?.platform === "MacIntel" && globalThis.navigator?.maxTouchPoints > 1 || /iPad|iPhone|iPod/.test(globalThis.navigator?.platform);
|
|
38621
|
+
var isAndroid = platform2 === "Android" || globalThis.navigator?.platform === "Android" || globalThis.navigator?.userAgent?.includes(" Android ") === true || globalThis.process?.platform === "android";
|
|
38424
38622
|
|
|
38425
38623
|
// ../../node_modules/.pnpm/ansi-escapes@7.3.0/node_modules/ansi-escapes/base.js
|
|
38426
38624
|
var ESC = "\x1B[";
|
|
@@ -43874,7 +44072,7 @@ var import_react21 = __toESM(require_react(), 1);
|
|
|
43874
44072
|
var import_react26 = __toESM(require_react(), 1);
|
|
43875
44073
|
|
|
43876
44074
|
// src/core/input-history.ts
|
|
43877
|
-
import { existsSync as
|
|
44075
|
+
import { existsSync as existsSync13, readFileSync as readFileSync17, writeFileSync as writeFileSync9 } from "fs";
|
|
43878
44076
|
import { join as join28 } from "path";
|
|
43879
44077
|
var MAX_HISTORY = 200;
|
|
43880
44078
|
function historyPath(profileDir2) {
|
|
@@ -43882,7 +44080,7 @@ function historyPath(profileDir2) {
|
|
|
43882
44080
|
}
|
|
43883
44081
|
function loadInputHistory(profileDir2) {
|
|
43884
44082
|
const path = historyPath(profileDir2);
|
|
43885
|
-
if (!
|
|
44083
|
+
if (!existsSync13(path)) return [];
|
|
43886
44084
|
try {
|
|
43887
44085
|
const data = JSON.parse(readFileSync17(path, "utf8"));
|
|
43888
44086
|
return Array.isArray(data) ? data.filter((x) => typeof x === "string") : [];
|
|
@@ -44144,7 +44342,7 @@ function TranscriptLine({ line }) {
|
|
|
44144
44342
|
var import_react24 = __toESM(require_react(), 1);
|
|
44145
44343
|
|
|
44146
44344
|
// src/ui/slash-commands.ts
|
|
44147
|
-
import { existsSync as
|
|
44345
|
+
import { existsSync as existsSync14 } from "fs";
|
|
44148
44346
|
import { join as join29 } from "path";
|
|
44149
44347
|
var CONFIG_KEYS = [
|
|
44150
44348
|
"aiCli",
|
|
@@ -44207,7 +44405,7 @@ function runConfig(ctx) {
|
|
|
44207
44405
|
ctx.print(`\u2714 ${verb} default config: ${path}`);
|
|
44208
44406
|
ctx.print("add claude profiles: /config set claudeHome .claude .claude-1 (tried in order)");
|
|
44209
44407
|
};
|
|
44210
|
-
if (
|
|
44408
|
+
if (existsSync14(path)) {
|
|
44211
44409
|
ctx.confirm(
|
|
44212
44410
|
`config exists: ${path} \u2014 replace it with defaults? (y/N)`,
|
|
44213
44411
|
() => writeDefaults("replaced with")
|