billion-context-pi 0.1.29 → 0.1.30

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.
@@ -0,0 +1,23 @@
1
+ import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
2
+ /**
3
+ * Host compatibility layer for pi vs omp (oh-my-pi) API differences.
4
+ *
5
+ * pi: systemPrompt is string, getSystemPrompt() returns string
6
+ * omp: systemPrompt is string[], getSystemPrompt() returns string[]
7
+ *
8
+ * These helpers normalize the differences so the rest of the codebase
9
+ * can work with a consistent string interface.
10
+ */
11
+ /** Normalize systemPrompt to a single string (join with newlines if array). */
12
+ export declare function normalizeSystemPrompt(input: string | string[] | undefined): string;
13
+ /**
14
+ * Format systemPrompt for before_agent_start event handler.
15
+ * Always returns string to satisfy pi's type definition, but handles
16
+ * both string (pi) and string[] (omp) input types at runtime.
17
+ */
18
+ export declare function formatSystemPromptForEvent(base: string | string[], append: string): string;
19
+ /**
20
+ * Get the system prompt as a single string, regardless of host type.
21
+ * Handles both pi (string) and omp (string[]) return types.
22
+ */
23
+ export declare function getSystemPromptText(ctx: ExtensionContext): string;
package/dist/index.js CHANGED
@@ -2730,6 +2730,50 @@ function isPiHost(sm) {
2730
2730
  const source = sm;
2731
2731
  return typeof source.buildContextEntries === "function";
2732
2732
  }
