@tekmidian/pai 0.7.3 → 0.7.5

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.
@@ -3793,7 +3793,7 @@ function cmdLogs(opts) {
3793
3793
  }
3794
3794
  function registerDaemonCommands(daemonCmd) {
3795
3795
  daemonCmd.command("serve").description("Start the PAI daemon in the foreground").action(async () => {
3796
- const { serve } = await import("../daemon-D8ZxcFhU.mjs").then((n) => n.t);
3796
+ const { serve } = await import("../daemon-D8qqODkf.mjs").then((n) => n.t);
3797
3797
  const { loadConfig: lc, ensureConfigDir } = await import("../config-BuhHWyOK.mjs").then((n) => n.r);
3798
3798
  ensureConfigDir();
3799
3799
  await serve(lc());
@@ -8,7 +8,7 @@ import "../indexer-D53l5d1U.mjs";
8
8
  import { t as PaiClient } from "../ipc-client-CoyUHPod.mjs";
9
9
  import { i as ensureConfigDir, o as loadConfig } from "../config-BuhHWyOK.mjs";
10
10
  import "../factory-Ygqe_bVZ.mjs";
11
- import { n as serve } from "../daemon-D8ZxcFhU.mjs";
11
+ import { n as serve } from "../daemon-D8qqODkf.mjs";
12
12
  import "../state-C6_vqz7w.mjs";
13
13
  import "../tools-DcaJlYDN.mjs";
14
14
  import "../detector-jGBuYQJM.mjs";
@@ -1480,7 +1480,7 @@ ${filesSection ? `\nFILES MODIFIED:\n${filesSection}` : ""}`;
1480
1480
  * 1. Finding the current session's JSONL transcript
1481
1481
  * 2. Extracting user messages and assistant context
1482
1482
  * 3. Gathering git commits from the session period
1483
- * 4. Spawning Haiku via `claude` CLI to generate a structured summary
1483
+ * 4. Spawning Claude (sonnet for compaction, opus for session end) to generate a structured summary
1484
1484
  * 5. Writing the summary to the project's session note
1485
1485
  *
1486
1486
  * Designed to run inside the daemon's work queue worker. All errors are
@@ -1488,12 +1488,21 @@ ${filesSection ? `\nFILES MODIFIED:\n${filesSection}` : ""}`;
1488
1488
  */
1489
1489
  /** Minimum interval between summaries for the same project (ms). */
1490
1490
  const SUMMARY_COOLDOWN_MS = 1800 * 1e3;
1491
- /** Maximum JSONL content to feed to Haiku (characters). */
1492
- const MAX_JSONL_CHARS = 5e4;
1491
+ /** Maximum JSONL content to feed to the summarizer (characters). */
1492
+ /** Max JSONL chars per model. Opus/Sonnet can handle much more than Haiku. */
1493
+ const MAX_JSONL_CHARS = {
1494
+ haiku: 5e4,
1495
+ sonnet: 2e5,
1496
+ opus: 5e5
1497
+ };
1493
1498
  /** Maximum user messages to include in the prompt. */
1494
1499
  const MAX_USER_MESSAGES = 30;
1495
1500
  /** Timeout for the claude CLI process (ms). */
1496
- const CLAUDE_TIMEOUT_MS = 6e4;
1501
+ const CLAUDE_TIMEOUT_MS = {
1502
+ haiku: 6e4,
1503
+ sonnet: 12e4,
1504
+ opus: 3e5
1505
+ };
1497
1506
  /** File tracking last summary timestamps per project. */
1498
1507
  const COOLDOWN_FILE = join(homedir(), ".config", "pai", "summary-cooldowns.json");
1499
1508
  /** Claude Code projects directory. */
@@ -1578,9 +1587,9 @@ function findLatestJsonl(cwd) {
1578
1587
  }
1579
1588
  /**
1580
1589
  * Parse a JSONL transcript and extract relevant content.
1581
- * Filters noise, truncates to MAX_JSONL_CHARS from the end of the file.
1590
+ * Filters noise, truncates to model-appropriate size from the end of the file.
1582
1591
  */
1583
- function extractFromJsonl(jsonlPath) {
1592
+ function extractFromJsonl(jsonlPath, model = "sonnet") {
1584
1593
  const result = {
1585
1594
  userMessages: [],
1586
1595
  filesModified: [],
@@ -1592,8 +1601,9 @@ function extractFromJsonl(jsonlPath) {
1592
1601
  } catch (e) {
1593
1602
  throw new Error(`Could not read JSONL at ${jsonlPath}: ${e}`);
1594
1603
  }
1595
- if (raw.length > MAX_JSONL_CHARS) {
1596
- const truncPoint = raw.indexOf("\n", raw.length - MAX_JSONL_CHARS);
1604
+ const maxChars = MAX_JSONL_CHARS[model] ?? 2e5;
1605
+ if (raw.length > maxChars) {
1606
+ const truncPoint = raw.indexOf("\n", raw.length - maxChars);
1597
1607
  raw = truncPoint >= 0 ? raw.slice(truncPoint + 1) : raw.slice(-MAX_JSONL_CHARS);
1598
1608
  }
1599
1609
  const lines = raw.trim().split("\n");
@@ -1707,11 +1717,14 @@ function findClaudeBinary() {
1707
1717
  return null;
1708
1718
  }
1709
1719
  /**
1710
- * Spawn Haiku via the claude CLI to generate a session summary.
1711
- * Pipes the prompt via stdin to `claude --model haiku --print --no-input`.
1720
+ * Spawn a Claude model via the CLI to generate a session summary.
1721
+ * Pipes the prompt via stdin. Model selection:
1722
+ * - opus: session end (best quality for final summary, runs once)
1723
+ * - sonnet: auto-compaction (good quality for incremental checkpoints, runs often)
1724
+ * - haiku: fallback / budget mode
1712
1725
  * Returns the generated text, or null if spawning fails.
1713
1726
  */
1714
- async function spawnHaikuSummarizer(prompt) {
1727
+ async function spawnSummarizer(prompt, model = "sonnet") {
1715
1728
  const claudeBin = findClaudeBinary();
1716
1729
  if (!claudeBin) {
1717
1730
  process.stderr.write("[session-summary] Claude CLI not found in PATH or common locations.\n");
@@ -1722,7 +1735,7 @@ async function spawnHaikuSummarizer(prompt) {
1722
1735
  let timer = null;
1723
1736
  const child = spawn(claudeBin, [
1724
1737
  "--model",
1725
- "haiku",
1738
+ model,
1726
1739
  "-p",
1727
1740
  "--no-session-persistence"
1728
1741
  ], {
@@ -1746,7 +1759,7 @@ async function spawnHaikuSummarizer(prompt) {
1746
1759
  clearTimeout(timer);
1747
1760
  timer = null;
1748
1761
  }
1749
- process.stderr.write(`[session-summary] Haiku spawn error: ${err.message}\n`);
1762
+ process.stderr.write(`[session-summary] ${model} spawn error: ${err.message}\n`);
1750
1763
  resolve(null);
1751
1764
  });
1752
1765
  child.on("close", (code) => {
@@ -1755,15 +1768,15 @@ async function spawnHaikuSummarizer(prompt) {
1755
1768
  timer = null;
1756
1769
  }
1757
1770
  if (code !== 0) {
1758
- process.stderr.write(`[session-summary] Haiku exited with code ${code}: ${stderr.slice(0, 300)}\n`);
1771
+ process.stderr.write(`[session-summary] ${model} exited with code ${code}: ${stderr.slice(0, 300)}\n`);
1759
1772
  resolve(null);
1760
1773
  } else resolve(stdout.trim() || null);
1761
1774
  });
1762
1775
  timer = setTimeout(() => {
1763
- process.stderr.write("[session-summary] Haiku timed out — killing process.\n");
1776
+ process.stderr.write(`[session-summary] ${model} timed out — killing process.\n`);
1764
1777
  child.kill("SIGTERM");
1765
1778
  resolve(null);
1766
- }, CLAUDE_TIMEOUT_MS);
1779
+ }, CLAUDE_TIMEOUT_MS[model] ?? 12e4);
1767
1780
  child.stdin.write(prompt);
1768
1781
  child.stdin.end();
1769
1782
  });
@@ -1896,7 +1909,8 @@ async function handleSessionSummary(payload) {
1896
1909
  return;
1897
1910
  }
1898
1911
  process.stderr.write(`[session-summary] Using transcript: ${jsonlPath}\n`);
1899
- const extracted = extractFromJsonl(jsonlPath);
1912
+ const selectedModel = payload.model ?? (force ? "opus" : "sonnet");
1913
+ const extracted = extractFromJsonl(jsonlPath, selectedModel);
1900
1914
  if (extracted.userMessages.length === 0) {
1901
1915
  process.stderr.write("[session-summary] No user messages found in transcript — skipping.\n");
1902
1916
  return;
@@ -1921,14 +1935,14 @@ async function handleSessionSummary(payload) {
1921
1935
  filesModified: extracted.filesModified,
1922
1936
  existingNote
1923
1937
  });
1924
- process.stderr.write(`[session-summary] Sending ${prompt.length} char prompt to Haiku...\n`);
1925
- const summaryText = await spawnHaikuSummarizer(prompt);
1938
+ process.stderr.write(`[session-summary] Sending ${prompt.length} char prompt to ${selectedModel}...\n`);
1939
+ const summaryText = await spawnSummarizer(prompt, selectedModel);
1926
1940
  if (!summaryText) {
1927
- process.stderr.write("[session-summary] Haiku did not produce output — falling back to mechanical checkpoint.\n");
1941
+ process.stderr.write(`[session-summary] ${selectedModel} did not produce output — falling back to mechanical checkpoint.\n`);
1928
1942
  markCooldown(cwd);
1929
1943
  return;
1930
1944
  }
1931
- process.stderr.write(`[session-summary] Haiku produced ${summaryText.length} char summary.\n`);
1945
+ process.stderr.write(`[session-summary] ${selectedModel} produced ${summaryText.length} char summary.\n`);
1932
1946
  const notePath = writeSessionNote(cwd, summaryText, extracted.filesModified);
1933
1947
  if (notePath) process.stderr.write(`[session-summary] Session note written: ${basename(notePath)}\n`);
1934
1948
  markCooldown(cwd);
@@ -2755,4 +2769,4 @@ var daemon_exports = /* @__PURE__ */ __exportAll({ serve: () => serve });
2755
2769
 
2756
2770
  //#endregion
2757
2771
  export { serve as n, daemon_exports as t };
2758
- //# sourceMappingURL=daemon-D8ZxcFhU.mjs.map
2772
+ //# sourceMappingURL=daemon-D8qqODkf.mjs.map