billion-context-pi 0.1.39 → 0.1.41

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.
@@ -81,6 +81,11 @@ export declare function makeEventApplier(opts: {
81
81
  onUsage?: (usage: Usage) => void;
82
82
  onSettled?: () => void;
83
83
  }, writers: EventApplierWriters): EventApplier;
84
+ /** Resolve a wait timeout to ms. Agents frequently pass seconds (e.g. 180)
85
+ * instead of milliseconds; values below the 1s floor make no sense as a wait
86
+ * duration, so rescale them to seconds before clamping — otherwise 180 clamps
87
+ * to 1000ms and the wait times out in 1s. */
88
+ export declare function resolveWaitTimeoutMs(raw: number | undefined): number;
84
89
  declare const DelegateParams: Type.TObject<{
85
90
  agent: Type.TString;
86
91
  task: Type.TString;
package/dist/index.js CHANGED
@@ -2828,6 +2828,19 @@ function clamp(v, lo, hi) {
2828
2828
  return v < lo ? lo : v > hi ? hi : v;
2829
2829
  }
2830
2830
 
2831
+ // src/tag-tokens.ts
2832
+ function formatTokens3(tokens) {
2833
+ if (tokens < 1e3) return String(tokens);
2834
+ if (tokens < 1e4) return `${(tokens / 1e3).toFixed(1)}K`;
2835
+ return `${Math.round(tokens / 1e3)}K`;
2836
+ }
2837
+ function stableTagTokens(text) {
2838
+ return formatTokens3(defaultCountTokens(text));
2839
+ }
2840
+ function rewriteTagTokens(tag, body) {
2841
+ return tag.replace(/tokens="[^"]*"/, `tokens="${stableTagTokens(body)}"`);
2842
+ }
2843
+
2831
2844
  // src/messages.ts
2832
2845
  var REF_TAG_SOURCE = "(?:<acp\\s[^>]*>m\\d{5}</acp>|\\[m\\d{1,5}\\])";
2833
2846
  var REF_TAG = new RegExp(`^${REF_TAG_SOURCE}\\s?\\n?`);
@@ -3037,6 +3050,7 @@ function reconstructToolCallMessage(original, firstCore, survivingCallIds) {
3037
3050
  return true;
3038
3051
  });
3039
3052
  const peeled = peelRefTagBlocks(filtered);
3053
+ const stableTag = rewriteTagTokens(tag, coreBodyOf(firstCore.text ?? "", tag));
3040
3054
  const lastTextIdx = [...peeled].reverse().findIndex((b) => b.type === "text");
3041
3055
  if (lastTextIdx >= 0) {
3042
3056
  const idx = peeled.length - 1 - lastTextIdx;
@@ -3044,10 +3058,16 @@ function reconstructToolCallMessage(original, firstCore, survivingCallIds) {
3044
3058
  const baseText = lastBlock.text ?? "";
3045
3059
  peeled[idx] = { ...lastBlock, text: baseText.length > 0 ? `${baseText}
3046
3060
 
3047
- ${tag}` : tag };
3061
+ ${stableTag}` : stableTag };
3048
3062
  return { ...original, content: peeled };
3049
3063
  }
3050
- return { ...original, content: [{ type: "text", text: tag }, ...peeled] };
3064
+ return { ...original, content: [{ type: "text", text: stableTag }, ...peeled] };
3065
+ }
3066
+ function coreBodyOf(coreText, tag) {
3067
+ const tagCore = tag.replace(/\s+$/, "");
3068
+ let bodyStart = tagCore.length;
3069
+ if (coreText.charAt(bodyStart) === "\n") bodyStart += 1;
3070
+ return coreText.slice(bodyStart);
3051
3071
  }
3052
3072
  function patchRefTag(original, core) {
3053
3073
  const match = core.text ? core.text.match(REF_TAG) : null;
@@ -3055,15 +3075,13 @@ function patchRefTag(original, core) {
3055
3075
  if (!tag) return original;
3056
3076
  const base = original;
3057
3077
  if (base.role === "assistant") return original;
3058
- const tagCore = tag.replace(/\s+$/, "");
3059
- let bodyStart = tagCore.length;
3060
- if (core.text && core.text.charAt(bodyStart) === "\n") bodyStart += 1;
3061
- const coreBody = core.text ? core.text.slice(bodyStart) : "";
3078
+ const coreBody = coreBodyOf(core.text ?? "", tag);
3062
3079
  const originalBody = extractText(base.content);
3063
3080
  const trimEnd = (s) => s.replace(/\s+$/, "");
3064
3081
  if (coreBody && trimEnd(coreBody) !== trimEnd(originalBody)) {
3065
- return rebuildBodyFromCore(original, coreBody, tag);
3082
+ return rebuildBodyFromCore(original, coreBody, rewriteTagTokens(tag, coreBody));
3066
3083
  }
3084
+ const stableTag = rewriteTagTokens(tag, originalBody);
3067
3085
  const rawBlocks = Array.isArray(base.content) ? base.content : typeof base.content === "string" ? [{ type: "text", text: base.content }] : [];
3068
3086
  const peeled = peelRefTagBlocks(rawBlocks);
3069
3087
  const newBlocks = [...peeled];
@@ -3074,7 +3092,7 @@ function patchRefTag(original, core) {
3074
3092
  const baseText = b.text.replace(/\n*$/, "");
3075
3093
  newBlocks[i] = { ...b, text: `${baseText}
3076
3094
 
3077
- ${tag}` };
3095
+ ${stableTag}` };
3078
3096
  injected = true;
3079
3097
  break;
3080
3098
  }
