@4pm/cli 1.4.1 → 1.4.3

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.
Files changed (2) hide show
  1. package/dist/index.js +287 -127
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -28550,7 +28550,7 @@ ${INSECURE_URL_WARNING}
28550
28550
 
28551
28551
  // src/commands/start.ts
28552
28552
  import { spawn as spawn9 } from "child_process";
28553
- import { join as join30 } from "path";
28553
+ import { join as join29 } from "path";
28554
28554
 
28555
28555
  // src/core/update.ts
28556
28556
  import { execSync as execSync2 } from "child_process";
@@ -28723,7 +28723,7 @@ async function checkAndUpdate(serverUrl, autoUpdate) {
28723
28723
  // src/core/ws-client.ts
28724
28724
  init_wrapper();
28725
28725
  import { randomUUID } from "crypto";
28726
- import { basename as basename4, join as join25 } from "path";
28726
+ import { basename as basename4, join as join24 } from "path";
28727
28727
 
28728
28728
  // vendor/@4pm/utils/helpers.ts
28729
28729
  function backoffJitterMs(attempt, baseMs = 500, maxMs = 1e4) {
@@ -33087,6 +33087,19 @@ var createProjectRequestSchema = external_exports.object({
33087
33087
  var copyProjectRequestSchema = external_exports.object({
33088
33088
  name: external_exports.string().min(1).max(100)
33089
33089
  });
33090
+ var PROJECT_ALERT_KINDS = ["budgetPercent", "absolute"];
33091
+ var projectAlertRuleSchema = external_exports.object({
33092
+ id: external_exports.string().min(1).max(64),
33093
+ kind: external_exports.enum(PROJECT_ALERT_KINDS),
33094
+ metric: external_exports.enum([UsageMetric.AI_TOKENS, UsageMetric.COMMANDS]),
33095
+ threshold: external_exports.number().int().min(1),
33096
+ email: external_exports.union([external_exports.string().email(), external_exports.literal("")]).optional(),
33097
+ notifyUserId: external_exports.union([external_exports.string().uuid(), external_exports.literal("")]).optional(),
33098
+ enabled: external_exports.boolean().default(true)
33099
+ });
33100
+ var projectAlertsSchema = external_exports.object({
33101
+ rules: external_exports.array(projectAlertRuleSchema).max(20).default([])
33102
+ });
33090
33103
  var DEFAULT_OUTBOUND_RULES = {
33091
33104
  secret: [
33092
33105
  String.raw`/\b(api[_-]?key|secret|password|passwd|access[_-]?token|bearer)\b\s*[:=]\s*\S+/i`,
@@ -33309,9 +33322,47 @@ async function readCgroup(file) {
33309
33322
  return null;
33310
33323
  }
33311
33324
  }
33325
+ function parseKv(text) {
33326
+ const map = /* @__PURE__ */ new Map();
33327
+ if (!text) return map;
33328
+ for (const line of text.split("\n")) {
33329
+ const [k, v] = line.trim().split(/\s+/);
33330
+ if (k && v !== void 0) {
33331
+ const n = Number(v);
33332
+ if (Number.isFinite(n)) map.set(k, n);
33333
+ }
33334
+ }
33335
+ return map;
33336
+ }
33337
+ function parsePressureSome(text) {
33338
+ if (!text) return void 0;
33339
+ const some = text.split("\n").find((l) => l.startsWith("some "));
33340
+ const m = some?.match(/avg10=([\d.]+)/);
33341
+ const n = m ? Number(m[1]) : NaN;
33342
+ return Number.isFinite(n) ? clampPct(n) : void 0;
33343
+ }
33344
+ function parseIoStat(text) {
33345
+ if (!text) return null;
33346
+ let rBytes = 0;
33347
+ let wBytes = 0;
33348
+ for (const line of text.split("\n")) {
33349
+ const r = line.match(/\brbytes=(\d+)/);
33350
+ const w = line.match(/\bwbytes=(\d+)/);
33351
+ if (r) rBytes += Number(r[1]);
33352
+ if (w) wBytes += Number(w[1]);
33353
+ }
33354
+ return { rBytes, wBytes };
33355
+ }
33356
+ function parseMaybeMax(text) {
33357
+ if (text === null) return null;
33358
+ if (text === "max") return null;
33359
+ const n = Number(text);
33360
+ return Number.isFinite(n) ? n : null;
33361
+ }
33312
33362
  function createWorkerMetricsSampler(diskPath) {
33313
33363
  const cgroupV2 = existsSync4(`${CGROUP}/cpu.stat`) && existsSync4(`${CGROUP}/memory.current`);
33314
- let prev = null;
33364
+ let cgPrev = null;
33365
+ let osPrev = null;
33315
33366
  async function cgroupCpuCount() {
33316
33367
  const raw = await readCgroup("cpu.max");
33317
33368
  if (raw) {
@@ -33323,22 +33374,6 @@ function createWorkerMetricsSampler(diskPath) {
33323
33374
  }
33324
33375
  return cpus().length;
33325
33376
  }
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
33377
  function osCpuPct() {
33343
33378
  let busy = 0;
33344
33379
  let total = 0;
@@ -33347,13 +33382,13 @@ function createWorkerMetricsSampler(diskPath) {
33347
33382
  busy += t.user + t.nice + t.sys + t.irq;
33348
33383
  total += t.user + t.nice + t.sys + t.irq + t.idle;
33349
33384
  }
33350
- if (!prev) {
33351
- prev = { busy, ref: total };
33385
+ if (!osPrev) {
33386
+ osPrev = { busy, total };
33352
33387
  return 0;
33353
33388
  }
33354
- const dBusy = busy - prev.busy;
33355
- const dTotal = total - prev.ref;
33356
- prev = { busy, ref: total };
33389
+ const dBusy = busy - osPrev.busy;
33390
+ const dTotal = total - osPrev.total;
33391
+ osPrev = { busy, total };
33357
33392
  if (dTotal <= 0) return 0;
33358
33393
  return clampPct(dBusy / dTotal * 100);
33359
33394
  }
@@ -33367,9 +33402,74 @@ function createWorkerMetricsSampler(diskPath) {
33367
33402
  return { usedGb: 0, totalGb: 0 };
33368
33403
  }
33369
33404
  }
33405
+ async function cgroupExtended(cpuCount, now) {
33406
+ const [cpuStatRaw, memStatRaw, ioStatRaw, cpuPsi, memPsi, ioPsi, swapCurRaw, swapMaxRaw, memEventsRaw, pidsCurRaw, pidsMaxRaw] = await Promise.all([
33407
+ readCgroup("cpu.stat"),
33408
+ readCgroup("memory.stat"),
33409
+ readCgroup("io.stat"),
33410
+ readCgroup("cpu.pressure"),
33411
+ readCgroup("memory.pressure"),
33412
+ readCgroup("io.pressure"),
33413
+ readCgroup("memory.swap.current"),
33414
+ readCgroup("memory.swap.max"),
33415
+ readCgroup("memory.events"),
33416
+ readCgroup("pids.current"),
33417
+ readCgroup("pids.max")
33418
+ ]);
33419
+ const cpuStat = parseKv(cpuStatRaw);
33420
+ const usageUsec = cpuStat.get("usage_usec") ?? NaN;
33421
+ const nrThrottled = cpuStat.get("nr_throttled") ?? 0;
33422
+ const nrPeriods = cpuStat.get("nr_periods") ?? 0;
33423
+ const io = parseIoStat(ioStatRaw);
33424
+ const extra = {};
33425
+ extra.cpuPressurePct = parsePressureSome(cpuPsi);
33426
+ extra.memPressurePct = parsePressureSome(memPsi);
33427
+ extra.ioPressurePct = parsePressureSome(ioPsi);
33428
+ const memStat = parseKv(memStatRaw);
33429
+ if (memStat.has("anon")) extra.memAnonMb = Math.round(memStat.get("anon") / MB);
33430
+ if (memStat.has("file")) extra.memCacheMb = Math.round(memStat.get("file") / MB);
33431
+ if (swapCurRaw !== null) extra.swapUsedMb = Math.round(Number(swapCurRaw) / MB);
33432
+ if (swapMaxRaw !== null) {
33433
+ const max = parseMaybeMax(swapMaxRaw);
33434
+ extra.swapTotalMb = max === null ? null : Math.round(max / MB);
33435
+ }
33436
+ const memEvents = parseKv(memEventsRaw);
33437
+ if (memEvents.has("oom_kill")) extra.oomKills = memEvents.get("oom_kill");
33438
+ if (pidsCurRaw !== null) {
33439
+ const n = Number(pidsCurRaw);
33440
+ if (Number.isFinite(n)) extra.pidsCurrent = n;
33441
+ }
33442
+ if (pidsMaxRaw !== null) extra.pidsMax = parseMaybeMax(pidsMaxRaw);
33443
+ let cpuPct = 0;
33444
+ if (Number.isFinite(usageUsec)) {
33445
+ if (cgPrev) {
33446
+ const dWallUsec = (now - cgPrev.wallMs) * 1e3;
33447
+ if (dWallUsec > 0) cpuPct = clampPct((usageUsec - cgPrev.usageUsec) / (dWallUsec * cpuCount) * 100);
33448
+ const dPeriods = nrPeriods - cgPrev.nrPeriods;
33449
+ if (dPeriods > 0) extra.cpuThrottledPct = clampPct((nrThrottled - cgPrev.nrThrottled) / dPeriods * 100);
33450
+ if (io) {
33451
+ const dSec = (now - cgPrev.wallMs) / 1e3;
33452
+ if (dSec > 0) {
33453
+ extra.diskReadMbps = round1((io.rBytes - cgPrev.ioR) / MB / dSec);
33454
+ extra.diskWriteMbps = round1((io.wBytes - cgPrev.ioW) / MB / dSec);
33455
+ }
33456
+ }
33457
+ }
33458
+ cgPrev = {
33459
+ usageUsec,
33460
+ nrThrottled,
33461
+ nrPeriods,
33462
+ ioR: io?.rBytes ?? 0,
33463
+ ioW: io?.wBytes ?? 0,
33464
+ wallMs: now
33465
+ };
33466
+ }
33467
+ return { cpuPct, extra };
33468
+ }
33370
33469
  return {
33371
33470
  async sample() {
33372
- const at = (/* @__PURE__ */ new Date()).toISOString();
33471
+ const now = Date.now();
33472
+ const at = new Date(now).toISOString();
33373
33473
  const { usedGb: diskUsedGb, totalGb: diskTotalGb } = await disk();
33374
33474
  const base = { platform: platform(), arch: arch(), diskUsedGb, diskTotalGb, at };
33375
33475
  if (cgroupV2) {
@@ -33378,14 +33478,15 @@ function createWorkerMetricsSampler(diskPath) {
33378
33478
  const memTotalBytes = memMaxRaw && memMaxRaw !== "max" ? Number(memMaxRaw) : totalmem();
33379
33479
  const memUsedBytes = memCurRaw ? Number(memCurRaw) : totalmem() - freemem();
33380
33480
  const cpuCount = await cgroupCpuCount();
33381
- const cpuPct = await cgroupCpuPct(cpuCount);
33481
+ const { cpuPct, extra } = await cgroupExtended(cpuCount, now);
33382
33482
  return {
33383
33483
  ...base,
33384
33484
  source: "cgroup",
33385
33485
  cpuCount,
33386
33486
  cpuPct,
33387
33487
  memUsedMb: Math.round(memUsedBytes / MB),
33388
- memTotalMb: Math.round(memTotalBytes / MB)
33488
+ memTotalMb: Math.round(memTotalBytes / MB),
33489
+ ...extra
33389
33490
  };
33390
33491
  }
33391
33492
  const total = totalmem();
@@ -33641,7 +33742,7 @@ function decryptPayload(key, payloadBase64, nonceBase64) {
33641
33742
  }
33642
33743
 
33643
33744
  // src/core/ws-client.ts
33644
- import { existsSync as existsSync11, mkdirSync as mkdirSync5, rmSync as rmSync5 } from "fs";
33745
+ import { existsSync as existsSync12, mkdirSync as mkdirSync5, rmSync as rmSync4 } from "fs";
33645
33746
  import { randomUUID as randomCommandId } from "crypto";
33646
33747
 
33647
33748
  // src/core/update-scheduler.ts
@@ -35404,28 +35505,87 @@ async function removePackage(root, slug) {
35404
35505
  }
35405
35506
  }
35406
35507
 
35407
- // src/core/sandbox.ts
35408
- import { rmSync as rmSync4, writeFileSync as writeFileSync6 } from "fs";
35409
- import { join as join16 } from "path";
35410
- var EGRESS_ALLOWLIST_FILE = "sandbox-egress.txt";
35411
- function writeEgressAllowlist(profileDir2, policy) {
35412
- const path = join16(profileDir2, EGRESS_ALLOWLIST_FILE);
35508
+ // src/core/network-probe.ts
35509
+ import { existsSync as existsSync9, readFileSync as readFileSync14 } from "fs";
35510
+ import { connect } from "net";
35511
+ var CANARY_TARGETS = [
35512
+ { host: "1.1.1.1", port: 443 },
35513
+ { host: "8.8.8.8", port: 443 }
35514
+ ];
35515
+ var PROBE_TIMEOUT_MS = 2500;
35516
+ function detectContainerized() {
35413
35517
  try {
35414
- if (policy && policy.network === "allowlist") {
35415
- const body = ["# 4PM egress allowlist (ADR-0192) \u2014 generated from the project sandbox policy"].concat(policy.allowedDomains).join("\n");
35416
- writeFileSync6(path, `${body}
35417
- `, "utf8");
35418
- } else {
35419
- rmSync4(path, { force: true });
35518
+ if (existsSync9("/.dockerenv")) return true;
35519
+ const cgroup = readFileSync14("/proc/1/cgroup", "utf8");
35520
+ return /docker|containerd|kubepods|libpod/.test(cgroup);
35521
+ } catch {
35522
+ return false;
35523
+ }
35524
+ }
35525
+ function canReach(host, port) {
35526
+ return new Promise((resolve8) => {
35527
+ const socket = connect({ host, port });
35528
+ let done = false;
35529
+ const finish = (ok) => {
35530
+ if (done) return;
35531
+ done = true;
35532
+ socket.destroy();
35533
+ resolve8(ok);
35534
+ };
35535
+ socket.setTimeout(PROBE_TIMEOUT_MS);
35536
+ socket.once("connect", () => finish(true));
35537
+ socket.once("timeout", () => finish(false));
35538
+ socket.once("error", () => finish(false));
35539
+ });
35540
+ }
35541
+ async function probeOutbound() {
35542
+ try {
35543
+ const results = await Promise.all(CANARY_TARGETS.map((t) => canReach(t.host, t.port)));
35544
+ return results.some(Boolean) ? "open" : "restricted";
35545
+ } catch {
35546
+ return "restricted";
35547
+ }
35548
+ }
35549
+ function probeInbound() {
35550
+ const isExposed = (path, loopbackHexPrefixes) => {
35551
+ let body;
35552
+ try {
35553
+ body = readFileSync14(path, "utf8");
35554
+ } catch {
35555
+ return false;
35420
35556
  }
35557
+ for (const line of body.split("\n").slice(1)) {
35558
+ const cols = line.trim().split(/\s+/);
35559
+ const local = cols[1];
35560
+ const st = cols[3];
35561
+ if (!local || st !== "0A") continue;
35562
+ const addrHex = local.split(":")[0]?.toUpperCase() ?? "";
35563
+ if (loopbackHexPrefixes.some((p) => addrHex === p)) continue;
35564
+ return true;
35565
+ }
35566
+ return false;
35567
+ };
35568
+ try {
35569
+ const v4 = isExposed("/proc/net/tcp", ["0100007F"]);
35570
+ const v6 = isExposed("/proc/net/tcp6", ["00000000000000000000000001000000"]);
35571
+ return v4 || v6 ? "exposed" : "isolated";
35421
35572
  } catch {
35573
+ return "isolated";
35422
35574
  }
35423
35575
  }
35576
+ async function probeNetwork() {
35577
+ return {
35578
+ outbound: await probeOutbound(),
35579
+ inbound: probeInbound(),
35580
+ containerized: detectContainerized(),
35581
+ checkedAt: (/* @__PURE__ */ new Date()).toISOString()
35582
+ };
35583
+ }
35424
35584
 
35425
35585
  // src/core/git-auth.ts
35426
- import { writeFileSync as writeFileSync7 } from "fs";
35586
+ import { writeFileSync as writeFileSync6 } from "fs";
35427
35587
  import { homedir as homedir4 } from "os";
35428
- import { join as join17 } from "path";
35588
+ import { join as join16 } from "path";
35429
35589
  function tokenTarget(method) {
35430
35590
  if (method === "gitlab-group-token") {
35431
35591
  return { host: process.env.FOURPM_GIT_HOST || "gitlab.com", user: "oauth2" };
@@ -35443,7 +35603,7 @@ function applyGitAuth(method) {
35443
35603
  try {
35444
35604
  const line = `https://${target.user}:${token}@${target.host}
35445
35605
  `;
35446
- writeFileSync7(join17(homedir4(), ".git-credentials"), line, { encoding: "utf8", mode: 384 });
35606
+ writeFileSync6(join16(homedir4(), ".git-credentials"), line, { encoding: "utf8", mode: 384 });
35447
35607
  return true;
35448
35608
  } catch {
35449
35609
  return false;
@@ -35452,7 +35612,7 @@ function applyGitAuth(method) {
35452
35612
 
35453
35613
  // src/core/secrets.ts
35454
35614
  import { readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
35455
- import { join as join18 } from "path";
35615
+ import { join as join17 } from "path";
35456
35616
  var SECURITY_REL = "AI_SECURITY.md";
35457
35617
  var PLACEHOLDER_REL = "AI_PLACEHOLDER.md";
35458
35618
  var SECRETS_REL = "project.secrets.json";
@@ -35465,7 +35625,7 @@ async function readText3(path, fallback = "") {
35465
35625
  }
35466
35626
  async function readSecretsObject(root) {
35467
35627
  try {
35468
- const v = JSON.parse(await readFile6(join18(root, SECRETS_REL), "utf8"));
35628
+ const v = JSON.parse(await readFile6(join17(root, SECRETS_REL), "utf8"));
35469
35629
  return v && typeof v === "object" ? v : {};
35470
35630
  } catch {
35471
35631
  return {};
@@ -35484,8 +35644,8 @@ function placeholderKeys(text) {
35484
35644
  }
35485
35645
  async function readSecrets(root) {
35486
35646
  const [security, placeholder, secrets] = await Promise.all([
35487
- readText3(join18(root, SECURITY_REL)),
35488
- readText3(join18(root, PLACEHOLDER_REL)),
35647
+ readText3(join17(root, SECURITY_REL)),
35648
+ readText3(join17(root, PLACEHOLDER_REL)),
35489
35649
  readSecretsObject(root)
35490
35650
  ]);
35491
35651
  const names = /* @__PURE__ */ new Set([...placeholderKeys(placeholder), ...Object.keys(secrets)]);
@@ -35498,14 +35658,14 @@ async function readSecrets(root) {
35498
35658
  async function writeSecrets(root, req) {
35499
35659
  try {
35500
35660
  if (req.kind === "security") {
35501
- await writeFile5(join18(root, SECURITY_REL), req.content, "utf8");
35661
+ await writeFile5(join17(root, SECURITY_REL), req.content, "utf8");
35502
35662
  } else if (req.kind === "placeholder") {
35503
- await writeFile5(join18(root, PLACEHOLDER_REL), req.content, "utf8");
35663
+ await writeFile5(join17(root, PLACEHOLDER_REL), req.content, "utf8");
35504
35664
  } else {
35505
35665
  const secrets = await readSecretsObject(root);
35506
35666
  if (req.kind === "secret") secrets[req.key] = req.value;
35507
35667
  else delete secrets[req.key];
35508
- await writeFile5(join18(root, SECRETS_REL), JSON.stringify(secrets, null, 2) + "\n", "utf8");
35668
+ await writeFile5(join17(root, SECRETS_REL), JSON.stringify(secrets, null, 2) + "\n", "utf8");
35509
35669
  }
35510
35670
  return { ok: true };
35511
35671
  } catch (err) {
@@ -35515,13 +35675,13 @@ async function writeSecrets(root, req) {
35515
35675
 
35516
35676
  // src/core/agent-tools.ts
35517
35677
  import { readFile as readFile7, writeFile as writeFile6, mkdir as mkdir5 } from "fs/promises";
35518
- import { dirname as dirname5, join as join19 } from "path";
35678
+ import { dirname as dirname5, join as join18 } from "path";
35519
35679
  var SHARED_REL = ".claude/settings.json";
35520
35680
  var LOCAL_REL = ".claude/settings.local.json";
35521
35681
  var SECRETS_DENY = "Read(./project.secrets.json)";
35522
35682
  var MODES = ["default", "acceptEdits", "plan", "bypassPermissions"];
35523
35683
  function fileFor(root, scope) {
35524
- return join19(root, scope === "shared" ? SHARED_REL : LOCAL_REL);
35684
+ return join18(root, scope === "shared" ? SHARED_REL : LOCAL_REL);
35525
35685
  }
35526
35686
  async function readSettingsObject(path) {
35527
35687
  try {
@@ -35558,7 +35718,7 @@ async function writeAgentTools(root, scope, permissions) {
35558
35718
 
35559
35719
  // src/core/graph.ts
35560
35720
  import { readFile as readFile8, readdir as readdir5 } from "fs/promises";
35561
- import { join as join20, relative as relative2, dirname as dirname6, resolve as resolve4, extname, basename as basename2 } from "path";
35721
+ import { join as join19, relative as relative2, dirname as dirname6, resolve as resolve4, extname, basename as basename2 } from "path";
35562
35722
  var MAX_FILES = 2e3;
35563
35723
  var MAX_NODES = 3e3;
35564
35724
  var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", ".next", "out", "coverage", ".turbo"]);
@@ -35578,7 +35738,7 @@ async function walk(root, accept) {
35578
35738
  if (e.name.startsWith(".") && e.name !== ".claude") {
35579
35739
  if (e.isDirectory()) continue;
35580
35740
  }
35581
- const full = join20(dir2, e.name);
35741
+ const full = join19(dir2, e.name);
35582
35742
  if (e.isDirectory()) {
35583
35743
  if (!SKIP_DIRS.has(e.name)) stack.push(full);
35584
35744
  } else if (accept(full)) {
@@ -35698,10 +35858,10 @@ async function buildGraph(root, mode) {
35698
35858
 
35699
35859
  // src/core/rag.ts
35700
35860
  import { readFile as readFile9, writeFile as writeFile7, statfs as statfs2, mkdir as mkdir6 } from "fs/promises";
35701
- import { existsSync as existsSync9 } from "fs";
35861
+ import { existsSync as existsSync10 } from "fs";
35702
35862
  import { execFile as execFile4, spawn as spawn7 } from "child_process";
35703
35863
  import { totalmem as totalmem2, cpus as cpus2 } from "os";
35704
- import { join as join21 } from "path";
35864
+ import { join as join20 } from "path";
35705
35865
  import { promisify as promisify4 } from "util";
35706
35866
  var run3 = promisify4(execFile4);
35707
35867
  var RAG_REL = ".claude/rag";
@@ -35722,7 +35882,7 @@ async function detectPython() {
35722
35882
  }
35723
35883
  async function installLog(root) {
35724
35884
  try {
35725
- const text = await readFile9(join21(root, RAG_REL, "install.log"), "utf8");
35885
+ const text = await readFile9(join20(root, RAG_REL, "install.log"), "utf8");
35726
35886
  return text.split("\n").filter((l) => l.length > 0).slice(-200);
35727
35887
  } catch {
35728
35888
  return [];
@@ -35784,14 +35944,14 @@ async function ragStatus(root) {
35784
35944
  };
35785
35945
  let modelName = "";
35786
35946
  try {
35787
- modelName = (await readFile9(join21(root, RAG_REL, ".installed"), "utf8")).trim();
35947
+ modelName = (await readFile9(join20(root, RAG_REL, ".installed"), "utf8")).trim();
35788
35948
  } catch {
35789
35949
  modelName = "";
35790
35950
  }
35791
35951
  const modelPresent = modelName.length > 0;
35792
35952
  return {
35793
35953
  installed: fastembed && sqliteVec && modelPresent,
35794
- installing: existsSync9(join21(root, RAG_REL, ".installing")),
35954
+ installing: existsSync10(join20(root, RAG_REL, ".installing")),
35795
35955
  python: { found: py.found, version: py.version },
35796
35956
  deps: { pip, fastembed, sqliteVec },
35797
35957
  model: { present: modelPresent, name: modelName },
@@ -35802,9 +35962,9 @@ async function ragStatus(root) {
35802
35962
  };
35803
35963
  }
35804
35964
  async function readIndexMeta(root) {
35805
- const indexing = existsSync9(join21(root, RAG_REL, ".indexing"));
35965
+ const indexing = existsSync10(join20(root, RAG_REL, ".indexing"));
35806
35966
  try {
35807
- const m = JSON.parse(await readFile9(join21(root, RAG_REL, ".index.json"), "utf8"));
35967
+ const m = JSON.parse(await readFile9(join20(root, RAG_REL, ".index.json"), "utf8"));
35808
35968
  return {
35809
35969
  present: true,
35810
35970
  indexing,
@@ -35871,14 +36031,14 @@ if __name__ == "__main__":
35871
36031
  elif cmd == "query": query(sys.argv[2], int(sys.argv[3]) if len(sys.argv) > 3 else 8)
35872
36032
  `;
35873
36033
  async function ensureEngine(root) {
35874
- await mkdir6(join21(root, RAG_REL), { recursive: true }).catch(() => void 0);
35875
- await writeFile7(join21(root, RAG_REL, "rag_engine.py"), RAG_ENGINE_PY, "utf8");
36034
+ await mkdir6(join20(root, RAG_REL), { recursive: true }).catch(() => void 0);
36035
+ await writeFile7(join20(root, RAG_REL, "rag_engine.py"), RAG_ENGINE_PY, "utf8");
35876
36036
  }
35877
36037
  async function ragReindex(root) {
35878
36038
  const py = await detectPython();
35879
36039
  if (!py.found) return { ok: false, started: false, error: "python3 not found" };
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 };
36040
+ if (!existsSync10(join20(root, RAG_REL, ".installed"))) return { ok: false, started: false, error: "RAG is not installed" };
36041
+ if (existsSync10(join20(root, RAG_REL, ".indexing"))) return { ok: true, started: true };
35882
36042
  await ensureEngine(root);
35883
36043
  const script = `
35884
36044
  set +e
@@ -35898,12 +36058,12 @@ rm -f "${RAG_REL}/.indexing"
35898
36058
  async function ragQuery(root, queryText, k = 8) {
35899
36059
  const py = await detectPython();
35900
36060
  if (!py.found) return { results: [], error: "python3 not found" };
35901
- if (!existsSync9(join21(root, RAG_REL, "index.db"))) return { results: [], error: "no index \u2014 reindex first" };
36061
+ if (!existsSync10(join20(root, RAG_REL, "index.db"))) return { results: [], error: "no index \u2014 reindex first" };
35902
36062
  await ensureEngine(root);
35903
36063
  try {
35904
36064
  const { stdout } = await run3(
35905
36065
  py.bin,
35906
- [join21(RAG_REL, "rag_engine.py"), "query", queryText, String(Math.min(Math.max(k, 1), 20))],
36066
+ [join20(RAG_REL, "rag_engine.py"), "query", queryText, String(Math.min(Math.max(k, 1), 20))],
35907
36067
  { cwd: root, timeout: 3e4, maxBuffer: 4 * 1024 * 1024 }
35908
36068
  );
35909
36069
  const parsed = JSON.parse(stdout.trim() || '{"results":[]}');
@@ -35915,9 +36075,9 @@ async function ragQuery(root, queryText, k = 8) {
35915
36075
  async function ragInstall(root, model) {
35916
36076
  const py = await detectPython();
35917
36077
  if (!py.found) return { ok: false, started: false, error: "python3 not found on the worker" };
35918
- if (existsSync9(join21(root, RAG_REL, ".installing"))) return { ok: true, started: true };
36078
+ if (existsSync10(join20(root, RAG_REL, ".installing"))) return { ok: true, started: true };
35919
36079
  try {
35920
- await mkdir6(join21(root, RAG_REL), { recursive: true });
36080
+ await mkdir6(join20(root, RAG_REL), { recursive: true });
35921
36081
  } catch {
35922
36082
  }
35923
36083
  const script = `
@@ -36005,12 +36165,12 @@ ${stderr}`;
36005
36165
  // src/core/git-ssh-key.ts
36006
36166
  import { execFile as execFile7 } from "child_process";
36007
36167
  import { readFile as readFile11, rm as rm3, mkdir as mkdir7 } from "fs/promises";
36008
- import { join as join22 } from "path";
36168
+ import { join as join21 } from "path";
36009
36169
  import { promisify as promisify7 } from "util";
36010
36170
  var run6 = promisify7(execFile7);
36011
36171
  function keyPaths(profileDir2) {
36012
- const dir2 = join22(profileDir2, ".ssh");
36013
- const key = join22(dir2, "id_4pm");
36172
+ const dir2 = join21(profileDir2, ".ssh");
36173
+ const key = join21(dir2, "id_4pm");
36014
36174
  return { dir: dir2, key, pub: `${key}.pub` };
36015
36175
  }
36016
36176
  async function readPublicKey(pub) {
@@ -36202,7 +36362,7 @@ async function setCommitAuthor(cwd2, machineUsername) {
36202
36362
  // src/core/scaffold.ts
36203
36363
  import { cp, mkdir as mkdir8, writeFile as writeFile8 } from "fs/promises";
36204
36364
  import { execFile as execFile10 } from "child_process";
36205
- import { dirname as dirname8, join as join23, resolve as resolve7 } from "path";
36365
+ import { dirname as dirname8, join as join22, resolve as resolve7 } from "path";
36206
36366
  import { fileURLToPath as fileURLToPath3 } from "url";
36207
36367
  import { promisify as promisify10 } from "util";
36208
36368
  var run9 = promisify10(execFile10);
@@ -36231,7 +36391,7 @@ async function provisionRepos(target, repos, emit, opts = {}) {
36231
36391
  }
36232
36392
  continue;
36233
36393
  }
36234
- const dir2 = join23(target, subDirName(repo));
36394
+ const dir2 = join22(target, subDirName(repo));
36235
36395
  if (repo.url) {
36236
36396
  emit("git", `Cloning sub-repo ${repo.url}\u2026`);
36237
36397
  await run9("git", ["clone", repo.url, dir2], { timeout: 12e4 });
@@ -36251,14 +36411,14 @@ async function scaffoldProject(payload, profileDir2, onProgress) {
36251
36411
  const emit = (step, message) => onProgress?.({ projectId: payload.projectId, step, message });
36252
36412
  try {
36253
36413
  const root = process.env.SCAFFOLD_ROOT ? resolve7(process.env.SCAFFOLD_ROOT) : resolve7(profileDir2);
36254
- const target = join23(root, payload.projectName);
36414
+ const target = join22(root, payload.projectName);
36255
36415
  await mkdir8(target, { recursive: true });
36256
36416
  emit("copy", "Copying the sample template\u2026");
36257
36417
  await cp(sampleDir(), target, { recursive: true, force: false, errorOnExist: false });
36258
36418
  if (payload.spec) {
36259
36419
  emit("spec", "Writing project.spec.json\u2026");
36260
36420
  await writeFile8(
36261
- join23(target, "project.spec.json"),
36421
+ join22(target, "project.spec.json"),
36262
36422
  JSON.stringify(payload.spec, null, 2),
36263
36423
  "utf8"
36264
36424
  );
@@ -36276,7 +36436,7 @@ async function aiInit(target, spec, emit) {
36276
36436
  emit("ai-init", "AI init: subagents, README, CLAUDE.md\u2026");
36277
36437
  const subagents = Array.isArray(spec.subagents) ? spec.subagents : [];
36278
36438
  if (subagents.length > 0) {
36279
- await mkdir8(join23(target, ".claude", "agents"), { recursive: true });
36439
+ await mkdir8(join22(target, ".claude", "agents"), { recursive: true });
36280
36440
  for (const sa of subagents) {
36281
36441
  const name = (sa.name || "").trim().replace(/[^\w.-]+/g, "-").replace(/^-+|-+$/g, "");
36282
36442
  if (!name) continue;
@@ -36286,17 +36446,17 @@ name: ${name}
36286
36446
 
36287
36447
  ${(sa.description || "").trim()}
36288
36448
  `;
36289
- await writeFile8(join23(target, ".claude", "agents", `${name}.md`), body, "utf8");
36449
+ await writeFile8(join22(target, ".claude", "agents", `${name}.md`), body, "utf8");
36290
36450
  }
36291
36451
  }
36292
36452
  const specJson = JSON.stringify(spec);
36293
36453
  await generateFile(
36294
- join23(target, "README.md"),
36454
+ join22(target, "README.md"),
36295
36455
  `Write a concise README.md (Markdown only, no preamble) for this project from its spec JSON:
36296
36456
  ${specJson}`
36297
36457
  );
36298
36458
  await generateFile(
36299
- join23(target, "CLAUDE.md"),
36459
+ join22(target, "CLAUDE.md"),
36300
36460
  `Write a CLAUDE.md (Markdown only, no preamble) with guidance/conventions for AI agents working in this project, derived from its spec JSON:
36301
36461
  ${specJson}`
36302
36462
  );
@@ -36312,7 +36472,7 @@ async function addProject(payload, profileDir2, onProgress) {
36312
36472
  const emit = (step, message) => onProgress?.({ projectId: payload.projectId, step, message });
36313
36473
  try {
36314
36474
  const root = process.env.SCAFFOLD_ROOT ? resolve7(process.env.SCAFFOLD_ROOT) : resolve7(profileDir2);
36315
- const target = join23(root, payload.projectName);
36475
+ const target = join22(root, payload.projectName);
36316
36476
  await mkdir8(target, { recursive: true });
36317
36477
  const repos = payload.repos ?? [];
36318
36478
  if (repos.length > 0) await provisionRepos(target, repos, emit, { clonePrimary: true });
@@ -36324,14 +36484,14 @@ async function addProject(payload, profileDir2, onProgress) {
36324
36484
  }
36325
36485
 
36326
36486
  // src/core/config-sync.ts
36327
- import { existsSync as existsSync10, readFileSync as readFileSync14 } from "fs";
36328
- import { join as join24 } from "path";
36487
+ import { existsSync as existsSync11, readFileSync as readFileSync15 } from "fs";
36488
+ import { join as join23 } from "path";
36329
36489
  var SERVER_MANAGED_KEYS = ["physicPath", "sessionSwitchPct", "perPromptTokenLimit"];
36330
36490
  function readConfigText(profileDir2) {
36331
- const path = join24(profileDir2, "config.json");
36332
- if (existsSync10(path)) {
36491
+ const path = join23(profileDir2, "config.json");
36492
+ if (existsSync11(path)) {
36333
36493
  try {
36334
- return readFileSync14(path, "utf8");
36494
+ return readFileSync15(path, "utf8");
36335
36495
  } catch {
36336
36496
  }
36337
36497
  }
@@ -36756,7 +36916,6 @@ var WsClient = class {
36756
36916
  });
36757
36917
  this.outboundReviewEnabled = token.outboundReview?.enabled === true;
36758
36918
  this.restrictToFolder = token.aiRestrictToFolder === true;
36759
- writeEgressAllowlist(this.context.profileDir, token.aiSandbox ?? null);
36760
36919
  applyGitAuth(token.gitAuth ?? null);
36761
36920
  this.machineUsername = token.machineUsername ?? "";
36762
36921
  if (token.scope && token.scope !== this.credential.scope) {
@@ -36904,8 +37063,8 @@ var WsClient = class {
36904
37063
  const oldRoot = this.physicFolderPath(sync.oldName);
36905
37064
  if (oldRoot) void uninstallCron(oldRoot).catch(() => void 0);
36906
37065
  }
36907
- if (sync.oldName) rmSync5(join25(this.context.profileDir, sync.oldName), { recursive: true, force: true });
36908
- mkdirSync5(join25(this.context.profileDir, sync.newName), { recursive: true });
37066
+ if (sync.oldName) rmSync4(join24(this.context.profileDir, sync.oldName), { recursive: true, force: true });
37067
+ mkdirSync5(join24(this.context.profileDir, sync.newName), { recursive: true });
36909
37068
  this.physicRoot = this.physicFolderPath(sync.newName);
36910
37069
  this.bus.setProject(sync.newName);
36911
37070
  this.bus.log(`Physic project folder synced \u2192 ${sync.newName}`);
@@ -36916,7 +37075,7 @@ var WsClient = class {
36916
37075
  if (del.name) {
36917
37076
  const delRoot = this.physicFolderPath(del.name);
36918
37077
  if (delRoot) void uninstallCron(delRoot).catch(() => void 0);
36919
- rmSync5(join25(this.context.profileDir, del.name), { recursive: true, force: true });
37078
+ rmSync4(join24(this.context.profileDir, del.name), { recursive: true, force: true });
36920
37079
  this.bus.log(`Physic project folder deleted (project removed) \u2192 ${del.name}`);
36921
37080
  }
36922
37081
  void manageSshKey("delete", this.context.profileDir).catch(() => void 0);
@@ -37288,7 +37447,7 @@ var WsClient = class {
37288
37447
  }
37289
37448
  case WsChannels.LOG_READ: {
37290
37449
  const limit = Math.min(Math.max(payload.limit ?? 200, 1), 2e3);
37291
- const lines = readRecentLogLines(join25(this.context.profileDir, "logs"), limit);
37450
+ const lines = readRecentLogLines(join24(this.context.profileDir, "logs"), limit);
37292
37451
  this.send(WsChannels.LOG_READ, { lines }, message.id);
37293
37452
  break;
37294
37453
  }
@@ -37874,7 +38033,7 @@ var WsClient = class {
37874
38033
  /** Create the physic folder at an absolute path if missing (best-effort). */
37875
38034
  ensurePhysicFolderPath(folder) {
37876
38035
  try {
37877
- if (!existsSync11(folder)) {
38036
+ if (!existsSync12(folder)) {
37878
38037
  mkdirSync5(folder, { recursive: true });
37879
38038
  this.bus.log(`Created physic project folder: ${folder}`);
37880
38039
  }
@@ -37889,7 +38048,7 @@ var WsClient = class {
37889
38048
  */
37890
38049
  physicFolderPath(projectName) {
37891
38050
  const safe = projectName.replace(/[/\\]/g, "_").replace(/\.\./g, "_").trim();
37892
- return safe ? join25(this.context.profileDir, safe) : null;
38051
+ return safe ? join24(this.context.profileDir, safe) : null;
37893
38052
  }
37894
38053
  /**
37895
38054
  * Report machine.status: version + the state of the physic project being served
@@ -37903,7 +38062,7 @@ var WsClient = class {
37903
38062
  projects: [],
37904
38063
  version: CLI_VERSION,
37905
38064
  physicPath,
37906
- physicPathExists: physicPath ? existsSync11(physicPath) : void 0,
38065
+ physicPathExists: physicPath ? existsSync12(physicPath) : void 0,
37907
38066
  // Real coarse state (ADR-0152): !paused and a recent tick (was hard-coded false).
37908
38067
  autonomousRunning: physicPath ? isAutonomousRunning(physicPath) : false
37909
38068
  });
@@ -37951,6 +38110,7 @@ var WsClient = class {
37951
38110
  };
37952
38111
  snapshot.aiCli = aiCli2;
37953
38112
  snapshot.profile = profile;
38113
+ snapshot.network = await probeNetwork();
37954
38114
  this.usageSnapshot = snapshot;
37955
38115
  this.bus.setUsage?.(snapshot);
37956
38116
  this.send(WsChannels.MACHINE_USAGE, snapshot);
@@ -37992,7 +38152,7 @@ var WsClient = class {
37992
38152
  */
37993
38153
  uploadLog() {
37994
38154
  try {
37995
- const upload = readLogUpload(join25(this.context.profileDir, "logs"));
38155
+ const upload = readLogUpload(join24(this.context.profileDir, "logs"));
37996
38156
  if (!upload) return;
37997
38157
  const sig = `${upload.fileName}:${upload.totalBytes}`;
37998
38158
  if (sig === this.lastLogSig) return;
@@ -38020,10 +38180,10 @@ var WsClient = class {
38020
38180
  };
38021
38181
 
38022
38182
  // src/core/instance-lock.ts
38023
- import { readFileSync as readFileSync15, rmSync as rmSync6, writeFileSync as writeFileSync8 } from "fs";
38024
- import { join as join26 } from "path";
38183
+ import { readFileSync as readFileSync16, rmSync as rmSync5, writeFileSync as writeFileSync7 } from "fs";
38184
+ import { join as join25 } from "path";
38025
38185
  function lockPath(profileDir2) {
38026
- return join26(profileDir2, "start.lock");
38186
+ return join25(profileDir2, "start.lock");
38027
38187
  }
38028
38188
  function isAlive(pid) {
38029
38189
  try {
@@ -38035,7 +38195,7 @@ function isAlive(pid) {
38035
38195
  }
38036
38196
  function lockHolder(profileDir2) {
38037
38197
  try {
38038
- const pid = Number.parseInt(readFileSync15(lockPath(profileDir2), "utf8").trim(), 10);
38198
+ const pid = Number.parseInt(readFileSync16(lockPath(profileDir2), "utf8").trim(), 10);
38039
38199
  if (Number.isInteger(pid) && pid > 0 && pid !== process.pid && isAlive(pid)) return pid;
38040
38200
  } catch {
38041
38201
  }
@@ -38043,13 +38203,13 @@ function lockHolder(profileDir2) {
38043
38203
  }
38044
38204
  function acquireInstanceLock(profileDir2) {
38045
38205
  if (lockHolder(profileDir2) !== null) return false;
38046
- writeFileSync8(lockPath(profileDir2), String(process.pid), "utf8");
38206
+ writeFileSync7(lockPath(profileDir2), String(process.pid), "utf8");
38047
38207
  return true;
38048
38208
  }
38049
38209
  function releaseInstanceLock(profileDir2) {
38050
38210
  try {
38051
- const pid = Number.parseInt(readFileSync15(lockPath(profileDir2), "utf8").trim(), 10);
38052
- if (pid === process.pid) rmSync6(lockPath(profileDir2), { force: true });
38211
+ const pid = Number.parseInt(readFileSync16(lockPath(profileDir2), "utf8").trim(), 10);
38212
+ if (pid === process.pid) rmSync5(lockPath(profileDir2), { force: true });
38053
38213
  } catch {
38054
38214
  }
38055
38215
  }
@@ -38310,8 +38470,8 @@ var SessionBus = class {
38310
38470
 
38311
38471
  // src/core/control-server.ts
38312
38472
  import { createServer } from "net";
38313
- import { rmSync as rmSync7 } from "fs";
38314
- import { join as join27 } from "path";
38473
+ import { rmSync as rmSync6 } from "fs";
38474
+ import { join as join26 } from "path";
38315
38475
 
38316
38476
  // src/core/control-protocol.ts
38317
38477
  var CONTROL_SOCKET_FILE = "control.sock";
@@ -38340,9 +38500,9 @@ function createFrameParser() {
38340
38500
 
38341
38501
  // src/core/control-server.ts
38342
38502
  function startControlServer(bus, profileDir2, info) {
38343
- const socketPath = join27(profileDir2, CONTROL_SOCKET_FILE);
38503
+ const socketPath = join26(profileDir2, CONTROL_SOCKET_FILE);
38344
38504
  try {
38345
- rmSync7(socketPath, { force: true });
38505
+ rmSync6(socketPath, { force: true });
38346
38506
  } catch {
38347
38507
  }
38348
38508
  const clients = /* @__PURE__ */ new Set();
@@ -38408,7 +38568,7 @@ function startControlServer(bus, profileDir2, info) {
38408
38568
  clients.clear();
38409
38569
  server.close();
38410
38570
  try {
38411
- rmSync7(socketPath, { force: true });
38571
+ rmSync6(socketPath, { force: true });
38412
38572
  } catch {
38413
38573
  }
38414
38574
  };
@@ -40388,7 +40548,7 @@ var src_default = Yoga;
40388
40548
 
40389
40549
  // ../../node_modules/.pnpm/ink@5.2.1_@types+react@18.3.31_react@18.3.1/node_modules/ink/build/reconciler.js
40390
40550
  var import_react_reconciler = __toESM(require_react_reconciler(), 1);
40391
- var import_constants6 = __toESM(require_constants2(), 1);
40551
+ var import_constants7 = __toESM(require_constants2(), 1);
40392
40552
  import process3 from "process";
40393
40553
 
40394
40554
  // ../../node_modules/.pnpm/ansi-regex@6.2.2/node_modules/ansi-regex/index.js
@@ -41630,7 +41790,7 @@ var reconciler_default = (0, import_react_reconciler.default)({
41630
41790
  scheduleTimeout: setTimeout,
41631
41791
  cancelTimeout: clearTimeout,
41632
41792
  noTimeout: -1,
41633
- getCurrentEventPriority: () => import_constants6.DefaultEventPriority,
41793
+ getCurrentEventPriority: () => import_constants7.DefaultEventPriority,
41634
41794
  beforeActiveInstanceBlur() {
41635
41795
  },
41636
41796
  afterActiveInstanceBlur() {
@@ -44072,17 +44232,17 @@ var import_react21 = __toESM(require_react(), 1);
44072
44232
  var import_react26 = __toESM(require_react(), 1);
44073
44233
 
44074
44234
  // src/core/input-history.ts
44075
- import { existsSync as existsSync13, readFileSync as readFileSync17, writeFileSync as writeFileSync9 } from "fs";
44076
- import { join as join28 } from "path";
44235
+ import { existsSync as existsSync14, readFileSync as readFileSync18, writeFileSync as writeFileSync8 } from "fs";
44236
+ import { join as join27 } from "path";
44077
44237
  var MAX_HISTORY = 200;
44078
44238
  function historyPath(profileDir2) {
44079
- return join28(profileDir2, "input-history.json");
44239
+ return join27(profileDir2, "input-history.json");
44080
44240
  }
44081
44241
  function loadInputHistory(profileDir2) {
44082
44242
  const path = historyPath(profileDir2);
44083
- if (!existsSync13(path)) return [];
44243
+ if (!existsSync14(path)) return [];
44084
44244
  try {
44085
- const data = JSON.parse(readFileSync17(path, "utf8"));
44245
+ const data = JSON.parse(readFileSync18(path, "utf8"));
44086
44246
  return Array.isArray(data) ? data.filter((x) => typeof x === "string") : [];
44087
44247
  } catch {
44088
44248
  return [];
@@ -44093,7 +44253,7 @@ function appendInputHistory(profileDir2, line, current) {
44093
44253
  if (!trimmed || current[current.length - 1] === trimmed) return current;
44094
44254
  const next = [...current, trimmed].slice(-MAX_HISTORY);
44095
44255
  try {
44096
- writeFileSync9(historyPath(profileDir2), JSON.stringify(next), "utf8");
44256
+ writeFileSync8(historyPath(profileDir2), JSON.stringify(next), "utf8");
44097
44257
  } catch {
44098
44258
  }
44099
44259
  return next;
@@ -44342,8 +44502,8 @@ function TranscriptLine({ line }) {
44342
44502
  var import_react24 = __toESM(require_react(), 1);
44343
44503
 
44344
44504
  // src/ui/slash-commands.ts
44345
- import { existsSync as existsSync14 } from "fs";
44346
- import { join as join29 } from "path";
44505
+ import { existsSync as existsSync15 } from "fs";
44506
+ import { join as join28 } from "path";
44347
44507
  var CONFIG_KEYS = [
44348
44508
  "aiCli",
44349
44509
  "claudeHome",
@@ -44355,7 +44515,7 @@ var CONFIG_KEYS = [
44355
44515
  "aiEnv"
44356
44516
  ];
44357
44517
  function configPath(profileDir2) {
44358
- return join29(profileDir2, "config.json");
44518
+ return join28(profileDir2, "config.json");
44359
44519
  }
44360
44520
  function parseConfigAssignment(key, valueTokens) {
44361
44521
  const value = valueTokens.join(" ").trim();
@@ -44405,7 +44565,7 @@ function runConfig(ctx) {
44405
44565
  ctx.print(`\u2714 ${verb} default config: ${path}`);
44406
44566
  ctx.print("add claude profiles: /config set claudeHome .claude .claude-1 (tried in order)");
44407
44567
  };
44408
- if (existsSync14(path)) {
44568
+ if (existsSync15(path)) {
44409
44569
  ctx.confirm(
44410
44570
  `config exists: ${path} \u2014 replace it with defaults? (y/N)`,
44411
44571
  () => writeDefaults("replaced with")
@@ -44490,7 +44650,7 @@ function runOutput(ctx) {
44490
44650
  }
44491
44651
  function runLogs(ctx) {
44492
44652
  const n = Math.max(1, Math.min(200, Number(ctx.args[0]) || 20));
44493
- const dir2 = join29(ctx.info.profileDir, "logs");
44653
+ const dir2 = join28(ctx.info.profileDir, "logs");
44494
44654
  const lines = readRecentLogLines(dir2, n);
44495
44655
  if (lines.length === 0) {
44496
44656
  ctx.print("No log lines yet.");
@@ -45011,7 +45171,7 @@ async function runStart(profileDir2, profileName) {
45011
45171
  return;
45012
45172
  }
45013
45173
  logger.configure({
45014
- dir: join30(profileDir2, "logs"),
45174
+ dir: join29(profileDir2, "logs"),
45015
45175
  level: resolveLogLevel(),
45016
45176
  base: { version: CLI_VERSION, profile: profileName, scope: credential.scope }
45017
45177
  });
@@ -45117,13 +45277,13 @@ async function runStart(profileDir2, profileName) {
45117
45277
  }
45118
45278
 
45119
45279
  // src/commands/attach.ts
45120
- import { join as join31 } from "path";
45280
+ import { join as join30 } from "path";
45121
45281
 
45122
45282
  // src/core/control-client.ts
45123
- import { connect } from "net";
45283
+ import { connect as connect2 } from "net";
45124
45284
  function connectControl(socketPath, bus) {
45125
45285
  return new Promise((resolve8, reject) => {
45126
- const socket = connect(socketPath);
45286
+ const socket = connect2(socketPath);
45127
45287
  socket.setEncoding("utf8");
45128
45288
  let ready = false;
45129
45289
  const forwardSubmit = bus.onLocalSubmit((input) => {
@@ -45216,7 +45376,7 @@ async function runAttach(profileDir2, profileName) {
45216
45376
  process.exitCode = 1;
45217
45377
  return;
45218
45378
  }
45219
- const socketPath = join31(profileDir2, CONTROL_SOCKET_FILE);
45379
+ const socketPath = join30(profileDir2, CONTROL_SOCKET_FILE);
45220
45380
  const bus = new SessionBus();
45221
45381
  let conn;
45222
45382
  try {
@@ -45301,7 +45461,7 @@ Tip: for the credentials to survive \`docker rm\`/recreate, keep each profile pa
45301
45461
  }
45302
45462
 
45303
45463
  // src/commands/unlink.ts
45304
- import { rmSync as rmSync8 } from "fs";
45464
+ import { rmSync as rmSync7 } from "fs";
45305
45465
  async function runUnlink(profileDir2, profileName) {
45306
45466
  const cred = readCredential(profileDir2, profileName);
45307
45467
  if (!cred) {
@@ -45316,7 +45476,7 @@ async function runUnlink(profileDir2, profileName) {
45316
45476
  `\u26A0 Could not reach the server to revoke \u2014 revoke it at web /machines. (${err.message})`
45317
45477
  );
45318
45478
  }
45319
- rmSync8(profileDir2, { recursive: true, force: true });
45479
+ rmSync7(profileDir2, { recursive: true, force: true });
45320
45480
  clearDefaultProfileIf(profileName);
45321
45481
  console.log("\u2714 Deleted the profile and its physic project folder.");
45322
45482
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@4pm/cli",
3
- "version": "1.4.1",
3
+ "version": "1.4.3",
4
4
  "private": false,
5
5
  "description": "4PM CLI — drives Claude/Codex CLIs on AI worker machines (Node + TypeScript)",
6
6
  "license": "LicenseRef-4PM-Source-Available",