billion-context-omp 0.3.2-pr.139.4 → 0.3.2-pr.142.7

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
@@ -1,3 +1,6 @@
1
+ // src/index.ts
2
+ import { settings } from "@oh-my-pi/pi-coding-agent";
3
+
1
4
  // node_modules/acp-kernel/dist/chunk-MWXUJVMN.js
2
5
  import { createRequire } from "module";
3
6
  var require2 = createRequire(import.meta.url);
@@ -2348,6 +2351,144 @@ function countOccurrences(haystack, needle) {
2348
2351
  }
2349
2352
  return count;
2350
2353
  }
2354
+ var COMPRESS_TOOL_NAME = "compress";
2355
+ var DECOMPRESS_TOOL_NAME = "decompress";
2356
+ var SEARCH_CONTEXT_TOOL_NAME = "search_context";
2357
+ var ACP_STATUS_TOOL_NAME = "acp_status";
2358
+ var COMPRESS_TOOL = {
2359
+ name: COMPRESS_TOOL_NAME,
2360
+ description: "Replace a contiguous range of older conversation with a detailed summary you write. Use when content is genuinely consumed. Batch form: content=[{startId,endId,summary,topic?}]. REQUIRED \u2014 compress without content is invalid.",
2361
+ input_schema: {
2362
+ type: "object",
2363
+ properties: {
2364
+ topic: { type: "string", description: "Optional short title for the compressed range" },
2365
+ content: {
2366
+ type: "array",
2367
+ description: "One or more ranges to compress into separate summary blocks",
2368
+ items: {
2369
+ type: "object",
2370
+ properties: {
2371
+ topic: { type: "string" },
2372
+ startId: { type: "string", description: "mNNNNN ref at the start of the range" },
2373
+ endId: { type: "string", description: "mNNNNN ref at the end of the range" },
2374
+ summary: { type: "string", description: "Self-contained summary replacing the range" }
2375
+ },
2376
+ required: ["startId", "endId", "summary"]
2377
+ }
2378
+ }
2379
+ },
2380
+ required: ["content"]
2381
+ }
2382
+ };
2383
+ var COMPRESS_TOOL_OPENAI = {
2384
+ type: "function",
2385
+ function: {
2386
+ name: COMPRESS_TOOL_NAME,
2387
+ description: COMPRESS_TOOL.description,
2388
+ parameters: {
2389
+ type: "object",
2390
+ properties: {
2391
+ topic: { type: "string", description: "Optional short title for the compressed range" },
2392
+ content: {
2393
+ type: "array",
2394
+ description: "One or more ranges to compress into separate summary blocks. REQUIRED \u2014 compress without content is invalid.",
2395
+ items: {
2396
+ type: "object",
2397
+ properties: {
2398
+ topic: { type: "string" },
2399
+ startId: { type: "string", description: "mNNNNN ref at the start of the range" },
2400
+ endId: { type: "string", description: "mNNNNN ref at the end of the range" },
2401
+ summary: { type: "string", description: "Self-contained summary replacing the range" }
2402
+ },
2403
+ required: ["startId", "endId", "summary"]
2404
+ }
2405
+ }
2406
+ },
2407
+ required: ["content"]
2408
+ }
2409
+ }
2410
+ };
2411
+ var DECOMPRESS_TOOL_OPENAI = {
2412
+ type: "function",
2413
+ function: {
2414
+ name: DECOMPRESS_TOOL_NAME,
2415
+ description: "Restores previously compressed content. Use when you need exact details lost in compression. By default restores one tier up. Use full:true for all the way to original messages. Use toFile to write to file instead of inflating context.",
2416
+ parameters: {
2417
+ type: "object",
2418
+ properties: {
2419
+ blockId: { type: "string", description: "Block ID to decompress (e.g. b5)" },
2420
+ toFile: { type: "string", description: "Optional: write content to file instead of context" },
2421
+ full: { type: "boolean", description: "Restore all the way to original messages" }
2422
+ },
2423
+ required: ["blockId"]
2424
+ }
2425
+ }
2426
+ };
2427
+ var SEARCH_CONTEXT_TOOL_OPENAI = {
2428
+ type: "function",
2429
+ function: {
2430
+ name: SEARCH_CONTEXT_TOOL_NAME,
2431
+ description: "Search through compressed block summaries by keyword. Use BEFORE decompressing to find the right block.",
2432
+ parameters: {
2433
+ type: "object",
2434
+ properties: {
2435
+ query: { type: "string", description: "Search query" },
2436
+ limit: { type: "number", description: "Max results (default 5)" }
2437
+ },
2438
+ required: ["query"]
2439
+ }
2440
+ }
2441
+ };
2442
+ var ACP_STATUS_TOOL_OPENAI = {
2443
+ type: "function",
2444
+ function: {
2445
+ name: ACP_STATUS_TOOL_NAME,
2446
+ description: "Show context usage and compressible ranges. No args = overview. Use to find what to compress next.",
2447
+ parameters: {
2448
+ type: "object",
2449
+ properties: {}
2450
+ }
2451
+ }
2452
+ };
2453
+ var DECOMPRESS_TOOL = {
2454
+ name: DECOMPRESS_TOOL_NAME,
2455
+ description: DECOMPRESS_TOOL_OPENAI.function.description,
2456
+ input_schema: DECOMPRESS_TOOL_OPENAI.function.parameters
2457
+ };
2458
+ var SEARCH_CONTEXT_TOOL = {
2459
+ name: SEARCH_CONTEXT_TOOL_NAME,
2460
+ description: SEARCH_CONTEXT_TOOL_OPENAI.function.description,
2461
+ input_schema: SEARCH_CONTEXT_TOOL_OPENAI.function.parameters
2462
+ };
2463
+ var ACP_STATUS_TOOL = {
2464
+ name: ACP_STATUS_TOOL_NAME,
2465
+ description: ACP_STATUS_TOOL_OPENAI.function.description,
2466
+ input_schema: ACP_STATUS_TOOL_OPENAI.function.parameters
2467
+ };
2468
+ var COMPRESS_TOOL_RESPONSES = {
2469
+ type: "function",
2470
+ name: COMPRESS_TOOL_NAME,
2471
+ description: COMPRESS_TOOL.description,
2472
+ parameters: COMPRESS_TOOL_OPENAI.function.parameters
2473
+ };
2474
+ var DECOMPRESS_TOOL_RESPONSES = {
2475
+ type: "function",
2476
+ name: DECOMPRESS_TOOL_OPENAI.function.name,
2477
+ description: DECOMPRESS_TOOL_OPENAI.function.description,
2478
+ parameters: DECOMPRESS_TOOL_OPENAI.function.parameters
2479
+ };
2480
+ var SEARCH_CONTEXT_TOOL_RESPONSES = {
2481
+ type: "function",
2482
+ name: SEARCH_CONTEXT_TOOL_OPENAI.function.name,
2483
+ description: SEARCH_CONTEXT_TOOL_OPENAI.function.description,
2484
+ parameters: SEARCH_CONTEXT_TOOL_OPENAI.function.parameters
2485
+ };
2486
+ var ACP_STATUS_TOOL_RESPONSES = {
2487
+ type: "function",
2488
+ name: ACP_STATUS_TOOL_OPENAI.function.name,
2489
+ description: ACP_STATUS_TOOL_OPENAI.function.description,
2490
+ parameters: ACP_STATUS_TOOL_OPENAI.function.parameters
2491
+ };
2351
2492
  function parseBlockIdArg(arg) {
2352
2493
  const normalized = arg.trim().toLowerCase();
2353
2494
  const refMatch = /^b0*(\d+)$/.exec(normalized);
@@ -3529,6 +3670,7 @@ When context usage passes a threshold, the system appends a breakdown showing wh
3529
3670
 
3530
3671
  // node_modules/acp-kernel/dist/wire/index.js
3531
3672
  import { createHash as createHash2 } from "crypto";
3673
+ import { createHash as createHash22 } from "crypto";
3532
3674
  function hashId(s) {
3533
3675
  return createHash2("sha256").update(s, "utf8").digest("hex").slice(0, 16);
3534
3676
  }
@@ -4359,12 +4501,6 @@ function mirrorResponsesToCore(view, systemText) {
4359
4501
  });
