@4pm/cli 1.5.17 → 1.5.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -5713,14 +5713,14 @@ var require_react_development = __commonJS({
5713
5713
  var thenableResult = result;
5714
5714
  var wasAwaited = false;
5715
5715
  var thenable = {
5716
- then: function(resolve8, reject) {
5716
+ then: function(resolve9, reject) {
5717
5717
  wasAwaited = true;
5718
5718
  thenableResult.then(function(returnValue2) {
5719
5719
  popActScope(prevActScopeDepth);
5720
5720
  if (actScopeDepth === 0) {
5721
- recursivelyFlushAsyncActWork(returnValue2, resolve8, reject);
5721
+ recursivelyFlushAsyncActWork(returnValue2, resolve9, reject);
5722
5722
  } else {
5723
- resolve8(returnValue2);
5723
+ resolve9(returnValue2);
5724
5724
  }
5725
5725
  }, function(error2) {
5726
5726
  popActScope(prevActScopeDepth);
@@ -5750,20 +5750,20 @@ var require_react_development = __commonJS({
5750
5750
  ReactCurrentActQueue.current = null;
5751
5751
  }
5752
5752
  var _thenable = {
5753
- then: function(resolve8, reject) {
5753
+ then: function(resolve9, reject) {
5754
5754
  if (ReactCurrentActQueue.current === null) {
5755
5755
  ReactCurrentActQueue.current = [];
5756
- recursivelyFlushAsyncActWork(returnValue, resolve8, reject);
5756
+ recursivelyFlushAsyncActWork(returnValue, resolve9, reject);
5757
5757
  } else {
5758
- resolve8(returnValue);
5758
+ resolve9(returnValue);
5759
5759
  }
5760
5760
  }
5761
5761
  };
5762
5762
  return _thenable;
5763
5763
  } else {
5764
5764
  var _thenable2 = {
5765
- then: function(resolve8, reject) {
5766
- resolve8(returnValue);
5765
+ then: function(resolve9, reject) {
5766
+ resolve9(returnValue);
5767
5767
  }
5768
5768
  };
5769
5769
  return _thenable2;
@@ -5779,7 +5779,7 @@ var require_react_development = __commonJS({
5779
5779
  actScopeDepth = prevActScopeDepth;
5780
5780
  }
5781
5781
  }
5782
- function recursivelyFlushAsyncActWork(returnValue, resolve8, reject) {
5782
+ function recursivelyFlushAsyncActWork(returnValue, resolve9, reject) {
5783
5783
  {
5784
5784
  var queue = ReactCurrentActQueue.current;
5785
5785
  if (queue !== null) {
@@ -5788,16 +5788,16 @@ var require_react_development = __commonJS({
5788
5788
  enqueueTask(function() {
5789
5789
  if (queue.length === 0) {
5790
5790
  ReactCurrentActQueue.current = null;
5791
- resolve8(returnValue);
5791
+ resolve9(returnValue);
5792
5792
  } else {
5793
- recursivelyFlushAsyncActWork(returnValue, resolve8, reject);
5793
+ recursivelyFlushAsyncActWork(returnValue, resolve9, reject);
5794
5794
  }
5795
5795
  });
5796
5796
  } catch (error2) {
5797
5797
  reject(error2);
5798
5798
  }
5799
5799
  } else {
5800
- resolve8(returnValue);
5800
+ resolve9(returnValue);
5801
5801
  }
5802
5802
  }
5803
5803
  }
@@ -28775,7 +28775,7 @@ async function checkAndUpdate(serverUrl, autoUpdate) {
28775
28775
  // src/core/ws-client.ts
28776
28776
  init_wrapper();
28777
28777
  import { randomUUID } from "crypto";
28778
- import { basename as basename4, join as join26 } from "path";
28778
+ import { basename as basename5, join as join26 } from "path";
28779
28779
 
28780
28780
  // vendor/@4pm/utils/helpers.ts
28781
28781
  function backoffJitterMs(attempt, baseMs = 500, maxMs = 1e4) {
@@ -28807,6 +28807,24 @@ function prettyResult(text) {
28807
28807
  return trimmed;
28808
28808
  }
28809
28809
 
28810
+ // vendor/@4pm/constants/project-template.ts
28811
+ var PROJECT_TEMPLATE = {
28812
+ version: "1.0.0",
28813
+ changelog: [
28814
+ {
28815
+ version: "1.0.0",
28816
+ date: "2026-09-12",
28817
+ summary: "Baseline scaffold template with version tracking.",
28818
+ notes: [
28819
+ "Initial CLAUDE.md, .claude config (settings, hooks, skills, agents, autonomous).",
28820
+ "Standard docs/tests/reports/src layout and placeholder files.",
28821
+ "Introduces .4pm/.4pm.json template-version tracking."
28822
+ ],
28823
+ files: []
28824
+ }
28825
+ ]
28826
+ };
28827
+
28810
28828
  // vendor/@4pm/constants/quota.ts
28811
28829
  var UsageMetric = {
28812
28830
  AI_TOKENS: "ai_tokens",
@@ -32939,6 +32957,14 @@ var commandImageRefSchema = external_exports.object({
32939
32957
  name: external_exports.string().max(255),
32940
32958
  mime: external_exports.enum(COMMAND_IMAGE_MIME_TYPES)
32941
32959
  });
32960
+ var aiRunConfigSchema = external_exports.object({
32961
+ /** `--model` override for this run (must match the resolved provider's model id). */
32962
+ model: external_exports.string().trim().max(120).optional(),
32963
+ /** Coarse reasoning-budget level, mapped to the provider's own mechanism. */
32964
+ thinking: external_exports.enum(["off", "low", "medium", "high"]).optional(),
32965
+ /** Sampling temperature 0..1 (best-effort per provider). */
32966
+ temperature: external_exports.number().min(0).max(1).optional()
32967
+ });
32942
32968
  var dispatchCommandRequestSchema = external_exports.object({
32943
32969
  projectId: external_exports.string().uuid(),
32944
32970
  // Target cli. Required unless `pick` is set — with `pick:"idle"` the server chooses the
@@ -32986,7 +33012,22 @@ var dispatchCommandRequestSchema = external_exports.object({
32986
33012
  * the repo / edit files / loop forever. Only meaningful with `ai:true`; absent ⇒ a full
32987
33013
  * agent run (the Console tab + Git merge, which legitimately use tools).
32988
33014
  */
32989
- aiOneShot: external_exports.boolean().optional()
33015
+ aiOneShot: external_exports.boolean().optional(),
33016
+ /**
33017
+ * Read-only agent AI mode (ADR-0265): the prompt is a task that must **read + inspect the repo
33018
+ * but write nothing** (the project-template "Analyze impact"). Unlike `aiOneShot` it keeps the
33019
+ * read/search tools (`Read`/`Glob`/`Grep`/`Bash`) and runs multi-turn, but the cli blocks the
33020
+ * write/orchestration tools and runs claude under `--permission-mode plan` (codex `--sandbox
33021
+ * read-only`) so it can diff files without editing them. Only meaningful with `ai:true`;
33022
+ * **mutually exclusive with `aiOneShot`** (a run is one-shot | read-only | full-agent).
33023
+ */
33024
+ aiReadOnly: external_exports.boolean().optional(),
33025
+ /**
33026
+ * Per-run AI execution overrides (ADR-0261): model/thinking/temperature chosen in the web
33027
+ * "AI settings" modal (per-user localStorage), layered over the profile default by the cli.
33028
+ * Only meaningful with `ai:true`.
33029
+ */
33030
+ aiConfig: aiRunConfigSchema.optional()
32990
33031
  }).superRefine((v, ctx) => {
32991
33032
  if (v.machineLinkId == null === (v.pick == null)) {
32992
33033
  ctx.addIssue({
@@ -32995,6 +33036,13 @@ var dispatchCommandRequestSchema = external_exports.object({
32995
33036
  message: "Provide exactly one of machineLinkId or pick."
32996
33037
  });
32997
33038
  }
33039
+ if (v.aiOneShot && v.aiReadOnly) {
33040
+ ctx.addIssue({
33041
+ code: external_exports.ZodIssueCode.custom,
33042
+ path: ["aiReadOnly"],
33043
+ message: "aiOneShot and aiReadOnly are mutually exclusive."
33044
+ });
33045
+ }
32998
33046
  if (!v.ai && v.command.length > COMMAND_MAX_LEN) {
32999
33047
  ctx.addIssue({
33000
33048
  code: external_exports.ZodIssueCode.too_big,
@@ -33129,6 +33177,17 @@ var fsWriteRequestSchema = external_exports.object({
33129
33177
  /** Full new UTF-8 content (replaces the file wholesale). */
33130
33178
  content: external_exports.string().max(FILE_WRITE_MAX_BYTES)
33131
33179
  });
33180
+ var fsMutateRequestSchema = external_exports.object({
33181
+ op: external_exports.enum(["mkdir", "create", "move", "delete"]),
33182
+ path: external_exports.string().max(1024).optional(),
33183
+ content: external_exports.string().max(FILE_WRITE_MAX_BYTES).optional(),
33184
+ from: external_exports.string().max(1024).optional(),
33185
+ to: external_exports.string().max(1024).optional()
33186
+ });
33187
+ var taskApproveRequestSchema = external_exports.object({
33188
+ taskId: external_exports.string().min(1).max(64),
33189
+ approved: external_exports.boolean()
33190
+ });
33132
33191
  var autonomousWriteRequestSchema = external_exports.discriminatedUnion("kind", [
33133
33192
  external_exports.object({ kind: external_exports.literal("settings"), settings: external_exports.string().max(64 * 1024) }),
33134
33193
  external_exports.object({ kind: external_exports.literal("approvals"), taskId: external_exports.string().min(1).max(64), approved: external_exports.boolean() }),
@@ -33275,16 +33334,6 @@ var MEMO_MAX_LENGTH = 65536;
33275
33334
  var putMemoRequestSchema = external_exports.object({
33276
33335
  content: external_exports.string().max(MEMO_MAX_LENGTH)
33277
33336
  });
33278
- var MEMO_ITEM_MAX_LENGTH = 2e3;
33279
- var createMemoItemSchema = external_exports.object({
33280
- content: external_exports.string().trim().min(1).max(MEMO_ITEM_MAX_LENGTH)
33281
- });
33282
- var updateMemoItemSchema = external_exports.object({
33283
- content: external_exports.string().trim().min(1).max(MEMO_ITEM_MAX_LENGTH).optional(),
33284
- done: external_exports.boolean().optional()
33285
- }).refine((v) => v.content !== void 0 || v.done !== void 0, {
33286
- message: "content or done required"
33287
- });
33288
33337
  var HTTP_JSON_BODY_LIMIT_BYTES = 2 * 1048576;
33289
33338
  var putSpecDraftRequestSchema = external_exports.object({
33290
33339
  spec: external_exports.record(external_exports.unknown()),
@@ -33710,6 +33759,9 @@ var WsChannels = {
33710
33759
  // ADR-0151) — the Git tab's manual conflict resolution (`project.git_write`); the only
33711
33760
  // git-tab write not carried by a git command over command dispatch.
33712
33761
  FS_WRITE: "fs.write",
33762
+ // server → cli (reply): create/rename/move/delete a file or folder in the project tree,
33763
+ // each op path-clamped to the physic root (machine-0059, ADR-0260, `project.files_write`).
33764
+ FS_MUTATE: "fs.mutate",
33713
33765
  GIT_DIFF: "git.diff",
33714
33766
  GIT_ENV: "git.env",
33715
33767
  // server → cli (reply): read/write the paired profile's config.json (machine-0025/0026,
@@ -34026,8 +34078,8 @@ function resolveInstallTimeoutMs(sec) {
34026
34078
  return sec && sec > 0 ? sec * 1e3 : TOOL_INSTALL_TIMEOUT_DEFAULT_MS;
34027
34079
  }
34028
34080
  function sleep(ms) {
34029
- return new Promise((resolve8) => {
34030
- const t = setTimeout(resolve8, ms);
34081
+ return new Promise((resolve9) => {
34082
+ const t = setTimeout(resolve9, ms);
34031
34083
  t.unref?.();
34032
34084
  });
34033
34085
  }
@@ -34049,14 +34101,14 @@ function classifyToolFailure(code, out) {
34049
34101
  return { reason: "other", retryable: false };
34050
34102
  }
34051
34103
  function run(cmd, args, onLine, timeoutMs = 18e4) {
34052
- return new Promise((resolve8) => {
34104
+ return new Promise((resolve9) => {
34053
34105
  let out = "";
34054
34106
  let buf = "";
34055
34107
  let child = null;
34056
34108
  const done = (code) => {
34057
34109
  clearTimeout(timer);
34058
34110
  if (onLine && buf.trim()) onLine(buf.trim());
34059
- resolve8({ code, out });
34111
+ resolve9({ code, out });
34060
34112
  };
34061
34113
  const timer = setTimeout(() => {
34062
34114
  child?.kill();
@@ -34437,7 +34489,7 @@ async function runCommand(dispatch, emit, opts) {
34437
34489
  });
34438
34490
  child.stdout?.on("data", (data) => batcher.push(data.toString("utf8")));
34439
34491
  child.stderr?.on("data", (data) => batcher.push(data.toString("utf8")));
34440
- await new Promise((resolve8) => {
34492
+ await new Promise((resolve9) => {
34441
34493
  child.on("close", (exitCode) => {
34442
34494
  clearTimers();
34443
34495
  batcher.flush();
@@ -34450,7 +34502,7 @@ async function runCommand(dispatch, emit, opts) {
34450
34502
  // server settles the command as failed and the web surfaces the note instead of spinning.
34451
34503
  exitCode: timedOut ? 124 : exitCode ?? -1
34452
34504
  });
34453
- resolve8();
34505
+ resolve9();
34454
34506
  });
34455
34507
  child.on("error", (err) => {
34456
34508
  clearTimers();
@@ -34462,7 +34514,7 @@ async function runCommand(dispatch, emit, opts) {
34462
34514
  done: true,
34463
34515
  exitCode: -1
34464
34516
  });
34465
- resolve8();
34517
+ resolve9();
34466
34518
  });
34467
34519
  });
34468
34520
  }
@@ -34599,15 +34651,15 @@ function isOutOfCredits(text) {
34599
34651
  );
34600
34652
  }
34601
34653
  function runAttempt(commandId, cmd, args, stdin, cwd2, env3, onChunk, timeoutMs) {
34602
- return new Promise((resolve8) => {
34654
+ return new Promise((resolve9) => {
34603
34655
  runCommand(
34604
34656
  { commandId, cmd, args, path: cwd2, env: env3 },
34605
34657
  (out) => {
34606
34658
  if (out.chunk) onChunk(out.chunk);
34607
- if (out.done) resolve8(out.exitCode ?? -1);
34659
+ if (out.done) resolve9(out.exitCode ?? -1);
34608
34660
  },
34609
34661
  { stdin, ...timeoutMs > 0 ? { timeoutMs } : {} }
34610
- ).catch(() => resolve8(-1));
34662
+ ).catch(() => resolve9(-1));
34611
34663
  });
34612
34664
  }
34613
34665
  async function runAiFailover(plan, commandId, cwd2, handlers, timeoutMs = 0) {
@@ -34797,6 +34849,48 @@ function oneShotArgs(cmd) {
34797
34849
  if (!cmd.includes("claude")) return [];
34798
34850
  return ["--max-turns=1", "--disallowedTools", ONE_SHOT_DISALLOWED_CLAUDE_TOOLS, "--permission-mode", "default"];
34799
34851
  }
34852
+ var READ_ONLY_DISALLOWED_CLAUDE_TOOLS = [
34853
+ "Edit",
34854
+ "Write",
34855
+ "NotebookEdit",
34856
+ "Task",
34857
+ "SlashCommand",
34858
+ "Skill",
34859
+ "WebSearch",
34860
+ "WebFetch",
34861
+ "TaskCreate",
34862
+ "TaskGet",
34863
+ "TaskList",
34864
+ "TaskOutput",
34865
+ "TaskStop",
34866
+ "TaskUpdate",
34867
+ "Monitor",
34868
+ "DesignSync",
34869
+ "CronCreate",
34870
+ "CronDelete",
34871
+ "CronList",
34872
+ "EnterWorktree",
34873
+ "ExitWorktree",
34874
+ "RemoteTrigger",
34875
+ "ScheduleWakeup",
34876
+ "SendMessage",
34877
+ "PushNotification"
34878
+ ].join(",");
34879
+ var READ_ONLY_MAX_TURNS = 40;
34880
+ function readOnlyArgs(cmd, profileMaxTurns) {
34881
+ if (cmd.includes("claude")) {
34882
+ const turns = typeof profileMaxTurns === "number" && profileMaxTurns > 0 ? Math.floor(profileMaxTurns) : READ_ONLY_MAX_TURNS;
34883
+ return [
34884
+ `--max-turns=${turns}`,
34885
+ "--disallowedTools",
34886
+ READ_ONLY_DISALLOWED_CLAUDE_TOOLS,
34887
+ "--permission-mode",
34888
+ "plan"
34889
+ ];
34890
+ }
34891
+ if (cmd.includes("codex")) return ["--sandbox", "read-only"];
34892
+ return [];
34893
+ }
34800
34894
  function requiredArgs(cmd) {
34801
34895
  if (cmd.includes("claude")) return REQUIRED_AI_ARGS.claude;
34802
34896
  if (cmd.includes("codex")) return REQUIRED_AI_ARGS.codex;
@@ -34856,15 +34950,36 @@ function folderScopeGuard(folder, prompt) {
34856
34950
  prompt
34857
34951
  ].join("\n");
34858
34952
  }
34859
- function buildRunArgs(profile, cmd, resumeId, oneShot = false) {
34953
+ var THINKING_TOKENS = { low: 4e3, medium: 1e4, high: 31999 };
34954
+ function overrideArgs(cmd, o) {
34955
+ if (!o || !cmd.includes("codex")) return [];
34956
+ const args = [];
34957
+ if (o.thinking && o.thinking !== "off") args.push("-c", `model_reasoning_effort="${o.thinking}"`);
34958
+ if (typeof o.temperature === "number") args.push("-c", `model_temperature=${o.temperature}`);
34959
+ return args;
34960
+ }
34961
+ function overrideEnv(cmd, o) {
34962
+ if (!o || !cmd.includes("claude")) return {};
34963
+ if (!o.thinking || o.thinking === "off") return {};
34964
+ const budget = THINKING_TOKENS[o.thinking];
34965
+ return budget ? { MAX_THINKING_TOKENS: String(budget) } : {};
34966
+ }
34967
+ function buildRunArgs(profile, cmd, resumeId, oneShot = false, override, readOnly = false) {
34860
34968
  const extras = profile.args ?? [];
34861
- const model = profile.model?.trim();
34969
+ const model = override?.model?.trim() || profile.model?.trim();
34862
34970
  const modelArgs = model ? ["--model", model] : [];
34863
34971
  const resumeArgs = resumeId && cmd.includes("claude") ? ["--resume", resumeId] : [];
34864
34972
  const turns = profile.maxTurns;
34865
- const perProfileTurns = !oneShot && cmd.includes("claude") && typeof turns === "number" && turns > 0 ? [`--max-turns=${Math.floor(turns)}`] : [];
34866
- const oneShotExtra = oneShot ? oneShotArgs(cmd) : perProfileTurns;
34867
- return [...requiredArgs(cmd), ...resumeArgs, ...extras, ...modelArgs, ...oneShotExtra];
34973
+ const perProfileTurns = !oneShot && !readOnly && cmd.includes("claude") && typeof turns === "number" && turns > 0 ? [`--max-turns=${Math.floor(turns)}`] : [];
34974
+ const modeExtra = oneShot ? oneShotArgs(cmd) : readOnly ? readOnlyArgs(cmd, turns) : perProfileTurns;
34975
+ return [
34976
+ ...requiredArgs(cmd),
34977
+ ...resumeArgs,
34978
+ ...extras,
34979
+ ...modelArgs,
34980
+ ...overrideArgs(cmd, override),
34981
+ ...modeExtra
34982
+ ];
34868
34983
  }
34869
34984
  function claudeHomeDirs(config) {
34870
34985
  const dirs = profileDirs(claudeProfilesOf(config));
@@ -34903,10 +35018,10 @@ function resolveClaudeProfiles(config, workingDir) {
34903
35018
  if (idx > 0) profiles.unshift(profiles.splice(idx, 1)[0]);
34904
35019
  return profiles;
34905
35020
  }
34906
- function planAiRun(prompt, config, hint = {}, resume = /* @__PURE__ */ new Map(), oneShot = false) {
34907
- return isUnifiedConfig(config) ? planUnifiedRun(prompt, config, hint.credential ?? null, resume, oneShot) : planLegacyRun(prompt, config, hint.dir ?? null, resume, oneShot);
35021
+ function planAiRun(prompt, config, hint = {}, resume = /* @__PURE__ */ new Map(), oneShot = false, override, readOnly = false) {
35022
+ return isUnifiedConfig(config) ? planUnifiedRun(prompt, config, hint.credential ?? null, resume, oneShot, override, readOnly) : planLegacyRun(prompt, config, hint.dir ?? null, resume, oneShot, override, readOnly);
34908
35023
  }
34909
- function planUnifiedRun(prompt, config, workingCredential, resume, oneShot) {
35024
+ function planUnifiedRun(prompt, config, workingCredential, resume, oneShot, override, readOnly = false) {
34910
35025
  const baseEnv = config.aiEnv ?? {};
34911
35026
  const active = activeProvider(config);
34912
35027
  const usable = config.aiProfiles.filter(isUsableCredential);
@@ -34915,7 +35030,7 @@ function planUnifiedRun(prompt, config, workingCredential, resume, oneShot) {
34915
35030
  return {
34916
35031
  cmd: active,
34917
35032
  attempts: [
34918
- { cmd: active, label: "default", dir: null, key: null, args: buildRunArgs({ profile: "" }, active, void 0, oneShot), stdin: prompt, env: { ...baseEnv } }
35033
+ { cmd: active, label: "default", dir: null, key: null, args: buildRunArgs({ profile: "" }, active, void 0, oneShot, override, readOnly), stdin: prompt, env: { ...baseEnv, ...overrideEnv(active, override) } }
34919
35034
  ]
34920
35035
  };
34921
35036
  }
@@ -34933,20 +35048,20 @@ function planUnifiedRun(prompt, config, workingCredential, resume, oneShot) {
34933
35048
  label: cred.label?.trim() || profileDisplayLabel(dir2),
34934
35049
  dir: dir2,
34935
35050
  key,
34936
- args: buildRunArgs(cred, cmd, resume.get(key), oneShot),
35051
+ args: buildRunArgs(cred, cmd, resume.get(key), oneShot, override, readOnly),
34937
35052
  stdin: prompt,
34938
- env: envVar ? { ...baseEnv, [envVar]: dir2 } : { ...baseEnv }
35053
+ env: envVar ? { ...baseEnv, [envVar]: dir2, ...overrideEnv(cmd, override) } : { ...baseEnv, ...overrideEnv(cmd, override) }
34939
35054
  }));
34940
35055
  return { cmd: attempts[0]?.cmd ?? DEFAULT_AI_CLI, attempts };
34941
35056
  }
34942
- function planLegacyRun(prompt, config, workingDir, resume, oneShot) {
35057
+ function planLegacyRun(prompt, config, workingDir, resume, oneShot, override, readOnly = false) {
34943
35058
  const cmd = config.aiCli || DEFAULT_AI_CLI;
34944
35059
  const baseEnv = config.aiEnv ?? {};
34945
35060
  const envVar = profileEnvVar(cmd);
34946
35061
  const defaultPlan = {
34947
35062
  cmd,
34948
35063
  attempts: [
34949
- { cmd, label: "default", dir: null, key: null, args: buildRunArgs({ profile: "" }, cmd, void 0, oneShot), stdin: prompt, env: { ...baseEnv } }
35064
+ { cmd, label: "default", dir: null, key: null, args: buildRunArgs({ profile: "" }, cmd, void 0, oneShot, override, readOnly), stdin: prompt, env: { ...baseEnv, ...overrideEnv(cmd, override) } }
34950
35065
  ]
34951
35066
  };
34952
35067
  if (!envVar) return defaultPlan;
@@ -34963,9 +35078,9 @@ function planLegacyRun(prompt, config, workingDir, resume, oneShot) {
34963
35078
  label: profileDisplayLabel(dir2),
34964
35079
  dir: dir2,
34965
35080
  key,
34966
- args: buildRunArgs(profile, cmd, resume.get(key), oneShot),
35081
+ args: buildRunArgs(profile, cmd, resume.get(key), oneShot, override, readOnly),
34967
35082
  stdin: prompt,
34968
- env: { ...baseEnv, [envVar]: dir2 }
35083
+ env: { ...baseEnv, [envVar]: dir2, ...overrideEnv(cmd, override) }
34969
35084
  };
34970
35085
  });
34971
35086
  return { cmd, attempts };
@@ -35006,16 +35121,16 @@ async function fetchUsage(token) {
35006
35121
  }
35007
35122
  }
35008
35123
  function runUsageCli(dir2, aiCli2) {
35009
- return new Promise((resolve8) => {
35124
+ return new Promise((resolve9) => {
35010
35125
  let out = "";
35011
35126
  let child = null;
35012
35127
  const finish = () => {
35013
35128
  clearTimeout(timer);
35014
- resolve8(out);
35129
+ resolve9(out);
35015
35130
  };
35016
35131
  const timer = setTimeout(() => {
35017
35132
  child?.kill();
35018
- resolve8(out);
35133
+ resolve9(out);
35019
35134
  }, 3e4);
35020
35135
  timer.unref?.();
35021
35136
  try {
@@ -35537,6 +35652,80 @@ async function writeWorkerFile(root, relPath, content) {
35537
35652
  }
35538
35653
  }
35539
35654
 
35655
+ // src/core/fs-mutate.ts
35656
+ import { mkdir as mkdir3, writeFile as writeFile2, rename, rm, stat } from "fs/promises";
35657
+ import { basename as basename2, dirname as dirname4, resolve as resolve4, sep as sep4 } from "path";
35658
+ var MAX_BYTES3 = 2 * 1024 * 1024;
35659
+ function resolveInRoot2(root, rel) {
35660
+ const base = resolve4(root);
35661
+ const target = resolve4(base, rel || ".");
35662
+ return target === base || target.startsWith(base + sep4) ? target : null;
35663
+ }
35664
+ async function isDir(p) {
35665
+ try {
35666
+ return (await stat(p)).isDirectory();
35667
+ } catch {
35668
+ return false;
35669
+ }
35670
+ }
35671
+ async function exists(p) {
35672
+ try {
35673
+ await stat(p);
35674
+ return true;
35675
+ } catch {
35676
+ return false;
35677
+ }
35678
+ }
35679
+ async function mutateFs(root, req) {
35680
+ if (!root) return { ok: false, path: req.path ?? req.from ?? "", error: "no project served" };
35681
+ const escaped = (p) => ({ ok: false, path: p, error: "path escapes the project root" });
35682
+ try {
35683
+ switch (req.op) {
35684
+ case "mkdir": {
35685
+ const target = resolveInRoot2(root, req.path ?? "");
35686
+ if (!target || target === resolve4(root)) return escaped(req.path ?? "");
35687
+ await mkdir3(target, { recursive: true });
35688
+ return { ok: true, path: target };
35689
+ }
35690
+ case "create": {
35691
+ const target = resolveInRoot2(root, req.path ?? "");
35692
+ if (!target || target === resolve4(root)) return escaped(req.path ?? "");
35693
+ if (await exists(target)) return { ok: false, path: target, error: "already exists" };
35694
+ const content = req.content ?? "";
35695
+ if (Buffer.byteLength(content, "utf8") > MAX_BYTES3) {
35696
+ return { ok: false, path: target, error: `content too large (max ${MAX_BYTES3} bytes)` };
35697
+ }
35698
+ await mkdir3(dirname4(target), { recursive: true });
35699
+ await writeFile2(target, content, "utf8");
35700
+ return { ok: true, path: target };
35701
+ }
35702
+ case "move": {
35703
+ const from = resolveInRoot2(root, req.from ?? "");
35704
+ let to = resolveInRoot2(root, req.to ?? "");
35705
+ if (!from || !to) return escaped(req.from ?? req.to ?? "");
35706
+ if (from === resolve4(root)) return { ok: false, path: from, error: "cannot move the project root" };
35707
+ if (await isDir(to)) to = resolve4(to, basename2(from));
35708
+ if (to !== resolve4(root) && !to.startsWith(resolve4(root) + sep4)) return escaped(req.to ?? "");
35709
+ if (await exists(to)) return { ok: false, path: to, error: "destination already exists" };
35710
+ await mkdir3(dirname4(to), { recursive: true });
35711
+ await rename(from, to);
35712
+ return { ok: true, path: to };
35713
+ }
35714
+ case "delete": {
35715
+ const target = resolveInRoot2(root, req.path ?? "");
35716
+ if (!target) return escaped(req.path ?? "");
35717
+ if (target === resolve4(root)) return { ok: false, path: target, error: "cannot delete the project root" };
35718
+ await rm(target, { recursive: true, force: true });
35719
+ return { ok: true, path: target };
35720
+ }
35721
+ default:
35722
+ return { ok: false, path: "", error: "unknown op" };
35723
+ }
35724
+ } catch (err) {
35725
+ return { ok: false, path: req.path ?? req.from ?? "", error: err instanceof Error ? err.message : String(err) };
35726
+ }
35727
+ }
35728
+
35540
35729
  // src/core/support-answer.ts
35541
35730
  import { spawn as spawn5 } from "child_process";
35542
35731
  import { execFile as execFile2 } from "child_process";
@@ -35661,7 +35850,7 @@ function parseModeratedAnswer(text) {
35661
35850
  return { body: text.trim() };
35662
35851
  }
35663
35852
  function runClaudeOnce(cmd, profile, prompt, extraEnv) {
35664
- return new Promise((resolve8, reject) => {
35853
+ return new Promise((resolve9, reject) => {
35665
35854
  const isClaude = cmd.includes("claude");
35666
35855
  const args = [
35667
35856
  "-p",
@@ -35691,7 +35880,7 @@ function runClaudeOnce(cmd, profile, prompt, extraEnv) {
35691
35880
  child.on("close", (code) => {
35692
35881
  clearTimeout(timer);
35693
35882
  out += parser.flush();
35694
- resolve8({ code: code ?? -1, out, err, usage: parser.usage() });
35883
+ resolve9({ code: code ?? -1, out, err, usage: parser.usage() });
35695
35884
  });
35696
35885
  child.stdin.write(prompt);
35697
35886
  child.stdin.end();
@@ -35762,7 +35951,7 @@ Extra focus from the author: ${req.prompt}` : "";
35762
35951
  ].join("\n");
35763
35952
  }
35764
35953
  function runOnce(cmd, profile, prompt, cwd2, extraEnv) {
35765
- return new Promise((resolve8, reject) => {
35954
+ return new Promise((resolve9, reject) => {
35766
35955
  const args = ["-p", ...profile?.model ? ["--model", profile.model] : []];
35767
35956
  const env3 = {
35768
35957
  ...process.env,
@@ -35785,7 +35974,7 @@ function runOnce(cmd, profile, prompt, cwd2, extraEnv) {
35785
35974
  });
35786
35975
  child.on("close", (code) => {
35787
35976
  clearTimeout(timer);
35788
- resolve8({ code: code ?? -1, out, err });
35977
+ resolve9({ code: code ?? -1, out, err });
35789
35978
  });
35790
35979
  child.stdin.write(prompt);
35791
35980
  child.stdin.end();
@@ -35815,7 +36004,7 @@ async function runKnowledgeCompose(req, ai, physicRoot) {
35815
36004
  }
35816
36005
 
35817
36006
  // src/core/autonomous.ts
35818
- import { readFile as readFile3, writeFile as writeFile2, chmod } from "fs/promises";
36007
+ import { readFile as readFile3, writeFile as writeFile3, chmod } from "fs/promises";
35819
36008
  import { readFileSync as readFileSync13 } from "fs";
35820
36009
  import { execFile as execFile3, spawn as spawn7 } from "child_process";
35821
36010
  import { join as join14 } from "path";
@@ -35861,10 +36050,10 @@ async function crontabList() {
35861
36050
  }
35862
36051
  }
35863
36052
  async function crontabSet(content) {
35864
- return new Promise((resolve8) => {
36053
+ return new Promise((resolve9) => {
35865
36054
  const child = spawn7("crontab", ["-"], { stdio: ["pipe", "ignore", "ignore"] });
35866
- child.on("error", () => resolve8(false));
35867
- child.on("close", (code) => resolve8(code === 0));
36055
+ child.on("error", () => resolve9(false));
36056
+ child.on("close", (code) => resolve9(code === 0));
35868
36057
  child.stdin.end(content.endsWith("\n") ? content : content + "\n");
35869
36058
  });
35870
36059
  }
@@ -35940,14 +36129,14 @@ async function writeAutonomous(root, req, by) {
35940
36129
  switch (req.kind) {
35941
36130
  case "settings": {
35942
36131
  if (!parseJson(req.settings)) return { ok: false, error: "settings is not valid JSON" };
35943
- await writeFile2(join14(root, SETTINGS_REL), req.settings, "utf8");
36132
+ await writeFile3(join14(root, SETTINGS_REL), req.settings, "utf8");
35944
36133
  break;
35945
36134
  }
35946
36135
  case "approvals": {
35947
36136
  const map = parseJson(await readText(join14(root, APPROVALS_REL), "{}")) ?? {};
35948
36137
  if (req.approved) map[req.taskId] = { approved: true, by, at: (/* @__PURE__ */ new Date()).toISOString() };
35949
36138
  else delete map[req.taskId];
35950
- await writeFile2(join14(root, APPROVALS_REL), JSON.stringify(map, null, 2) + "\n", "utf8");
36139
+ await writeFile3(join14(root, APPROVALS_REL), JSON.stringify(map, null, 2) + "\n", "utf8");
35951
36140
  break;
35952
36141
  }
35953
36142
  case "userTodo": {
@@ -35957,7 +36146,7 @@ async function writeAutonomous(root, req, by) {
35957
36146
  > posted by ${by} at ${(/* @__PURE__ */ new Date()).toISOString()}
35958
36147
  ${req.content.trim()}
35959
36148
  `;
35960
- await writeFile2(join14(root, BOOK_FILES.userTodo), cur.trimEnd() + block, "utf8");
36149
+ await writeFile3(join14(root, BOOK_FILES.userTodo), cur.trimEnd() + block, "utf8");
35961
36150
  break;
35962
36151
  }
35963
36152
  case "cron": {
@@ -35973,7 +36162,7 @@ ${req.content.trim()}
35973
36162
  }
35974
36163
 
35975
36164
  // src/core/agents.ts
35976
- import { readFile as readFile4, writeFile as writeFile3, mkdir as mkdir3, readdir as readdir3, rm } from "fs/promises";
36165
+ import { readFile as readFile4, writeFile as writeFile4, mkdir as mkdir4, readdir as readdir3, rm as rm2 } from "fs/promises";
35977
36166
  import { join as join15 } from "path";
35978
36167
  var AGENTS_REL = ".claude/agents";
35979
36168
  var SKILLS_REL = ".claude/skills";
@@ -36036,14 +36225,14 @@ async function writeAgent(root, req) {
36036
36225
  if (!n) return { ok: false, error: "invalid name" };
36037
36226
  try {
36038
36227
  if (req.action === "delete") {
36039
- if (req.kind === "subagent") await rm(itemPath(root, "subagent", n), { force: true });
36040
- else await rm(join15(root, SKILLS_REL, n), { recursive: true, force: true });
36228
+ if (req.kind === "subagent") await rm2(itemPath(root, "subagent", n), { force: true });
36229
+ else await rm2(join15(root, SKILLS_REL, n), { recursive: true, force: true });
36041
36230
  return { ok: true };
36042
36231
  }
36043
36232
  if (req.content === void 0) return { ok: false, error: "content is required" };
36044
36233
  const path = itemPath(root, req.kind, n);
36045
- await mkdir3(join15(path, ".."), { recursive: true });
36046
- await writeFile3(path, req.content, "utf8");
36234
+ await mkdir4(join15(path, ".."), { recursive: true });
36235
+ await writeFile4(path, req.content, "utf8");
36047
36236
  return { ok: true };
36048
36237
  } catch (err) {
36049
36238
  return { ok: false, error: err instanceof Error ? err.message : String(err) };
@@ -36052,8 +36241,8 @@ async function writeAgent(root, req) {
36052
36241
 
36053
36242
  // src/core/packages.ts
36054
36243
  import { createHash as createHash4 } from "crypto";
36055
- import { readFile as readFile5, writeFile as writeFile4, mkdir as mkdir4, readdir as readdir4, rm as rm2, stat } from "fs/promises";
36056
- import { dirname as dirname4, join as join16, relative } from "path";
36244
+ import { readFile as readFile5, writeFile as writeFile5, mkdir as mkdir5, readdir as readdir4, rm as rm3, stat as stat2 } from "fs/promises";
36245
+ import { dirname as dirname5, join as join16, relative } from "path";
36057
36246
  var AGENTS_REL2 = ".claude/agents";
36058
36247
  var SKILLS_REL2 = ".claude/skills";
36059
36248
  var MANIFEST_REL = ".claude/.4pm-packages.json";
@@ -36117,7 +36306,7 @@ async function artifactSha256(root, kind, slug) {
36117
36306
  async function artifactExists(root, kind, slug) {
36118
36307
  const target = kind === "subagent" ? join16(root, AGENTS_REL2, `${slug}.md`) : join16(root, SKILLS_REL2, slug);
36119
36308
  try {
36120
- await stat(target);
36309
+ await stat2(target);
36121
36310
  return true;
36122
36311
  } catch {
36123
36312
  return false;
@@ -36134,34 +36323,34 @@ async function readManifest(root) {
36134
36323
  }
36135
36324
  async function writeManifest(root, manifest) {
36136
36325
  const path = join16(root, MANIFEST_REL);
36137
- await mkdir4(dirname4(path), { recursive: true });
36138
- await writeFile4(path, JSON.stringify(manifest, null, 2), "utf8");
36326
+ await mkdir5(dirname5(path), { recursive: true });
36327
+ await writeFile5(path, JSON.stringify(manifest, null, 2), "utf8");
36139
36328
  }
36140
36329
  async function writeArtifactFiles(root, kind, slug, files) {
36141
36330
  const byPath = new Map(files.map((f) => [f.path, Buffer.from(f.contentBase64, "base64")]));
36142
36331
  if (kind === "subagent") {
36143
36332
  const agent = byPath.get("agent.md");
36144
36333
  if (agent) {
36145
- await mkdir4(join16(root, AGENTS_REL2), { recursive: true });
36146
- await writeFile4(join16(root, AGENTS_REL2, `${slug}.md`), agent);
36334
+ await mkdir5(join16(root, AGENTS_REL2), { recursive: true });
36335
+ await writeFile5(join16(root, AGENTS_REL2, `${slug}.md`), agent);
36147
36336
  }
36148
36337
  const short = byPath.get("short-memory.md");
36149
36338
  if (short) {
36150
- await mkdir4(join16(root, AGENTS_REL2, "short-memory"), { recursive: true });
36151
- await writeFile4(join16(root, AGENTS_REL2, "short-memory", `${slug}.md`), short);
36339
+ await mkdir5(join16(root, AGENTS_REL2, "short-memory"), { recursive: true });
36340
+ await writeFile5(join16(root, AGENTS_REL2, "short-memory", `${slug}.md`), short);
36152
36341
  }
36153
36342
  const long = byPath.get("long-memory.md");
36154
36343
  if (long) {
36155
- await mkdir4(join16(root, AGENTS_REL2, "long-memory"), { recursive: true });
36156
- await writeFile4(join16(root, AGENTS_REL2, "long-memory", `${slug}.md`), long);
36344
+ await mkdir5(join16(root, AGENTS_REL2, "long-memory"), { recursive: true });
36345
+ await writeFile5(join16(root, AGENTS_REL2, "long-memory", `${slug}.md`), long);
36157
36346
  }
36158
36347
  } else {
36159
36348
  const base = join16(root, SKILLS_REL2, slug);
36160
36349
  for (const [rel, buf] of byPath) {
36161
36350
  if (rel.includes("..") || rel.startsWith("/")) continue;
36162
36351
  const dest = join16(base, rel);
36163
- await mkdir4(dirname4(dest), { recursive: true });
36164
- await writeFile4(dest, buf);
36352
+ await mkdir5(dirname5(dest), { recursive: true });
36353
+ await writeFile5(dest, buf);
36165
36354
  }
36166
36355
  }
36167
36356
  }
@@ -36225,11 +36414,11 @@ async function removePackage(root, slug) {
36225
36414
  const entry = manifest[n];
36226
36415
  if (!entry) return { ok: false, error: "not installed" };
36227
36416
  if (entry.kind === "subagent") {
36228
- await rm2(join16(root, AGENTS_REL2, `${n}.md`), { force: true });
36229
- await rm2(join16(root, AGENTS_REL2, "short-memory", `${n}.md`), { force: true });
36230
- await rm2(join16(root, AGENTS_REL2, "long-memory", `${n}.md`), { force: true });
36417
+ await rm3(join16(root, AGENTS_REL2, `${n}.md`), { force: true });
36418
+ await rm3(join16(root, AGENTS_REL2, "short-memory", `${n}.md`), { force: true });
36419
+ await rm3(join16(root, AGENTS_REL2, "long-memory", `${n}.md`), { force: true });
36231
36420
  } else {
36232
- await rm2(join16(root, SKILLS_REL2, n), { recursive: true, force: true });
36421
+ await rm3(join16(root, SKILLS_REL2, n), { recursive: true, force: true });
36233
36422
  }
36234
36423
  delete manifest[n];
36235
36424
  await writeManifest(root, manifest);
@@ -36257,14 +36446,14 @@ function detectContainerized() {
36257
36446
  }
36258
36447
  }
36259
36448
  function canReach(host, port) {
36260
- return new Promise((resolve8) => {
36449
+ return new Promise((resolve9) => {
36261
36450
  const socket = connect({ host, port });
36262
36451
  let done = false;
36263
36452
  const finish = (ok) => {
36264
36453
  if (done) return;
36265
36454
  done = true;
36266
36455
  socket.destroy();
36267
- resolve8(ok);
36456
+ resolve9(ok);
36268
36457
  };
36269
36458
  socket.setTimeout(PROBE_TIMEOUT_MS);
36270
36459
  socket.once("connect", () => finish(true));
@@ -36345,7 +36534,7 @@ function applyGitAuth(method) {
36345
36534
  }
36346
36535
 
36347
36536
  // src/core/secrets.ts
36348
- import { readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
36537
+ import { readFile as readFile6, writeFile as writeFile6 } from "fs/promises";
36349
36538
  import { join as join18 } from "path";
36350
36539
  var SECURITY_REL = "AI_SECURITY.md";
36351
36540
  var PLACEHOLDER_REL = "AI_PLACEHOLDER.md";
@@ -36392,14 +36581,14 @@ async function readSecrets(root) {
36392
36581
  async function writeSecrets(root, req) {
36393
36582
  try {
36394
36583
  if (req.kind === "security") {
36395
- await writeFile5(join18(root, SECURITY_REL), req.content, "utf8");
36584
+ await writeFile6(join18(root, SECURITY_REL), req.content, "utf8");
36396
36585
  } else if (req.kind === "placeholder") {
36397
- await writeFile5(join18(root, PLACEHOLDER_REL), req.content, "utf8");
36586
+ await writeFile6(join18(root, PLACEHOLDER_REL), req.content, "utf8");
36398
36587
  } else {
36399
36588
  const secrets = await readSecretsObject(root);
36400
36589
  if (req.kind === "secret") secrets[req.key] = req.value;
36401
36590
  else delete secrets[req.key];
36402
- await writeFile5(join18(root, SECRETS_REL), JSON.stringify(secrets, null, 2) + "\n", "utf8");
36591
+ await writeFile6(join18(root, SECRETS_REL), JSON.stringify(secrets, null, 2) + "\n", "utf8");
36403
36592
  }
36404
36593
  return { ok: true };
36405
36594
  } catch (err) {
@@ -36408,8 +36597,8 @@ async function writeSecrets(root, req) {
36408
36597
  }
36409
36598
 
36410
36599
  // src/core/agent-tools.ts
36411
- import { readFile as readFile7, writeFile as writeFile6, mkdir as mkdir5 } from "fs/promises";
36412
- import { dirname as dirname5, join as join19 } from "path";
36600
+ import { readFile as readFile7, writeFile as writeFile7, mkdir as mkdir6 } from "fs/promises";
36601
+ import { dirname as dirname6, join as join19 } from "path";
36413
36602
  var SHARED_REL = ".claude/settings.json";
36414
36603
  var LOCAL_REL = ".claude/settings.local.json";
36415
36604
  var SECRETS_DENY = "Read(./project.secrets.json)";
@@ -36442,8 +36631,8 @@ async function writeAgentTools(root, scope, permissions) {
36442
36631
  const next = normalizePermissions(permissions);
36443
36632
  if (scope === "shared" && !next.deny.includes(SECRETS_DENY)) next.deny = [...next.deny, SECRETS_DENY];
36444
36633
  obj.permissions = next;
36445
- await mkdir5(dirname5(path), { recursive: true });
36446
- await writeFile6(path, JSON.stringify(obj, null, 2) + "\n", "utf8");
36634
+ await mkdir6(dirname6(path), { recursive: true });
36635
+ await writeFile7(path, JSON.stringify(obj, null, 2) + "\n", "utf8");
36447
36636
  return { ok: true };
36448
36637
  } catch (err) {
36449
36638
  return { ok: false, error: err instanceof Error ? err.message : String(err) };
@@ -36452,7 +36641,7 @@ async function writeAgentTools(root, scope, permissions) {
36452
36641
 
36453
36642
  // src/core/graph.ts
36454
36643
  import { readFile as readFile8, readdir as readdir5 } from "fs/promises";
36455
- import { join as join20, relative as relative2, dirname as dirname6, resolve as resolve4, extname, basename as basename2 } from "path";
36644
+ import { join as join20, relative as relative2, dirname as dirname7, resolve as resolve5, extname, basename as basename3 } from "path";
36456
36645
  var MAX_FILES = 2e3;
36457
36646
  var MAX_NODES = 3e3;
36458
36647
  var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", ".next", "out", "coverage", ".turbo"]);
@@ -36492,7 +36681,7 @@ async function buildDocs(root) {
36492
36681
  const ids = new Set(files.map((f) => relative2(root, f).split("\\").join("/")));
36493
36682
  const nodes = files.map((f) => {
36494
36683
  const rel = relative2(root, f).split("\\").join("/");
36495
- return { id: rel, label: basename2(rel), kind: "doc", file: rel };
36684
+ return { id: rel, label: basename3(rel), kind: "doc", file: rel };
36496
36685
  });
36497
36686
  const edges = [];
36498
36687
  const seen = /* @__PURE__ */ new Set();
@@ -36507,7 +36696,7 @@ async function buildDocs(root) {
36507
36696
  for (const m of text.matchAll(/\[[^\]]*\]\(([^)]+)\)/g)) {
36508
36697
  const href = (m[1] ?? "").split("#")[0].trim();
36509
36698
  if (!href || !href.endsWith(".md") || href.startsWith("http")) continue;
36510
- const target = relative2(root, resolve4(dirname6(f), href)).split("\\").join("/");
36699
+ const target = relative2(root, resolve5(dirname7(f), href)).split("\\").join("/");
36511
36700
  if (ids.has(target) && target !== rel) {
36512
36701
  const key = `${rel}->${target}`;
36513
36702
  if (!seen.has(key)) {
@@ -36591,7 +36780,7 @@ async function buildGraph(root, mode) {
36591
36780
  }
36592
36781
 
36593
36782
  // src/core/rag.ts
36594
- import { readFile as readFile9, writeFile as writeFile7, statfs as statfs2, mkdir as mkdir6 } from "fs/promises";
36783
+ import { readFile as readFile9, writeFile as writeFile8, statfs as statfs2, mkdir as mkdir7 } from "fs/promises";
36595
36784
  import { existsSync as existsSync11 } from "fs";
36596
36785
  import { execFile as execFile4, spawn as spawn8 } from "child_process";
36597
36786
  import { totalmem as totalmem2, cpus as cpus2 } from "os";
@@ -36765,8 +36954,8 @@ if __name__ == "__main__":
36765
36954
  elif cmd == "query": query(sys.argv[2], int(sys.argv[3]) if len(sys.argv) > 3 else 8)
36766
36955
  `;
36767
36956
  async function ensureEngine(root) {
36768
- await mkdir6(join21(root, RAG_REL), { recursive: true }).catch(() => void 0);
36769
- await writeFile7(join21(root, RAG_REL, "rag_engine.py"), RAG_ENGINE_PY, "utf8");
36957
+ await mkdir7(join21(root, RAG_REL), { recursive: true }).catch(() => void 0);
36958
+ await writeFile8(join21(root, RAG_REL, "rag_engine.py"), RAG_ENGINE_PY, "utf8");
36770
36959
  }
36771
36960
  async function ragReindex(root) {
36772
36961
  const py = await detectPython();
@@ -36814,7 +37003,7 @@ async function ragInstall(root, model) {
36814
37003
  if (!py.found) return { ok: false, started: false, error: "python3 not found on the worker" };
36815
37004
  if (existsSync11(join21(root, RAG_REL, ".installing"))) return { ok: true, started: true };
36816
37005
  try {
36817
- await mkdir6(join21(root, RAG_REL), { recursive: true });
37006
+ await mkdir7(join21(root, RAG_REL), { recursive: true });
36818
37007
  } catch {
36819
37008
  }
36820
37009
  const script = `
@@ -36843,13 +37032,13 @@ rm -f "${RAG_REL}/.installing"
36843
37032
  // src/core/git-diff.ts
36844
37033
  import { readFile as readFile10 } from "fs/promises";
36845
37034
  import { execFile as execFile5 } from "child_process";
36846
- import { basename as basename3, dirname as dirname7, resolve as resolve5 } from "path";
37035
+ import { basename as basename4, dirname as dirname8, resolve as resolve6 } from "path";
36847
37036
  import { promisify as promisify5 } from "util";
36848
37037
  var run5 = promisify5(execFile5);
36849
37038
  async function gitDiff(path) {
36850
- const target = resolve5(path);
36851
- const dir2 = dirname7(target);
36852
- const base = basename3(target);
37039
+ const target = resolve6(path);
37040
+ const dir2 = dirname8(target);
37041
+ const base = basename4(target);
36853
37042
  let newContent = "";
36854
37043
  try {
36855
37044
  newContent = await readFile10(target, "utf8");
@@ -36901,7 +37090,7 @@ ${stderr}`;
36901
37090
 
36902
37091
  // src/core/git-ssh-key.ts
36903
37092
  import { execFile as execFile7 } from "child_process";
36904
- import { readFile as readFile11, rm as rm3, mkdir as mkdir7 } from "fs/promises";
37093
+ import { readFile as readFile11, rm as rm4, mkdir as mkdir8 } from "fs/promises";
36905
37094
  import { join as join22 } from "path";
36906
37095
  import { promisify as promisify7 } from "util";
36907
37096
  var run7 = promisify7(execFile7);
@@ -36934,9 +37123,9 @@ async function configureGit(key) {
36934
37123
  }
36935
37124
  async function generate(profileDir2) {
36936
37125
  const { dir: dir2, key, pub } = keyPaths(profileDir2);
36937
- await mkdir7(dir2, { recursive: true });
36938
- await rm3(key, { force: true });
36939
- await rm3(pub, { force: true });
37126
+ await mkdir8(dir2, { recursive: true });
37127
+ await rm4(key, { force: true });
37128
+ await rm4(pub, { force: true });
36940
37129
  await run7("ssh-keygen", ["-t", "ed25519", "-f", key, "-N", "", "-C", "4pm-deploy-key"], {
36941
37130
  timeout: 15e3
36942
37131
  });
@@ -36945,8 +37134,8 @@ async function generate(profileDir2) {
36945
37134
  }
36946
37135
  async function remove(profileDir2) {
36947
37136
  const { key, pub } = keyPaths(profileDir2);
36948
- await rm3(key, { force: true });
36949
- await rm3(pub, { force: true });
37137
+ await rm4(key, { force: true });
37138
+ await rm4(pub, { force: true });
36950
37139
  await run7("git", ["config", "--global", "--unset", "core.sshCommand"], { timeout: 5e3 }).catch(
36951
37140
  () => void 0
36952
37141
  );
@@ -36970,16 +37159,16 @@ async function manageSshKey(op, profileDir2) {
36970
37159
  // src/core/git-history.ts
36971
37160
  import { readdir as readdir6 } from "fs/promises";
36972
37161
  import { execFile as execFile8 } from "child_process";
36973
- import { resolve as resolve6, sep as sep4 } from "path";
37162
+ import { resolve as resolve7, sep as sep5 } from "path";
36974
37163
  import { promisify as promisify8 } from "util";
36975
37164
  var run8 = promisify8(execFile8);
36976
37165
  var FS = "";
36977
37166
  var RS = "";
36978
37167
  function resolveRepo(root, repo) {
36979
37168
  if (!root) return null;
36980
- const base = resolve6(root);
36981
- const requested = resolve6(base, repo && repo.trim() ? repo : ".");
36982
- return requested === base || requested.startsWith(base + sep4) ? requested : base;
37169
+ const base = resolve7(root);
37170
+ const requested = resolve7(base, repo && repo.trim() ? repo : ".");
37171
+ return requested === base || requested.startsWith(base + sep5) ? requested : base;
36983
37172
  }
36984
37173
  async function git(cwd2, args) {
36985
37174
  try {
@@ -36995,13 +37184,13 @@ async function git(cwd2, args) {
36995
37184
  }
36996
37185
  async function gitRepos(root) {
36997
37186
  if (!root) return { repos: [] };
36998
- const base = resolve6(root);
37187
+ const base = resolve7(root);
36999
37188
  const found = /* @__PURE__ */ new Set();
37000
37189
  const repos = [];
37001
37190
  const add = async (dir2) => {
37002
37191
  const inside = await git(dir2, ["rev-parse", "--show-toplevel"]);
37003
37192
  const top = inside.trim();
37004
- if (!top || found.has(top) || !(top === base || top.startsWith(base + sep4))) return;
37193
+ if (!top || found.has(top) || !(top === base || top.startsWith(base + sep5))) return;
37005
37194
  found.add(top);
37006
37195
  const subdir = top === base ? "" : top.slice(base.length + 1);
37007
37196
  const remote = (await git(top, ["remote", "get-url", "origin"])).trim();
@@ -37012,13 +37201,13 @@ async function gitRepos(root) {
37012
37201
  const lvl1 = await readdir6(base, { withFileTypes: true });
37013
37202
  for (const d of lvl1) {
37014
37203
  if (!d.isDirectory() || d.name === ".git" || d.name === "node_modules") continue;
37015
- const p1 = resolve6(base, d.name);
37204
+ const p1 = resolve7(base, d.name);
37016
37205
  await add(p1);
37017
37206
  try {
37018
37207
  const lvl2 = await readdir6(p1, { withFileTypes: true });
37019
37208
  for (const d2 of lvl2) {
37020
37209
  if (!d2.isDirectory() || d2.name === ".git" || d2.name === "node_modules") continue;
37021
- await add(resolve6(p1, d2.name));
37210
+ await add(resolve7(p1, d2.name));
37022
37211
  }
37023
37212
  } catch {
37024
37213
  }
@@ -37097,10 +37286,10 @@ async function setCommitAuthor(cwd2, machineUsername) {
37097
37286
  }
37098
37287
 
37099
37288
  // src/core/scaffold.ts
37100
- import { cp, mkdir as mkdir8, writeFile as writeFile8 } from "fs/promises";
37289
+ import { cp, mkdir as mkdir9, writeFile as writeFile9 } from "fs/promises";
37101
37290
  import { existsSync as existsSync12 } from "fs";
37102
37291
  import { execFile as execFile10 } from "child_process";
37103
- import { dirname as dirname8, join as join23, resolve as resolve7 } from "path";
37292
+ import { dirname as dirname9, join as join23, resolve as resolve8 } from "path";
37104
37293
  import { fileURLToPath as fileURLToPath3 } from "url";
37105
37294
  import { promisify as promisify10 } from "util";
37106
37295
  var run10 = promisify10(execFile10);
@@ -37135,31 +37324,35 @@ async function provisionRepos(target, repos, emit, opts = {}) {
37135
37324
  await run10("git", ["clone", repo.url, dir2], { timeout: 12e4 });
37136
37325
  } else {
37137
37326
  emit("git", `Initializing sub-repo ${subDirName(repo)}\u2026`);
37138
- await mkdir8(dir2, { recursive: true });
37327
+ await mkdir9(dir2, { recursive: true });
37139
37328
  await run10("git", ["init"], { cwd: dir2, timeout: 2e4 });
37140
37329
  }
37141
37330
  }
37142
37331
  }
37143
37332
  function sampleDir() {
37144
37333
  if (process.env.SCAFFOLD_SAMPLE_DIR) return process.env.SCAFFOLD_SAMPLE_DIR;
37145
- const here = dirname8(fileURLToPath3(import.meta.url));
37146
- const bundled = resolve7(here, "project-sample");
37147
- for (const candidate of [bundled, resolve7(here, "../project-sample"), resolve7(here, "../../project-sample")]) {
37334
+ const here = dirname9(fileURLToPath3(import.meta.url));
37335
+ const bundled = resolve8(here, "project-sample");
37336
+ for (const candidate of [bundled, resolve8(here, "../project-sample"), resolve8(here, "../../project-sample")]) {
37148
37337
  if (existsSync12(candidate)) return candidate;
37149
37338
  }
37150
37339
  return bundled;
37151
37340
  }
37152
37341
  async function scaffoldProject(payload, profileDir2, onProgress) {
37153
- const emit = (step, message) => onProgress?.({ projectId: payload.projectId, step, message });
37342
+ let lastStep = "start";
37343
+ const emit = (step, message) => {
37344
+ lastStep = step;
37345
+ onProgress?.({ projectId: payload.projectId, step, message });
37346
+ };
37154
37347
  try {
37155
- const root = process.env.SCAFFOLD_ROOT ? resolve7(process.env.SCAFFOLD_ROOT) : resolve7(profileDir2);
37348
+ const root = process.env.SCAFFOLD_ROOT ? resolve8(process.env.SCAFFOLD_ROOT) : resolve8(profileDir2);
37156
37349
  const target = join23(root, payload.projectName);
37157
- await mkdir8(target, { recursive: true });
37350
+ await mkdir9(target, { recursive: true });
37158
37351
  emit("copy", "Copying the sample template\u2026");
37159
37352
  await cp(sampleDir(), target, { recursive: true, force: false, errorOnExist: false });
37160
37353
  if (payload.spec) {
37161
37354
  emit("spec", "Writing project.spec.json\u2026");
37162
- await writeFile8(
37355
+ await writeFile9(
37163
37356
  join23(target, "project.spec.json"),
37164
37357
  JSON.stringify(payload.spec, null, 2),
37165
37358
  "utf8"
@@ -37168,17 +37361,25 @@ async function scaffoldProject(payload, profileDir2, onProgress) {
37168
37361
  const repos = reposOf(payload.spec);
37169
37362
  if (repos.length > 0) await provisionRepos(target, repos, emit);
37170
37363
  if (payload.spec) await aiInit(target, payload.spec, emit);
37364
+ emit("version", "Writing .4pm/.4pm.json\u2026");
37365
+ await writeTemplateMarker(target);
37171
37366
  onProgress?.({ projectId: payload.projectId, step: "done", message: "Scaffold complete.", done: true });
37172
37367
  return { ok: true, path: target };
37173
37368
  } catch (err) {
37174
- return { ok: false, error: err instanceof Error ? err.message : String(err) };
37369
+ return { ok: false, error: err instanceof Error ? err.message : String(err), step: lastStep };
37175
37370
  }
37176
37371
  }
37372
+ async function writeTemplateMarker(target) {
37373
+ const dir2 = join23(target, ".4pm");
37374
+ await mkdir9(dir2, { recursive: true });
37375
+ const marker = { templateVersion: PROJECT_TEMPLATE.version, scaffoldedAt: (/* @__PURE__ */ new Date()).toISOString() };
37376
+ await writeFile9(join23(dir2, ".4pm.json"), JSON.stringify(marker, null, 2) + "\n", "utf8");
37377
+ }
37177
37378
  async function aiInit(target, spec, emit) {
37178
37379
  emit("ai-init", "AI init: subagents, README, CLAUDE.md\u2026");
37179
37380
  const subagents = Array.isArray(spec.subagents) ? spec.subagents : [];
37180
37381
  if (subagents.length > 0) {
37181
- await mkdir8(join23(target, ".claude", "agents"), { recursive: true });
37382
+ await mkdir9(join23(target, ".claude", "agents"), { recursive: true });
37182
37383
  for (const sa of subagents) {
37183
37384
  const name = (sa.name || "").trim().replace(/[^\w.-]+/g, "-").replace(/^-+|-+$/g, "");
37184
37385
  if (!name) continue;
@@ -37188,7 +37389,7 @@ name: ${name}
37188
37389
 
37189
37390
  ${(sa.description || "").trim()}
37190
37391
  `;
37191
- await writeFile8(join23(target, ".claude", "agents", `${name}.md`), body, "utf8");
37392
+ await writeFile9(join23(target, ".claude", "agents", `${name}.md`), body, "utf8");
37192
37393
  }
37193
37394
  }
37194
37395
  const specJson = JSON.stringify(spec);
@@ -37206,22 +37407,26 @@ ${specJson}`
37206
37407
  async function generateFile(path, prompt) {
37207
37408
  try {
37208
37409
  const text = await aiGenerate(prompt);
37209
- if (text.trim()) await writeFile8(path, text.trim() + "\n", "utf8");
37410
+ if (text.trim()) await writeFile9(path, text.trim() + "\n", "utf8");
37210
37411
  } catch {
37211
37412
  }
37212
37413
  }
37213
37414
  async function addProject(payload, profileDir2, onProgress) {
37214
- const emit = (step, message) => onProgress?.({ projectId: payload.projectId, step, message });
37415
+ let lastStep = "start";
37416
+ const emit = (step, message) => {
37417
+ lastStep = step;
37418
+ onProgress?.({ projectId: payload.projectId, step, message });
37419
+ };
37215
37420
  try {
37216
- const root = process.env.SCAFFOLD_ROOT ? resolve7(process.env.SCAFFOLD_ROOT) : resolve7(profileDir2);
37421
+ const root = process.env.SCAFFOLD_ROOT ? resolve8(process.env.SCAFFOLD_ROOT) : resolve8(profileDir2);
37217
37422
  const target = join23(root, payload.projectName);
37218
- await mkdir8(target, { recursive: true });
37423
+ await mkdir9(target, { recursive: true });
37219
37424
  const repos = payload.repos ?? [];
37220
37425
  if (repos.length > 0) await provisionRepos(target, repos, emit, { clonePrimary: true });
37221
37426
  onProgress?.({ projectId: payload.projectId, step: "done", message: "Project added.", done: true });
37222
37427
  return { ok: true, path: target };
37223
37428
  } catch (err) {
37224
- return { ok: false, error: err instanceof Error ? err.message : String(err) };
37429
+ return { ok: false, error: err instanceof Error ? err.message : String(err), step: lastStep };
37225
37430
  }
37226
37431
  }
37227
37432
 
@@ -37639,7 +37844,7 @@ function buildPrompt3(input) {
37639
37844
  ].join("\n");
37640
37845
  }
37641
37846
  function runOnce2(cmd, profile, prompt, cwd2, extraEnv) {
37642
- return new Promise((resolve8, reject) => {
37847
+ return new Promise((resolve9, reject) => {
37643
37848
  const args = ["-p", ...profile?.model ? ["--model", profile.model] : []];
37644
37849
  const env3 = {
37645
37850
  ...process.env,
@@ -37662,7 +37867,7 @@ function runOnce2(cmd, profile, prompt, cwd2, extraEnv) {
37662
37867
  });
37663
37868
  child.on("close", (code) => {
37664
37869
  clearTimeout(timer);
37665
- resolve8({ code: code ?? -1, out, err });
37870
+ resolve9({ code: code ?? -1, out, err });
37666
37871
  });
37667
37872
  child.stdin.write(prompt);
37668
37873
  child.stdin.end();
@@ -37937,14 +38142,14 @@ var WsClient = class {
37937
38142
  */
37938
38143
  awaitConnected(timeoutMs) {
37939
38144
  if (this.sessionKey && this.bus.status === "connected") return Promise.resolve(true);
37940
- return new Promise((resolve8) => {
38145
+ return new Promise((resolve9) => {
37941
38146
  const waiter = () => {
37942
38147
  clearTimeout(timer);
37943
- resolve8(true);
38148
+ resolve9(true);
37944
38149
  };
37945
38150
  const timer = setTimeout(() => {
37946
38151
  this.connectWaiters = this.connectWaiters.filter((w) => w !== waiter);
37947
- resolve8(false);
38152
+ resolve9(false);
37948
38153
  }, timeoutMs);
37949
38154
  this.connectWaiters.push(waiter);
37950
38155
  });
@@ -37971,16 +38176,16 @@ var WsClient = class {
37971
38176
  this.forceReconnect = false;
37972
38177
  return Promise.resolve();
37973
38178
  }
37974
- return new Promise((resolve8) => {
38179
+ return new Promise((resolve9) => {
37975
38180
  const timer = setTimeout(() => {
37976
38181
  this.wakeReconnect = null;
37977
- resolve8();
38182
+ resolve9();
37978
38183
  }, ms);
37979
38184
  this.wakeReconnect = () => {
37980
38185
  clearTimeout(timer);
37981
38186
  this.wakeReconnect = null;
37982
38187
  this.forceReconnect = false;
37983
- resolve8();
38188
+ resolve9();
37984
38189
  };
37985
38190
  });
37986
38191
  }
@@ -38034,7 +38239,7 @@ var WsClient = class {
38034
38239
  * One WS session: token → connect → handshake → handle messages until close.
38035
38240
  */
38036
38241
  connectOnce() {
38037
- return new Promise((resolve8, reject) => {
38242
+ return new Promise((resolve9, reject) => {
38038
38243
  void (async () => {
38039
38244
  this.sessionEstablished = false;
38040
38245
  this.bus.setStatus("connecting");
@@ -38128,7 +38333,7 @@ var WsClient = class {
38128
38333
  if (code === CLOSE_DRAINING) {
38129
38334
  this.bus.log("Server draining \u2014 will reconnect (backoff + jitter).");
38130
38335
  }
38131
- resolve8();
38336
+ resolve9();
38132
38337
  });
38133
38338
  socket.on("error", (err) => {
38134
38339
  this.clearHeartbeat();
@@ -38285,7 +38490,9 @@ var WsClient = class {
38285
38490
  dispatch.commandId,
38286
38491
  "server",
38287
38492
  dispatch.aiOneShot ?? false,
38288
- dispatch.images
38493
+ dispatch.images,
38494
+ dispatch.aiConfig,
38495
+ dispatch.aiReadOnly ?? false
38289
38496
  );
38290
38497
  }
38291
38498
  break;
@@ -38341,6 +38548,13 @@ var WsClient = class {
38341
38548
  );
38342
38549
  break;
38343
38550
  }
38551
+ case WsChannels.FS_MUTATE: {
38552
+ const req = payload;
38553
+ void mutateFs(this.physicRoot, req).then(
38554
+ (reply) => this.send(WsChannels.FS_MUTATE, reply, message.id)
38555
+ );
38556
+ break;
38557
+ }
38344
38558
  case WsChannels.SUPPORT_ANSWER: {
38345
38559
  const req = payload;
38346
38560
  const supportConfig = readProfileConfig(this.context.profileDir);
@@ -38775,7 +38989,7 @@ var WsClient = class {
38775
38989
  * exactly like typing the prompt in the cli (tries profiles, meters real tokens) instead
38776
38990
  * of spawning the text as a raw command. Streams output to the transcript AND the server.
38777
38991
  */
38778
- async runAiPrompt(prompt, commandId, origin, oneShot = false, images) {
38992
+ async runAiPrompt(prompt, commandId, origin, oneShot = false, images, aiConfig, readOnly = false) {
38779
38993
  const config = readProfileConfig(this.context.profileDir);
38780
38994
  const projectTimeoutSec = config.projectAiRunTimeoutSec ?? 0;
38781
38995
  const machineTimeoutSec = config.aiRunTimeoutSec ?? 0;
@@ -38847,7 +39061,7 @@ var WsClient = class {
38847
39061
  const guardedPrompt = this.restrictToFolder && this.physicRoot ? folderScopeGuard(this.physicRoot, aiBodyPrompt) : aiBodyPrompt;
38848
39062
  const hint = unified ? { credential: startCred ?? workingCred } : { dir: startDir ?? workingDir };
38849
39063
  const memCfg = resolveMemoryConfig(config);
38850
- const firstAttempt = planAiRun(guardedPrompt, config, hint).attempts[0];
39064
+ const firstAttempt = planAiRun(guardedPrompt, config, hint, /* @__PURE__ */ new Map(), oneShot, aiConfig, readOnly).attempts[0];
38851
39065
  const resumeId = memCfg.enabled && firstAttempt?.key && firstAttempt.cmd === "claude" ? this.sessionIdByKey.get(firstAttempt.key) : void 0;
38852
39066
  let effectivePrompt = guardedPrompt;
38853
39067
  let resume = /* @__PURE__ */ new Map();
@@ -38859,7 +39073,7 @@ ${this.aiMemory}
38859
39073
 
38860
39074
  ${guardedPrompt}`;
38861
39075
  }
38862
- const plan = planAiRun(effectivePrompt, config, hint, resume, oneShot);
39076
+ const plan = planAiRun(effectivePrompt, config, hint, resume, oneShot, aiConfig, readOnly);
38863
39077
  const markerArgs = plan.attempts[0]?.args ?? [];
38864
39078
  const startStamp = formatTimestampInZone(/* @__PURE__ */ new Date(), this.orgTimezone);
38865
39079
  this.bus.push({ source: origin, kind: "aireq", text: `${startStamp} ${plan.cmd} \u2039 ${prompt}` });
@@ -39068,7 +39282,7 @@ ${guardedPrompt}`;
39068
39282
  const info = {
39069
39283
  version: CLI_VERSION,
39070
39284
  scope: this.bus.scope ?? "project",
39071
- profile: basename4(this.context.profileDir),
39285
+ profile: basename5(this.context.profileDir),
39072
39286
  profileDir: this.context.profileDir,
39073
39287
  serverUrl: this.context.credential.serverUrl,
39074
39288
  physicPath: this.physicRoot ?? config.physicPath ?? null,
@@ -39398,7 +39612,7 @@ ${guardedPrompt}`;
39398
39612
  * Used for quota.check before spawning an AI cli (ADR-0020).
39399
39613
  */
39400
39614
  request(channel, data) {
39401
- return new Promise((resolve8, reject) => {
39615
+ return new Promise((resolve9, reject) => {
39402
39616
  if (!this.socket || !this.sessionKey) {
39403
39617
  reject(new Error("Not connected to the server."));
39404
39618
  return;
@@ -39418,7 +39632,7 @@ ${guardedPrompt}`;
39418
39632
  }, 15e3);
39419
39633
  timer.unref?.();
39420
39634
  this.pending.set(envelope.id, {
39421
- resolve: (value) => resolve8(value),
39635
+ resolve: (value) => resolve9(value),
39422
39636
  timer
39423
39637
  });
39424
39638
  this.socket.send(JSON.stringify(envelope));
@@ -39544,7 +39758,7 @@ ${guardedPrompt}`;
39544
39758
  const working = getWorkingProfile(this.context.profileDir, aiCli2);
39545
39759
  const configured = claudeHomeDirs(config);
39546
39760
  const dirs = working ? [working, ...configured.filter((d) => d !== working)] : configured;
39547
- const profile = working ? basename4(working) : dirs[0] ? basename4(dirs[0]) : "default";
39761
+ const profile = working ? basename5(working) : dirs[0] ? basename5(dirs[0]) : "default";
39548
39762
  const api = await checkClaudeUsage(dirs, aiCli2);
39549
39763
  const snapshot = api ?? {
39550
39764
  plan: "?",
@@ -42003,7 +42217,7 @@ var src_default = Yoga;
42003
42217
 
42004
42218
  // ../../node_modules/.pnpm/ink@5.2.1_@types+react@18.3.31_react@18.3.1/node_modules/ink/build/reconciler.js
42005
42219
  var import_react_reconciler = __toESM(require_react_reconciler(), 1);
42006
- var import_constants7 = __toESM(require_constants2(), 1);
42220
+ var import_constants8 = __toESM(require_constants2(), 1);
42007
42221
  import process3 from "process";
42008
42222
 
42009
42223
  // ../../node_modules/.pnpm/ansi-regex@6.2.2/node_modules/ansi-regex/index.js
@@ -43245,7 +43459,7 @@ var reconciler_default = (0, import_react_reconciler.default)({
43245
43459
  scheduleTimeout: setTimeout,
43246
43460
  cancelTimeout: clearTimeout,
43247
43461
  noTimeout: -1,
43248
- getCurrentEventPriority: () => import_constants7.DefaultEventPriority,
43462
+ getCurrentEventPriority: () => import_constants8.DefaultEventPriority,
43249
43463
  beforeActiveInstanceBlur() {
43250
43464
  },
43251
43465
  afterActiveInstanceBlur() {
@@ -45319,8 +45533,8 @@ var Ink = class {
45319
45533
  }
45320
45534
  }
45321
45535
  async waitUntilExit() {
45322
- this.exitPromise ||= new Promise((resolve8, reject) => {
45323
- this.resolveExitPromise = resolve8;
45536
+ this.exitPromise ||= new Promise((resolve9, reject) => {
45537
+ this.resolveExitPromise = resolve9;
45324
45538
  this.rejectExitPromise = reject;
45325
45539
  });
45326
45540
  return this.exitPromise;
@@ -46381,7 +46595,7 @@ async function runStart(profileDir2, profileName) {
46381
46595
  logger.error("ws.run.crash", { message: e.message, stack: e.stack });
46382
46596
  if (client.isStopped) return;
46383
46597
  bus.log(`Recovered from an internal error \u2014 reconnecting: ${e.message}`, "error");
46384
- await new Promise((resolve8) => setTimeout(resolve8, 1e3));
46598
+ await new Promise((resolve9) => setTimeout(resolve9, 1e3));
46385
46599
  }
46386
46600
  }
46387
46601
  };
@@ -46427,7 +46641,7 @@ import { join as join31 } from "path";
46427
46641
  // src/core/control-client.ts
46428
46642
  import { connect as connect2 } from "net";
46429
46643
  function connectControl(socketPath, bus) {
46430
- return new Promise((resolve8, reject) => {
46644
+ return new Promise((resolve9, reject) => {
46431
46645
  const socket = connect2(socketPath);
46432
46646
  socket.setEncoding("utf8");
46433
46647
  let ready = false;
@@ -46474,7 +46688,7 @@ function connectControl(socketPath, bus) {
46474
46688
  bus.setTokens(frame.tokens);
46475
46689
  for (const entry of frame.transcript) bus.pushEntry(entry);
46476
46690
  ready = true;
46477
- resolve8({ info: frame.info, close });
46691
+ resolve9({ info: frame.info, close });
46478
46692
  break;
46479
46693
  case "transcript":
46480
46694
  bus.pushEntry(frame.entry);
@@ -46555,18 +46769,18 @@ async function runAttach(profileDir2, profileName) {
46555
46769
  // src/commands/ai-login.ts
46556
46770
  import { spawn as spawn11 } from "child_process";
46557
46771
  import { mkdirSync as mkdirSync7 } from "fs";
46558
- import { basename as basename5 } from "path";
46772
+ import { basename as basename6 } from "path";
46559
46773
  function runProviderLogin(cmd, envVar, dir2) {
46560
- return new Promise((resolve8) => {
46774
+ return new Promise((resolve9) => {
46561
46775
  const child = spawn11(cmd, [], {
46562
46776
  stdio: "inherit",
46563
46777
  env: { ...process.env, [envVar]: dir2 }
46564
46778
  });
46565
46779
  child.on("error", (err) => {
46566
46780
  console.error(` \u2716 Could not launch \`${cmd}\` \u2014 is it installed? (${err.message})`);
46567
- resolve8(1);
46781
+ resolve9(1);
46568
46782
  });
46569
- child.on("exit", (code) => resolve8(code ?? 0));
46783
+ child.on("exit", (code) => resolve9(code ?? 0));
46570
46784
  });
46571
46785
  }
46572
46786
  async function runAiLogin(profileDir2, profileName, aiFilter) {
@@ -46579,7 +46793,7 @@ async function runAiLogin(profileDir2, profileName, aiFilter) {
46579
46793
  return;
46580
46794
  }
46581
46795
  const selected = aiFilter ? credentials.filter(
46582
- (c, i) => c.profile === aiFilter || basename5(resolveHomePath(c.profile)) === aiFilter || String(i + 1) === aiFilter
46796
+ (c, i) => c.profile === aiFilter || basename6(resolveHomePath(c.profile)) === aiFilter || String(i + 1) === aiFilter
46583
46797
  ) : credentials;
46584
46798
  if (selected.length === 0) {
46585
46799
  console.log(`No AI profile matches --ai "${aiFilter}". Available: ${credentials.map((c) => c.profile).join(", ")}`);
@@ -46712,10 +46926,10 @@ function Picker({
46712
46926
  ] });
46713
46927
  }
46714
46928
  function selectFromList(items, title) {
46715
- return new Promise((resolve8) => {
46929
+ return new Promise((resolve9) => {
46716
46930
  let chosen = null;
46717
46931
  const app = render_default(/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Picker, { items, title, onDone: (v) => chosen = v }));
46718
- void app.waitUntilExit().then(() => resolve8(chosen));
46932
+ void app.waitUntilExit().then(() => resolve9(chosen));
46719
46933
  });
46720
46934
  }
46721
46935