@ekkos/cli 0.2.7 → 0.2.8

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,13 +55,20 @@ export interface SessionMeta {
55
55
  project_path?: string;
56
56
  created_at: string;
57
57
  }
58
+ /**
59
+ * Open loop detected during stream restore (incomplete tool, etc.)
60
+ */
61
+ export interface OpenLoop {
62
+ type: string;
63
+ detail: string;
64
+ }
58
65
  /**
59
66
  * Restore payload returned by RestoreOrchestrator
60
67
  */
61
68
  export interface RestorePayload {
62
69
  session_id: string;
63
70
  session_name: string;
64
- source: 'local' | 'redis' | 'supabase';
71
+ source: 'local' | 'redis' | 'supabase' | 'stream';
65
72
  restored_turns: Turn[];
66
73
  latest: {
67
74
  user_query: string;
@@ -80,6 +87,8 @@ export interface RestorePayload {
80
87
  token_estimate: number;
81
88
  complete_turn_count: number;
82
89
  has_pending: boolean;
90
+ is_stream_restore?: boolean;
91
+ open_loops?: OpenLoop[];
83
92
  };
84
93
  }
85
94
  /**
@@ -121,7 +130,7 @@ export interface CacheResult<T> {
121
130
  success: boolean;
122
131
  data?: T;
123
132
  error?: string;
124
- source?: 'local' | 'redis' | 'supabase';
133
+ source?: 'local' | 'redis' | 'supabase' | 'stream';
125
134
  latency_ms?: number;
126
135
  }
127
136
  /**
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Stream capture module for ekkOS
3
+ *
4
+ * Provides real-time capture of Claude Code transcripts for
5
+ * near-zero context loss on /continue.
6
+ */
7
+ export * from './types';
8
+ export * from './stream-tailer';
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ /**
3
+ * Stream capture module for ekkOS
4
+ *
5
+ * Provides real-time capture of Claude Code transcripts for
6
+ * near-zero context loss on /continue.
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
20
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
21
+ };
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ __exportStar(require("./types"), exports);
24
+ __exportStar(require("./stream-tailer"), exports);
@@ -0,0 +1,138 @@
1
+ /**
2
+ * JSONL Stream Tailer for Claude Code transcripts
3
+ *
4
+ * Tails ~/.claude/projects/{encoded-path}/{session-uuid}.jsonl
5
+ * and extracts assistant_stream + tool events in real-time.
6
+ *
7
+ * This is the core component for "near-zero context loss" on /continue.
8
+ */
9
+ import { EventEmitter } from 'events';
10
+ import { TailerState, StreamEvent, TurnStatus } from './types';
11
+ export interface StreamTailerOptions {
12
+ transcriptPath: string;
13
+ sessionId: string;
14
+ sessionName?: string;
15
+ cacheDir: string;
16
+ onEvent?: (event: StreamEvent) => void;
17
+ }
18
+ export declare class StreamTailer extends EventEmitter {
19
+ private state;
20
+ private cacheDir;
21
+ private eventLogPath;
22
+ private stateMachinePath;
23
+ private checkpointPath;
24
+ private pollTimer;
25
+ private checkpointTimer;
26
+ private running;
27
+ private onEventCallback?;
28
+ private eventCounter;
29
+ private stateMachine;
30
+ private inProgressText;
31
+ private eventsSinceCheckpoint;
32
+ private seenEventIds;
33
+ /**
34
+ * Generate a stable event_id for idempotency
35
+ *
36
+ * CRITICAL: event_id must be stable for the same underlying transcript data.
37
+ * Using transcript_line_uuid + block_index ensures:
38
+ * - Same ID after tailer restart
39
+ * - De-dupe when reading overlapping transcript ranges
40
+ * - True idempotency for append operations
41
+ *
42
+ * Format: {kind_prefix}_{transcript_line_uuid}_{block_index}_{content_hash}
43
+ */
44
+ private generateEventId;
45
+ /**
46
+ * Generate content hash for delta events
47
+ */
48
+ private hashContent;
49
+ /**
50
+ * Initialize state machine with default values
51
+ */
52
+ private initStateMachine;
53
+ /**
54
+ * Update state machine state
55
+ */
56
+ private updateState;
57
+ /**
58
+ * Update in-progress text head/tail
59
+ */
60
+ private updateInProgressText;
61
+ /**
62
+ * Clear in-progress text (on turn seal)
63
+ */
64
+ private clearInProgressText;
65
+ /**
66
+ * Add open loop
67
+ */
68
+ private addOpenLoop;
69
+ /**
70
+ * Close open loop
71
+ */
72
+ private closeOpenLoop;
73
+ /**
74
+ * Save state machine to disk
75
+ */
76
+ private saveStateMachine;
77
+ /**
78
+ * Save checkpoint
79
+ */
80
+ private saveCheckpoint;
81
+ constructor(options: StreamTailerOptions);
82
+ /**
83
+ * Start tailing the transcript file
84
+ */
85
+ start(): Promise<void>;
86
+ /**
87
+ * Stop tailing
88
+ */
89
+ stop(): void;
90
+ /**
91
+ * Get current state (for debugging/status)
92
+ */
93
+ getState(): Readonly<TailerState>;
94
+ private schedulePoll;
95
+ private poll;
96
+ private readNewContent;
97
+ private processBuffer;
98
+ private processLine;
99
+ private handleUserEvent;
100
+ private handleAssistantEvent;
101
+ private emitEvent;
102
+ }
103
+ /**
104
+ * Utility: Reconstruct StreamTurn from event log
105
+ */
106
+ export declare function reconstructTurnFromEvents(eventLogPath: string, turnId?: number): Promise<{
107
+ turns: Map<number, {
108
+ user_query: string;
109
+ assistant_stream: string;
110
+ tools: Array<{
111
+ kind: string;
112
+ id: string;
113
+ name?: string;
114
+ ts: string;
115
+ }>;
116
+ status: TurnStatus;
117
+ }>;
118
+ latestTurnId: number;
119
+ }>;
120
+ /**
121
+ * Utility: Middle-truncate text (keep head + tail)
122
+ */
123
+ export declare function middleTruncate(text: string, opts?: {
124
+ headChars?: number;
125
+ tailChars?: number;
126
+ maxTotal?: number;
127
+ }): string;
128
+ /**
129
+ * Utility: Detect open loops (incomplete tools)
130
+ */
131
+ export declare function detectOpenLoops(tools: Array<{
132
+ kind: string;
133
+ id: string;
134
+ ts: string;
135
+ }>): Array<{
136
+ type: string;
137
+ detail: string;
138
+ }>;