@@ -3084,7 +3102,7 @@ ${tag}` };
3084
3102
  }
3085
3103
  return {
3086
3104
  ...original,
3087
- content: [...peeled, { type: "text", text: tag }]
3105
+ content: [...peeled, { type: "text", text: stableTag }]
3088
3106
  };
3089
3107
  }
3090
3108
  function rebuildBodyFromCore(original, coreBody, tag) {
@@ -3341,6 +3359,64 @@ function mergeInitialState(parsed) {
3341
3359
  };
3342
3360
  }
3343
3361
 
3362
+ // src/user-config.ts
3363
+ import { promises as fs2 } from "fs";
3364
+ import * as path3 from "path";
3365
+ import { homedir as homedir2 } from "os";
3366
+ import { CONFIG_DIR_NAME as CONFIG_DIR_NAME2 } from "@earendil-works/pi-coding-agent";
3367
+ async function loadUserConfig(cwd) {
3368
+ const home = homedir2();
3369
+ const merged = {};
3370
+ for (const base of [join4(home, CONFIG_DIR_NAME2), join4(cwd, CONFIG_DIR_NAME2)]) {
3371
+ const file = join4(base, "acp.json");
3372
+ try {
3373
+ const raw = await fs2.readFile(file, "utf8");
3374
+ const parsed = JSON.parse(raw);
3375
+ if (parsed && typeof parsed === "object") {
3376
+ Object.assign(merged, pickKnown(parsed));
3377
+ debug.event("config-loaded", { file });
3378
+ }
3379
+ } catch (e) {
3380
+ const code = e.code;
3381
+ if (code !== "ENOENT") {
3382
+ logWarn("config", { event: "load-failed", file, error: e instanceof Error ? e.message : String(e) });
3383
+ }
3384
+ }
3385
+ }
3386
+ return merged;
3387
+ }
3388
+ function join4(...parts) {
3389
+ return path3.join(...parts);
3390
+ }
3391
+ var KNOWN = /* @__PURE__ */ new Set([
3392
+ "debug",
3393
+ "autoUpdate",
3394
+ "modelContextLimit",
3395
+ "toolBashDefaultTimeout",
3396
+ "toolOutputMaxBytes",
3397
+ "delegate",
3398
+ "compress",
3399
+ "displayUsage",
3400
+ "prompts",
3401
+ "acknowledgePromptsRisk"
3402
+ ]);
3403
+ function pickKnown(parsed) {
3404
+ const out = {};
3405
+ for (const [k, v] of Object.entries(parsed)) {
3406
+ if (KNOWN.has(k)) out[k] = v;
3407
+ }
3408
+ return out;
3409
+ }
3410
+ function applyUserConfig(adapter, user) {
3411
+ return {
3412
+ ...adapter,
3413
+ ...user,
3414
+ coreOverrides: adapter.coreOverrides,
3415
+ protectedTools: adapter.protectedTools,
3416
+ preserveRecentMessages: adapter.preserveRecentMessages
3417
+ };
3418
+ }
3419
+
3344
3420
  // src/sequence-match.ts
3345
3421
  function findUniqueLongestRun(candidates, live) {
3346
3422
  if (candidates.length === 0 || live.length === 0) return void 0;
@@ -3565,7 +3641,9 @@ function createRuntime(adapter) {
3565
3641
  const store = new SessionStateStore();
3566
3642
  const lastActiveBlockIds = /* @__PURE__ */ new Map();
3567
3643
  const locks = /* @__PURE__ */ new Map();
3644
+ const factoryAdapter = adapter;
3568
3645
  let adapterRef = adapter;
3646
+ let lastUserConfigKey;
3569
3647
  let promptsRef = defaultPrompts;
3570
3648
  const nudgeShownTurns = /* @__PURE__ */ new Set();
3571
3649
  async function acquireLock(sid) {
@@ -3591,6 +3669,25 @@ function createRuntime(adapter) {
3591
3669
  const m = ctx.model;
3592
3670
  return resolveConfig(adapterRef, liveContextLimit(ctx), m?.provider, m?.id);
3593
3671
  }
3672
+ async function reloadConfig(cwd) {
3673
+ let user;
3674
+ try {
3675
+ user = await loadUserConfig(cwd);
3676
+ } catch (e) {
3677
+ logWarn("runtime", { event: "config-reload-failed", error: e instanceof Error ? e.message : String(e) });
3678
+ return;
3679
+ }
3680
+ try {
3681
+ const key = JSON.stringify(user);
3682
+ if (key === lastUserConfigKey) return;
3683
+ lastUserConfigKey = key;
3684
+ adapterRef = applyUserConfig(factoryAdapter, user);
3685
+ if (adapterRef.debug !== void 0) setDebugEnabled(adapterRef.debug);
3686
+ logInfo("runtime", { event: "config-reloaded", limit: adapterRef.modelContextLimit ?? null });
3687
+ } catch (e) {
3688
+ logWarn("runtime", { event: "config-reload-failed", error: e instanceof Error ? e.message : String(e) });
3689
+ }
3690
+ }
3594
3691
  async function stateFor(ctx, liveMessages) {
3595
3692
  const sm = ctx.sessionManager;
3596
3693
  const sessionFile = sm.getSessionFile() ?? void 0;
@@ -3626,8 +3723,6 @@ function createRuntime(adapter) {
3626
3723
  countModelId = m;
3627
3724
  }, noteActiveBlocks, clearSessionTracking, get adapter() {
3628
3725
  return adapterRef;
3629
- }, setAdapter: (a) => {
3630
- adapterRef = a;
3631
3726
  }, get prompts() {
3632
3727
  return promptsRef;
3633
3728
  }, setPrompts: (p) => {
@@ -3636,7 +3731,7 @@ function createRuntime(adapter) {
3636
3731
  nudgeShownTurns.add(k);
3637
3732
  }, nudgeShownFor: (k) => nudgeShownTurns.has(k), clearNudgeTracking: () => {
3638
3733
  nudgeShownTurns.clear();
3639
- }, liveContextLimit, configFor, stateFor, save, acquireLock };
3734
+ }, liveContextLimit, configFor, reloadConfig, stateFor, save, acquireLock };
3640
3735
  }
3641
3736
 
3642
3737
  // node_modules/typebox/build/system/memory/memory.mjs
@@ -8159,7 +8254,14 @@ async function handleCompress(args, runtime, ctx, toolCallId) {
8159
8254
  });
8160
8255
  await runtime.save(applied.state, ctx);
8161
8256
  const { blocksCreated, tokensCompressed, errors, warnings } = applied.result;
8162
- const afterTokens = Math.max(0, beforeTokens - tokensCompressed);
8257
+ const afterTurn = runtime.core.processTurn({
8258
+ messages: coreMessages,
8259
+ state: applied.state,
8260
+ config,
8261
+ tokenCount: calibrateTokens(sentTokens, density)
8262
+ });
8263
+ const afterTokens = calibrateTokens(estimateTokens(afterTurn.messages, collectCoveredMessageIds(applied.state)), density);
8264
+ const reclaimed = Math.max(0, beforeTokens - afterTokens);
8163
8265
  const newBlocks = applied.state.blocks.slice(-blocksCreated);
8164
8266
  debug.event("compress-out", {
8165
8267
  sid: ctx.sessionManager.getSessionId(),
@@ -8190,9 +8292,9 @@ async function handleCompress(args, runtime, ctx, toolCallId) {
8190
8292
  logError("compress", { sid: ctx.sessionManager.getSessionId(), event: "errors", count: errors.length, errors: errors.slice(0, 5) });
8191
8293
  }
8192
8294
  if (warnings.length > 0) {
8193
- logError("compress", { sid: ctx.sessionManager.getSessionId(), event: "warnings", count: warnings.length, warnings: warnings.slice(0, 5) });
8295
+ logWarn("compress", { sid: ctx.sessionManager.getSessionId(), event: "warnings", count: warnings.length, warnings: warnings.slice(0, 5) });
8194
8296
  }
8195
- const lines = [`\u25A3 ACP | ${formatK2(beforeTokens)} \u2192 ${formatK2(afterTokens)} tokens (~${formatK2(tokensCompressed)} reclaimed, ${blocksCreated} block${blocksCreated > 1 ? "s" : ""})`];
8297
+ const lines = [`\u25A3 ACP | ${formatK2(beforeTokens)} \u2192 ${formatK2(afterTokens)} tokens (~${formatK2(reclaimed)} reclaimed, ${blocksCreated} block${blocksCreated > 1 ? "s" : ""})`];
8196
8298
  if (warnings.length > 0) lines.push("\u26A0\uFE0F " + warnings.join("; "));
8197
8299
  if (errors.length > 0) lines.push("Errors: " + errors.join("; "));
8198
8300
  return lines.join("\n");
@@ -8201,9 +8303,9 @@ async function handleCompress(args, runtime, ctx, toolCallId) {
8201
8303
  // src/decompress-tool.ts
8202
8304
  import { writeFile, mkdir } from "fs/promises";
8203
8305
  import { existsSync as existsSync2, lstatSync, readlinkSync, realpathSync } from "fs";
8204
- import { resolve, relative, isAbsolute, join as join3, basename as basename2, dirname as dirname3 } from "path";
8205
- import { tmpdir, homedir as homedir2 } from "os";
8206
- var AUTO_DIR = join3(homedir2() || tmpdir(), ".cache", "pi", "acp-decompress");
8306
+ import { resolve, relative, isAbsolute, join as join5, basename as basename2, dirname as dirname3 } from "path";
8307
+ import { tmpdir, homedir as homedir3 } from "os";
8308
+ var AUTO_DIR = join5(homedir3() || tmpdir(), ".cache", "pi", "acp-decompress");
8207
8309
  var PREVIEW_CHARS = 600;
8208
8310
  var MESSAGE_INLINE_THRESHOLD = 2e3;
8209
8311
  var DecompressParams = typebox_exports.Object({
@@ -8239,11 +8341,11 @@ function makeDecompressTool(runtime) {
8239
8341
  }
8240
8342
  var ALLOWED_DIRS = [
8241
8343
  tmpdir(),
8242
- join3(homedir2(), ".cache", "opencode"),
8243
- join3(homedir2(), ".cache", "pi")
8344
+ join5(homedir3(), ".cache", "opencode"),
8345
+ join5(homedir3(), ".cache", "pi")
8244
8346
  ];
8245
8347
  function resolveToFilePath(targetPath) {
8246
- const expanded = targetPath.startsWith("~/") ? join3(homedir2(), targetPath.slice(2)) : targetPath;
8348
+ const expanded = targetPath.startsWith("~/") ? join5(homedir3(), targetPath.slice(2)) : targetPath;
8247
8349
  const resolved = resolve(expanded);
8248
8350
  let probe = resolved;
8249
8351
  const suffix = [];
@@ -8254,7 +8356,7 @@ function resolveToFilePath(targetPath) {
8254
8356
  const real = existsSync2(probe) ? realpathSync(probe) : probe;
8255
8357
  let checked = real;
8256
8358
  for (const part of suffix) {
8257
- checked = join3(checked, part);
8359
+ checked = join5(checked, part);
8258
8360
  try {
8259
8361
  if (lstatSync(checked).isSymbolicLink()) {
8260
8362
  const target = readlinkSync(checked);
@@ -8280,7 +8382,7 @@ function resolveToFilePath(targetPath) {
8280
8382
  return checked;
8281
8383
  }
8282
8384
  function autoFilePath(blockId) {
8283
- return join3(AUTO_DIR, `${blockId}-${Date.now()}.txt`);
8385
+ return join5(AUTO_DIR, `${blockId}-${Date.now()}.txt`);
8284
8386
  }
8285
8387
  function headPreview(text) {
8286
8388
  if (text.length <= PREVIEW_CHARS) return text;
@@ -8627,7 +8729,7 @@ import {
8627
8729
  import { createWriteStream, existsSync as existsSync3 } from "fs";
8628
8730
  import { mkdir as mkdir2, mkdtemp, writeFile as writeFile2, rm, appendFile } from "fs/promises";
8629
8731
  import { tmpdir as tmpdir2 } from "os";
8630
- import { dirname as dirname4, join as join4, resolve as resolvePath } from "path";
8732
+ import { dirname as dirname4, join as join6, resolve as resolvePath } from "path";
8631
8733
 
8632
8734
  // src/footer-status.ts
8633
8735
  var FOOTER_STATUS_KEY = "billion-context-pi";
@@ -9031,7 +9133,7 @@ var IDLE_GRACE_MS = 5 * 6e4;
9031
9133
  var ASYNC_TIMEOUT_MS = 30 * 6e4;
9032
9134
  var KILL_GRACE_MS = 1e4;
9033
9135
  var RESULT_SUMMARY_CHARS = 500;
9034
- var OUT_DIR = join4(tmpdir2(), "acp-delegate");
9136
+ var OUT_DIR = join6(tmpdir2(), "acp-delegate");
9035
9137
  function delegateSpawnOptions(cwd, env) {
9036
9138
  return {
9037
9139
  cwd,
@@ -9041,11 +9143,11 @@ function delegateSpawnOptions(cwd, env) {
9041
9143
  };
9042
9144
  }
9043
9145
  var PI_CLI_ENTRY_RE = /[\\/]pi-coding-agent[\\/]dist[\\/]cli\.js$/;
9044
- var PI_PACKAGE_REL = join4("@earendil-works", "pi-coding-agent", "dist", "cli.js");
9146
+ var PI_PACKAGE_REL = join6("@earendil-works", "pi-coding-agent", "dist", "cli.js");
9045
9147
  function probeUpFromArgv(argv1) {
9046
9148
  let dir = resolvePath(dirname4(argv1) || process.cwd());
9047
9149
  for (; ; ) {
9048
- const candidate = join4(dir, "node_modules", PI_PACKAGE_REL);
9150
+ const candidate = join6(dir, "node_modules", PI_PACKAGE_REL);
9049
9151
  if (existsSync3(candidate)) return candidate;
9050
9152
  const parent = dirname4(dir);
9051
9153
  if (parent === dir) return null;
@@ -9055,12 +9157,12 @@ function probeUpFromArgv(argv1) {
9055
9157
  function piCliGlobalCandidates(env) {
9056
9158
  const candidates = [];
9057
9159
  if (process.platform === "win32") {
9058
- if (env.APPDATA) candidates.push(join4(env.APPDATA, "npm", "node_modules", PI_PACKAGE_REL));
9160
+ if (env.APPDATA) candidates.push(join6(env.APPDATA, "npm", "node_modules", PI_PACKAGE_REL));
9059
9161
  } else {
9060
9162
  const home = env.HOME ?? env.USERPROFILE;
9061
- if (home) candidates.push(join4(home, ".local", "lib", "node_modules", PI_PACKAGE_REL));
9062
- candidates.push(join4("/usr/local", "lib", "node_modules", PI_PACKAGE_REL));
9063
- candidates.push(join4("/usr", "lib", "node_modules", PI_PACKAGE_REL));
9163
+ if (home) candidates.push(join6(home, ".local", "lib", "node_modules", PI_PACKAGE_REL));
9164
+ candidates.push(join6("/usr/local", "lib", "node_modules", PI_PACKAGE_REL));
9165
+ candidates.push(join6("/usr", "lib", "node_modules", PI_PACKAGE_REL));
9064
9166
  }
9065
9167
  return candidates;
9066
9168
  }
@@ -9212,6 +9314,11 @@ function makeEventApplier(opts, writers) {
9212
9314
  }
9213
9315
  var WAIT_TIMEOUT_MS_DEFAULT = 1e4;
9214
9316
  var WAIT_TIMEOUT_MS_MAX = 3e5;
9317
+ function resolveWaitTimeoutMs(raw) {
9318
+ if (raw === void 0) return WAIT_TIMEOUT_MS_DEFAULT;
9319
+ const ms = raw < 1e3 ? raw * 1e3 : raw;
9320
+ return Math.min(Math.max(ms, 1e3), WAIT_TIMEOUT_MS_MAX);
9321
+ }
9215
9322
  var DelegateParams = typebox_exports.Object({
9216
9323
  agent: typebox_exports.String({
9217
9324
  description: `Role of the delegate. One of: ${AGENT_NAMES.join(", ")}. See tool description for what each does.`
@@ -9243,7 +9350,7 @@ var WaitParams = typebox_exports.Object({
9243
9350
  runId: typebox_exports.String({ description: "The runId returned by acp_delegate to wait for." }),
9244
9351
  timeout: typebox_exports.Optional(
9245
9352
  typebox_exports.Integer({
9246
- description: `Maximum milliseconds to block waiting for the result. Default ${WAIT_TIMEOUT_MS_DEFAULT} (10s); max ${WAIT_TIMEOUT_MS_MAX} (300s). If the delegate does not finish in time, returns "failed (not ready)" \u2014 do NOT keep waiting or retry; go do other work, and a completion notification will still be injected when it completes.`
9353
+ description: `Maximum time to block waiting for the result, in milliseconds. Default ${WAIT_TIMEOUT_MS_DEFAULT} (10s); max ${WAIT_TIMEOUT_MS_MAX} (300s). Values below 1000 are treated as seconds (so 180 means 180s, not 180ms). If the delegate does not finish in time, returns "failed (not ready)" \u2014 do NOT keep waiting or retry; go do other work, and a completion notification will still be injected when it completes.`
9247
9354
  })
9248
9355
  )
9249
9356
  });
@@ -9402,10 +9509,7 @@ function makeDelegateWaitTool(_pi) {
9402
9509
  }
9403
9510
  return buildWaitResult(run, formatRunResult(run), displayMode);
9404
9511
  }
9405
- const timeoutMs = Math.min(
9406
- Math.max(args.timeout ?? WAIT_TIMEOUT_MS_DEFAULT, 1e3),
9407
- WAIT_TIMEOUT_MS_MAX
9408
- );
9512
+ const timeoutMs = resolveWaitTimeoutMs(args.timeout);
9409
9513
  if (run.waiter) {
9410
9514
  return { details: void 0, content: [{ type: "text", text: `Delegate \`${args.runId}\` already has a wait in progress; do not wait on it twice.` }] };
