@pikiloom/kernel 0.3.12 → 0.3.14

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.
@@ -55,6 +55,10 @@ export type DriverEvent = {
55
55
  } | {
56
56
  type: 'activity';
57
57
  line: string;
58
+ } | {
59
+ type: 'compaction';
60
+ trigger: 'auto' | 'manual';
61
+ atTokens?: number | null;
58
62
  };
59
63
  export type SteerFn = (prompt: string, attachments?: string[]) => Promise<boolean>;
60
64
  export interface DriverContext {
@@ -468,6 +468,15 @@ export function handleClaudeEvent(ev, s, emit) {
468
468
  }
469
469
  s.model = ev.model ?? s.model;
470
470
  s.contextWindow = claudeEffectiveContextWindow(claudeContextWindowFromModel(s.model)) ?? s.contextWindow;
471
+ // Claude compacted the running context (subtype `compact_boundary`): `trigger` is
472
+ // `auto` (the context filled up) or `manual` (a `/compact` command). Surface it live
473
+ // so a terminal can show a "compacting" affordance; the compacted summary itself lands
474
+ // in the native transcript and settles into a divider separately.
475
+ if (ev.subtype === 'compact_boundary') {
476
+ const meta = (ev.compact_metadata ?? {});
477
+ emit({ type: 'compaction', trigger: meta.trigger === 'manual' ? 'manual' : 'auto', atTokens: typeof meta.pre_tokens === 'number' ? meta.pre_tokens : null });
478
+ return;
479
+ }
471
480
  // Live thinking progress (system/thinking_tokens, ~every 1.4s of sustained thinking): during
472
481
  // extended thinking a subscription account streams no plaintext (signature_delta only) and no
473
482
  // usage until the message settles, so without projecting these the terminal shows a dead
@@ -320,6 +320,9 @@ export class CodexDriver {
320
320
  state.sessionId = threadId;
321
321
  ctx.emit({ type: 'session', sessionId: threadId });
322
322
  }
323
+ // Codex emits no explicit compaction event, so track peak occupancy: a sharp
324
+ // mid-turn drop is an auto-compaction, surfaced as a live `compaction` signal.
325
+ let compactPeakTokens = 0;
323
326
  srv.onNotification((method, params) => {
324
327
  if (params?.threadId && params.threadId !== state.sessionId && method !== 'turn/started')
325
328
  return;
@@ -444,6 +447,21 @@ export class CodexDriver {
444
447
  case 'thread/tokenUsage/updated': {
445
448
  applyCodexTokenUsage(state, params?.tokenUsage || params?.usage);
446
449
  ctx.emit({ type: 'usage', usage: codexUsageOf(state) });
450
+ // No explicit boundary event: a sharp drop from a high peak IS a compaction.
451
+ // Conservative thresholds (peak ≥ 50% of window, drop ≥ 25% of window) so
452
+ // ordinary turn churn never trips it; re-baseline so it fires once per drop.
453
+ {
454
+ const cw = state.contextWindow ?? 0;
455
+ const used = state.contextUsed ?? 0;
456
+ if (cw > 0 && used >= 0) {
457
+ if (used > compactPeakTokens)
458
+ compactPeakTokens = used;
459
+ else if (compactPeakTokens / cw >= 0.5 && (compactPeakTokens - used) / cw >= 0.25) {
460
+ ctx.emit({ type: 'compaction', trigger: 'auto', atTokens: compactPeakTokens });
461
+ compactPeakTokens = used;
462
+ }
463
+ }
464
+ }
447
465
  break;
448
466
  }
449
467
  case 'turn/completed': {
@@ -86,6 +86,14 @@ export interface UniversalSnapshot {
86
86
  toolCalls?: UniversalToolCall[];
87
87
  subAgents?: UniversalSubAgent[];
88
88
  usage?: UniversalUsage | null;
89
+ /** Set when the CLI compacted the context mid-turn (its `compact_boundary`
90
+ * event). `trigger` separates an automatic (context-full) compaction from a
91
+ * manual `/compact`. Drives a live "compacting" affordance; because a runner
92
+ * owns one turn, it naturally clears on the next turn. */
93
+ compaction?: {
94
+ trigger: 'auto' | 'manual';
95
+ atTokens?: number | null;
96
+ } | null;
89
97
  artifacts?: UniversalArtifact[];
90
98
  interactions?: UniversalInteraction[];
91
99
  queued?: UniversalQueuedTask[];
@@ -96,6 +96,9 @@ export class SessionRunner {
96
96
  case 'usage':
97
97
  this.snapshot.usage = mergeUsage(this.snapshot.usage, e.usage);
98
98
  break;
99
+ case 'compaction':
100
+ this.snapshot.compaction = { trigger: e.trigger, atTokens: e.atTokens ?? null };
101
+ break;
99
102
  // toolCalls is the structured SSOT; activity is its derived human-readable view.
100
103
  // A driver that streams explicit `activity` lines (e.g. echo) owns activity directly;
101
104
  // any driver that emits structured tool/subagent events gets the projection for free.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pikiloom/kernel",
3
- "version": "0.3.12",
3
+ "version": "0.3.14",
4
4
  "description": "Heterogeneous coding agents (Claude / Codex / Gemini / ACP) -> an interaction-friendly, accumulating session snapshot + control handle, over pluggable surfaces (IM, Web, tunnel, TUI). The reusable core pikiloom itself is built on.",
5
5
  "type": "module",
6
6
  "license": "MIT",