4360
4502
  return msgs;
4361
4503
  }
4362
-
4363
- // src/messages.ts
4364
- import { createHash as createHash3 } from "crypto";
4365
- var REF_TAG_SOURCE = "(?:<acp\\s[^>]*>m\\d+</acp>|\\[m\\d+\\])";
4366
- var REF_TAG = new RegExp(`^${REF_TAG_SOURCE}\\s?\\n?`);
4367
- var TRAILING_REF_TAG = new RegExp(`\\n*${REF_TAG_SOURCE}\\s*$`);
4368
4504
  function compressToolArgs(call) {
4369
4505
  let args = call.arguments;
4370
4506
  if (typeof args === "string") {
@@ -4395,12 +4531,159 @@ function compressToolArgs(call) {
4395
4531
  const ia = inner;
4396
4532
  return Array.isArray(ia.content) ? { content: ia.content, topic: ia.topic, summaryMaxChars: ia.summaryMaxChars } : { content: [ia] };
4397
4533
  }
4534
+ function toolCallNames(msgs) {
4535
+ const names = /* @__PURE__ */ new Map();
4536
+ for (const m of msgs) {
4537
+ if (m.contentType === "tool-call" && m.toolCallId && m.toolName) names.set(m.toolCallId, m.toolName);
4538
+ }
4539
+ return names;
4540
+ }
4541
+ function toolResultTextsCore(msgs) {
4542
+ const results = /* @__PURE__ */ new Map();
4543
+ for (const m of msgs) {
4544
+ if (m.contentType !== "tool-result" || !m.toolCallId) continue;
4545
+ results.set(m.toolCallId, m.text ?? "");
4546
+ }
4547
+ return results;
4548
+ }
4549
+ function findCompressCallsCore(msg) {
4550
+ if (msg.contentType !== "tool-call" || !msg.toolName) return [];
4551
+ const args = compressToolArgs({ name: msg.toolName, arguments: msg.text });
4552
+ if (!args) return [];
4553
+ const content = args.content;
4554
+ if (!Array.isArray(content)) return [];
4555
+ const ranges = [];
4556
+ const callTopic = typeof args.topic === "string" ? args.topic : void 0;
4557
+ for (const item of content) {
4558
+ const r = item;
4559
+ if (typeof r.startId !== "string" || typeof r.endId !== "string" || typeof r.summary !== "string" || r.summary.length === 0) continue;
4560
+ ranges.push({
4561
+ startRef: r.startId,
4562
+ endRef: r.endId,
4563
+ summary: r.summary,
4564
+ topic: typeof r.topic === "string" ? r.topic : callTopic,
4565
+ summaryMaxChars: typeof args.summaryMaxChars === "number" ? args.summaryMaxChars : void 0,
4566
+ compressCallId: msg.toolCallId ?? ""
4567
+ });
4568
+ }
4569
+ return ranges.length > 0 ? [{ id: msg.toolCallId ?? "", ranges }] : [];
4570
+ }
4571
+ function corePieceKey(cm) {
4572
+ return `${cm.role}|${cm.contentType}|${cm.toolName ?? ""}|${(cm.text ?? "").slice(0, 4096)}`;
4573
+ }
4574
+ function spanFingerprintCore(coreMessages, startId, endId) {
4575
+ const find = (id) => coreMessages.find((cm) => cm.id === id);
4576
+ const first = find(startId);
4577
+ const last = find(endId);
4578
+ if (!first || !last) return "";
4579
+ return createHash22("sha1").update(`${corePieceKey(first)}\0${corePieceKey(last)}`).digest("hex").slice(0, 8);
4580
+ }
4581
+ function spanFingerprintCoreIdx(coreMessages, startIdx, endIdx) {
4582
+ const first = coreMessages[startIdx];
4583
+ const last = coreMessages[endIdx];
4584
+ if (!first || !last) return "";
4585
+ return createHash22("sha1").update(`${corePieceKey(first)}\0${corePieceKey(last)}`).digest("hex").slice(0, 8);
4586
+ }
4587
+ function boundaryRawCore(ref, byRef, blocks, coreMessages, pick) {
4588
+ const raw = byRef[ref];
4589
+ if (raw) return raw;
4590
+ const m = /^b(\d+)$/i.exec(ref.trim());
4591
+ if (!m) return "";
4592
+ const block = blocks.find((b) => b.blockId.toLowerCase() === `b${m[1]}`);
4593
+ if (!block) return "";
4594
+ const idx = (id) => coreMessages.findIndex((cm) => cm.id === (byRef[id] ?? id));
4595
+ let best = -1;
4596
+ for (const id of block.effectiveMessageIds) {
4597
+ const i = idx(id);
4598
+ if (i < 0) continue;
4599
+ if (best < 0 || (pick === "min" ? i < best : i > best)) best = i;
4600
+ }
4601
+ return best < 0 ? "" : coreMessages[best]?.id ?? "";
4602
+ }
4603
+ function boundaryIndexCore(ref, byRef, blocks, coreMessages, pick, fallbackIdx = -1) {
4604
+ const id = boundaryRawCore(ref, byRef, blocks, coreMessages, pick);
4605
+ if (id) {
4606
+ const i = coreMessages.findIndex((cm) => cm.id === id);
4607
+ if (i >= 0) return i;
4608
+ }
4609
+ return fallbackIdx >= 0 && fallbackIdx < coreMessages.length ? fallbackIdx : -1;
4610
+ }
4611
+ function refOfPieceCore(coreMessages, idx, byRef) {
4612
+ const id = coreMessages[idx]?.id;
4613
+ if (!id) return "";
4614
+ for (const [ref, mapped] of Object.entries(byRef)) if (mapped === id) return ref;
4615
+ return "";
4616
+ }
4617
+ function staleRangeCore(r, rangeIndex, resultText, coreMessages, callIndex, byRef, blocks) {
4618
+ const pm = resultText.match(/\[pos=([0-9,-]+)\]/);
4619
+ const pair = pm ? pm[1].split(",")[rangeIndex] ?? "-" : "-";
4620
+ const hinted = pair !== "-";
4621
+ const [ps, pe] = pair === "-" ? ["", ""] : pair.split("-");
4622
+ const fbStart = ps && ps !== "" ? Number.parseInt(ps, 10) : -1;
4623
+ const fbEnd = pe && pe !== "" ? Number.parseInt(pe, 10) : -1;
4624
+ const startRaw = boundaryRawCore(r.startRef, byRef, blocks, coreMessages, "min");
4625
+ const endRaw = boundaryRawCore(r.endRef, byRef, blocks, coreMessages, "max");
4626
+ const rawStartIdx = startRaw ? coreMessages.findIndex((cm) => cm.id === startRaw) : -1;
4627
+ const rawEndIdx = endRaw ? coreMessages.findIndex((cm) => cm.id === endRaw) : -1;
4628
+ const startIdx = rawStartIdx >= 0 ? rawStartIdx : fbStart >= 0 && fbStart < coreMessages.length ? fbStart : -1;
4629
+ const endIdx = rawEndIdx >= 0 ? rawEndIdx : fbEnd >= 0 && fbEnd < coreMessages.length ? fbEnd : -1;
4630
+ if (startIdx < 0 || endIdx < 0) {
4631
+ if (!/^b\d+$/i.test(r.startRef.trim()) && !/^b\d+$/i.test(r.endRef.trim()))
4632
+ return { reject: `unresolved ${r.startRef}..${r.endRef} -> ${startIdx}..${endIdx}`, ...hinted ? { hint: true } : {} };
4633
+ return {};
4634
+ }
4635
+ if (endIdx > callIndex) return { reject: `end idx ${endIdx} > callIndex ${callIndex}`, ...hinted ? { hint: true } : {} };
4636
+ const m = resultText.match(/\[fp=([0-9a-f,-]+)\]/);
4637
+ if (m) {
4638
+ const want = m[1].split(",")[rangeIndex];
4639
+ if (want !== void 0 && want !== "-") {
4640
+ const got = spanFingerprintCoreIdx(coreMessages, startIdx, endIdx);
4641
+ if (want !== got) return { reject: `fp ${r.startRef}..${r.endRef} want ${want} got ${got} @${startIdx}..${endIdx}`, ...hinted ? { hint: true } : {} };
4642
+ }
4643
+ }
4644
+ const remap = {};
4645
+ if (/^m\d+$/i.test(r.startRef.trim()) && rawStartIdx < 0) {
4646
+ const ref = refOfPieceCore(coreMessages, startIdx, byRef);
4647
+ if (!ref) return { reject: `recovered ${r.startRef} @${startIdx} has no ref (protected piece)`, ...hinted ? { hint: true } : {} };
4648
+ remap.startRef = ref;
4649
+ }
4650
+ if (/^m\d+$/i.test(r.endRef.trim()) && rawEndIdx < 0) {
4651
+ const ref = refOfPieceCore(coreMessages, endIdx, byRef);
4652
+ if (!ref) return { reject: `recovered ${r.endRef} @${endIdx} has no ref (protected piece)`, ...hinted ? { hint: true } : {} };
4653
+ remap.endRef = ref;
4654
+ }
4655
+ if (!remap.startRef && !remap.endRef) return {};
4656
+ return { remap, recovered: { pos: pair, startIdx, endIdx } };
4657
+ }
4658
+ function rangeFingerprintsCore(ranges, coreMessages, byRef, blocks) {
4659
+ return ranges.map((r) => {
4660
+ const start = boundaryRawCore(r.startRef, byRef, blocks, coreMessages, "min");
4661
+ const end = start ? boundaryRawCore(r.endRef, byRef, blocks, coreMessages, "max") : "";
4662
+ if (start && end) {
4663
+ const fp = spanFingerprintCore(coreMessages, start, end);
4664
+ if (fp.length > 0) return fp;
4665
+ }
4666
+ return "-";
4667
+ });
4668
+ }
4669
+ function rangePositionsCore(ranges, coreMessages, byRef, blocks) {
4670
+ return ranges.map((r) => {
4671
+ const s = boundaryIndexCore(r.startRef, byRef, blocks, coreMessages, "min");
4672
+ const e = s >= 0 ? boundaryIndexCore(r.endRef, byRef, blocks, coreMessages, "max") : -1;
4673
+ return s >= 0 && e >= 0 ? `${s}-${e}` : "-";
4674
+ });
4675
+ }
4676
+
4677
+ // src/messages.ts
4678
+ import { createHash as createHash3 } from "crypto";
4679
+ var REF_TAG_SOURCE = "(?:<acp\\s[^>]*>m\\d+</acp>|\\[m\\d+\\])";
4680
+ var REF_TAG = new RegExp(`^${REF_TAG_SOURCE}\\s?\\n?`);
4681
+ var TRAILING_REF_TAG = new RegExp(`\\n*${REF_TAG_SOURCE}\\s*$`);
4398
4682
  function stripRefTag(text) {
4399
4683
  return text.replace(REF_TAG, "").replace(TRAILING_REF_TAG, "");
4400
4684
  }
4401
4685
 
4402
4686
  // src/wire-fold.ts
4403
- import { createHash as createHash4 } from "crypto";
4404
4687
  function detectProviderWireFormat(payload) {
4405
4688
  const fmt2 = detectWireFormat(payload);
4406
4689
  if (fmt2 === "anthropic" || fmt2 === "openai" || fmt2 === "responses") return fmt2;
@@ -4565,148 +4848,6 @@ function coreIdentity(msg) {
4565
4848
  text: stripRefTag(msg.text ?? "")
4566
4849
  });
4567
4850
  }
4568
- function toolCallNames(msgs) {
4569
- const names = /* @__PURE__ */ new Map();
4570
- for (const m of msgs) {
4571
- if (m.contentType === "tool-call" && m.toolCallId && m.toolName) names.set(m.toolCallId, m.toolName);
4572
- }
4573
- return names;
4574
- }
4575
- function toolResultTextsCore(msgs) {
4576
- const results = /* @__PURE__ */ new Map();
4577
- for (const m of msgs) {
4578
- if (m.contentType !== "tool-result" || !m.toolCallId) continue;
4579
- results.set(m.toolCallId, m.text ?? "");
4580
- }
4581
- return results;
4582
- }
4583
- function findCompressCallsCore(msg) {
4584
- if (msg.contentType !== "tool-call" || !msg.toolName) return [];
4585
- const args = compressToolArgs({ name: msg.toolName, arguments: msg.text });
4586
- if (!args) return [];
4587
- const content = args.content;
4588
- if (!Array.isArray(content)) return [];
4589
- const ranges = [];
4590
- const callTopic = typeof args.topic === "string" ? args.topic : void 0;
4591
- for (const item of content) {
4592
- const r = item;
4593
- if (typeof r.startId !== "string" || typeof r.endId !== "string" || typeof r.summary !== "string" || r.summary.length === 0) continue;
4594
- ranges.push({
4595
- startRef: r.startId,
4596
- endRef: r.endId,
4597
- summary: r.summary,
4598
- topic: typeof r.topic === "string" ? r.topic : callTopic,
4599
- summaryMaxChars: typeof args.summaryMaxChars === "number" ? args.summaryMaxChars : void 0,
4600
- compressCallId: msg.toolCallId ?? ""
4601
- });
4602
- }
4603
- return ranges.length > 0 ? [{ id: msg.toolCallId ?? "", ranges }] : [];
4604
- }
4605
- function corePieceKey(cm) {
4606
- return `${cm.role}|${cm.contentType}|${cm.toolName ?? ""}|${(cm.text ?? "").slice(0, 4096)}`;
4607
- }
4608
- function spanFingerprintCore(coreMessages, startId, endId) {
4609
- const find = (id) => coreMessages.find((cm) => cm.id === id);
4610
- const first = find(startId);
4611
- const last = find(endId);
4612
- if (!first || !last) return "";
4613
- return createHash4("sha1").update(`${corePieceKey(first)}\0${corePieceKey(last)}`).digest("hex").slice(0, 8);
4614
- }
4615
- function spanFingerprintCoreIdx(coreMessages, startIdx, endIdx) {
4616
- const first = coreMessages[startIdx];
4617
- const last = coreMessages[endIdx];
4618
- if (!first || !last) return "";
4619
- return createHash4("sha1").update(`${corePieceKey(first)}\0${corePieceKey(last)}`).digest("hex").slice(0, 8);
4620
- }
4621
- function boundaryRawCore(ref, byRef, blocks, coreMessages, pick) {
4622
- const raw = byRef[ref];
4623
- if (raw) return raw;
4624
- const m = /^b(\d+)$/i.exec(ref.trim());
4625
- if (!m) return "";
4626
- const block = blocks.find((b) => b.blockId.toLowerCase() === `b${m[1]}`);
4627
- if (!block) return "";
4628
- const idx = (id) => coreMessages.findIndex((cm) => cm.id === (byRef[id] ?? id));
4629
- let best = -1;
4630
- for (const id of block.effectiveMessageIds) {
4631
- const i = idx(id);
4632
- if (i < 0) continue;
4633
- if (best < 0 || (pick === "min" ? i < best : i > best)) best = i;
4634
- }
4635
- return best < 0 ? "" : coreMessages[best]?.id ?? "";
4636
- }
4637
- function boundaryIndexCore(ref, byRef, blocks, coreMessages, pick, fallbackIdx = -1) {
4638
- const id = boundaryRawCore(ref, byRef, blocks, coreMessages, pick);
4639
- if (id) {
4640
- const i = coreMessages.findIndex((cm) => cm.id === id);
4641
- if (i >= 0) return i;
4642
- }
4643
- return fallbackIdx >= 0 && fallbackIdx < coreMessages.length ? fallbackIdx : -1;
4644
- }
4645
- function refOfPieceCore(coreMessages, idx, byRef) {
4646
- const id = coreMessages[idx]?.id;
4647
- if (!id) return "";
4648
- for (const [ref, mapped] of Object.entries(byRef)) if (mapped === id) return ref;
4649
- return "";
4650
- }
4651
- function staleRangeCore(r, rangeIndex, resultText, coreMessages, callIndex, byRef, blocks) {
4652
- const pm = resultText.match(/\[pos=([0-9,-]+)\]/);
4653
- const pair = pm ? pm[1].split(",")[rangeIndex] ?? "-" : "-";
4654
- const hinted = pair !== "-";
4655
- const [ps, pe] = pair === "-" ? ["", ""] : pair.split("-");
4656
- const fbStart = ps && ps !== "" ? Number.parseInt(ps, 10) : -1;
4657
- const fbEnd = pe && pe !== "" ? Number.parseInt(pe, 10) : -1;
4658
- const startRaw = boundaryRawCore(r.startRef, byRef, blocks, coreMessages, "min");
4659
- const endRaw = boundaryRawCore(r.endRef, byRef, blocks, coreMessages, "max");
4660
- const rawStartIdx = startRaw ? coreMessages.findIndex((cm) => cm.id === startRaw) : -1;
4661
- const rawEndIdx = endRaw ? coreMessages.findIndex((cm) => cm.id === endRaw) : -1;
4662
- const startIdx = rawStartIdx >= 0 ? rawStartIdx : fbStart >= 0 && fbStart < coreMessages.length ? fbStart : -1;
4663
- const endIdx = rawEndIdx >= 0 ? rawEndIdx : fbEnd >= 0 && fbEnd < coreMessages.length ? fbEnd : -1;
4664
- if (startIdx < 0 || endIdx < 0) {
4665
- if (!/^b\d+$/i.test(r.startRef.trim()) && !/^b\d+$/i.test(r.endRef.trim()))
4666
- return { reject: `unresolved ${r.startRef}..${r.endRef} -> ${startIdx}..${endIdx}`, ...hinted ? { hint: true } : {} };
4667
- return {};
4668
- }
4669
- if (endIdx > callIndex) return { reject: `end idx ${endIdx} > callIndex ${callIndex}`, ...hinted ? { hint: true } : {} };
4670
- const m = resultText.match(/\[fp=([0-9a-f,-]+)\]/);
4671
- if (m) {
4672
- const want = m[1].split(",")[rangeIndex];
4673
- if (want !== void 0 && want !== "-") {
4674
- const got = spanFingerprintCoreIdx(coreMessages, startIdx, endIdx);
4675
- if (want !== got) return { reject: `fp ${r.startRef}..${r.endRef} want ${want} got ${got} @${startIdx}..${endIdx}`, ...hinted ? { hint: true } : {} };
4676
- }
4677
- }
4678
- const remap = {};
4679
- if (/^m\d+$/i.test(r.startRef.trim()) && rawStartIdx < 0) {
4680
- const ref = refOfPieceCore(coreMessages, startIdx, byRef);
4681
- if (!ref) return { reject: `recovered ${r.startRef} @${startIdx} has no ref (protected piece)`, ...hinted ? { hint: true } : {} };
4682
- remap.startRef = ref;
4683
- }
4684
- if (/^m\d+$/i.test(r.endRef.trim()) && rawEndIdx < 0) {
4685
- const ref = refOfPieceCore(coreMessages, endIdx, byRef);
4686
- if (!ref) return { reject: `recovered ${r.endRef} @${endIdx} has no ref (protected piece)`, ...hinted ? { hint: true } : {} };
4687
- remap.endRef = ref;
4688
- }
4689
- if (!remap.startRef && !remap.endRef) return {};
4690
- return { remap, recovered: { pos: pair, startIdx, endIdx } };
4691
- }
4692
- function rangeFingerprintsCore(ranges, coreMessages, byRef, blocks) {
4693
- return ranges.map((r) => {
4694
- const start = boundaryRawCore(r.startRef, byRef, blocks, coreMessages, "min");
4695
- const end = start ? boundaryRawCore(r.endRef, byRef, blocks, coreMessages, "max") : "";
4696
- if (start && end) {
4697
- const fp = spanFingerprintCore(coreMessages, start, end);
4698
- if (fp.length > 0) return fp;
4699
- }
4700
- return "-";
4701
- });
4702
- }
4703
- function rangePositionsCore(ranges, coreMessages, byRef, blocks) {
4704
- return ranges.map((r) => {
4705
- const s = boundaryIndexCore(r.startRef, byRef, blocks, coreMessages, "min");
4706
- const e = s >= 0 ? boundaryIndexCore(r.endRef, byRef, blocks, coreMessages, "max") : -1;
4707
- return s >= 0 && e >= 0 ? `${s}-${e}` : "-";
4708
- });
4709
- }
4710
4851
  function toMirrorView(view) {
4711
4852
  const out = [];
4712
4853
  for (const message of view) {
@@ -4832,6 +4973,14 @@ function createRuntime(adapter) {
4832
4973
  coreSlots.set(sid, slot);
4833
4974
  lcp = 0;
4834
4975
  }
4976
+ if (lcp === 0 && slot.state.blocks.length > 0) {
4977
+ const presentIds = new Set(ids);
4978
+ const surviving = slot.state.blocks.filter((b) => b.active === false || b.effectiveMessageIds.some((id) => presentIds.has(id)));
4979
+ if (surviving.length < slot.state.blocks.length) {
4980
+ debug.event("fold-purge-stale-blocks", { sid, before: slot.state.blocks.length, after: surviving.length });
4981
+ slot.state = { ...slot.state, blocks: surviving };
4982
+ }
4983
+ }
4835
4984
  const coreMessages = stream;
4836
4985
  const config = configFor(ctx);
4837
4986
  const names = toolCallNames(stream);
@@ -4967,17 +5116,31 @@ ${acp}`);
4967
5116
  logInfo("fold", { sid, event: "fold-restore-empty" });
4968
5117
  return false;
4969
5118
  }
5119
+ const byId = /* @__PURE__ */ new Map();
5120
+ for (const b of r.state.blocks) {
5121
+ const prev = byId.get(b.blockId);
5122
+ if (!prev || b.createdAt > prev.createdAt) byId.set(b.blockId, b);
5123
+ }
5124
+ const blocks = [...byId.values()];
5125
+ if (blocks.length < r.state.blocks.length) {
5126
+ logInfo("fold", { sid, event: "fold-restore-dedup", before: r.state.blocks.length, after: blocks.length });
5127
+ }
5128
+ const maxId = blocks.reduce((m, b) => {
5129
+ const n = /^b(\d+)$/i.exec(b.blockId);
5130
+ return n ? Math.max(m, Number.parseInt(n[1], 10)) : m;
5131
+ }, 0);
5132
+ const state = { ...r.state, blocks, nextBlockId: Math.max(r.state.nextBlockId ?? 1, maxId + 1) };
4970
5133
  coreSlots.set(sid, {
4971
5134
  identities: r.identities,
4972
5135
  foldedLen: r.foldedLen,
4973
5136
  preview: false,
4974
5137
  live: true,
4975
- state: r.state,
5138
+ state,
4976
5139
  coreMessages: r.coreMessages,
4977
5140
  appliedCallIds: r.appliedCallIds,
4978
5141
  rejectStreak: r.rejectStreak
4979
5142
  });
4980
- logInfo("fold", { sid, event: "fold-restore", blocks: r.state.blocks.length, foldedLen: r.foldedLen });
5143
+ logInfo("fold", { sid, event: "fold-restore", blocks: state.blocks.length, foldedLen: r.foldedLen, nextBlockId: state.nextBlockId });
4981
5144
  return true;
4982
5145
  }
4983
5146
  function snapshotOf(slot) {
@@ -5991,68 +6154,23 @@ import { fileURLToPath } from "url";
5991
6154
  import { execFile } from "child_process";
5992
6155
  import { CONFIG_DIR_NAME as CONFIG_DIR_NAME3 } from "@oh-my-pi/pi-utils";
5993
6156
  var PACKAGE_NAME = "billion-context-omp";
5994
- var registryUrl = (tag) => `https://registry.npmjs.org/${PACKAGE_NAME}/${encodeURIComponent(tag)}`;
6157
+ var REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
5995
6158
  var SEMVER_RE = /^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/;
5996
6159
  var CHECK_INTERVAL_MS = 3 * 60 * 1e3;
5997
6160
  var throttleFile = () => join4(homeDir(), CONFIG_DIR_NAME3, ".billion-context-omp-update-check");
5998
6161
  var updateInFlight = false;
5999
- function isAutoUpdatableSpec(spec) {
6000
- const value = spec.trim();
6001
- if (!value) return false;
6002
- if (value === "latest" || value === "*") return true;
6003
- if (/^[~^]/.test(value)) return true;
6004
- if (/^(?:>=|>|<=|<)/.test(value)) return true;
6005
- if (/\s+(?:\|\||-|[<>=])\s+/.test(value)) return true;
6006
- if (isDistTag(value)) return true;
6007
- return false;
6162
+ function parseVersion(v) {
6163
+ return v.replace(/^v/, "").split(".").map((n) => parseInt(n, 10) || 0);
6008
6164
  }
6009
- function specUpdateTag(spec) {
6010
- const value = spec.trim();
6011
- if (!isAutoUpdatableSpec(value)) return void 0;
6012
- if (value === "*") return "latest";
6013
- if (isDistTag(value)) return value;
6014
- return "latest";
6015
- }
6016
- function isDistTag(value) {
6017
- if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(value)) return false;
6018
- if (parseSemVer(value)) return false;
6019
- if (/\.x(\.|$)/i.test(value)) return false;
6020
- return true;
6021
- }
6022
- function isVersionNewer(latest, current) {
6023
- const next = parseSemVer(latest);
6024
- const prev = parseSemVer(current);
6025
- if (!next || !prev) return false;
6165
+ function isNewer(latest, current) {
6166
+ const l = parseVersion(latest);
6167
+ const c = parseVersion(current);
6026
6168
  for (let i = 0; i < 3; i++) {
6027
- const a = next.parts[i] ?? 0;
6028
- const b = prev.parts[i] ?? 0;
6029
- if (a !== b) return a > b;
6030
- }
6031
- if (!next.pre.length && prev.pre.length) return true;
6032
- if (next.pre.length && !prev.pre.length) return false;
6033
- for (let i = 0; i < Math.max(next.pre.length, prev.pre.length); i++) {
6034
- const a = next.pre[i];
6035
- const b = prev.pre[i];
6036
- if (a === void 0) return false;
6037
- if (b === void 0) return true;
6038
- if (a === b) continue;
6039
- const aNumber = /^\d+$/.test(a) ? Number(a) : void 0;
6040
- const bNumber = /^\d+$/.test(b) ? Number(b) : void 0;
6041
- if (aNumber !== void 0 && bNumber !== void 0) return aNumber > bNumber;
6042
- if (aNumber !== void 0) return false;
6043
- if (bNumber !== void 0) return true;
6044
- return a > b;
6169
+ if ((l[i] ?? 0) > (c[i] ?? 0)) return true;
6170
+ if ((l[i] ?? 0) < (c[i] ?? 0)) return false;
6045
6171
  }
6046
6172
  return false;
6047
6173
  }
6048
- function parseSemVer(version) {
6049
- const match = version.match(/^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+.+)?$/);
6050
- if (!match) return void 0;
6051
- return {
6052
- parts: [Number(match[1]), Number(match[2]), Number(match[3])],
6053
- pre: match[4]?.split(".") ?? []
6054
- };
6055
- }
6056
6174
  async function readLastCheck() {
6057
6175
  try {
6058
6176
  const data = await readFile(throttleFile(), "utf-8");
@@ -6119,7 +6237,6 @@ var runNodeImpl = (args) => new Promise((resolve2) => {
6119
6237
  );
6120
6238
  });
6121
6239
  var runNode = runNodeImpl;
6122
- var installedSpecOverride = null;
6123
6240
  function declaredEntries(pkg) {
6124
6241
  const entries = /* @__PURE__ */ new Set();
6125
6242
  for (const ext of pkg.omp?.extensions ?? []) {
@@ -6217,14 +6334,7 @@ async function checkForUpdate(autoUpdate, notify) {
6217
6334
  const lastCheck = await readLastCheck();
6218
6335
  if (now - lastCheck < CHECK_INTERVAL_MS) return;
6219
6336
  const runtimeVersion = await getRuntimeVersion();
6220
- const spec = await getInstalledSpec();
6221
- const tag = spec ? specUpdateTag(spec) : "latest";
6222
- if (!tag) {
6223
- await writeLastCheck(now);
6224
- debug.event("update-check", { event: "skip", reason: "pinned-spec", spec });
6225
- return;
6226
- }
6227
- const res = await fetch(registryUrl(tag), {
6337
+ const res = await fetch(REGISTRY_URL, {
6228
6338
  signal: AbortSignal.timeout(5e3),
6229
6339
  headers: { Accept: "application/json" }
6230
6340
  });
@@ -6237,11 +6347,10 @@ async function checkForUpdate(autoUpdate, notify) {
6237
6347
  const latest = data.version;
6238
6348
  if (!latest) return;
6239
6349
  const current = runtimeVersion ?? "0.3.2";
6240
- const hasUpdate = isVersionNewer(latest, current);
6350
+ const hasUpdate = isNewer(latest, current);
6241
6351
  debug.event("update-check", {
6242
6352
  current,
6243
6353
  latest,
6244
- tag,
6245
6354
  hasUpdate
6246
6355
  });
6247
6356
  logInfo("update", { event: "check", current, latest, hasUpdate });
@@ -6270,15 +6379,6 @@ async function getRuntimeVersion() {
6270
6379
  const pkg = await readPackageJson(join4(extDir, "package.json"));
6271
6380
  return pkg?.version;
6272
6381
  }
6273
- async function getInstalledSpec() {
6274
- if (installedSpecOverride !== null) return installedSpecOverride;
6275
- const extDir = await findExtensionDir();
6276
- if (!extDir) return void 0;
6277
- const npmRoot = findNpmRoot(extDir);
6278
- if (!npmRoot) return void 0;
6279
- const hostPkg = await readPackageJson(join4(npmRoot, "package.json"));
6280
- return hostPkg?.dependencies?.[PACKAGE_NAME];
6281
- }
6282
6382
 
6283
6383
  // src/dump.ts
6284
6384
  import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, readdirSync as readdirSync2, unlinkSync as unlinkSync2 } from "fs";
@@ -6460,8 +6560,16 @@ function applyUserConfig(adapter, user) {
6460
6560
  }
6461
6561
 
6462
6562
  // src/index.ts
6563
+ function disableHostCompaction() {
6564
+ try {
6565
+ settings.override("compaction.enabled", false);
6566
+ settings.override("compaction.strategy", "off");
6567
+ } catch {
6568
+ }
6569
+ }
6463
6570
  function createAcpExtension(adapter = {}) {
6464
6571
  return (pi) => {
6572
+ disableHostCompaction();
6465
6573
  const runtime = createRuntime(adapter);
6466
6574
  const warnDelivery = makeDeliveryWarner();
6467
6575
  wireSessionLifecycle(pi, runtime);