@4pm/cli 1.19.9 → 1.20.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.
Files changed (2) hide show
  1. package/dist/index.js +276 -109
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -29519,8 +29519,8 @@ async function runLink(serverUrl, explicitProfile, token = null) {
29519
29519
  }
29520
29520
 
29521
29521
  // src/commands/start.ts
29522
- import { spawn as spawn10 } from "child_process";
29523
- import { join as join36 } from "path";
29522
+ import { spawn as spawn11 } from "child_process";
29523
+ import { join as join37 } from "path";
29524
29524
 
29525
29525
  // src/core/update.ts
29526
29526
  import { execSync as execSync2 } from "child_process";
@@ -32732,9 +32732,9 @@ async function checkAndUpdate(serverUrl, autoUpdate) {
32732
32732
 
32733
32733
  // src/core/ws-client.ts
32734
32734
  init_wrapper();
32735
- import { randomUUID as randomUUID3 } from "crypto";
32736
- import { basename as basename7, join as join31 } from "path";
32737
- import { existsSync as existsSync16, mkdirSync as mkdirSync7 } from "fs";
32735
+ import { randomUUID as randomUUID4 } from "crypto";
32736
+ import { basename as basename7, join as join32 } from "path";
32737
+ import { existsSync as existsSync17, mkdirSync as mkdirSync8 } from "fs";
32738
32738
 
32739
32739
  // vendor/@4pm/utils/helpers.ts
32740
32740
  function backoffJitterMs(attempt, baseMs = 500, maxMs = 1e4) {
@@ -38389,6 +38389,12 @@ var WsChannels = {
38389
38389
  // AI knowledge distill (ADR-0190): server → project cli request–reply. The worker runs the AI CLI
38390
38390
  // in the project's working dir with a distillation prompt and replies with the composed markdown.
38391
38391
  KNOWLEDGE_COMPOSE: "knowledge.compose",
38392
+ // Ticket → FAQ synthesis (ADR-0333): server (platform-pool dispatcher) → platform-pool cli
38393
+ // request–reply. The dispatcher sends the selected support tickets + the 4pm-faq repo with a
38394
+ // short-lived WRITE token; the worker runs an agent-write that distils the tickets into FAQ
38395
+ // entries, commits, pushes a branch, opens a PR, then wipes the token/clone, and replies with the
38396
+ // PR URL. The write token never persists on the worker (leak-safety on release/reassign).
38397
+ FAQ_COMPOSE: "faq.compose",
38392
38398
  // Shared AI memory (ADR-0245): cli → server one-way write-back of the compacted rolling memory for
38393
38399
  // the project it serves (persisted per project × machine-user link). The read direction rides
38394
38400
  // `ws_token` (seeds the cli cache on connect); this channel only carries updates.
@@ -42799,6 +42805,145 @@ async function runKnowledgeCompose(req, ai2, physicRoot) {
42799
42805
  return { bodyMarkdown: "", error: lastReason };
42800
42806
  }
42801
42807
 
42808
+ // src/core/faq-compose.ts
42809
+ import { spawn as spawn9, execFile as execFile10 } from "child_process";
42810
+ import { existsSync as existsSync14, mkdirSync as mkdirSync7, rmSync as rmSync7 } from "fs";
42811
+ import { randomUUID as randomUUID3 } from "crypto";
42812
+ import { join as join24 } from "path";
42813
+ import { tmpdir as tmpdir3 } from "os";
42814
+ import { promisify as promisify10 } from "util";
42815
+ var execFileAsync2 = promisify10(execFile10);
42816
+ var NO_USAGE2 = { tokens: 0, input: 0, output: 0, cacheRead: 0, cacheCreation: 0 };
42817
+ var COMPOSE_TIMEOUT_MS2 = 10 * 60 * 1e3;
42818
+ function authedUrl2(url, token) {
42819
+ if (url.startsWith("https://")) return url.replace("https://", `https://x-access-token:${token}@`);
42820
+ return url;
42821
+ }
42822
+ function buildPrompt4(tickets) {
42823
+ const transcript = tickets.map((t2) => {
42824
+ const thread = t2.messages.map((m2) => ` [${m2.author}] ${m2.body}`).join("\n");
42825
+ return `### Ticket ${t2.id} \u2014 ${t2.subject} (${t2.category})
42826
+ ${thread}`;
42827
+ }).join("\n\n");
42828
+ return [
42829
+ "You are maintaining the 4PM product FAQ, stored as markdown in THIS git repository (your CWD).",
42830
+ "From the resolved support tickets below, distil reusable, product-general FAQ entries and add or",
42831
+ "update the appropriate markdown file(s) in this repo (e.g. an FAQ.md, or the closest existing",
42832
+ "topic file \u2014 inspect the repo first and match its structure/style).",
42833
+ "",
42834
+ "Rules:",
42835
+ "- Write generalized Q&A, NOT ticket-specific replies; never include customer names, emails, ids,",
42836
+ " org names or any personal data from the tickets.",
42837
+ "- Merge with existing entries instead of duplicating; keep the existing formatting and headings.",
42838
+ "- If a ticket yields no reusable FAQ value, skip it. If nothing is worth adding, make NO changes.",
42839
+ "- Only edit markdown documentation files; do not touch code, CI, or unrelated files.",
42840
+ "- Do NOT run git commit/push or open a PR yourself \u2014 just leave the edited files in the working",
42841
+ " tree; the surrounding tooling handles commit + PR.",
42842
+ "",
42843
+ "===== RESOLVED TICKETS =====",
42844
+ transcript
42845
+ ].join("\n");
42846
+ }
42847
+ function runClaudeOnce2(cmd, profile, prompt, cwd2, extraEnv) {
42848
+ return new Promise((resolve10, reject) => {
42849
+ const isClaude = cmd.includes("claude");
42850
+ const args = [
42851
+ "-p",
42852
+ ...profile?.model ? ["--model", profile.model] : [],
42853
+ ...isClaude ? ["--output-format", "stream-json", "--verbose"] : [],
42854
+ // Write-capable headless agent (ADR-0271): auto-approve tools so it never stalls on a prompt.
42855
+ ...isClaude ? ["--permission-mode", "bypassPermissions"] : [],
42856
+ ...cmd.includes("codex") ? ["--dangerously-bypass-approvals-and-sandbox"] : []
42857
+ ];
42858
+ const env3 = {
42859
+ ...process.env,
42860
+ ...extraEnv,
42861
+ ...profile ? { CLAUDE_CONFIG_DIR: profile.dir } : {}
42862
+ };
42863
+ const child = spawn9(cmd, args, { stdio: ["pipe", "pipe", "pipe"], cwd: cwd2, env: env3 });
42864
+ const parser = createAiStreamParser(cmd);
42865
+ let out = "";
42866
+ let err = "";
42867
+ const timer = setTimeout(() => {
42868
+ child.kill("SIGKILL");
42869
+ reject(new Error("faq-compose agent timed out"));
42870
+ }, COMPOSE_TIMEOUT_MS2);
42871
+ timer.unref();
42872
+ child.stdout.on("data", (d) => out += parser.push(d.toString()));
42873
+ child.stderr.on("data", (d) => err += d.toString());
42874
+ child.on("error", (e) => {
42875
+ clearTimeout(timer);
42876
+ reject(e);
42877
+ });
42878
+ child.on("close", (code) => {
42879
+ clearTimeout(timer);
42880
+ out += parser.flush();
42881
+ resolve10({ code: code ?? -1, out, err, usage: parser.usage() });
42882
+ });
42883
+ child.stdin.write(prompt);
42884
+ child.stdin.end();
42885
+ });
42886
+ }
42887
+ async function runClaudeWithFailover2(prompt, cwd2, ai2) {
42888
+ const attempts = ai2.profiles.length > 0 ? ai2.profiles : [null];
42889
+ let lastReason = "no attempt";
42890
+ for (let i = 0; i < attempts.length; i++) {
42891
+ const { code, out, err, usage } = await runClaudeOnce2(ai2.cmd, attempts[i], prompt, cwd2, ai2.env);
42892
+ if (code === 0) return usage;
42893
+ lastReason = `exited ${code}: ${(err || out).slice(0, 500)}`;
42894
+ if (i === attempts.length - 1) break;
42895
+ }
42896
+ throw new Error(`claude ${lastReason}`);
42897
+ }
42898
+ async function runFaqCompose(req, ai2) {
42899
+ if (!req.repo.token) return { prUrl: "", error: "no write token" };
42900
+ const workDir = join24(tmpdir3(), "4pm-faq-sync", randomUUID3());
42901
+ const gitEnv = { ...process.env, GIT_TERMINAL_PROMPT: "0" };
42902
+ const authed = authedUrl2(req.repo.url, req.repo.token);
42903
+ try {
42904
+ mkdirSync7(workDir, { recursive: true });
42905
+ await execFileAsync2("git", ["clone", "--depth", "1", "--branch", req.repo.branch, authed, workDir], { env: gitEnv });
42906
+ await execFileAsync2("git", ["-C", workDir, "config", "user.name", "4PM FAQ Bot"], { env: gitEnv });
42907
+ await execFileAsync2("git", ["-C", workDir, "config", "user.email", "faq-bot@4pm.app"], { env: gitEnv });
42908
+ await execFileAsync2("git", ["-C", workDir, "checkout", "-b", req.headBranch], { env: gitEnv });
42909
+ const usage = await runClaudeWithFailover2(buildPrompt4(req.tickets), workDir, ai2);
42910
+ await execFileAsync2("git", ["-C", workDir, "add", "-A"], { env: gitEnv });
42911
+ const staged = await execFileAsync2("git", ["-C", workDir, "diff", "--cached", "--name-only"], { env: gitEnv });
42912
+ if (!staged.stdout.trim()) return { prUrl: "", tokens: usage.tokens || estimateTokens2(""), finishedAt: (/* @__PURE__ */ new Date()).toISOString() };
42913
+ await execFileAsync2("git", ["-C", workDir, "commit", "-m", "docs(faq): synthesize from support tickets (4PM)"], { env: gitEnv });
42914
+ await execFileAsync2("git", ["-C", workDir, "push", "-u", "origin", req.headBranch], { env: gitEnv });
42915
+ let prUrl = "";
42916
+ try {
42917
+ const pr2 = await execFileAsync2(
42918
+ "gh",
42919
+ ["pr", "create", "--fill", "--head", req.headBranch, "--base", req.repo.branch],
42920
+ { cwd: workDir, env: { ...gitEnv, GH_TOKEN: req.repo.token } }
42921
+ );
42922
+ prUrl = pr2.stdout.trim().split("\n").pop() ?? "";
42923
+ } catch (err) {
42924
+ logger.warn("faq.compose.pr.failed", { error: String(err) });
42925
+ }
42926
+ const u2 = usage.tokens > 0 ? usage : { ...NO_USAGE2 };
42927
+ return {
42928
+ prUrl,
42929
+ branch: req.headBranch,
42930
+ tokens: u2.tokens,
42931
+ ...usage.tokens > 0 ? { tokensBreakdown: { input: usage.input, output: usage.output, cacheRead: usage.cacheRead, cacheCreation: usage.cacheCreation } } : {},
42932
+ finishedAt: (/* @__PURE__ */ new Date()).toISOString()
42933
+ };
42934
+ } catch (err) {
42935
+ logger.warn("faq.compose.failed", { error: String(err) });
42936
+ return { prUrl: "", error: String(err) };
42937
+ } finally {
42938
+ if (existsSync14(workDir)) {
42939
+ try {
42940
+ rmSync7(workDir, { recursive: true, force: true });
42941
+ } catch {
42942
+ }
42943
+ }
42944
+ }
42945
+ }
42946
+
42802
42947
  // src/core/ws-client/handlers/support.ts
42803
42948
  function handleSupportChannels(ctx, message, payload) {
42804
42949
  switch (message.channel) {
@@ -42855,6 +43000,28 @@ function handleSupportChannels(ctx, message, payload) {
42855
43000
  }).finally(() => ctx.bus.endBusy("knowledge-compose"));
42856
43001
  return true;
42857
43002
  }
43003
+ case WsChannels.FAQ_COMPOSE: {
43004
+ const freq = payload;
43005
+ const fcfg = readProfileConfig(ctx.profileDir);
43006
+ const fcmd = fcfg.aiCli || "claude";
43007
+ const fai = {
43008
+ cmd: fcmd,
43009
+ profiles: resolveClaudeProfiles(fcfg, getWorkingProfile(ctx.profileDir, fcmd)),
43010
+ env: fcfg.aiEnv
43011
+ };
43012
+ ctx.bus.push({ source: "server", kind: "aireq", text: `${fcmd} \u2039 synthesize FAQ (${freq.tickets.length} tickets)` });
43013
+ ctx.bus.startBusy("faq-compose");
43014
+ void runFaqCompose(freq, fai).then((reply) => {
43015
+ if (reply.error) {
43016
+ ctx.bus.push({ source: "server", kind: "log", text: `faq-compose failed: ${reply.error}`, level: "warn" });
43017
+ } else {
43018
+ ctx.bus.push({ source: "server", kind: "aires", text: `${fcmd} \u203A ${reply.prUrl || "no changes"}` });
43019
+ }
43020
+ reportToolResult(fcmd, !reply.error, reply.error);
43021
+ ctx.send(WsChannels.FAQ_COMPOSE, reply, message.id);
43022
+ }).finally(() => ctx.bus.endBusy("faq-compose"));
43023
+ return true;
43024
+ }
42858
43025
  default:
42859
43026
  return false;
42860
43027
  }
@@ -42953,7 +43120,7 @@ function handleToolsChannels(ctx, message, payload) {
42953
43120
 
42954
43121
  // src/core/agents.ts
42955
43122
  import { readFile as readFile10, writeFile as writeFile8, mkdir as mkdir8, readdir as readdir4, rm as rm5 } from "fs/promises";
42956
- import { join as join24 } from "path";
43123
+ import { join as join25 } from "path";
42957
43124
  var AGENTS_REL = ".claude/agents";
42958
43125
  var SKILLS_REL = ".claude/skills";
42959
43126
  var MEMORY_DIRS = /* @__PURE__ */ new Set(["short-memory", "long-memory"]);
@@ -42977,17 +43144,17 @@ async function listAgents(root) {
42977
43144
  const subagents = [];
42978
43145
  const skills = [];
42979
43146
  try {
42980
- for (const e of await readdir4(join24(root, AGENTS_REL), { withFileTypes: true })) {
43147
+ for (const e of await readdir4(join25(root, AGENTS_REL), { withFileTypes: true })) {
42981
43148
  if (!e.isFile() || !e.name.endsWith(".md") || MEMORY_DIRS.has(e.name)) continue;
42982
- const fm = frontmatter(await readText2(join24(root, AGENTS_REL, e.name)));
43149
+ const fm = frontmatter(await readText2(join25(root, AGENTS_REL, e.name)));
42983
43150
  subagents.push({ name: e.name.replace(/\.md$/, ""), description: fm.description });
42984
43151
  }
42985
43152
  } catch {
42986
43153
  }
42987
43154
  try {
42988
- for (const e of await readdir4(join24(root, SKILLS_REL), { withFileTypes: true })) {
43155
+ for (const e of await readdir4(join25(root, SKILLS_REL), { withFileTypes: true })) {
42989
43156
  if (!e.isDirectory()) continue;
42990
- const fm = frontmatter(await readText2(join24(root, SKILLS_REL, e.name, "SKILL.md")));
43157
+ const fm = frontmatter(await readText2(join25(root, SKILLS_REL, e.name, "SKILL.md")));
42991
43158
  skills.push({ name: e.name, description: fm.description });
42992
43159
  }
42993
43160
  } catch {
@@ -42998,15 +43165,15 @@ async function listAgents(root) {
42998
43165
  }
42999
43166
  function itemPath(root, kind, name) {
43000
43167
  const n = safeName(name);
43001
- return kind === "subagent" ? join24(root, AGENTS_REL, `${n}.md`) : join24(root, SKILLS_REL, n, "SKILL.md");
43168
+ return kind === "subagent" ? join25(root, AGENTS_REL, `${n}.md`) : join25(root, SKILLS_REL, n, "SKILL.md");
43002
43169
  }
43003
43170
  async function readAgent(root, kind, name) {
43004
43171
  const content = await readText2(itemPath(root, kind, name));
43005
43172
  if (kind !== "subagent") return { content };
43006
43173
  const n = safeName(name);
43007
43174
  const [short, long] = await Promise.all([
43008
- readText2(join24(root, AGENTS_REL, "short-memory", `${n}.md`)),
43009
- readText2(join24(root, AGENTS_REL, "long-memory", `${n}.md`))
43175
+ readText2(join25(root, AGENTS_REL, "short-memory", `${n}.md`)),
43176
+ readText2(join25(root, AGENTS_REL, "long-memory", `${n}.md`))
43010
43177
  ]);
43011
43178
  return { content, memory: { short, long } };
43012
43179
  }
@@ -43016,12 +43183,12 @@ async function writeAgent(root, req) {
43016
43183
  try {
43017
43184
  if (req.action === "delete") {
43018
43185
  if (req.kind === "subagent") await rm5(itemPath(root, "subagent", n), { force: true });
43019
- else await rm5(join24(root, SKILLS_REL, n), { recursive: true, force: true });
43186
+ else await rm5(join25(root, SKILLS_REL, n), { recursive: true, force: true });
43020
43187
  return { ok: true };
43021
43188
  }
43022
43189
  if (req.content === void 0) return { ok: false, error: "content is required" };
43023
43190
  const path = itemPath(root, req.kind, n);
43024
- await mkdir8(join24(path, ".."), { recursive: true });
43191
+ await mkdir8(join25(path, ".."), { recursive: true });
43025
43192
  await writeFile8(path, req.content, "utf8");
43026
43193
  return { ok: true };
43027
43194
  } catch (err) {
@@ -43031,7 +43198,7 @@ async function writeAgent(root, req) {
43031
43198
 
43032
43199
  // src/core/secrets.ts
43033
43200
  import { readFile as readFile11, writeFile as writeFile9 } from "fs/promises";
43034
- import { join as join25 } from "path";
43201
+ import { join as join26 } from "path";
43035
43202
  var SECURITY_REL = "AI_SECURITY.md";
43036
43203
  var PLACEHOLDER_REL = "AI_PLACEHOLDER.md";
43037
43204
  var SECRETS_REL = "project.secrets.json";
@@ -43044,7 +43211,7 @@ async function readText3(path, fallback = "") {
43044
43211
  }
43045
43212
  async function readSecretsObject(root) {
43046
43213
  try {
43047
- const v2 = JSON.parse(await readFile11(join25(root, SECRETS_REL), "utf8"));
43214
+ const v2 = JSON.parse(await readFile11(join26(root, SECRETS_REL), "utf8"));
43048
43215
  return v2 && typeof v2 === "object" ? v2 : {};
43049
43216
  } catch {
43050
43217
  return {};
@@ -43063,8 +43230,8 @@ function placeholderKeys(text) {
43063
43230
  }
43064
43231
  async function readSecrets(root) {
43065
43232
  const [security, placeholder, secrets] = await Promise.all([
43066
- readText3(join25(root, SECURITY_REL)),
43067
- readText3(join25(root, PLACEHOLDER_REL)),
43233
+ readText3(join26(root, SECURITY_REL)),
43234
+ readText3(join26(root, PLACEHOLDER_REL)),
43068
43235
  readSecretsObject(root)
43069
43236
  ]);
43070
43237
  const names = /* @__PURE__ */ new Set([...placeholderKeys(placeholder), ...Object.keys(secrets)]);
@@ -43077,14 +43244,14 @@ async function readSecrets(root) {
43077
43244
  async function writeSecrets(root, req) {
43078
43245
  try {
43079
43246
  if (req.kind === "security") {
43080
- await writeFile9(join25(root, SECURITY_REL), req.content, "utf8");
43247
+ await writeFile9(join26(root, SECURITY_REL), req.content, "utf8");
43081
43248
  } else if (req.kind === "placeholder") {
43082
- await writeFile9(join25(root, PLACEHOLDER_REL), req.content, "utf8");
43249
+ await writeFile9(join26(root, PLACEHOLDER_REL), req.content, "utf8");
43083
43250
  } else {
43084
43251
  const secrets = await readSecretsObject(root);
43085
43252
  if (req.kind === "secret") secrets[req.key] = req.value;
43086
43253
  else delete secrets[req.key];
43087
- await writeFile9(join25(root, SECRETS_REL), JSON.stringify(secrets, null, 2) + "\n", "utf8");
43254
+ await writeFile9(join26(root, SECRETS_REL), JSON.stringify(secrets, null, 2) + "\n", "utf8");
43088
43255
  }
43089
43256
  return { ok: true };
43090
43257
  } catch (err) {
@@ -43094,12 +43261,12 @@ async function writeSecrets(root, req) {
43094
43261
 
43095
43262
  // src/core/agent-tools.ts
43096
43263
  import { readFile as readFile12, writeFile as writeFile10, mkdir as mkdir9 } from "fs/promises";
43097
- import { dirname as dirname8, join as join26 } from "path";
43264
+ import { dirname as dirname8, join as join27 } from "path";
43098
43265
  var SHARED_REL = ".claude/settings.json";
43099
43266
  var LOCAL_REL = ".claude/settings.local.json";
43100
43267
  var SECRETS_DENY = "Read(./project.secrets.json)";
43101
43268
  function fileFor(root, scope) {
43102
- return join26(root, scope === "shared" ? SHARED_REL : LOCAL_REL);
43269
+ return join27(root, scope === "shared" ? SHARED_REL : LOCAL_REL);
43103
43270
  }
43104
43271
  async function readSettingsObject(path) {
43105
43272
  try {
@@ -43136,7 +43303,7 @@ async function writeAgentTools(root, scope, permissions) {
43136
43303
  // src/core/packages.ts
43137
43304
  import { createHash as createHash4 } from "crypto";
43138
43305
  import { readFile as readFile13, writeFile as writeFile11, mkdir as mkdir10, readdir as readdir5, rm as rm6, stat as stat4 } from "fs/promises";
43139
- import { dirname as dirname9, join as join27, relative } from "path";
43306
+ import { dirname as dirname9, join as join28, relative } from "path";
43140
43307
  var AGENTS_REL2 = ".claude/agents";
43141
43308
  var SKILLS_REL2 = ".claude/skills";
43142
43309
  var MANIFEST_REL = ".claude/.4pm-packages.json";
@@ -43160,7 +43327,7 @@ async function listFilesRel(dir2) {
43160
43327
  return;
43161
43328
  }
43162
43329
  for (const e of entries2) {
43163
- const full = join27(d, e.name);
43330
+ const full = join28(d, e.name);
43164
43331
  if (e.isDirectory()) await walk2(full);
43165
43332
  else if (e.isFile()) out.push(relative(dir2, full));
43166
43333
  }
@@ -43171,16 +43338,16 @@ async function listFilesRel(dir2) {
43171
43338
  async function readArtifactFiles(root, kind, slug) {
43172
43339
  const files = [];
43173
43340
  if (kind === "subagent") {
43174
- const agent = await readMaybe(join27(root, AGENTS_REL2, `${slug}.md`));
43341
+ const agent = await readMaybe(join28(root, AGENTS_REL2, `${slug}.md`));
43175
43342
  if (agent) files.push({ path: "agent.md", contentBase64: agent.toString("base64") });
43176
- const short = await readMaybe(join27(root, AGENTS_REL2, "short-memory", `${slug}.md`));
43343
+ const short = await readMaybe(join28(root, AGENTS_REL2, "short-memory", `${slug}.md`));
43177
43344
  if (short) files.push({ path: "short-memory.md", contentBase64: short.toString("base64") });
43178
- const long = await readMaybe(join27(root, AGENTS_REL2, "long-memory", `${slug}.md`));
43345
+ const long = await readMaybe(join28(root, AGENTS_REL2, "long-memory", `${slug}.md`));
43179
43346
  if (long) files.push({ path: "long-memory.md", contentBase64: long.toString("base64") });
43180
43347
  } else {
43181
- const base = join27(root, SKILLS_REL2, slug);
43348
+ const base = join28(root, SKILLS_REL2, slug);
43182
43349
  for (const rel of await listFilesRel(base)) {
43183
- const buf = await readMaybe(join27(base, rel));
43350
+ const buf = await readMaybe(join28(base, rel));
43184
43351
  if (buf) files.push({ path: rel.split("\\").join("/"), contentBase64: buf.toString("base64") });
43185
43352
  }
43186
43353
  }
@@ -43198,7 +43365,7 @@ async function artifactSha256(root, kind, slug) {
43198
43365
  return h.digest("hex");
43199
43366
  }
43200
43367
  async function artifactExists(root, kind, slug) {
43201
- const target = kind === "subagent" ? join27(root, AGENTS_REL2, `${slug}.md`) : join27(root, SKILLS_REL2, slug);
43368
+ const target = kind === "subagent" ? join28(root, AGENTS_REL2, `${slug}.md`) : join28(root, SKILLS_REL2, slug);
43202
43369
  try {
43203
43370
  await stat4(target);
43204
43371
  return true;
@@ -43207,7 +43374,7 @@ async function artifactExists(root, kind, slug) {
43207
43374
  }
43208
43375
  }
43209
43376
  async function readManifest(root) {
43210
- const buf = await readMaybe(join27(root, MANIFEST_REL));
43377
+ const buf = await readMaybe(join28(root, MANIFEST_REL));
43211
43378
  if (!buf) return {};
43212
43379
  try {
43213
43380
  return JSON.parse(buf.toString("utf8"));
@@ -43216,7 +43383,7 @@ async function readManifest(root) {
43216
43383
  }
43217
43384
  }
43218
43385
  async function writeManifest(root, manifest) {
43219
- const path = join27(root, MANIFEST_REL);
43386
+ const path = join28(root, MANIFEST_REL);
43220
43387
  await mkdir10(dirname9(path), { recursive: true });
43221
43388
  await writeFile11(path, JSON.stringify(manifest, null, 2), "utf8");
43222
43389
  }
@@ -43225,24 +43392,24 @@ async function writeArtifactFiles(root, kind, slug, files) {
43225
43392
  if (kind === "subagent") {
43226
43393
  const agent = byPath.get("agent.md");
43227
43394
  if (agent) {
43228
- await mkdir10(join27(root, AGENTS_REL2), { recursive: true });
43229
- await writeFile11(join27(root, AGENTS_REL2, `${slug}.md`), agent);
43395
+ await mkdir10(join28(root, AGENTS_REL2), { recursive: true });
43396
+ await writeFile11(join28(root, AGENTS_REL2, `${slug}.md`), agent);
43230
43397
  }
43231
43398
  const short = byPath.get("short-memory.md");
43232
43399
  if (short) {
43233
- await mkdir10(join27(root, AGENTS_REL2, "short-memory"), { recursive: true });
43234
- await writeFile11(join27(root, AGENTS_REL2, "short-memory", `${slug}.md`), short);
43400
+ await mkdir10(join28(root, AGENTS_REL2, "short-memory"), { recursive: true });
43401
+ await writeFile11(join28(root, AGENTS_REL2, "short-memory", `${slug}.md`), short);
43235
43402
  }
43236
43403
  const long = byPath.get("long-memory.md");
43237
43404
  if (long) {
43238
- await mkdir10(join27(root, AGENTS_REL2, "long-memory"), { recursive: true });
43239
- await writeFile11(join27(root, AGENTS_REL2, "long-memory", `${slug}.md`), long);
43405
+ await mkdir10(join28(root, AGENTS_REL2, "long-memory"), { recursive: true });
43406
+ await writeFile11(join28(root, AGENTS_REL2, "long-memory", `${slug}.md`), long);
43240
43407
  }
43241
43408
  } else {
43242
- const base = join27(root, SKILLS_REL2, slug);
43409
+ const base = join28(root, SKILLS_REL2, slug);
43243
43410
  for (const [rel, buf] of byPath) {
43244
43411
  if (rel.includes("..") || rel.startsWith("/")) continue;
43245
- const dest = join27(base, rel);
43412
+ const dest = join28(base, rel);
43246
43413
  await mkdir10(dirname9(dest), { recursive: true });
43247
43414
  await writeFile11(dest, buf);
43248
43415
  }
@@ -43308,11 +43475,11 @@ async function removePackage(root, slug) {
43308
43475
  const entry = manifest[n];
43309
43476
  if (!entry) return { ok: false, error: "not installed" };
43310
43477
  if (entry.kind === "subagent") {
43311
- await rm6(join27(root, AGENTS_REL2, `${n}.md`), { force: true });
43312
- await rm6(join27(root, AGENTS_REL2, "short-memory", `${n}.md`), { force: true });
43313
- await rm6(join27(root, AGENTS_REL2, "long-memory", `${n}.md`), { force: true });
43478
+ await rm6(join28(root, AGENTS_REL2, `${n}.md`), { force: true });
43479
+ await rm6(join28(root, AGENTS_REL2, "short-memory", `${n}.md`), { force: true });
43480
+ await rm6(join28(root, AGENTS_REL2, "long-memory", `${n}.md`), { force: true });
43314
43481
  } else {
43315
- await rm6(join27(root, SKILLS_REL2, n), { recursive: true, force: true });
43482
+ await rm6(join28(root, SKILLS_REL2, n), { recursive: true, force: true });
43316
43483
  }
43317
43484
  delete manifest[n];
43318
43485
  await writeManifest(root, manifest);
@@ -43324,7 +43491,7 @@ async function removePackage(root, slug) {
43324
43491
 
43325
43492
  // src/core/graph.ts
43326
43493
  import { readFile as readFile14, readdir as readdir6 } from "fs/promises";
43327
- import { join as join28, relative as relative2, dirname as dirname10, resolve as resolve9, extname as extname2, basename as basename6 } from "path";
43494
+ import { join as join29, relative as relative2, dirname as dirname10, resolve as resolve9, extname as extname2, basename as basename6 } from "path";
43328
43495
  var MAX_FILES = 2e3;
43329
43496
  var MAX_NODES = 3e3;
43330
43497
  var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", ".next", "out", "coverage", ".turbo"]);
@@ -43344,7 +43511,7 @@ async function walk(root, accept) {
43344
43511
  if (e.name.startsWith(".") && e.name !== ".claude") {
43345
43512
  if (e.isDirectory()) continue;
43346
43513
  }
43347
- const full = join28(dir2, e.name);
43514
+ const full = join29(dir2, e.name);
43348
43515
  if (e.isDirectory()) {
43349
43516
  if (!SKIP_DIRS.has(e.name)) stack.push(full);
43350
43517
  } else if (accept(full)) {
@@ -43464,12 +43631,12 @@ async function buildGraph(root, mode) {
43464
43631
 
43465
43632
  // src/core/rag.ts
43466
43633
  import { readFile as readFile15, writeFile as writeFile12, statfs as statfs2, mkdir as mkdir11 } from "fs/promises";
43467
- import { existsSync as existsSync14 } from "fs";
43468
- import { execFile as execFile10, spawn as spawn9 } from "child_process";
43634
+ import { existsSync as existsSync15 } from "fs";
43635
+ import { execFile as execFile11, spawn as spawn10 } from "child_process";
43469
43636
  import { totalmem as totalmem2, cpus as cpus2 } from "os";
43470
- import { join as join29 } from "path";
43471
- import { promisify as promisify10 } from "util";
43472
- var run10 = promisify10(execFile10);
43637
+ import { join as join30 } from "path";
43638
+ import { promisify as promisify11 } from "util";
43639
+ var run10 = promisify11(execFile11);
43473
43640
  var RAG_REL = ".claude/rag";
43474
43641
  async function tryRun(cmd, args) {
43475
43642
  try {
@@ -43488,7 +43655,7 @@ async function detectPython() {
43488
43655
  }
43489
43656
  async function installLog(root) {
43490
43657
  try {
43491
- const text = await readFile15(join29(root, RAG_REL, "install.log"), "utf8");
43658
+ const text = await readFile15(join30(root, RAG_REL, "install.log"), "utf8");
43492
43659
  return text.split("\n").filter((l) => l.length > 0).slice(-200);
43493
43660
  } catch {
43494
43661
  return [];
@@ -43550,14 +43717,14 @@ async function ragStatus(root) {
43550
43717
  };
43551
43718
  let modelName = "";
43552
43719
  try {
43553
- modelName = (await readFile15(join29(root, RAG_REL, ".installed"), "utf8")).trim();
43720
+ modelName = (await readFile15(join30(root, RAG_REL, ".installed"), "utf8")).trim();
43554
43721
  } catch {
43555
43722
  modelName = "";
43556
43723
  }
43557
43724
  const modelPresent = modelName.length > 0;
43558
43725
  return {
43559
43726
  installed: fastembed && sqliteVec && modelPresent,
43560
- installing: existsSync14(join29(root, RAG_REL, ".installing")),
43727
+ installing: existsSync15(join30(root, RAG_REL, ".installing")),
43561
43728
  python: { found: py.found, version: py.version },
43562
43729
  deps: { pip, fastembed, sqliteVec },
43563
43730
  model: { present: modelPresent, name: modelName },
@@ -43568,9 +43735,9 @@ async function ragStatus(root) {
43568
43735
  };
43569
43736
  }
43570
43737
  async function readIndexMeta(root) {
43571
- const indexing = existsSync14(join29(root, RAG_REL, ".indexing"));
43738
+ const indexing = existsSync15(join30(root, RAG_REL, ".indexing"));
43572
43739
  try {
43573
- const m2 = JSON.parse(await readFile15(join29(root, RAG_REL, ".index.json"), "utf8"));
43740
+ const m2 = JSON.parse(await readFile15(join30(root, RAG_REL, ".index.json"), "utf8"));
43574
43741
  return {
43575
43742
  present: true,
43576
43743
  indexing,
@@ -43637,14 +43804,14 @@ if __name__ == "__main__":
43637
43804
  elif cmd == "query": query(sys.argv[2], int(sys.argv[3]) if len(sys.argv) > 3 else 8)
43638
43805
  `;
43639
43806
  async function ensureEngine(root) {
43640
- await mkdir11(join29(root, RAG_REL), { recursive: true }).catch(() => void 0);
43641
- await writeFile12(join29(root, RAG_REL, "rag_engine.py"), RAG_ENGINE_PY, "utf8");
43807
+ await mkdir11(join30(root, RAG_REL), { recursive: true }).catch(() => void 0);
43808
+ await writeFile12(join30(root, RAG_REL, "rag_engine.py"), RAG_ENGINE_PY, "utf8");
43642
43809
  }
43643
43810
  async function ragReindex(root) {
43644
43811
  const py = await detectPython();
43645
43812
  if (!py.found) return { ok: false, started: false, error: "python3 not found" };
43646
- if (!existsSync14(join29(root, RAG_REL, ".installed"))) return { ok: false, started: false, error: "RAG is not installed" };
43647
- if (existsSync14(join29(root, RAG_REL, ".indexing"))) return { ok: true, started: true };
43813
+ if (!existsSync15(join30(root, RAG_REL, ".installed"))) return { ok: false, started: false, error: "RAG is not installed" };
43814
+ if (existsSync15(join30(root, RAG_REL, ".indexing"))) return { ok: true, started: true };
43648
43815
  await ensureEngine(root);
43649
43816
  const script = `
43650
43817
  set +e
@@ -43652,7 +43819,7 @@ touch "${RAG_REL}/.indexing"
43652
43819
  { echo "[reindex] $(date)"; "$RAG_PY" "${RAG_REL}/rag_engine.py" reindex 2>&1; } >> "${RAG_REL}/index.log" 2>&1
43653
43820
  rm -f "${RAG_REL}/.indexing"
43654
43821
  `;
43655
- const child = spawn9("bash", ["-c", script], {
43822
+ const child = spawn10("bash", ["-c", script], {
43656
43823
  cwd: root,
43657
43824
  env: { ...process.env, RAG_PY: py.bin },
43658
43825
  detached: true,
@@ -43664,12 +43831,12 @@ rm -f "${RAG_REL}/.indexing"
43664
43831
  async function ragQuery(root, queryText, k2 = 8) {
43665
43832
  const py = await detectPython();
43666
43833
  if (!py.found) return { results: [], error: "python3 not found" };
43667
- if (!existsSync14(join29(root, RAG_REL, "index.db"))) return { results: [], error: "no index \u2014 reindex first" };
43834
+ if (!existsSync15(join30(root, RAG_REL, "index.db"))) return { results: [], error: "no index \u2014 reindex first" };
43668
43835
  await ensureEngine(root);
43669
43836
  try {
43670
43837
  const { stdout } = await run10(
43671
43838
  py.bin,
43672
- [join29(RAG_REL, "rag_engine.py"), "query", queryText, String(Math.min(Math.max(k2, 1), 20))],
43839
+ [join30(RAG_REL, "rag_engine.py"), "query", queryText, String(Math.min(Math.max(k2, 1), 20))],
43673
43840
  { cwd: root, timeout: 3e4, maxBuffer: 4 * 1024 * 1024 }
43674
43841
  );
43675
43842
  const parsed = JSON.parse(stdout.trim() || '{"results":[]}');
@@ -43684,9 +43851,9 @@ async function ragInstall(root, model) {
43684
43851
  }
43685
43852
  const py = await detectPython();
43686
43853
  if (!py.found) return { ok: false, started: false, error: "python3 not found on the worker" };
43687
- if (existsSync14(join29(root, RAG_REL, ".installing"))) return { ok: true, started: true };
43854
+ if (existsSync15(join30(root, RAG_REL, ".installing"))) return { ok: true, started: true };
43688
43855
  try {
43689
- await mkdir11(join29(root, RAG_REL), { recursive: true });
43856
+ await mkdir11(join30(root, RAG_REL), { recursive: true });
43690
43857
  } catch {
43691
43858
  }
43692
43859
  const script = `
@@ -43702,7 +43869,7 @@ rm -f "${RAG_REL}/.installed"
43702
43869
  } >> "${RAG_REL}/install.log" 2>&1
43703
43870
  rm -f "${RAG_REL}/.installing"
43704
43871
  `;
43705
- const child = spawn9("bash", ["-c", script], {
43872
+ const child = spawn10("bash", ["-c", script], {
43706
43873
  cwd: root,
43707
43874
  env: { ...process.env, RAG_PY: py.bin, RAG_MODEL: model },
43708
43875
  detached: true,
@@ -43713,8 +43880,8 @@ rm -f "${RAG_REL}/.installing"
43713
43880
  }
43714
43881
 
43715
43882
  // src/core/config-sync.ts
43716
- import { existsSync as existsSync15, readFileSync as readFileSync16 } from "fs";
43717
- import { join as join30 } from "path";
43883
+ import { existsSync as existsSync16, readFileSync as readFileSync16 } from "fs";
43884
+ import { join as join31 } from "path";
43718
43885
  var SERVER_MANAGED_KEYS = [
43719
43886
  "physicPath",
43720
43887
  "sessionSwitchPct",
@@ -43731,8 +43898,8 @@ var SERVER_MANAGED_KEYS = [
43731
43898
  "projectAiMemoryBudgetChars"
43732
43899
  ];
43733
43900
  function readConfigText(profileDir2) {
43734
- const path = join30(profileDir2, "config.json");
43735
- if (existsSync15(path)) {
43901
+ const path = join31(profileDir2, "config.json");
43902
+ if (existsSync16(path)) {
43736
43903
  try {
43737
43904
  return readFileSync16(path, "utf8");
43738
43905
  } catch {
@@ -44521,7 +44688,7 @@ var WsClient = class {
44521
44688
  }
44522
44689
  const { payload, nonce } = encryptPayload(this.sessionKey, data);
44523
44690
  const envelope = {
44524
- id: randomUUID3(),
44691
+ id: randomUUID4(),
44525
44692
  replyTo,
44526
44693
  channel,
44527
44694
  wsToken: this.wsToken,
@@ -44542,7 +44709,7 @@ var WsClient = class {
44542
44709
  }
44543
44710
  const { payload, nonce } = encryptPayload(this.sessionKey, data);
44544
44711
  const envelope = {
44545
- id: randomUUID3(),
44712
+ id: randomUUID4(),
44546
44713
  replyTo: null,
44547
44714
  channel,
44548
44715
  wsToken: this.wsToken,
@@ -44609,8 +44776,8 @@ var WsClient = class {
44609
44776
  /** Create the physic folder at an absolute path if missing (best-effort). */
44610
44777
  ensurePhysicFolderPath(folder) {
44611
44778
  try {
44612
- if (!existsSync16(folder)) {
44613
- mkdirSync7(folder, { recursive: true });
44779
+ if (!existsSync17(folder)) {
44780
+ mkdirSync8(folder, { recursive: true });
44614
44781
  this.bus.log(t("project.createdFolder", { folder }));
44615
44782
  }
44616
44783
  } catch (err) {
@@ -44624,7 +44791,7 @@ var WsClient = class {
44624
44791
  */
44625
44792
  physicFolderPath(projectName) {
44626
44793
  const safe = projectName.replace(/[/\\]/g, "_").replace(/\.\./g, "_").trim();
44627
- return safe ? join31(this.context.profileDir, safe) : null;
44794
+ return safe ? join32(this.context.profileDir, safe) : null;
44628
44795
  }
44629
44796
  /**
44630
44797
  * Report machine.status: version + the state of the physic project being served
@@ -44639,7 +44806,7 @@ var WsClient = class {
44639
44806
  projects: [],
44640
44807
  version: CLI_VERSION,
44641
44808
  physicPath,
44642
- physicPathExists: physicPath ? existsSync16(physicPath) : void 0,
44809
+ physicPathExists: physicPath ? existsSync17(physicPath) : void 0,
44643
44810
  // Real coarse state (ADR-0152): !paused and a recent tick (was hard-coded false).
44644
44811
  autonomousRunning: physicPath ? isAutonomousRunning(physicPath, this.context.profileDir) : false,
44645
44812
  // The machine-user AI-run limit (0 = unlimited) + profile count so a dispatch can resolve the
@@ -44733,7 +44900,7 @@ var WsClient = class {
44733
44900
  */
44734
44901
  uploadLog() {
44735
44902
  try {
44736
- const upload = readLogUpload(join31(this.context.profileDir, "logs"));
44903
+ const upload = readLogUpload(join32(this.context.profileDir, "logs"));
44737
44904
  if (!upload) return;
44738
44905
  const sig = `${upload.fileName}:${upload.totalBytes}`;
44739
44906
  if (sig === this.lastLogSig) return;
@@ -44895,10 +45062,10 @@ var WsClient = class {
44895
45062
  };
44896
45063
 
44897
45064
  // src/core/instance-lock.ts
44898
- import { readFileSync as readFileSync17, rmSync as rmSync7, writeFileSync as writeFileSync9 } from "fs";
44899
- import { join as join32 } from "path";
45065
+ import { readFileSync as readFileSync17, rmSync as rmSync8, writeFileSync as writeFileSync9 } from "fs";
45066
+ import { join as join33 } from "path";
44900
45067
  function lockPath(profileDir2) {
44901
- return join32(profileDir2, "start.lock");
45068
+ return join33(profileDir2, "start.lock");
44902
45069
  }
44903
45070
  function isAlive(pid) {
44904
45071
  try {
@@ -44924,14 +45091,14 @@ function acquireInstanceLock(profileDir2) {
44924
45091
  function releaseInstanceLock(profileDir2) {
44925
45092
  try {
44926
45093
  const pid = Number.parseInt(readFileSync17(lockPath(profileDir2), "utf8").trim(), 10);
44927
- if (pid === process.pid) rmSync7(lockPath(profileDir2), { force: true });
45094
+ if (pid === process.pid) rmSync8(lockPath(profileDir2), { force: true });
44928
45095
  } catch {
44929
45096
  }
44930
45097
  }
44931
45098
 
44932
45099
  // src/core/session-bus.ts
44933
45100
  import { EventEmitter } from "events";
44934
- import { randomUUID as randomUUID4 } from "crypto";
45101
+ import { randomUUID as randomUUID5 } from "crypto";
44935
45102
  var REPLAY_CAP = 500;
44936
45103
  var SessionBus = class {
44937
45104
  emitter = new EventEmitter();
@@ -44962,7 +45129,7 @@ var SessionBus = class {
44962
45129
  /** Producer → consumers: push one transcript entry. Returns its id (for `updateEntry`). */
44963
45130
  push(input) {
44964
45131
  const entry = {
44965
- id: randomUUID4(),
45132
+ id: randomUUID5(),
44966
45133
  level: "info",
44967
45134
  ...input,
44968
45135
  ts: Date.now()
@@ -45219,8 +45386,8 @@ var SessionBus = class {
45219
45386
 
45220
45387
  // src/core/control-server.ts
45221
45388
  import { createServer } from "net";
45222
- import { chmodSync as chmodSync4, rmSync as rmSync8 } from "fs";
45223
- import { join as join34 } from "path";
45389
+ import { chmodSync as chmodSync4, rmSync as rmSync9 } from "fs";
45390
+ import { join as join35 } from "path";
45224
45391
 
45225
45392
  // src/core/control-protocol.ts
45226
45393
  var CONTROL_SOCKET_FILE = "control.sock";
@@ -45251,9 +45418,9 @@ function createFrameParser() {
45251
45418
  // src/core/control-token.ts
45252
45419
  import { chmodSync as chmodSync3, readFileSync as readFileSync18, writeFileSync as writeFileSync10 } from "fs";
45253
45420
  import { randomBytes as randomBytes3, timingSafeEqual } from "crypto";
45254
- import { join as join33 } from "path";
45421
+ import { join as join34 } from "path";
45255
45422
  function controlTokenPath(profileDir2) {
45256
- return join33(profileDir2, CONTROL_TOKEN_FILE);
45423
+ return join34(profileDir2, CONTROL_TOKEN_FILE);
45257
45424
  }
45258
45425
  function writeControlToken(profileDir2) {
45259
45426
  const token = randomBytes3(32).toString("hex");
@@ -45282,9 +45449,9 @@ function tokenMatches(expected, given) {
45282
45449
 
45283
45450
  // src/core/control-server.ts
45284
45451
  function startControlServer(bus, profileDir2, info) {
45285
- const socketPath = join34(profileDir2, CONTROL_SOCKET_FILE);
45452
+ const socketPath = join35(profileDir2, CONTROL_SOCKET_FILE);
45286
45453
  try {
45287
- rmSync8(socketPath, { force: true });
45454
+ rmSync9(socketPath, { force: true });
45288
45455
  } catch {
45289
45456
  }
45290
45457
  const clients = /* @__PURE__ */ new Set();
@@ -45370,8 +45537,8 @@ function startControlServer(bus, profileDir2, info) {
45370
45537
  clients.clear();
45371
45538
  server.close();
45372
45539
  try {
45373
- rmSync8(socketPath, { force: true });
45374
- rmSync8(controlTokenPath(profileDir2), { force: true });
45540
+ rmSync9(socketPath, { force: true });
45541
+ rmSync9(controlTokenPath(profileDir2), { force: true });
45375
45542
  } catch {
45376
45543
  }
45377
45544
  };
@@ -51034,15 +51201,15 @@ var import_react21 = __toESM(require_react(), 1);
51034
51201
  var import_react26 = __toESM(require_react(), 1);
51035
51202
 
51036
51203
  // src/core/input-history.ts
51037
- import { existsSync as existsSync18, readFileSync as readFileSync20, writeFileSync as writeFileSync11 } from "fs";
51038
- import { join as join35 } from "path";
51204
+ import { existsSync as existsSync19, readFileSync as readFileSync20, writeFileSync as writeFileSync11 } from "fs";
51205
+ import { join as join36 } from "path";
51039
51206
  var MAX_HISTORY = 200;
51040
51207
  function historyPath(profileDir2) {
51041
- return join35(profileDir2, "input-history.json");
51208
+ return join36(profileDir2, "input-history.json");
51042
51209
  }
51043
51210
  function loadInputHistory(profileDir2) {
51044
51211
  const path = historyPath(profileDir2);
51045
- if (!existsSync18(path)) return [];
51212
+ if (!existsSync19(path)) return [];
51046
51213
  try {
51047
51214
  const data = JSON.parse(readFileSync20(path, "utf8"));
51048
51215
  return Array.isArray(data) ? data.filter((x) => typeof x === "string") : [];
@@ -51652,7 +51819,7 @@ async function runStart(profileDir2, profileName) {
51652
51819
  return;
51653
51820
  }
51654
51821
  logger.configure({
51655
- dir: join36(profileDir2, "logs"),
51822
+ dir: join37(profileDir2, "logs"),
51656
51823
  level: resolveLogLevel(),
51657
51824
  base: { version: CLI_VERSION, profile: profileName, scope: credential.scope }
51658
51825
  });
@@ -51672,7 +51839,7 @@ async function runStart(profileDir2, profileName) {
51672
51839
  if (result.action === "updated") {
51673
51840
  logger.info("update.updated", { version: result.version });
51674
51841
  console.log(t("start.restarting"));
51675
- const child = spawn10(process.execPath, process.argv.slice(1), {
51842
+ const child = spawn11(process.execPath, process.argv.slice(1), {
51676
51843
  stdio: "inherit",
51677
51844
  env: { ...process.env, FOURPM_NO_UPDATE: "1" }
51678
51845
  });
@@ -51761,7 +51928,7 @@ async function runStart(profileDir2, profileName) {
51761
51928
  }
51762
51929
 
51763
51930
  // src/commands/attach.ts
51764
- import { join as join37 } from "path";
51931
+ import { join as join38 } from "path";
51765
51932
 
51766
51933
  // src/core/control-client.ts
51767
51934
  import { connect as connect2 } from "net";
@@ -51870,7 +52037,7 @@ async function runAttach(profileDir2, profileName) {
51870
52037
  process.exitCode = 1;
51871
52038
  return;
51872
52039
  }
51873
- const socketPath = join37(profileDir2, CONTROL_SOCKET_FILE);
52040
+ const socketPath = join38(profileDir2, CONTROL_SOCKET_FILE);
51874
52041
  const bus = new SessionBus();
51875
52042
  let conn;
51876
52043
  try {
@@ -51901,11 +52068,11 @@ async function runAttach(profileDir2, profileName) {
51901
52068
 
51902
52069
  // src/commands/auto-run.ts
51903
52070
  import { connect as connect3 } from "net";
51904
- import { join as join38 } from "path";
52071
+ import { join as join39 } from "path";
51905
52072
  var AUTO_RUN_TIMEOUT_MS = 3 * 60 * 60 * 1e3;
51906
52073
  async function runAutoRun(profileDir2, profileName) {
51907
52074
  initI18n(readProfileConfig(profileDir2).locale);
51908
- const socketPath = join38(profileDir2, CONTROL_SOCKET_FILE);
52075
+ const socketPath = join39(profileDir2, CONTROL_SOCKET_FILE);
51909
52076
  const token = readControlToken(profileDir2);
51910
52077
  const code = await new Promise((resolve10) => {
51911
52078
  let settled = false;
@@ -51961,12 +52128,12 @@ async function runAutoRun(profileDir2, profileName) {
51961
52128
  }
51962
52129
 
51963
52130
  // src/commands/ai-login.ts
51964
- import { spawn as spawn11 } from "child_process";
51965
- import { mkdirSync as mkdirSync8 } from "fs";
52131
+ import { spawn as spawn12 } from "child_process";
52132
+ import { mkdirSync as mkdirSync9 } from "fs";
51966
52133
  import { basename as basename8 } from "path";
51967
52134
  function runProviderLogin(cmd, envVar, dir2) {
51968
52135
  return new Promise((resolve10) => {
51969
- const child = spawn11(cmd, [], {
52136
+ const child = spawn12(cmd, [], {
51970
52137
  stdio: "inherit",
51971
52138
  env: { ...process.env, [envVar]: dir2 }
51972
52139
  });
@@ -51999,7 +52166,7 @@ async function runAiLogin(profileDir2, profileName, aiFilter) {
51999
52166
  continue;
52000
52167
  }
52001
52168
  const dir2 = resolveHomePath(cred.profile);
52002
- mkdirSync8(dir2, { recursive: true });
52169
+ mkdirSync9(dir2, { recursive: true });
52003
52170
  console.log(t("aiLogin.loggingIn", { provider: cred.provider, profile: cred.profile, envVar, dir: dir2 }));
52004
52171
  console.log(t("aiLogin.completeSignIn"));
52005
52172
  const code = await runProviderLogin(cred.provider, envVar, dir2);
@@ -52011,7 +52178,7 @@ async function runAiLogin(profileDir2, profileName, aiFilter) {
52011
52178
  }
52012
52179
 
52013
52180
  // src/commands/unlink.ts
52014
- import { rmSync as rmSync9 } from "fs";
52181
+ import { rmSync as rmSync10 } from "fs";
52015
52182
  async function runUnlink(profileDir2, profileName) {
52016
52183
  initI18n(readProfileConfig(profileDir2).locale);
52017
52184
  const cred = readCredential(profileDir2, profileName);
@@ -52025,7 +52192,7 @@ async function runUnlink(profileDir2, profileName) {
52025
52192
  } catch (err) {
52026
52193
  console.log(t("unlink.revokeFailed", { message: err.message }));
52027
52194
  }
52028
- rmSync9(profileDir2, { recursive: true, force: true });
52195
+ rmSync10(profileDir2, { recursive: true, force: true });
52029
52196
  clearDefaultProfileIf(profileName);
52030
52197
  console.log(t("unlink.deleted"));
52031
52198
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@4pm/cli",
3
- "version": "1.19.9",
3
+ "version": "1.20.0",
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",