2733
+ function mergeLiveEntries(entries, live) {
2734
+ const persisted = entries.filter((e) => e.type === "message");
2735
+ const out = [];
2736
+ let p = 0;
2737
+ let unmatched = 0;
2738
+ for (let i = 0; i < live.length; i++) {
2739
+ const msg = live[i];
2740
+ let matched;
2741
+ let j = p;
2742
+ while (j < persisted.length && persisted[j].message.role !== msg.role) j++;
2743
+ if (j < persisted.length && sameMessage(persisted[j].message, msg)) {
2744
+ matched = persisted[j];
2745
+ p = j + 1;
2746
+ }
2747
+ if (matched) {
2748
+ out.push(matched);
2749
+ } else {
2750
+ unmatched++;
2751
+ out.push({
2752
+ type: "message",
2753
+ id: `live-${i}`,
2754
+ parentId: null,
2755
+ timestamp: String(msg.timestamp ?? Date.now()),
2756
+ message: msg
2757
+ });
2758
+ }
2759
+ }
2760
+ if (unmatched > 0) logInfo("runtime", { event: "merge-live-entries", live: live.length, unmatched });
2761
+ return out;
2762
+ }
2763
+ function sameMessage(a, b) {
2764
+ const ra = a.role;
2765
+ const rb = b.role;
2766
+ if (ra !== rb) return false;
2767
+ const ca = a.content;
2768
+ const cb = b.content;
2769
+ if (ca === void 0 || cb === void 0) return false;
2770
+ try {
2771
+ return JSON.stringify(ca) === JSON.stringify(cb);
2772
+ } catch (e) {
2773
+ logWarn("runtime", { event: "message-compare-failed", error: e instanceof Error ? e.message : String(e) });
2774
+ return a === b;
2775
+ }
2776
+ }
2733
2777
  function createRuntime(adapter) {
2734
2778
  const core = createCore({ countTokens: defaultCountTokens });
2735
2779
  const store = new SessionStateStore();
@@ -2758,11 +2802,12 @@ function createRuntime(adapter) {
2758
2802
  function configFor(ctx) {
2759
2803
  return resolveConfig(adapterRef, liveContextLimit(ctx));
2760
2804
  }
2761
- async function stateFor(ctx) {
2805
+ async function stateFor(ctx, liveMessages) {
2762
2806
  const sm = ctx.sessionManager;
2763
2807
  const state = await store.load(sm.getSessionFile() ?? void 0, sm.getSessionId());
2764
2808
  const entries = readContextEntries(sm);
2765
- return { state, coreMessages: entriesToCoreMessages(entries), entries };
2809
+ const merged = isPiHost(sm) || !liveMessages || liveMessages.length === 0 ? entries : mergeLiveEntries(entries, liveMessages);
2810
+ return { state, coreMessages: entriesToCoreMessages(merged), entries: merged };
2766
2811
  }
2767
2812
  async function save(state, ctx) {
2768
2813
  const sm = ctx.sessionManager;
@@ -7469,7 +7514,7 @@ function buildMessageOwnerMap(state) {
7469
7514
  return m;
7470
7515
  }
7471
7516
  function estimateTokens2(text) {
7472
- if (!text) return 0;
7517
+ if (typeof text !== "string" || !text) return 0;
7473
7518
  const cjk = text.match(/[\u4e00-\u9fff\u3040-\u30ff\uac00-\ud7af]/g);
7474
7519
  const cjkCount = cjk?.length ?? 0;
7475
7520
  return cjkCount + Math.ceil((text.length - cjkCount) / 4);
@@ -8561,6 +8606,23 @@ function truncate2(s, n) {
8561
8606
  return s.slice(0, n - 1) + "\u2026";
8562
8607
  }
8563
8608
 
8609
+ // src/compat.ts
8610
+ function normalizeSystemPrompt(input) {
8611
+ if (input === void 0) return "";
8612
+ if (Array.isArray(input)) return input.join("\n");
8613
+ return input;
8614
+ }
8615
+ function formatSystemPromptForEvent(base, append) {
8616
+ const normalized = normalizeSystemPrompt(base);
8617
+ return `${normalized}
8618
+
8619
+ ${append}`;
8620
+ }
8621
+ function getSystemPromptText(ctx) {
8622
+ const result = ctx.getSystemPrompt?.();
8623
+ return normalizeSystemPrompt(result);
8624
+ }
8625
+
8564
8626
  // src/commands.ts
8565
8627
  function makeCommands(runtime) {
8566
8628
  return [
@@ -8648,7 +8710,7 @@ async function statusReport(runtime, ctx) {
8648
8710
  const bd = nudge?.contextBreakdown;
8649
8711
  const limit = config.modelContextLimit;
8650
8712
  const classified = bd ? bd.system + bd.tool + bd.summaries + bd.code + bd.text : 0;
8651
- const systemPromptText = ctx.getSystemPrompt?.() ?? "";
8713
+ const systemPromptText = getSystemPromptText(ctx);
8652
8714
  const systemPromptTokens = systemPromptText ? defaultCountTokens(systemPromptText) : 0;
8653
8715
  const framework = bd ? Math.max(0, tokenCount - classified - systemPromptTokens) : 0;
8654
8716
  const displayTotal = tokenCount;
@@ -8656,7 +8718,7 @@ async function statusReport(runtime, ctx) {
8656
8718
  const activeBlocksList = state.blocks.filter((b) => b.active);
8657
8719
  const totalBlocksList = state.blocks;
8658
8720
  const lines = [];
8659
- const versionStr = "0.1.29" ? `billion-context-pi@${"0.1.29"}` : "";
8721
+ const versionStr = "0.1.30" ? `billion-context-pi@${"0.1.30"}` : "";
8660
8722
  lines.push("\u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E");
8661
8723
  lines.push("\u2502 ACP Context Analysis \u2502");
8662
8724
  lines.push("\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F");
@@ -8961,11 +9023,12 @@ async function readPackageJson(path4) {
8961
9023
  }
8962
9024
  function findNpmRoot(extDir) {
8963
9025
  let dir = dirname3(extDir);
8964
- while (dir !== "/" && dir !== ".") {
9026
+ for (; ; ) {
8965
9027
  if (dir.endsWith("node_modules")) return dirname3(dir);
8966
- dir = dirname3(dir);
9028
+ const parent = dirname3(dir);
9029
+ if (parent === dir) return void 0;
9030
+ dir = parent;
8967
9031
  }
8968
- return void 0;
8969
9032
  }
8970
9033
  async function findExtensionDir() {
8971
9034
  let dir = dirname3(fileURLToPath(import.meta.url));
@@ -9021,7 +9084,7 @@ async function checkForUpdate(autoUpdate, notify) {
9021
9084
  const data = await res.json();
9022
9085
  const latest = data.version;
9023
9086
  if (!latest) return;
9024
- const current = runtimeVersion ?? "0.1.29";
9087
+ const current = runtimeVersion ?? "0.1.30";
9025
9088
  const hasUpdate = isNewer(latest, current);
9026
9089
  debug.event("update-check", {
9027
9090
  current,
@@ -9260,7 +9323,7 @@ function wireSessionLifecycle(pi, runtime) {
9260
9323
  runtime.store.invalidate();
9261
9324
  runtime.clearNudgeTracking();
9262
9325
  const sid = ctx.sessionManager.getSessionId();
9263
- logInfo("session", { event: "start", sid, cwd: ctx.cwd, debug: runtime.adapter.debug ?? null, version: true ? "0.1.29" : null });
9326
+ logInfo("session", { event: "start", sid, cwd: ctx.cwd, debug: runtime.adapter.debug ?? null, version: true ? "0.1.30" : null });
9264
9327
  try {
9265
9328
  const user = await loadUserConfig(ctx.cwd);
9266
9329
  runtime.setAdapter(applyUserConfig(runtime.adapter, user));
@@ -9289,7 +9352,7 @@ function wireContextTransform(pi, runtime) {
9289
9352
  const sid = ctx.sessionManager.getSessionId();
9290
9353
  const release = await runtime.acquireLock(sid);
9291
9354
  try {
9292
- const { state, coreMessages, entries } = await runtime.stateFor(ctx);
9355
+ const { state, coreMessages, entries } = await runtime.stateFor(ctx, event.messages);
9293
9356
  const config = runtime.configFor(ctx);
9294
9357
  const coveredIds = collectCoveredMessageIds(state);
9295
9358
  const realUsage = ctx.getContextUsage?.();
@@ -9382,15 +9445,13 @@ function wireSystemPrompt(pi, runtime) {
9382
9445
  const delegate = runtime.adapter.delegate !== false;
9383
9446
  const prompt = delegate ? `${ACP_SYSTEM_PROMPT}
9384
9447
  ${ACP_DELEGATE_PROMPT}` : ACP_SYSTEM_PROMPT;
9385
- return { systemPrompt: `${event.systemPrompt}
9386
-
9387
- ${prompt}` };
9448
+ return { systemPrompt: formatSystemPromptForEvent(event.systemPrompt, prompt) };
9388
9449
  });
9389
9450
  }
9390
9451
  function collectOriginals(entries) {
9391
9452
  const map = /* @__PURE__ */ new Map();
9392
9453
  for (const entry of entries) {
9393
- if (entry.type === "message") {
9454
+ if (entry.type === "message" && entry.message) {
9394
9455
  map.set(entry.id, entry.message);
9395
9456
  } else if (entry.type === "custom_message") {
9396
9457
  const content = typeof entry.content === "string" ? [{ type: "text", text: entry.content }] : entry.content;