@4pm/cli 1.5.17 → 1.5.22

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,13 @@ 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
+ * Per-run AI execution overrides (ADR-0261): model/thinking/temperature chosen in the web
33018
+ * "AI settings" modal (per-user localStorage), layered over the profile default by the cli.
33019
+ * Only meaningful with `ai:true`.
33020
+ */
33021
+ aiConfig: aiRunConfigSchema.optional()
32990
33022
  }).superRefine((v, ctx) => {
32991
33023
  if (v.machineLinkId == null === (v.pick == null)) {
32992
33024
  ctx.addIssue({
@@ -33129,6 +33161,17 @@ var fsWriteRequestSchema = external_exports.object({
33129
33161
  /** Full new UTF-8 content (replaces the file wholesale). */
33130
33162
  content: external_exports.string().max(FILE_WRITE_MAX_BYTES)
33131
33163
  });
33164
+ var fsMutateRequestSchema = external_exports.object({
33165
+ op: external_exports.enum(["mkdir", "create", "move", "delete"]),
33166
+ path: external_exports.string().max(1024).optional(),
33167
+ content: external_exports.string().max(FILE_WRITE_MAX_BYTES).optional(),
33168
+ from: external_exports.string().max(1024).optional(),
33169
+ to: external_exports.string().max(1024).optional()
33170
+ });
33171
+ var taskApproveRequestSchema = external_exports.object({
33172
+ taskId: external_exports.string().min(1).max(64),
33173
+ approved: external_exports.boolean()
33174
+ });
33132
33175
  var autonomousWriteRequestSchema = external_exports.discriminatedUnion("kind", [
33133
33176
  external_exports.object({ kind: external_exports.literal("settings"), settings: external_exports.string().max(64 * 1024) }),
33134
33177
  external_exports.object({ kind: external_exports.literal("approvals"), taskId: external_exports.string().min(1).max(64), approved: external_exports.boolean() }),
@@ -33710,6 +33753,9 @@ var WsChannels = {
33710
33753
  // ADR-0151) — the Git tab's manual conflict resolution (`project.git_write`); the only
33711
33754
  // git-tab write not carried by a git command over command dispatch.
33712
33755
  FS_WRITE: "fs.write",
33756
+ // server → cli (reply): create/rename/move/delete a file or folder in the project tree,
33757
+ // each op path-clamped to the physic root (machine-0059, ADR-0260, `project.files_write`).
33758
+ FS_MUTATE: "fs.mutate",
33713
33759
  GIT_DIFF: "git.diff",
33714
33760
  GIT_ENV: "git.env",
33715
33761
  // server → cli (reply): read/write the paired profile's config.json (machine-0025/0026,
@@ -34026,8 +34072,8 @@ function resolveInstallTimeoutMs(sec) {
34026
34072
  return sec && sec > 0 ? sec * 1e3 : TOOL_INSTALL_TIMEOUT_DEFAULT_MS;
34027
34073
  }
34028
34074
  function sleep(ms) {
34029
- return new Promise((resolve8) => {
34030
- const t = setTimeout(resolve8, ms);
34075
+ return new Promise((resolve9) => {
34076
+ const t = setTimeout(resolve9, ms);
34031
34077
  t.unref?.();
34032
34078
  });
34033
34079
  }
@@ -34049,14 +34095,14 @@ function classifyToolFailure(code, out) {
34049
34095
  return { reason: "other", retryable: false };
34050
34096
  }
34051
34097
  function run(cmd, args, onLine, timeoutMs = 18e4) {
34052
- return new Promise((resolve8) => {
34098
+ return new Promise((resolve9) => {
34053
34099
  let out = "";
34054
34100
  let buf = "";
34055
34101
  let child = null;
34056
34102
  const done = (code) => {
34057
34103
  clearTimeout(timer);
34058
34104
  if (onLine && buf.trim()) onLine(buf.trim());
34059
- resolve8({ code, out });
34105
+ resolve9({ code, out });
34060
34106
  };
34061
34107
  const timer = setTimeout(() => {
34062
34108
  child?.kill();
@@ -34437,7 +34483,7 @@ async function runCommand(dispatch, emit, opts) {
34437
34483
  });
34438
34484
  child.stdout?.on("data", (data) => batcher.push(data.toString("utf8")));
34439
34485
  child.stderr?.on("data", (data) => batcher.push(data.toString("utf8")));
34440
- await new Promise((resolve8) => {
34486
+ await new Promise((resolve9) => {
34441
34487
  child.on("close", (exitCode) => {
34442
34488
  clearTimers();
34443
34489
  batcher.flush();
@@ -34450,7 +34496,7 @@ async function runCommand(dispatch, emit, opts) {
34450
34496
  // server settles the command as failed and the web surfaces the note instead of spinning.
34451
34497
  exitCode: timedOut ? 124 : exitCode ?? -1
34452
34498
  });
34453
- resolve8();
34499
+ resolve9();
34454
34500
  });
34455
34501
  child.on("error", (err) => {
34456
34502
  clearTimers();
@@ -34462,7 +34508,7 @@ async function runCommand(dispatch, emit, opts) {
34462
34508
  done: true,
34463
34509
  exitCode: -1
34464
34510
  });
34465
- resolve8();
34511
+ resolve9();
34466
34512
  });
34467
34513
  });
34468
34514
  }
@@ -34599,15 +34645,15 @@ function isOutOfCredits(text) {
34599
34645
  );
34600
34646
  }
34601
34647
  function runAttempt(commandId, cmd, args, stdin, cwd2, env3, onChunk, timeoutMs) {
34602
- return new Promise((resolve8) => {
34648
+ return new Promise((resolve9) => {
34603
34649
  runCommand(
34604
34650
  { commandId, cmd, args, path: cwd2, env: env3 },
34605
34651
  (out) => {
34606
34652
  if (out.chunk) onChunk(out.chunk);
34607
- if (out.done) resolve8(out.exitCode ?? -1);
34653
+ if (out.done) resolve9(out.exitCode ?? -1);
34608
34654
  },
34609
34655
  { stdin, ...timeoutMs > 0 ? { timeoutMs } : {} }
34610
- ).catch(() => resolve8(-1));
34656
+ ).catch(() => resolve9(-1));
34611
34657
  });
34612
34658
  }
34613
34659
  async function runAiFailover(plan, commandId, cwd2, handlers, timeoutMs = 0) {
@@ -34856,15 +34902,36 @@ function folderScopeGuard(folder, prompt) {
34856
34902
  prompt
34857
34903
  ].join("\n");
34858
34904
  }
34859
- function buildRunArgs(profile, cmd, resumeId, oneShot = false) {
34905
+ var THINKING_TOKENS = { low: 4e3, medium: 1e4, high: 31999 };
34906
+ function overrideArgs(cmd, o) {
34907
+ if (!o || !cmd.includes("codex")) return [];
34908
+ const args = [];
34909
+ if (o.thinking && o.thinking !== "off") args.push("-c", `model_reasoning_effort="${o.thinking}"`);
34910
+ if (typeof o.temperature === "number") args.push("-c", `model_temperature=${o.temperature}`);
34911
+ return args;
34912
+ }
34913
+ function overrideEnv(cmd, o) {
34914
+ if (!o || !cmd.includes("claude")) return {};
34915
+ if (!o.thinking || o.thinking === "off") return {};
34916
+ const budget = THINKING_TOKENS[o.thinking];
34917
+ return budget ? { MAX_THINKING_TOKENS: String(budget) } : {};
34918
+ }
34919
+ function buildRunArgs(profile, cmd, resumeId, oneShot = false, override) {
34860
34920
  const extras = profile.args ?? [];
34861
- const model = profile.model?.trim();
34921
+ const model = override?.model?.trim() || profile.model?.trim();
34862
34922
  const modelArgs = model ? ["--model", model] : [];
34863
34923
  const resumeArgs = resumeId && cmd.includes("claude") ? ["--resume", resumeId] : [];
34864
34924
  const turns = profile.maxTurns;
34865
34925
  const perProfileTurns = !oneShot && cmd.includes("claude") && typeof turns === "number" && turns > 0 ? [`--max-turns=${Math.floor(turns)}`] : [];
34866
34926
  const oneShotExtra = oneShot ? oneShotArgs(cmd) : perProfileTurns;
34867
- return [...requiredArgs(cmd), ...resumeArgs, ...extras, ...modelArgs, ...oneShotExtra];
34927
+ return [
34928
+ ...requiredArgs(cmd),
34929
+ ...resumeArgs,
34930
+ ...extras,
34931
+ ...modelArgs,
34932
+ ...overrideArgs(cmd, override),
34933
+ ...oneShotExtra
34934
+ ];
34868
34935
  }
34869
34936
  function claudeHomeDirs(config) {
34870
34937
  const dirs = profileDirs(claudeProfilesOf(config));
@@ -34903,10 +34970,10 @@ function resolveClaudeProfiles(config, workingDir) {
34903
34970
  if (idx > 0) profiles.unshift(profiles.splice(idx, 1)[0]);
34904
34971
  return profiles;
34905
34972
  }
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);
34973
+ function planAiRun(prompt, config, hint = {}, resume = /* @__PURE__ */ new Map(), oneShot = false, override) {
34974
+ return isUnifiedConfig(config) ? planUnifiedRun(prompt, config, hint.credential ?? null, resume, oneShot, override) : planLegacyRun(prompt, config, hint.dir ?? null, resume, oneShot, override);
34908
34975
  }
34909
- function planUnifiedRun(prompt, config, workingCredential, resume, oneShot) {
34976
+ function planUnifiedRun(prompt, config, workingCredential, resume, oneShot, override) {
34910
34977
  const baseEnv = config.aiEnv ?? {};
34911
34978
  const active = activeProvider(config);
34912
34979
  const usable = config.aiProfiles.filter(isUsableCredential);
@@ -34915,7 +34982,7 @@ function planUnifiedRun(prompt, config, workingCredential, resume, oneShot) {
34915
34982
  return {
34916
34983
  cmd: active,
34917
34984
  attempts: [
34918
- { cmd: active, label: "default", dir: null, key: null, args: buildRunArgs({ profile: "" }, active, void 0, oneShot), stdin: prompt, env: { ...baseEnv } }
34985
+ { cmd: active, label: "default", dir: null, key: null, args: buildRunArgs({ profile: "" }, active, void 0, oneShot, override), stdin: prompt, env: { ...baseEnv, ...overrideEnv(active, override) } }
34919
34986
  ]
34920
34987
  };
34921
34988
  }
@@ -34933,20 +35000,20 @@ function planUnifiedRun(prompt, config, workingCredential, resume, oneShot) {
34933
35000
  label: cred.label?.trim() || profileDisplayLabel(dir2),
34934
35001
  dir: dir2,
34935
35002
  key,
34936
- args: buildRunArgs(cred, cmd, resume.get(key), oneShot),
35003
+ args: buildRunArgs(cred, cmd, resume.get(key), oneShot, override),
34937
35004
  stdin: prompt,
34938
- env: envVar ? { ...baseEnv, [envVar]: dir2 } : { ...baseEnv }
35005
+ env: envVar ? { ...baseEnv, [envVar]: dir2, ...overrideEnv(cmd, override) } : { ...baseEnv, ...overrideEnv(cmd, override) }
34939
35006
  }));
34940
35007
  return { cmd: attempts[0]?.cmd ?? DEFAULT_AI_CLI, attempts };
34941
35008
  }
34942
- function planLegacyRun(prompt, config, workingDir, resume, oneShot) {
35009
+ function planLegacyRun(prompt, config, workingDir, resume, oneShot, override) {
34943
35010
  const cmd = config.aiCli || DEFAULT_AI_CLI;
34944
35011
  const baseEnv = config.aiEnv ?? {};
34945
35012
  const envVar = profileEnvVar(cmd);
34946
35013
  const defaultPlan = {
34947
35014
  cmd,
34948
35015
  attempts: [
34949
- { cmd, label: "default", dir: null, key: null, args: buildRunArgs({ profile: "" }, cmd, void 0, oneShot), stdin: prompt, env: { ...baseEnv } }
35016
+ { cmd, label: "default", dir: null, key: null, args: buildRunArgs({ profile: "" }, cmd, void 0, oneShot, override), stdin: prompt, env: { ...baseEnv, ...overrideEnv(cmd, override) } }
34950
35017
  ]
34951
35018
  };
34952
35019
  if (!envVar) return defaultPlan;
@@ -34963,9 +35030,9 @@ function planLegacyRun(prompt, config, workingDir, resume, oneShot) {
34963
35030
  label: profileDisplayLabel(dir2),
34964
35031
  dir: dir2,
34965
35032
  key,
34966
- args: buildRunArgs(profile, cmd, resume.get(key), oneShot),
35033
+ args: buildRunArgs(profile, cmd, resume.get(key), oneShot, override),
34967
35034
  stdin: prompt,
34968
- env: { ...baseEnv, [envVar]: dir2 }
35035
+ env: { ...baseEnv, [envVar]: dir2, ...overrideEnv(cmd, override) }
34969
35036
  };
34970
35037
  });
34971
35038
  return { cmd, attempts };
@@ -35006,16 +35073,16 @@ async function fetchUsage(token) {
35006
35073
  }
35007
35074
  }
35008
35075
  function runUsageCli(dir2, aiCli2) {
35009
- return new Promise((resolve8) => {
35076
+ return new Promise((resolve9) => {
35010
35077
  let out = "";
35011
35078
  let child = null;
35012
35079
  const finish = () => {
35013
35080
  clearTimeout(timer);
35014
- resolve8(out);
35081
+ resolve9(out);
35015
35082
  };
35016
35083
  const timer = setTimeout(() => {
35017
35084
  child?.kill();
35018
- resolve8(out);
35085
+ resolve9(out);
35019
35086
  }, 3e4);
35020
35087
  timer.unref?.();
35021
35088
  try {
@@ -35537,6 +35604,80 @@ async function writeWorkerFile(root, relPath, content) {
35537
35604
  }
35538
35605
  }
35539
35606
 
35607
+ // src/core/fs-mutate.ts
35608
+ import { mkdir as mkdir3, writeFile as writeFile2, rename, rm, stat } from "fs/promises";
35609
+ import { basename as basename2, dirname as dirname4, resolve as resolve4, sep as sep4 } from "path";
35610
+ var MAX_BYTES3 = 2 * 1024 * 1024;
35611
+ function resolveInRoot2(root, rel) {
35612
+ const base = resolve4(root);
35613
+ const target = resolve4(base, rel || ".");
35614
+ return target === base || target.startsWith(base + sep4) ? target : null;
35615
+ }
35616
+ async function isDir(p) {
35617
+ try {
35618
+ return (await stat(p)).isDirectory();
35619
+ } catch {
35620
+ return false;
35621
+ }
35622
+ }
35623
+ async function exists(p) {
35624
+ try {
35625
+ await stat(p);
35626
+ return true;
35627
+ } catch {
35628
+ return false;
35629
+ }
35630
+ }
35631
+ async function mutateFs(root, req) {
35632
+ if (!root) return { ok: false, path: req.path ?? req.from ?? "", error: "no project served" };
35633
+ const escaped = (p) => ({ ok: false, path: p, error: "path escapes the project root" });
35634
+ try {
35635
+ switch (req.op) {
35636
+ case "mkdir": {
35637
+ const target = resolveInRoot2(root, req.path ?? "");
35638
+ if (!target || target === resolve4(root)) return escaped(req.path ?? "");
35639
+ await mkdir3(target, { recursive: true });
35640
+ return { ok: true, path: target };
35641
+ }
35642
+ case "create": {
35643
+ const target = resolveInRoot2(root, req.path ?? "");
35644
+ if (!target || target === resolve4(root)) return escaped(req.path ?? "");
35645
+ if (await exists(target)) return { ok: false, path: target, error: "already exists" };
35646
+ const content = req.content ?? "";
35647
+ if (Buffer.byteLength(content, "utf8") > MAX_BYTES3) {
35648
+ return { ok: false, path: target, error: `content too large (max ${MAX_BYTES3} bytes)` };
35649
+ }
35650
+ await mkdir3(dirname4(target), { recursive: true });
35651
+ await writeFile2(target, content, "utf8");
35652
+ return { ok: true, path: target };
35653
+ }
35654
+ case "move": {
35655
+ const from = resolveInRoot2(root, req.from ?? "");
35656
+ let to = resolveInRoot2(root, req.to ?? "");
35657
+ if (!from || !to) return escaped(req.from ?? req.to ?? "");
35658
+ if (from === resolve4(root)) return { ok: false, path: from, error: "cannot move the project root" };
35659
+ if (await isDir(to)) to = resolve4(to, basename2(from));
35660
+ if (to !== resolve4(root) && !to.startsWith(resolve4(root) + sep4)) return escaped(req.to ?? "");
35661
+ if (await exists(to)) return { ok: false, path: to, error: "destination already exists" };
35662
+ await mkdir3(dirname4(to), { recursive: true });
35663
+ await rename(from, to);
35664
+ return { ok: true, path: to };
35665
+ }
35666
+ case "delete": {
35667
+ const target = resolveInRoot2(root, req.path ?? "");
35668
+ if (!target) return escaped(req.path ?? "");
35669
+ if (target === resolve4(root)) return { ok: false, path: target, error: "cannot delete the project root" };
35670
+ await rm(target, { recursive: true, force: true });
35671
+ return { ok: true, path: target };
35672
+ }
35673
+ default:
35674
+ return { ok: false, path: "", error: "unknown op" };
35675
+ }
35676
+ } catch (err) {
35677
+ return { ok: false, path: req.path ?? req.from ?? "", error: err instanceof Error ? err.message : String(err) };
35678
+ }
35679
+ }
35680
+
35540
35681
  // src/core/support-answer.ts
35541
35682
  import { spawn as spawn5 } from "child_process";
35542
35683
  import { execFile as execFile2 } from "child_process";
@@ -35661,7 +35802,7 @@ function parseModeratedAnswer(text) {
35661
35802
  return { body: text.trim() };
35662
35803
  }
35663
35804
  function runClaudeOnce(cmd, profile, prompt, extraEnv) {
35664
- return new Promise((resolve8, reject) => {
35805
+ return new Promise((resolve9, reject) => {
35665
35806
  const isClaude = cmd.includes("claude");
35666
35807
  const args = [
35667
35808
  "-p",
@@ -35691,7 +35832,7 @@ function runClaudeOnce(cmd, profile, prompt, extraEnv) {
35691
35832
  child.on("close", (code) => {
35692
35833
  clearTimeout(timer);
35693
35834
  out += parser.flush();
35694
- resolve8({ code: code ?? -1, out, err, usage: parser.usage() });
35835
+ resolve9({ code: code ?? -1, out, err, usage: parser.usage() });
35695
35836
  });
35696
35837
  child.stdin.write(prompt);
35697
35838
  child.stdin.end();
@@ -35762,7 +35903,7 @@ Extra focus from the author: ${req.prompt}` : "";
35762
35903
  ].join("\n");
35763
35904
  }
35764
35905
  function runOnce(cmd, profile, prompt, cwd2, extraEnv) {
35765
- return new Promise((resolve8, reject) => {
35906
+ return new Promise((resolve9, reject) => {
35766
35907
  const args = ["-p", ...profile?.model ? ["--model", profile.model] : []];
35767
35908
  const env3 = {
35768
35909
  ...process.env,
@@ -35785,7 +35926,7 @@ function runOnce(cmd, profile, prompt, cwd2, extraEnv) {
35785
35926
  });
35786
35927
  child.on("close", (code) => {
35787
35928
  clearTimeout(timer);
35788
- resolve8({ code: code ?? -1, out, err });
35929
+ resolve9({ code: code ?? -1, out, err });
35789
35930
  });
35790
35931
  child.stdin.write(prompt);
35791
35932
  child.stdin.end();
@@ -35815,7 +35956,7 @@ async function runKnowledgeCompose(req, ai, physicRoot) {
35815
35956
  }
35816
35957
 
35817
35958
  // src/core/autonomous.ts
35818
- import { readFile as readFile3, writeFile as writeFile2, chmod } from "fs/promises";
35959
+ import { readFile as readFile3, writeFile as writeFile3, chmod } from "fs/promises";
35819
35960
  import { readFileSync as readFileSync13 } from "fs";
35820
35961
  import { execFile as execFile3, spawn as spawn7 } from "child_process";
35821
35962
  import { join as join14 } from "path";
@@ -35861,10 +36002,10 @@ async function crontabList() {
35861
36002
  }
35862
36003
  }
35863
36004
  async function crontabSet(content) {
35864
- return new Promise((resolve8) => {
36005
+ return new Promise((resolve9) => {
35865
36006
  const child = spawn7("crontab", ["-"], { stdio: ["pipe", "ignore", "ignore"] });
35866
- child.on("error", () => resolve8(false));
35867
- child.on("close", (code) => resolve8(code === 0));
36007
+ child.on("error", () => resolve9(false));
36008
+ child.on("close", (code) => resolve9(code === 0));
35868
36009
  child.stdin.end(content.endsWith("\n") ? content : content + "\n");
35869
36010
  });
35870
36011
  }
@@ -35940,14 +36081,14 @@ async function writeAutonomous(root, req, by) {
35940
36081
  switch (req.kind) {
35941
36082
  case "settings": {
35942
36083
  if (!parseJson(req.settings)) return { ok: false, error: "settings is not valid JSON" };
35943
- await writeFile2(join14(root, SETTINGS_REL), req.settings, "utf8");
36084
+ await writeFile3(join14(root, SETTINGS_REL), req.settings, "utf8");
35944
36085
  break;
35945
36086
  }
35946
36087
  case "approvals": {
35947
36088
  const map = parseJson(await readText(join14(root, APPROVALS_REL), "{}")) ?? {};
35948
36089
  if (req.approved) map[req.taskId] = { approved: true, by, at: (/* @__PURE__ */ new Date()).toISOString() };
35949
36090
  else delete map[req.taskId];
35950
- await writeFile2(join14(root, APPROVALS_REL), JSON.stringify(map, null, 2) + "\n", "utf8");
36091
+ await writeFile3(join14(root, APPROVALS_REL), JSON.stringify(map, null, 2) + "\n", "utf8");
35951
36092
  break;
35952
36093
  }
35953
36094
  case "userTodo": {
@@ -35957,7 +36098,7 @@ async function writeAutonomous(root, req, by) {
35957
36098
  > posted by ${by} at ${(/* @__PURE__ */ new Date()).toISOString()}
35958
36099
  ${req.content.trim()}
35959
36100
  `;
35960
- await writeFile2(join14(root, BOOK_FILES.userTodo), cur.trimEnd() + block, "utf8");
36101
+ await writeFile3(join14(root, BOOK_FILES.userTodo), cur.trimEnd() + block, "utf8");
35961
36102
  break;
35962
36103
  }
35963
36104
  case "cron": {
@@ -35973,7 +36114,7 @@ ${req.content.trim()}
35973
36114
  }
35974
36115
 
35975
36116
  // src/core/agents.ts
35976
- import { readFile as readFile4, writeFile as writeFile3, mkdir as mkdir3, readdir as readdir3, rm } from "fs/promises";
36117
+ import { readFile as readFile4, writeFile as writeFile4, mkdir as mkdir4, readdir as readdir3, rm as rm2 } from "fs/promises";
35977
36118
  import { join as join15 } from "path";
35978
36119
  var AGENTS_REL = ".claude/agents";
35979
36120
  var SKILLS_REL = ".claude/skills";
@@ -36036,14 +36177,14 @@ async function writeAgent(root, req) {
36036
36177
  if (!n) return { ok: false, error: "invalid name" };
36037
36178
  try {
36038
36179
  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 });
36180
+ if (req.kind === "subagent") await rm2(itemPath(root, "subagent", n), { force: true });
36181
+ else await rm2(join15(root, SKILLS_REL, n), { recursive: true, force: true });
36041
36182
  return { ok: true };
36042
36183
  }
36043
36184
  if (req.content === void 0) return { ok: false, error: "content is required" };
36044
36185
  const path = itemPath(root, req.kind, n);
36045
- await mkdir3(join15(path, ".."), { recursive: true });
36046
- await writeFile3(path, req.content, "utf8");
36186
+ await mkdir4(join15(path, ".."), { recursive: true });
36187
+ await writeFile4(path, req.content, "utf8");
36047
36188
  return { ok: true };
36048
36189
  } catch (err) {
36049
36190
  return { ok: false, error: err instanceof Error ? err.message : String(err) };
@@ -36052,8 +36193,8 @@ async function writeAgent(root, req) {
36052
36193
 
36053
36194
  // src/core/packages.ts
36054
36195
  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";
36196
+ import { readFile as readFile5, writeFile as writeFile5, mkdir as mkdir5, readdir as readdir4, rm as rm3, stat as stat2 } from "fs/promises";
36197
+ import { dirname as dirname5, join as join16, relative } from "path";
36057
36198
  var AGENTS_REL2 = ".claude/agents";
36058
36199
  var SKILLS_REL2 = ".claude/skills";
36059
36200
  var MANIFEST_REL = ".claude/.4pm-packages.json";
@@ -36117,7 +36258,7 @@ async function artifactSha256(root, kind, slug) {
36117
36258
  async function artifactExists(root, kind, slug) {
36118
36259
  const target = kind === "subagent" ? join16(root, AGENTS_REL2, `${slug}.md`) : join16(root, SKILLS_REL2, slug);
36119
36260
  try {
36120
- await stat(target);
36261
+ await stat2(target);
36121
36262
  return true;
36122
36263
  } catch {
36123
36264
  return false;
@@ -36134,34 +36275,34 @@ async function readManifest(root) {
36134
36275
  }
36135
36276
  async function writeManifest(root, manifest) {
36136
36277
  const path = join16(root, MANIFEST_REL);
36137
- await mkdir4(dirname4(path), { recursive: true });
36138
- await writeFile4(path, JSON.stringify(manifest, null, 2), "utf8");
36278
+ await mkdir5(dirname5(path), { recursive: true });
36279
+ await writeFile5(path, JSON.stringify(manifest, null, 2), "utf8");
36139
36280
  }
36140
36281
  async function writeArtifactFiles(root, kind, slug, files) {
36141
36282
  const byPath = new Map(files.map((f) => [f.path, Buffer.from(f.contentBase64, "base64")]));
36142
36283
  if (kind === "subagent") {
36143
36284
  const agent = byPath.get("agent.md");
36144
36285
  if (agent) {
36145
- await mkdir4(join16(root, AGENTS_REL2), { recursive: true });
36146
- await writeFile4(join16(root, AGENTS_REL2, `${slug}.md`), agent);
36286
+ await mkdir5(join16(root, AGENTS_REL2), { recursive: true });
36287
+ await writeFile5(join16(root, AGENTS_REL2, `${slug}.md`), agent);
36147
36288
  }
36148
36289
  const short = byPath.get("short-memory.md");
36149
36290
  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);
36291
+ await mkdir5(join16(root, AGENTS_REL2, "short-memory"), { recursive: true });
36292
+ await writeFile5(join16(root, AGENTS_REL2, "short-memory", `${slug}.md`), short);
36152
36293
  }
36153
36294
  const long = byPath.get("long-memory.md");
36154
36295
  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);
36296
+ await mkdir5(join16(root, AGENTS_REL2, "long-memory"), { recursive: true });
36297
+ await writeFile5(join16(root, AGENTS_REL2, "long-memory", `${slug}.md`), long);
36157
36298
  }
36158
36299
  } else {
36159
36300
  const base = join16(root, SKILLS_REL2, slug);
36160
36301
  for (const [rel, buf] of byPath) {
36161
36302
  if (rel.includes("..") || rel.startsWith("/")) continue;
36162
36303
  const dest = join16(base, rel);
36163
- await mkdir4(dirname4(dest), { recursive: true });
36164
- await writeFile4(dest, buf);
36304
+ await mkdir5(dirname5(dest), { recursive: true });
36305
+ await writeFile5(dest, buf);
36165
36306
  }
36166
36307
  }
36167
36308
  }
@@ -36225,11 +36366,11 @@ async function removePackage(root, slug) {
36225
36366
  const entry = manifest[n];
36226
36367
  if (!entry) return { ok: false, error: "not installed" };
36227
36368
  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 });
36369
+ await rm3(join16(root, AGENTS_REL2, `${n}.md`), { force: true });
36370
+ await rm3(join16(root, AGENTS_REL2, "short-memory", `${n}.md`), { force: true });
36371
+ await rm3(join16(root, AGENTS_REL2, "long-memory", `${n}.md`), { force: true });
36231
36372
  } else {
36232
- await rm2(join16(root, SKILLS_REL2, n), { recursive: true, force: true });
36373
+ await rm3(join16(root, SKILLS_REL2, n), { recursive: true, force: true });
36233
36374
  }
36234
36375
  delete manifest[n];
36235
36376
  await writeManifest(root, manifest);
@@ -36257,14 +36398,14 @@ function detectContainerized() {
36257
36398
  }
36258
36399
  }
36259
36400
  function canReach(host, port) {
36260
- return new Promise((resolve8) => {
36401
+ return new Promise((resolve9) => {
36261
36402
  const socket = connect({ host, port });
36262
36403
  let done = false;
36263
36404
  const finish = (ok) => {
36264
36405
  if (done) return;
36265
36406
  done = true;
36266
36407
  socket.destroy();
36267
- resolve8(ok);
36408
+ resolve9(ok);
36268
36409
  };
36269
36410
  socket.setTimeout(PROBE_TIMEOUT_MS);
36270
36411
  socket.once("connect", () => finish(true));
@@ -36345,7 +36486,7 @@ function applyGitAuth(method) {
36345
36486
  }
36346
36487
 
36347
36488
  // src/core/secrets.ts
36348
- import { readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
36489
+ import { readFile as readFile6, writeFile as writeFile6 } from "fs/promises";
36349
36490
  import { join as join18 } from "path";
36350
36491
  var SECURITY_REL = "AI_SECURITY.md";
36351
36492
  var PLACEHOLDER_REL = "AI_PLACEHOLDER.md";
@@ -36392,14 +36533,14 @@ async function readSecrets(root) {
36392
36533
  async function writeSecrets(root, req) {
36393
36534
  try {
36394
36535
  if (req.kind === "security") {
36395
- await writeFile5(join18(root, SECURITY_REL), req.content, "utf8");
36536
+ await writeFile6(join18(root, SECURITY_REL), req.content, "utf8");
36396
36537
  } else if (req.kind === "placeholder") {
36397
- await writeFile5(join18(root, PLACEHOLDER_REL), req.content, "utf8");
36538
+ await writeFile6(join18(root, PLACEHOLDER_REL), req.content, "utf8");
36398
36539
  } else {
36399
36540
  const secrets = await readSecretsObject(root);
36400
36541
  if (req.kind === "secret") secrets[req.key] = req.value;
36401
36542
  else delete secrets[req.key];
36402
- await writeFile5(join18(root, SECRETS_REL), JSON.stringify(secrets, null, 2) + "\n", "utf8");
36543
+ await writeFile6(join18(root, SECRETS_REL), JSON.stringify(secrets, null, 2) + "\n", "utf8");
36403
36544
  }
36404
36545
  return { ok: true };
36405
36546
  } catch (err) {
@@ -36408,8 +36549,8 @@ async function writeSecrets(root, req) {
36408
36549
  }
36409
36550
 
36410
36551
  // 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";
36552
+ import { readFile as readFile7, writeFile as writeFile7, mkdir as mkdir6 } from "fs/promises";
36553
+ import { dirname as dirname6, join as join19 } from "path";
36413
36554
  var SHARED_REL = ".claude/settings.json";
36414
36555
  var LOCAL_REL = ".claude/settings.local.json";
36415
36556
  var SECRETS_DENY = "Read(./project.secrets.json)";
@@ -36442,8 +36583,8 @@ async function writeAgentTools(root, scope, permissions) {
36442
36583
  const next = normalizePermissions(permissions);
36443
36584
  if (scope === "shared" && !next.deny.includes(SECRETS_DENY)) next.deny = [...next.deny, SECRETS_DENY];
36444
36585
  obj.permissions = next;
36445
- await mkdir5(dirname5(path), { recursive: true });
36446
- await writeFile6(path, JSON.stringify(obj, null, 2) + "\n", "utf8");
36586
+ await mkdir6(dirname6(path), { recursive: true });
36587
+ await writeFile7(path, JSON.stringify(obj, null, 2) + "\n", "utf8");
36447
36588
  return { ok: true };
36448
36589
  } catch (err) {
36449
36590
  return { ok: false, error: err instanceof Error ? err.message : String(err) };
@@ -36452,7 +36593,7 @@ async function writeAgentTools(root, scope, permissions) {
36452
36593
 
36453
36594
  // src/core/graph.ts
36454
36595
  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";
36596
+ import { join as join20, relative as relative2, dirname as dirname7, resolve as resolve5, extname, basename as basename3 } from "path";
36456
36597
  var MAX_FILES = 2e3;
36457
36598
  var MAX_NODES = 3e3;
36458
36599
  var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", ".next", "out", "coverage", ".turbo"]);
@@ -36492,7 +36633,7 @@ async function buildDocs(root) {
36492
36633
  const ids = new Set(files.map((f) => relative2(root, f).split("\\").join("/")));
36493
36634
  const nodes = files.map((f) => {
36494
36635
  const rel = relative2(root, f).split("\\").join("/");
36495
- return { id: rel, label: basename2(rel), kind: "doc", file: rel };
36636
+ return { id: rel, label: basename3(rel), kind: "doc", file: rel };
36496
36637
  });
36497
36638
  const edges = [];
36498
36639
  const seen = /* @__PURE__ */ new Set();
@@ -36507,7 +36648,7 @@ async function buildDocs(root) {
36507
36648
  for (const m of text.matchAll(/\[[^\]]*\]\(([^)]+)\)/g)) {
36508
36649
  const href = (m[1] ?? "").split("#")[0].trim();
36509
36650
  if (!href || !href.endsWith(".md") || href.startsWith("http")) continue;
36510
- const target = relative2(root, resolve4(dirname6(f), href)).split("\\").join("/");
36651
+ const target = relative2(root, resolve5(dirname7(f), href)).split("\\").join("/");
36511
36652
  if (ids.has(target) && target !== rel) {
36512
36653
  const key = `${rel}->${target}`;
36513
36654
  if (!seen.has(key)) {
@@ -36591,7 +36732,7 @@ async function buildGraph(root, mode) {
36591
36732
  }
36592
36733
 
36593
36734
  // src/core/rag.ts
36594
- import { readFile as readFile9, writeFile as writeFile7, statfs as statfs2, mkdir as mkdir6 } from "fs/promises";
36735
+ import { readFile as readFile9, writeFile as writeFile8, statfs as statfs2, mkdir as mkdir7 } from "fs/promises";
36595
36736
  import { existsSync as existsSync11 } from "fs";
36596
36737
  import { execFile as execFile4, spawn as spawn8 } from "child_process";
36597
36738
  import { totalmem as totalmem2, cpus as cpus2 } from "os";
@@ -36765,8 +36906,8 @@ if __name__ == "__main__":
36765
36906
  elif cmd == "query": query(sys.argv[2], int(sys.argv[3]) if len(sys.argv) > 3 else 8)
36766
36907
  `;
36767
36908
  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");
36909
+ await mkdir7(join21(root, RAG_REL), { recursive: true }).catch(() => void 0);
36910
+ await writeFile8(join21(root, RAG_REL, "rag_engine.py"), RAG_ENGINE_PY, "utf8");
36770
36911
  }
36771
36912
  async function ragReindex(root) {
36772
36913
  const py = await detectPython();
@@ -36814,7 +36955,7 @@ async function ragInstall(root, model) {
36814
36955
  if (!py.found) return { ok: false, started: false, error: "python3 not found on the worker" };
36815
36956
  if (existsSync11(join21(root, RAG_REL, ".installing"))) return { ok: true, started: true };
36816
36957
  try {
36817
- await mkdir6(join21(root, RAG_REL), { recursive: true });
36958
+ await mkdir7(join21(root, RAG_REL), { recursive: true });
36818
36959
  } catch {
36819
36960
  }
36820
36961
  const script = `
@@ -36843,13 +36984,13 @@ rm -f "${RAG_REL}/.installing"
36843
36984
  // src/core/git-diff.ts
36844
36985
  import { readFile as readFile10 } from "fs/promises";
36845
36986
  import { execFile as execFile5 } from "child_process";
36846
- import { basename as basename3, dirname as dirname7, resolve as resolve5 } from "path";
36987
+ import { basename as basename4, dirname as dirname8, resolve as resolve6 } from "path";
36847
36988
  import { promisify as promisify5 } from "util";
36848
36989
  var run5 = promisify5(execFile5);
36849
36990
  async function gitDiff(path) {
36850
- const target = resolve5(path);
36851
- const dir2 = dirname7(target);
36852
- const base = basename3(target);
36991
+ const target = resolve6(path);
36992
+ const dir2 = dirname8(target);
36993
+ const base = basename4(target);
36853
36994
  let newContent = "";
36854
36995
  try {
36855
36996
  newContent = await readFile10(target, "utf8");
@@ -36901,7 +37042,7 @@ ${stderr}`;
36901
37042
 
36902
37043
  // src/core/git-ssh-key.ts
36903
37044
  import { execFile as execFile7 } from "child_process";
36904
- import { readFile as readFile11, rm as rm3, mkdir as mkdir7 } from "fs/promises";
37045
+ import { readFile as readFile11, rm as rm4, mkdir as mkdir8 } from "fs/promises";
36905
37046
  import { join as join22 } from "path";
36906
37047
  import { promisify as promisify7 } from "util";
36907
37048
  var run7 = promisify7(execFile7);
@@ -36934,9 +37075,9 @@ async function configureGit(key) {
36934
37075
  }
36935
37076
  async function generate(profileDir2) {
36936
37077
  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 });
37078
+ await mkdir8(dir2, { recursive: true });
37079
+ await rm4(key, { force: true });
37080
+ await rm4(pub, { force: true });
36940
37081
  await run7("ssh-keygen", ["-t", "ed25519", "-f", key, "-N", "", "-C", "4pm-deploy-key"], {
36941
37082
  timeout: 15e3
36942
37083
  });
@@ -36945,8 +37086,8 @@ async function generate(profileDir2) {
36945
37086
  }
36946
37087
  async function remove(profileDir2) {
36947
37088
  const { key, pub } = keyPaths(profileDir2);
36948
- await rm3(key, { force: true });
36949
- await rm3(pub, { force: true });
37089
+ await rm4(key, { force: true });
37090
+ await rm4(pub, { force: true });
36950
37091
  await run7("git", ["config", "--global", "--unset", "core.sshCommand"], { timeout: 5e3 }).catch(
36951
37092
  () => void 0
36952
37093
  );
@@ -36970,16 +37111,16 @@ async function manageSshKey(op, profileDir2) {
36970
37111
  // src/core/git-history.ts
36971
37112
  import { readdir as readdir6 } from "fs/promises";
36972
37113
  import { execFile as execFile8 } from "child_process";
36973
- import { resolve as resolve6, sep as sep4 } from "path";
37114
+ import { resolve as resolve7, sep as sep5 } from "path";
36974
37115
  import { promisify as promisify8 } from "util";
36975
37116
  var run8 = promisify8(execFile8);
36976
37117
  var FS = "";
36977
37118
  var RS = "";
36978
37119
  function resolveRepo(root, repo) {
36979
37120
  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;
37121
+ const base = resolve7(root);
37122
+ const requested = resolve7(base, repo && repo.trim() ? repo : ".");
37123
+ return requested === base || requested.startsWith(base + sep5) ? requested : base;
36983
37124
  }
36984
37125
  async function git(cwd2, args) {
36985
37126
  try {
@@ -36995,13 +37136,13 @@ async function git(cwd2, args) {
36995
37136
  }
36996
37137
  async function gitRepos(root) {
36997
37138
  if (!root) return { repos: [] };
36998
- const base = resolve6(root);
37139
+ const base = resolve7(root);
36999
37140
  const found = /* @__PURE__ */ new Set();
37000
37141
  const repos = [];
37001
37142
  const add = async (dir2) => {
37002
37143
  const inside = await git(dir2, ["rev-parse", "--show-toplevel"]);
37003
37144
  const top = inside.trim();
37004
- if (!top || found.has(top) || !(top === base || top.startsWith(base + sep4))) return;
37145
+ if (!top || found.has(top) || !(top === base || top.startsWith(base + sep5))) return;
37005
37146
  found.add(top);
37006
37147
  const subdir = top === base ? "" : top.slice(base.length + 1);
37007
37148
  const remote = (await git(top, ["remote", "get-url", "origin"])).trim();
@@ -37012,13 +37153,13 @@ async function gitRepos(root) {
37012
37153
  const lvl1 = await readdir6(base, { withFileTypes: true });
37013
37154
  for (const d of lvl1) {
37014
37155
  if (!d.isDirectory() || d.name === ".git" || d.name === "node_modules") continue;
37015
- const p1 = resolve6(base, d.name);
37156
+ const p1 = resolve7(base, d.name);
37016
37157
  await add(p1);
37017
37158
  try {
37018
37159
  const lvl2 = await readdir6(p1, { withFileTypes: true });
37019
37160
  for (const d2 of lvl2) {
37020
37161
  if (!d2.isDirectory() || d2.name === ".git" || d2.name === "node_modules") continue;
37021
- await add(resolve6(p1, d2.name));
37162
+ await add(resolve7(p1, d2.name));
37022
37163
  }
37023
37164
  } catch {
37024
37165
  }
@@ -37097,10 +37238,10 @@ async function setCommitAuthor(cwd2, machineUsername) {
37097
37238
  }
37098
37239
 
37099
37240
  // src/core/scaffold.ts
37100
- import { cp, mkdir as mkdir8, writeFile as writeFile8 } from "fs/promises";
37241
+ import { cp, mkdir as mkdir9, writeFile as writeFile9 } from "fs/promises";
37101
37242
  import { existsSync as existsSync12 } from "fs";
37102
37243
  import { execFile as execFile10 } from "child_process";
37103
- import { dirname as dirname8, join as join23, resolve as resolve7 } from "path";
37244
+ import { dirname as dirname9, join as join23, resolve as resolve8 } from "path";
37104
37245
  import { fileURLToPath as fileURLToPath3 } from "url";
37105
37246
  import { promisify as promisify10 } from "util";
37106
37247
  var run10 = promisify10(execFile10);
@@ -37135,31 +37276,35 @@ async function provisionRepos(target, repos, emit, opts = {}) {
37135
37276
  await run10("git", ["clone", repo.url, dir2], { timeout: 12e4 });
37136
37277
  } else {
37137
37278
  emit("git", `Initializing sub-repo ${subDirName(repo)}\u2026`);
37138
- await mkdir8(dir2, { recursive: true });
37279
+ await mkdir9(dir2, { recursive: true });
37139
37280
  await run10("git", ["init"], { cwd: dir2, timeout: 2e4 });
37140
37281
  }
37141
37282
  }
37142
37283
  }
37143
37284
  function sampleDir() {
37144
37285
  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")]) {
37286
+ const here = dirname9(fileURLToPath3(import.meta.url));
37287
+ const bundled = resolve8(here, "project-sample");
37288
+ for (const candidate of [bundled, resolve8(here, "../project-sample"), resolve8(here, "../../project-sample")]) {
37148
37289
  if (existsSync12(candidate)) return candidate;
37149
37290
  }
37150
37291
  return bundled;
37151
37292
  }
37152
37293
  async function scaffoldProject(payload, profileDir2, onProgress) {
37153
- const emit = (step, message) => onProgress?.({ projectId: payload.projectId, step, message });
37294
+ let lastStep = "start";
37295
+ const emit = (step, message) => {
37296
+ lastStep = step;
37297
+ onProgress?.({ projectId: payload.projectId, step, message });
37298
+ };
37154
37299
  try {
37155
- const root = process.env.SCAFFOLD_ROOT ? resolve7(process.env.SCAFFOLD_ROOT) : resolve7(profileDir2);
37300
+ const root = process.env.SCAFFOLD_ROOT ? resolve8(process.env.SCAFFOLD_ROOT) : resolve8(profileDir2);
37156
37301
  const target = join23(root, payload.projectName);
37157
- await mkdir8(target, { recursive: true });
37302
+ await mkdir9(target, { recursive: true });
37158
37303
  emit("copy", "Copying the sample template\u2026");
37159
37304
  await cp(sampleDir(), target, { recursive: true, force: false, errorOnExist: false });
37160
37305
  if (payload.spec) {
37161
37306
  emit("spec", "Writing project.spec.json\u2026");
37162
- await writeFile8(
37307
+ await writeFile9(
37163
37308
  join23(target, "project.spec.json"),
37164
37309
  JSON.stringify(payload.spec, null, 2),
37165
37310
  "utf8"
@@ -37168,17 +37313,25 @@ async function scaffoldProject(payload, profileDir2, onProgress) {
37168
37313
  const repos = reposOf(payload.spec);
37169
37314
  if (repos.length > 0) await provisionRepos(target, repos, emit);
37170
37315
  if (payload.spec) await aiInit(target, payload.spec, emit);
37316
+ emit("version", "Writing .4pm/.4pm.json\u2026");
37317
+ await writeTemplateMarker(target);
37171
37318
  onProgress?.({ projectId: payload.projectId, step: "done", message: "Scaffold complete.", done: true });
37172
37319
  return { ok: true, path: target };
37173
37320
  } catch (err) {
37174
- return { ok: false, error: err instanceof Error ? err.message : String(err) };
37321
+ return { ok: false, error: err instanceof Error ? err.message : String(err), step: lastStep };
37175
37322
  }
37176
37323
  }
37324
+ async function writeTemplateMarker(target) {
37325
+ const dir2 = join23(target, ".4pm");
37326
+ await mkdir9(dir2, { recursive: true });
37327
+ const marker = { templateVersion: PROJECT_TEMPLATE.version, scaffoldedAt: (/* @__PURE__ */ new Date()).toISOString() };
37328
+ await writeFile9(join23(dir2, ".4pm.json"), JSON.stringify(marker, null, 2) + "\n", "utf8");
37329
+ }
37177
37330
  async function aiInit(target, spec, emit) {
37178
37331
  emit("ai-init", "AI init: subagents, README, CLAUDE.md\u2026");
37179
37332
  const subagents = Array.isArray(spec.subagents) ? spec.subagents : [];
37180
37333
  if (subagents.length > 0) {
37181
- await mkdir8(join23(target, ".claude", "agents"), { recursive: true });
37334
+ await mkdir9(join23(target, ".claude", "agents"), { recursive: true });
37182
37335
  for (const sa of subagents) {
37183
37336
  const name = (sa.name || "").trim().replace(/[^\w.-]+/g, "-").replace(/^-+|-+$/g, "");
37184
37337
  if (!name) continue;
@@ -37188,7 +37341,7 @@ name: ${name}
37188
37341
 
37189
37342
  ${(sa.description || "").trim()}
37190
37343
  `;
37191
- await writeFile8(join23(target, ".claude", "agents", `${name}.md`), body, "utf8");
37344
+ await writeFile9(join23(target, ".claude", "agents", `${name}.md`), body, "utf8");
37192
37345
  }
37193
37346
  }
37194
37347
  const specJson = JSON.stringify(spec);
@@ -37206,22 +37359,26 @@ ${specJson}`
37206
37359
  async function generateFile(path, prompt) {
37207
37360
  try {
37208
37361
  const text = await aiGenerate(prompt);
37209
- if (text.trim()) await writeFile8(path, text.trim() + "\n", "utf8");
37362
+ if (text.trim()) await writeFile9(path, text.trim() + "\n", "utf8");
37210
37363
  } catch {
37211
37364
  }
37212
37365
  }
37213
37366
  async function addProject(payload, profileDir2, onProgress) {
37214
- const emit = (step, message) => onProgress?.({ projectId: payload.projectId, step, message });
37367
+ let lastStep = "start";
37368
+ const emit = (step, message) => {
37369
+ lastStep = step;
37370
+ onProgress?.({ projectId: payload.projectId, step, message });
37371
+ };
37215
37372
  try {
37216
- const root = process.env.SCAFFOLD_ROOT ? resolve7(process.env.SCAFFOLD_ROOT) : resolve7(profileDir2);
37373
+ const root = process.env.SCAFFOLD_ROOT ? resolve8(process.env.SCAFFOLD_ROOT) : resolve8(profileDir2);
37217
37374
  const target = join23(root, payload.projectName);
37218
- await mkdir8(target, { recursive: true });
37375
+ await mkdir9(target, { recursive: true });
37219
37376
  const repos = payload.repos ?? [];
37220
37377
  if (repos.length > 0) await provisionRepos(target, repos, emit, { clonePrimary: true });
37221
37378
  onProgress?.({ projectId: payload.projectId, step: "done", message: "Project added.", done: true });
37222
37379
  return { ok: true, path: target };
37223
37380
  } catch (err) {
37224
- return { ok: false, error: err instanceof Error ? err.message : String(err) };
37381
+ return { ok: false, error: err instanceof Error ? err.message : String(err), step: lastStep };
37225
37382
  }
37226
37383
  }
37227
37384
 
@@ -37639,7 +37796,7 @@ function buildPrompt3(input) {
37639
37796
  ].join("\n");
37640
37797
  }
37641
37798
  function runOnce2(cmd, profile, prompt, cwd2, extraEnv) {
37642
- return new Promise((resolve8, reject) => {
37799
+ return new Promise((resolve9, reject) => {
37643
37800
  const args = ["-p", ...profile?.model ? ["--model", profile.model] : []];
37644
37801
  const env3 = {
37645
37802
  ...process.env,
@@ -37662,7 +37819,7 @@ function runOnce2(cmd, profile, prompt, cwd2, extraEnv) {
37662
37819
  });
37663
37820
  child.on("close", (code) => {
37664
37821
  clearTimeout(timer);
37665
- resolve8({ code: code ?? -1, out, err });
37822
+ resolve9({ code: code ?? -1, out, err });
37666
37823
  });
37667
37824
  child.stdin.write(prompt);
37668
37825
  child.stdin.end();
@@ -37937,14 +38094,14 @@ var WsClient = class {
37937
38094
  */
37938
38095
  awaitConnected(timeoutMs) {
37939
38096
  if (this.sessionKey && this.bus.status === "connected") return Promise.resolve(true);
37940
- return new Promise((resolve8) => {
38097
+ return new Promise((resolve9) => {
37941
38098
  const waiter = () => {
37942
38099
  clearTimeout(timer);
37943
- resolve8(true);
38100
+ resolve9(true);
37944
38101
  };
37945
38102
  const timer = setTimeout(() => {
37946
38103
  this.connectWaiters = this.connectWaiters.filter((w) => w !== waiter);
37947
- resolve8(false);
38104
+ resolve9(false);
37948
38105
  }, timeoutMs);
37949
38106
  this.connectWaiters.push(waiter);
37950
38107
  });
@@ -37971,16 +38128,16 @@ var WsClient = class {
37971
38128
  this.forceReconnect = false;
37972
38129
  return Promise.resolve();
37973
38130
  }
37974
- return new Promise((resolve8) => {
38131
+ return new Promise((resolve9) => {
37975
38132
  const timer = setTimeout(() => {
37976
38133
  this.wakeReconnect = null;
37977
- resolve8();
38134
+ resolve9();
37978
38135
  }, ms);
37979
38136
  this.wakeReconnect = () => {
37980
38137
  clearTimeout(timer);
37981
38138
  this.wakeReconnect = null;
37982
38139
  this.forceReconnect = false;
37983
- resolve8();
38140
+ resolve9();
37984
38141
  };
37985
38142
  });
37986
38143
  }
@@ -38034,7 +38191,7 @@ var WsClient = class {
38034
38191
  * One WS session: token → connect → handshake → handle messages until close.
38035
38192
  */
38036
38193
  connectOnce() {
38037
- return new Promise((resolve8, reject) => {
38194
+ return new Promise((resolve9, reject) => {
38038
38195
  void (async () => {
38039
38196
  this.sessionEstablished = false;
38040
38197
  this.bus.setStatus("connecting");
@@ -38128,7 +38285,7 @@ var WsClient = class {
38128
38285
  if (code === CLOSE_DRAINING) {
38129
38286
  this.bus.log("Server draining \u2014 will reconnect (backoff + jitter).");
38130
38287
  }
38131
- resolve8();
38288
+ resolve9();
38132
38289
  });
38133
38290
  socket.on("error", (err) => {
38134
38291
  this.clearHeartbeat();
@@ -38285,7 +38442,8 @@ var WsClient = class {
38285
38442
  dispatch.commandId,
38286
38443
  "server",
38287
38444
  dispatch.aiOneShot ?? false,
38288
- dispatch.images
38445
+ dispatch.images,
38446
+ dispatch.aiConfig
38289
38447
  );
38290
38448
  }
38291
38449
  break;
@@ -38341,6 +38499,13 @@ var WsClient = class {
38341
38499
  );
38342
38500
  break;
38343
38501
  }
38502
+ case WsChannels.FS_MUTATE: {
38503
+ const req = payload;
38504
+ void mutateFs(this.physicRoot, req).then(
38505
+ (reply) => this.send(WsChannels.FS_MUTATE, reply, message.id)
38506
+ );
38507
+ break;
38508
+ }
38344
38509
  case WsChannels.SUPPORT_ANSWER: {
38345
38510
  const req = payload;
38346
38511
  const supportConfig = readProfileConfig(this.context.profileDir);
@@ -38775,7 +38940,7 @@ var WsClient = class {
38775
38940
  * exactly like typing the prompt in the cli (tries profiles, meters real tokens) instead
38776
38941
  * of spawning the text as a raw command. Streams output to the transcript AND the server.
38777
38942
  */
38778
- async runAiPrompt(prompt, commandId, origin, oneShot = false, images) {
38943
+ async runAiPrompt(prompt, commandId, origin, oneShot = false, images, aiConfig) {
38779
38944
  const config = readProfileConfig(this.context.profileDir);
38780
38945
  const projectTimeoutSec = config.projectAiRunTimeoutSec ?? 0;
38781
38946
  const machineTimeoutSec = config.aiRunTimeoutSec ?? 0;
@@ -38847,7 +39012,7 @@ var WsClient = class {
38847
39012
  const guardedPrompt = this.restrictToFolder && this.physicRoot ? folderScopeGuard(this.physicRoot, aiBodyPrompt) : aiBodyPrompt;
38848
39013
  const hint = unified ? { credential: startCred ?? workingCred } : { dir: startDir ?? workingDir };
38849
39014
  const memCfg = resolveMemoryConfig(config);
38850
- const firstAttempt = planAiRun(guardedPrompt, config, hint).attempts[0];
39015
+ const firstAttempt = planAiRun(guardedPrompt, config, hint, /* @__PURE__ */ new Map(), oneShot, aiConfig).attempts[0];
38851
39016
  const resumeId = memCfg.enabled && firstAttempt?.key && firstAttempt.cmd === "claude" ? this.sessionIdByKey.get(firstAttempt.key) : void 0;
38852
39017
  let effectivePrompt = guardedPrompt;
38853
39018
  let resume = /* @__PURE__ */ new Map();
@@ -38859,7 +39024,7 @@ ${this.aiMemory}
38859
39024
 
38860
39025
  ${guardedPrompt}`;
38861
39026
  }
38862
- const plan = planAiRun(effectivePrompt, config, hint, resume, oneShot);
39027
+ const plan = planAiRun(effectivePrompt, config, hint, resume, oneShot, aiConfig);
38863
39028
  const markerArgs = plan.attempts[0]?.args ?? [];
38864
39029
  const startStamp = formatTimestampInZone(/* @__PURE__ */ new Date(), this.orgTimezone);
38865
39030
  this.bus.push({ source: origin, kind: "aireq", text: `${startStamp} ${plan.cmd} \u2039 ${prompt}` });
@@ -39068,7 +39233,7 @@ ${guardedPrompt}`;
39068
39233
  const info = {
39069
39234
  version: CLI_VERSION,
39070
39235
  scope: this.bus.scope ?? "project",
39071
- profile: basename4(this.context.profileDir),
39236
+ profile: basename5(this.context.profileDir),
39072
39237
  profileDir: this.context.profileDir,
39073
39238
  serverUrl: this.context.credential.serverUrl,
39074
39239
  physicPath: this.physicRoot ?? config.physicPath ?? null,
@@ -39398,7 +39563,7 @@ ${guardedPrompt}`;
39398
39563
  * Used for quota.check before spawning an AI cli (ADR-0020).
39399
39564
  */
39400
39565
  request(channel, data) {
39401
- return new Promise((resolve8, reject) => {
39566
+ return new Promise((resolve9, reject) => {
39402
39567
  if (!this.socket || !this.sessionKey) {
39403
39568
  reject(new Error("Not connected to the server."));
39404
39569
  return;
@@ -39418,7 +39583,7 @@ ${guardedPrompt}`;
39418
39583
  }, 15e3);
39419
39584
  timer.unref?.();
39420
39585
  this.pending.set(envelope.id, {
39421
- resolve: (value) => resolve8(value),
39586
+ resolve: (value) => resolve9(value),
39422
39587
  timer
39423
39588
  });
39424
39589
  this.socket.send(JSON.stringify(envelope));
@@ -39544,7 +39709,7 @@ ${guardedPrompt}`;
39544
39709
  const working = getWorkingProfile(this.context.profileDir, aiCli2);
39545
39710
  const configured = claudeHomeDirs(config);
39546
39711
  const dirs = working ? [working, ...configured.filter((d) => d !== working)] : configured;
39547
- const profile = working ? basename4(working) : dirs[0] ? basename4(dirs[0]) : "default";
39712
+ const profile = working ? basename5(working) : dirs[0] ? basename5(dirs[0]) : "default";
39548
39713
  const api = await checkClaudeUsage(dirs, aiCli2);
39549
39714
  const snapshot = api ?? {
39550
39715
  plan: "?",
@@ -42003,7 +42168,7 @@ var src_default = Yoga;
42003
42168
 
42004
42169
  // ../../node_modules/.pnpm/ink@5.2.1_@types+react@18.3.31_react@18.3.1/node_modules/ink/build/reconciler.js
42005
42170
  var import_react_reconciler = __toESM(require_react_reconciler(), 1);
42006
- var import_constants7 = __toESM(require_constants2(), 1);
42171
+ var import_constants8 = __toESM(require_constants2(), 1);
42007
42172
  import process3 from "process";
42008
42173
 
42009
42174
  // ../../node_modules/.pnpm/ansi-regex@6.2.2/node_modules/ansi-regex/index.js
@@ -43245,7 +43410,7 @@ var reconciler_default = (0, import_react_reconciler.default)({
43245
43410
  scheduleTimeout: setTimeout,
43246
43411
  cancelTimeout: clearTimeout,
43247
43412
  noTimeout: -1,
43248
- getCurrentEventPriority: () => import_constants7.DefaultEventPriority,
43413
+ getCurrentEventPriority: () => import_constants8.DefaultEventPriority,
43249
43414
  beforeActiveInstanceBlur() {
43250
43415
  },
43251
43416
  afterActiveInstanceBlur() {
@@ -45319,8 +45484,8 @@ var Ink = class {
45319
45484
  }
45320
45485
  }
45321
45486
  async waitUntilExit() {
45322
- this.exitPromise ||= new Promise((resolve8, reject) => {
45323
- this.resolveExitPromise = resolve8;
45487
+ this.exitPromise ||= new Promise((resolve9, reject) => {
45488
+ this.resolveExitPromise = resolve9;
45324
45489
  this.rejectExitPromise = reject;
45325
45490
  });
45326
45491
  return this.exitPromise;
@@ -46381,7 +46546,7 @@ async function runStart(profileDir2, profileName) {
46381
46546
  logger.error("ws.run.crash", { message: e.message, stack: e.stack });
46382
46547
  if (client.isStopped) return;
46383
46548
  bus.log(`Recovered from an internal error \u2014 reconnecting: ${e.message}`, "error");
46384
- await new Promise((resolve8) => setTimeout(resolve8, 1e3));
46549
+ await new Promise((resolve9) => setTimeout(resolve9, 1e3));
46385
46550
  }
46386
46551
  }
46387
46552
  };
@@ -46427,7 +46592,7 @@ import { join as join31 } from "path";
46427
46592
  // src/core/control-client.ts
46428
46593
  import { connect as connect2 } from "net";
46429
46594
  function connectControl(socketPath, bus) {
46430
- return new Promise((resolve8, reject) => {
46595
+ return new Promise((resolve9, reject) => {
46431
46596
  const socket = connect2(socketPath);
46432
46597
  socket.setEncoding("utf8");
46433
46598
  let ready = false;
@@ -46474,7 +46639,7 @@ function connectControl(socketPath, bus) {
46474
46639
  bus.setTokens(frame.tokens);
46475
46640
  for (const entry of frame.transcript) bus.pushEntry(entry);
46476
46641
  ready = true;
46477
- resolve8({ info: frame.info, close });
46642
+ resolve9({ info: frame.info, close });
46478
46643
  break;
46479
46644
  case "transcript":
46480
46645
  bus.pushEntry(frame.entry);
@@ -46555,18 +46720,18 @@ async function runAttach(profileDir2, profileName) {
46555
46720
  // src/commands/ai-login.ts
46556
46721
  import { spawn as spawn11 } from "child_process";
46557
46722
  import { mkdirSync as mkdirSync7 } from "fs";
46558
- import { basename as basename5 } from "path";
46723
+ import { basename as basename6 } from "path";
46559
46724
  function runProviderLogin(cmd, envVar, dir2) {
46560
- return new Promise((resolve8) => {
46725
+ return new Promise((resolve9) => {
46561
46726
  const child = spawn11(cmd, [], {
46562
46727
  stdio: "inherit",
46563
46728
  env: { ...process.env, [envVar]: dir2 }
46564
46729
  });
46565
46730
  child.on("error", (err) => {
46566
46731
  console.error(` \u2716 Could not launch \`${cmd}\` \u2014 is it installed? (${err.message})`);
46567
- resolve8(1);
46732
+ resolve9(1);
46568
46733
  });
46569
- child.on("exit", (code) => resolve8(code ?? 0));
46734
+ child.on("exit", (code) => resolve9(code ?? 0));
46570
46735
  });
46571
46736
  }
46572
46737
  async function runAiLogin(profileDir2, profileName, aiFilter) {
@@ -46579,7 +46744,7 @@ async function runAiLogin(profileDir2, profileName, aiFilter) {
46579
46744
  return;
46580
46745
  }
46581
46746
  const selected = aiFilter ? credentials.filter(
46582
- (c, i) => c.profile === aiFilter || basename5(resolveHomePath(c.profile)) === aiFilter || String(i + 1) === aiFilter
46747
+ (c, i) => c.profile === aiFilter || basename6(resolveHomePath(c.profile)) === aiFilter || String(i + 1) === aiFilter
46583
46748
  ) : credentials;
46584
46749
  if (selected.length === 0) {
46585
46750
  console.log(`No AI profile matches --ai "${aiFilter}". Available: ${credentials.map((c) => c.profile).join(", ")}`);
@@ -46712,10 +46877,10 @@ function Picker({
46712
46877
  ] });
46713
46878
  }
46714
46879
  function selectFromList(items, title) {
46715
- return new Promise((resolve8) => {
46880
+ return new Promise((resolve9) => {
46716
46881
  let chosen = null;
46717
46882
  const app = render_default(/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Picker, { items, title, onDone: (v) => chosen = v }));
46718
- void app.waitUntilExit().then(() => resolve8(chosen));
46883
+ void app.waitUntilExit().then(() => resolve9(chosen));
46719
46884
  });
46720
46885
  }
46721
46886