@oh-my-pi/pi-coding-agent 13.7.3 → 13.7.4

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/CHANGELOG.md CHANGED
@@ -2,6 +2,15 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [13.7.4] - 2026-03-04
6
+ ### Added
7
+ - Added `fetch.useKagiSummarizer` setting to toggle Kagi Universal Summarizer usage in the fetch tool.
8
+
9
+ ### Fixed
10
+
11
+ - Fixed incorrect message history reference in session title generation that could cause missing or stale titles on first message
12
+ - Added startup check requiring Bun 1.3.7+ for JSONL session parsing (`Bun.JSONL.parseChunk`) and clear upgrade guidance so `/resume` and `--resume` do not silently report missing sessions on older Bun runtimes
13
+
5
14
  ## [13.7.3] - 2026-03-04
6
15
 
7
16
  ### Added
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-coding-agent",
4
- "version": "13.7.3",
4
+ "version": "13.7.4",
5
5
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
6
6
  "homepage": "https://github.com/can1357/oh-my-pi",
7
7
  "author": "Can Boluk",
@@ -41,12 +41,12 @@
41
41
  },
42
42
  "dependencies": {
43
43
  "@mozilla/readability": "^0.6",
44
- "@oh-my-pi/omp-stats": "13.7.3",
45
- "@oh-my-pi/pi-agent-core": "13.7.3",
46
- "@oh-my-pi/pi-ai": "13.7.3",
47
- "@oh-my-pi/pi-natives": "13.7.3",
48
- "@oh-my-pi/pi-tui": "13.7.3",
49
- "@oh-my-pi/pi-utils": "13.7.3",
44
+ "@oh-my-pi/omp-stats": "13.7.4",
45
+ "@oh-my-pi/pi-agent-core": "13.7.4",
46
+ "@oh-my-pi/pi-ai": "13.7.4",
47
+ "@oh-my-pi/pi-natives": "13.7.4",
48
+ "@oh-my-pi/pi-tui": "13.7.4",
49
+ "@oh-my-pi/pi-utils": "13.7.4",
50
50
  "@sinclair/typebox": "^0.34",
51
51
  "@xterm/headless": "^6.0",
52
52
  "ajv": "^8.18",
package/src/cli.ts CHANGED
@@ -1,11 +1,39 @@
1
1
  #!/usr/bin/env bun
2
- import { APP_NAME, VERSION } from "@oh-my-pi/pi-utils";
2
+ import { APP_NAME, MIN_BUN_VERSION, VERSION } from "@oh-my-pi/pi-utils";
3
3
  /**
4
4
  * CLI entry point — registers all commands explicitly and delegates to the
5
5
  * lightweight CLI runner from pi-utils.
6
6
  */
7
7
  import { type CommandEntry, run } from "@oh-my-pi/pi-utils/cli";
8
8
 
9
+ function parseSemver(version: string): [number, number, number] {
10
+ function toint(value: string): number {
11
+ const int = Number.parseInt(value, 10);
12
+ if (Number.isNaN(int) || !Number.isFinite(int)) return 0;
13
+ return int;
14
+ }
15
+ const [majorRaw, minorRaw, patchRaw] = version.split(".").map(toint);
16
+ return [majorRaw, minorRaw, patchRaw];
17
+ }
18
+
19
+ function isAtLeastBunVersion(minimum: string): boolean {
20
+ const ver = parseSemver(Bun.version);
21
+ const min = parseSemver(minimum);
22
+ for (let i = 0; i < 3; i++) {
23
+ if (ver[i] !== min[i]) {
24
+ return ver[i] > min[i];
25
+ }
26
+ }
27
+ return true;
28
+ }
29
+
30
+ if (typeof Bun.JSONL?.parseChunk !== "function" || !isAtLeastBunVersion(MIN_BUN_VERSION)) {
31
+ process.stderr.write(
32
+ `error: Bun runtime must be >= ${MIN_BUN_VERSION} (found v${Bun.version}). Please update Bun: bun upgrade\n`,
33
+ );
34
+ process.exit(1);
35
+ }
36
+
9
37
  // Detect known Bun errata that cause TUI crashes (e.g. Bun.stringWidth mishandling OSC sequences).
10
38
  if (Bun.stringWidth("\x1b[0m\x1b]8;;\x07") !== 0) {
11
39
  process.stderr.write(`error: Bun runtime errata detected (v${Bun.version}). Please update Bun: bun upgrade\n`);
@@ -490,6 +490,15 @@ export const SETTINGS_SCHEMA = {
490
490
  default: true,
491
491
  ui: { tab: "tools", label: "Enable Fetch", description: "Enable the fetch tool for URL fetching" },
492
492
  },
493
+ "fetch.useKagiSummarizer": {
494
+ type: "boolean",
495
+ default: true,
496
+ ui: {
497
+ tab: "tools",
498
+ label: "Use Kagi in Fetch",
499
+ description: "Use Kagi Universal Summarizer when rendering HTML in fetch",
500
+ },
501
+ },
493
502
  "web_search.enabled": {
494
503
  type: "boolean",
495
504
  default: true,
@@ -300,7 +300,7 @@ export class InputController {
300
300
  this.ctx.flushPendingBashComponents();
301
301
 
302
302
  // Generate session title on first message
303
- const hasUserMessages = this.ctx.agent.state.messages.some((m: AgentMessage) => m.role === "user");
303
+ const hasUserMessages = this.ctx.session.messages.some((m: AgentMessage) => m.role === "user");
304
304
  if (!hasUserMessages && !this.ctx.sessionManager.getSessionName() && !$env.PI_NO_TITLE) {
305
305
  const registry = this.ctx.session.modelRegistry;
306
306
  const smolModel = this.ctx.settings.getModelRole("smol");
@@ -393,7 +393,7 @@ export class InputController {
393
393
  if (allQueued.length === 0) {
394
394
  this.ctx.updatePendingMessagesDisplay();
395
395
  if (options?.abort) {
396
- this.ctx.agent.abort();
396
+ this.ctx.session.abort();
397
397
  }
398
398
  return 0;
399
399
  }
@@ -403,7 +403,7 @@ export class InputController {
403
403
  this.ctx.editor.setText(combinedText);
404
404
  this.ctx.updatePendingMessagesDisplay();
405
405
  if (options?.abort) {
406
- this.ctx.agent.abort();
406
+ this.ctx.session.abort();
407
407
  }
408
408
  return allQueued.length;
409
409
  }
@@ -429,6 +429,7 @@ async function renderHtmlToText(
429
429
  url: string,
430
430
  html: string,
431
431
  timeout: number,
432
+ useKagiSummarizer: boolean,
432
433
  userSignal?: AbortSignal,
433
434
  ): Promise<{ content: string; ok: boolean; method: string }> {
434
435
  const signal = ptree.combineSignals(userSignal, timeout * 1000);
@@ -440,15 +441,17 @@ async function renderHtmlToText(
440
441
  signal,
441
442
  };
442
443
 
443
- // Try Kagi Universal Summarizer first (if KAGI_API_KEY is configured)
444
- try {
445
- const kagiSummary = await summarizeUrlWithKagi(url, { signal });
446
- if (kagiSummary && kagiSummary.length > 100 && !isLowQualityOutput(kagiSummary)) {
447
- return { content: kagiSummary, ok: true, method: "kagi" };
444
+ // Try Kagi Universal Summarizer first (if enabled and KAGI_API_KEY is configured)
445
+ if (useKagiSummarizer) {
446
+ try {
447
+ const kagiSummary = await summarizeUrlWithKagi(url, { signal });
448
+ if (kagiSummary && kagiSummary.length > 100 && !isLowQualityOutput(kagiSummary)) {
449
+ return { content: kagiSummary, ok: true, method: "kagi" };
450
+ }
451
+ } catch {
452
+ // Kagi failed, continue to next method
453
+ signal?.throwIfAborted();
448
454
  }
449
- } catch {
450
- // Kagi failed, continue to next method
451
- signal?.throwIfAborted();
452
455
  }
453
456
 
454
457
  // Try jina next (reader API)
@@ -564,7 +567,13 @@ async function handleSpecialUrls(url: string, timeout: number, signal?: AbortSig
564
567
  /**
565
568
  * Main render function implementing the full pipeline
566
569
  */
567
- async function renderUrl(url: string, timeout: number, raw: boolean, signal?: AbortSignal): Promise<RenderResult> {
570
+ async function renderUrl(
571
+ url: string,
572
+ timeout: number,
573
+ raw: boolean,
574
+ useKagiSummarizer: boolean,
575
+ signal?: AbortSignal,
576
+ ): Promise<RenderResult> {
568
577
  const notes: string[] = [];
569
578
  const fetchedAt = new Date().toISOString();
570
579
  if (signal?.aborted) {
@@ -803,7 +812,7 @@ async function renderUrl(url: string, timeout: number, raw: boolean, signal?: Ab
803
812
  }
804
813
 
805
814
  // Step 6: Render HTML with lynx or html2text
806
- const htmlResult = await renderHtmlToText(finalUrl, rawContent, timeout, signal);
815
+ const htmlResult = await renderHtmlToText(finalUrl, rawContent, timeout, useKagiSummarizer, signal);
807
816
  if (!htmlResult.ok) {
808
817
  notes.push("html rendering failed (lynx/html2text unavailable)");
809
818
  const output = finalizeOutput(rawContent);
@@ -926,7 +935,8 @@ export class FetchTool implements AgentTool<typeof fetchSchema, FetchToolDetails
926
935
  throw new ToolAbortError();
927
936
  }
928
937
 
929
- const result = await renderUrl(url, effectiveTimeout, raw, signal);
938
+ const useKagiSummarizer = this.session.settings.get("fetch.useKagiSummarizer");
939
+ const result = await renderUrl(url, effectiveTimeout, raw, useKagiSummarizer, signal);
930
940
  const truncation = truncateHead(result.content, {
931
941
  maxBytes: DEFAULT_MAX_BYTES,
932
942
  maxLines: FETCH_DEFAULT_MAX_LINES,