9411
9515
  }
@@ -9526,8 +9630,8 @@ async function runDelegate(pi, args, ctx, signal) {
9526
9630
  },
9527
9631
  { eofGraceMs: EOF_GRACE_MS, idleMs: IDLE_GRACE_MS, timeoutMs: ASYNC_TIMEOUT_MS, killGraceMs: KILL_GRACE_MS }
9528
9632
  );
9529
- const replyFile = join4(OUT_DIR, `${runId}.out`);
9530
- const activityFile = join4(OUT_DIR, `${runId}.activity`);
9633
+ const replyFile = join6(OUT_DIR, `${runId}.out`);
9634
+ const activityFile = join6(OUT_DIR, `${runId}.activity`);
9531
9635
  await mkdir2(OUT_DIR, { recursive: true });
9532
9636
  const replyStream = createWriteStream(replyFile, { flags: "a" });
9533
9637
  const activityStream = useJsonStream ? createWriteStream(activityFile, { flags: "a" }) : null;
@@ -9677,8 +9781,8 @@ async function runDelegate(pi, args, ctx, signal) {
9677
9781
  return formatSyncResult(args.agent, runId, args.task, result, file);
9678
9782
  }
9679
9783
  async function buildChildArgs(args, rolePrompt, ctx) {
9680
- const tmpDir = await mkdtemp(join4(tmpdir2(), "acp-delegate-"));
9681
- const promptFile = join4(tmpDir, "role.md");
9784
+ const tmpDir = await mkdtemp(join6(tmpdir2(), "acp-delegate-"));
9785
+ const promptFile = join6(tmpDir, "role.md");
9682
9786
  await writeFile2(promptFile, `${rolePrompt}
9683
9787
 
9684
9788
  ---
@@ -9815,7 +9919,7 @@ async function persistResult(runId, body) {
9815
9919
  await mkdir2(OUT_DIR, { recursive: true });
9816
9920
  } catch {
9817
9921
  }
9818
- const file = join4(OUT_DIR, `${runId}.out`);
9922
+ const file = join6(OUT_DIR, `${runId}.out`);
9819
9923
  try {
9820
9924
  await writeFile2(file, body, "utf8");
9821
9925
  return file;
@@ -10002,7 +10106,7 @@ async function statusReport(runtime, ctx) {
10002
10106
  const modelId = ctx.model?.id ?? "default";
10003
10107
  const sentTokens = estimateTokens(coreMessages, coveredIds) + systemPromptTokens;
10004
10108
  const turn = runtime.core.processTurn({ messages: coreMessages, state, config, tokenCount: calibrateTokens(sentTokens, runtime.density.densityFor(modelId)) });
10005
- const versionStr = "0.1.39" ? `billion-context-pi@${"0.1.39"}` : void 0;
10109
+ const versionStr = "0.1.41" ? `billion-context-pi@${"0.1.41"}` : void 0;
10006
10110
  let text = buildStatusPanel({
10007
10111
  version: versionStr,
10008
10112
  tokenCount: sessionTokens,
@@ -10215,16 +10319,16 @@ function wireToolGuardrails(pi, runtime) {
10215
10319
 
10216
10320
  // src/update.ts
10217
10321
  import { readFile, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
10218
- import { join as join5, dirname as dirname5 } from "path";
10322
+ import { join as join7, dirname as dirname5 } from "path";
10219
10323
  import { fileURLToPath } from "url";
10220
10324
  import { execFile } from "child_process";
10221
- import { homedir as homedir3 } from "os";
10222
- import { CONFIG_DIR_NAME as CONFIG_DIR_NAME2 } from "@earendil-works/pi-coding-agent";
10325
+ import { homedir as homedir4 } from "os";
10326
+ import { CONFIG_DIR_NAME as CONFIG_DIR_NAME3 } from "@earendil-works/pi-coding-agent";
10223
10327
  var PACKAGE_NAME = "billion-context-pi";
10224
10328
  var REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
10225
10329
  var SEMVER_RE = /^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/;
10226
10330
  var CHECK_INTERVAL_MS = 3 * 60 * 1e3;
10227
- var THROTTLE_FILE = join5(homedir3(), CONFIG_DIR_NAME2, "agent", ".billion-context-pi-update-check");
10331
+ var THROTTLE_FILE = join7(homedir4(), CONFIG_DIR_NAME3, "agent", ".billion-context-pi-update-check");
10228
10332
  var updateInFlight = false;
10229
10333
  function parseVersion(v) {
10230
10334
  return v.replace(/^v/, "").split(".").map((n) => parseInt(n, 10) || 0);
@@ -10273,7 +10377,7 @@ function findNpmRoot(extDir) {
10273
10377
  async function findExtensionDir() {
10274
10378
  let dir = dirname5(fileURLToPath(import.meta.url));
10275
10379
  for (; ; ) {
10276
- const pkg = await readPackageJson(join5(dir, "package.json"));
10380
+ const pkg = await readPackageJson(join7(dir, "package.json"));
10277
10381
  if (pkg?.name === PACKAGE_NAME) return dir;
10278
10382
  const parent = dirname5(dir);
10279
10383
  if (parent === dir) return void 0;
@@ -10324,7 +10428,7 @@ async function checkForUpdate(autoUpdate, notify) {
10324
10428
  const data = await res.json();
10325
10429
  const latest = data.version;
10326
10430
  if (!latest) return;
10327
- const current = runtimeVersion ?? "0.1.39";
10431
+ const current = runtimeVersion ?? "0.1.41";
10328
10432
  const hasUpdate = isNewer(latest, current);
10329
10433
  debug.event("update-check", {
10330
10434
  current,
@@ -10354,16 +10458,16 @@ async function checkForUpdate(autoUpdate, notify) {
10354
10458
  async function getRuntimeVersion() {
10355
10459
  const extDir = await findExtensionDir();
10356
10460
  if (!extDir) return void 0;
10357
- const pkg = await readPackageJson(join5(extDir, "package.json"));
10461
+ const pkg = await readPackageJson(join7(extDir, "package.json"));
10358
10462
  return pkg?.version;
10359
10463
  }
10360
10464
 
10361
10465
  // src/setup-subagent-tools.ts
10362
10466
  import { readFile as readFile2, writeFile as writeFile4, stat, copyFile, rename } from "fs/promises";
10363
10467
  import { existsSync as existsSync4 } from "fs";
10364
- import { homedir as homedir4 } from "os";
10365
- import { join as join6 } from "path";
10366
- import { CONFIG_DIR_NAME as CONFIG_DIR_NAME3 } from "@earendil-works/pi-coding-agent";
10468
+ import { homedir as homedir5 } from "os";
10469
+ import { join as join8 } from "path";
10470
+ import { CONFIG_DIR_NAME as CONFIG_DIR_NAME4 } from "@earendil-works/pi-coding-agent";
10367
10471
  var ACP_TOOLS2 = ["compress", "decompress", "search_context", "acp_status"];
10368
10472
  var BUILTIN_DEFAULT_TOOLS = {
10369
10473
  advisor: ["read", "grep", "find", "ls", "bash", "intercom"],
@@ -10378,9 +10482,9 @@ var BUILTIN_DEFAULT_TOOLS = {
10378
10482
  };
10379
10483
  function resolveAgentDir() {
10380
10484
  const configured = process.env.PI_CODING_AGENT_DIR;
10381
- if (configured === "~") return homedir4();
10382
- if (configured?.startsWith("~/")) return join6(homedir4(), configured.slice(2));
10383
- return configured || join6(homedir4(), CONFIG_DIR_NAME3, "agent");
10485
+ if (configured === "~") return homedir5();
10486
+ if (configured?.startsWith("~/")) return join8(homedir5(), configured.slice(2));
10487
+ return configured || join8(homedir5(), CONFIG_DIR_NAME4, "agent");
10384
10488
  }
10385
10489
  function desiredTools(existing, name) {
10386
10490
  const base = Array.isArray(existing?.tools) && existing.tools.length > 0 ? [...existing.tools] : [...BUILTIN_DEFAULT_TOOLS[name] ?? []];
@@ -10390,7 +10494,7 @@ function desiredTools(existing, name) {
10390
10494
  return { tools: base, changed: true };
10391
10495
  }
10392
10496
  async function ensureSubagentAcpTools(settingsPath) {
10393
- const path4 = settingsPath ?? join6(resolveAgentDir(), "settings.json");
10497
+ const path4 = settingsPath ?? join8(resolveAgentDir(), "settings.json");
10394
10498
  let raw;
10395
10499
  let mtimeMs;
10396
10500
  try {
@@ -10488,64 +10592,6 @@ async function runSetupAndNotify(notify) {
10488
10592
  }
10489
10593
  }
10490
10594
 
10491
- // src/user-config.ts
10492
- import { promises as fs2 } from "fs";
10493
- import * as path3 from "path";
10494
- import { homedir as homedir5 } from "os";
10495
- import { CONFIG_DIR_NAME as CONFIG_DIR_NAME4 } from "@earendil-works/pi-coding-agent";
10496
- async function loadUserConfig(cwd) {
10497
- const home = homedir5();
10498
- const merged = {};
10499
- for (const base of [join8(home, CONFIG_DIR_NAME4), join8(cwd, CONFIG_DIR_NAME4)]) {
10500
- const file = join8(base, "acp.json");
10501
- try {
10502
- const raw = await fs2.readFile(file, "utf8");
10503
- const parsed = JSON.parse(raw);
10504
- if (parsed && typeof parsed === "object") {
10505
- Object.assign(merged, pickKnown(parsed));
10506
- debug.event("config-loaded", { file });
10507
- }
10508
- } catch (e) {
10509
- const code = e.code;
10510
- if (code !== "ENOENT") {
10511
- logWarn("config", { event: "load-failed", file, error: e instanceof Error ? e.message : String(e) });
10512
- }
10513
- }
10514
- }
10515
- return merged;
10516
- }
10517
- function join8(...parts) {
10518
- return path3.join(...parts);
10519
- }
10520
- var KNOWN = /* @__PURE__ */ new Set([
10521
- "debug",
10522
- "autoUpdate",
10523
- "modelContextLimit",
10524
- "toolBashDefaultTimeout",
10525
- "toolOutputMaxBytes",
10526
- "delegate",
10527
- "compress",
10528
- "displayUsage",
10529
- "prompts",
10530
- "acknowledgePromptsRisk"
10531
- ]);
10532
- function pickKnown(parsed) {
10533
- const out = {};
10534
- for (const [k, v] of Object.entries(parsed)) {
10535
- if (KNOWN.has(k)) out[k] = v;
10536
- }
10537
- return out;
10538
- }
10539
- function applyUserConfig(adapter, user) {
10540
- return {
10541
- ...adapter,
10542
- ...user,
10543
- coreOverrides: adapter.coreOverrides,
10544
- protectedTools: adapter.protectedTools,
10545
- preserveRecentMessages: adapter.preserveRecentMessages
10546
- };
10547
- }
10548
-
10549
10595
  // src/index.ts
10550
10596
  function createAcpExtension(adapter = {}) {
10551
10597
  return (pi) => {
@@ -10579,12 +10625,10 @@ function wireSessionLifecycle(pi, runtime) {
10579
10625
  const sid = ctx.sessionManager.getSessionId();
10580
10626
  runtime.clearSessionTracking(sid);
10581
10627
  const modelInfo = ctx.model;
10582
- logInfo("session", { event: "start", sid, cwd: ctx.cwd, debug: runtime.adapter.debug ?? null, version: true ? "0.1.39" : null, model: modelInfo?.id ?? null, modelApi: modelInfo?.api ?? null, contextWindow: modelInfo?.contextWindow ?? null });
10628
+ logInfo("session", { event: "start", sid, cwd: ctx.cwd, debug: runtime.adapter.debug ?? null, version: true ? "0.1.41" : null, model: modelInfo?.id ?? null, modelApi: modelInfo?.api ?? null, contextWindow: modelInfo?.contextWindow ?? null });
10583
10629
  try {
10584
- const user = await loadUserConfig(ctx.cwd);
10585
- runtime.setAdapter(applyUserConfig(runtime.adapter, user));
10630
+ await runtime.reloadConfig(ctx.cwd);
10586
10631
  setDelegateDisplayUsage(resolveDelegate(runtime.adapter).displayUsage);
10587
- if (runtime.adapter.debug !== void 0) setDebugEnabled(runtime.adapter.debug);
10588
10632
  } catch (e) {
10589
10633
  logThrow("config", e, { sid, phase: "session_start" });
10590
10634
  }
@@ -10615,6 +10659,7 @@ function wireContextTransform(pi, runtime) {
10615
10659
  const sid = ctx.sessionManager.getSessionId();
10616
10660
  const release = await runtime.acquireLock(sid);
10617
10661
  try {
10662
+ await runtime.reloadConfig(ctx.cwd);
10618
10663
  const modelId = ctx.model?.id ?? "default";
10619
10664
  runtime.setCountModel(modelId);
10620
10665
  const { state, coreMessages, entries } = await runtime.stateFor(ctx, event.messages);