@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.
- package/dist/cache/types.d.ts +11 -2
- package/dist/capture/index.d.ts +8 -0
- package/dist/capture/index.js +24 -0
- package/dist/capture/stream-tailer.d.ts +138 -0
- package/dist/capture/stream-tailer.js +658 -0
- package/dist/capture/types.d.ts +227 -0
- package/dist/capture/types.js +5 -0
- package/dist/commands/run.js +117 -7
- package/dist/commands/stream.d.ts +19 -0
- package/dist/commands/stream.js +340 -0
- package/dist/index.js +58 -1
- package/dist/restore/RestoreOrchestrator.d.ts +6 -0
- package/dist/restore/RestoreOrchestrator.js +174 -22
- package/dist/utils/state.d.ts +39 -1
- package/dist/utils/state.js +152 -2
- package/package.json +1 -1
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stream capture types for mid-turn context preservation
|
|
3
|
+
*/
|
|
4
|
+
export type TurnStatus = 'in_progress' | 'complete';
|
|
5
|
+
/**
|
|
6
|
+
* How a turn was sealed (closed)
|
|
7
|
+
*/
|
|
8
|
+
export type SealReason = 'user_boundary' | 'explicit' | 'process_exit' | 'context_wall';
|
|
9
|
+
export interface ToolEvent {
|
|
10
|
+
kind: 'tool_use' | 'tool_result';
|
|
11
|
+
id: string;
|
|
12
|
+
name?: string;
|
|
13
|
+
input?: unknown;
|
|
14
|
+
output?: unknown;
|
|
15
|
+
is_error?: boolean;
|
|
16
|
+
ts: string;
|
|
17
|
+
transcript_line_uuid?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface StreamTurn {
|
|
20
|
+
session_id: string;
|
|
21
|
+
session_name?: string;
|
|
22
|
+
turn_id: number;
|
|
23
|
+
started_at: string;
|
|
24
|
+
updated_at: string;
|
|
25
|
+
user_query?: string;
|
|
26
|
+
assistant_stream: string;
|
|
27
|
+
assistant_response?: string;
|
|
28
|
+
status: TurnStatus;
|
|
29
|
+
stream_offset: number;
|
|
30
|
+
tools: ToolEvent[];
|
|
31
|
+
files_referenced?: string[];
|
|
32
|
+
files_modified?: string[];
|
|
33
|
+
last_text_delta_ts?: string;
|
|
34
|
+
last_tool_event_ts?: string;
|
|
35
|
+
sealed_at?: string;
|
|
36
|
+
sealed_by?: SealReason;
|
|
37
|
+
}
|
|
38
|
+
export type StreamEvent = {
|
|
39
|
+
kind: 'session_start';
|
|
40
|
+
event_id: string;
|
|
41
|
+
session_id: string;
|
|
42
|
+
session_name?: string;
|
|
43
|
+
ts: string;
|
|
44
|
+
} | {
|
|
45
|
+
kind: 'user_query';
|
|
46
|
+
event_id: string;
|
|
47
|
+
turn_id: number;
|
|
48
|
+
query: string;
|
|
49
|
+
ts: string;
|
|
50
|
+
transcript_line_uuid?: string;
|
|
51
|
+
} | {
|
|
52
|
+
kind: 'assistant_text_delta';
|
|
53
|
+
event_id: string;
|
|
54
|
+
turn_id: number;
|
|
55
|
+
delta: string;
|
|
56
|
+
offset: number;
|
|
57
|
+
ts: string;
|
|
58
|
+
transcript_line_uuid?: string;
|
|
59
|
+
} | {
|
|
60
|
+
kind: 'tool_use';
|
|
61
|
+
event_id: string;
|
|
62
|
+
turn_id: number;
|
|
63
|
+
id: string;
|
|
64
|
+
name: string;
|
|
65
|
+
input?: unknown;
|
|
66
|
+
ts: string;
|
|
67
|
+
transcript_line_uuid?: string;
|
|
68
|
+
} | {
|
|
69
|
+
kind: 'tool_result';
|
|
70
|
+
event_id: string;
|
|
71
|
+
turn_id: number;
|
|
72
|
+
id: string;
|
|
73
|
+
output?: unknown;
|
|
74
|
+
is_error?: boolean;
|
|
75
|
+
ts: string;
|
|
76
|
+
transcript_line_uuid?: string;
|
|
77
|
+
} | {
|
|
78
|
+
kind: 'seal_turn';
|
|
79
|
+
event_id: string;
|
|
80
|
+
turn_id: number;
|
|
81
|
+
reason: SealReason;
|
|
82
|
+
ts: string;
|
|
83
|
+
};
|
|
84
|
+
export interface TranscriptLine {
|
|
85
|
+
type: 'user' | 'assistant' | string;
|
|
86
|
+
uuid: string;
|
|
87
|
+
parentUuid?: string | null;
|
|
88
|
+
timestamp: string;
|
|
89
|
+
sessionId: string;
|
|
90
|
+
cwd?: string;
|
|
91
|
+
gitBranch?: string;
|
|
92
|
+
version?: string;
|
|
93
|
+
isMeta?: boolean;
|
|
94
|
+
message: {
|
|
95
|
+
role: 'user' | 'assistant';
|
|
96
|
+
model?: string;
|
|
97
|
+
content: string | ContentBlock[];
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
export interface ContentBlock {
|
|
101
|
+
type: 'text' | 'thinking' | 'tool_use' | 'tool_result';
|
|
102
|
+
text?: string;
|
|
103
|
+
thinking?: string;
|
|
104
|
+
signature?: string;
|
|
105
|
+
id?: string;
|
|
106
|
+
name?: string;
|
|
107
|
+
input?: unknown;
|
|
108
|
+
tool_use_id?: string;
|
|
109
|
+
content?: unknown;
|
|
110
|
+
is_error?: boolean;
|
|
111
|
+
}
|
|
112
|
+
export interface TailerState {
|
|
113
|
+
transcriptPath: string;
|
|
114
|
+
sessionId: string;
|
|
115
|
+
sessionName?: string;
|
|
116
|
+
readOffset: number;
|
|
117
|
+
pendingBuffer: string;
|
|
118
|
+
currentTurnId: number;
|
|
119
|
+
currentTurnStatus: TurnStatus;
|
|
120
|
+
lastActivityTs: number;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Stream state - where are we in the conversation flow?
|
|
124
|
+
*/
|
|
125
|
+
export type StreamState = 'idle' | 'assistant_streaming' | 'tool_running' | 'interrupted' | 'wall_hit';
|
|
126
|
+
/**
|
|
127
|
+
* Stream state machine - deterministic resume anchor
|
|
128
|
+
*/
|
|
129
|
+
export interface StreamStateMachine {
|
|
130
|
+
session_id: string;
|
|
131
|
+
session_name?: string;
|
|
132
|
+
state: StreamState;
|
|
133
|
+
state_entered_at: string;
|
|
134
|
+
last_complete_turn_id: number;
|
|
135
|
+
current_turn_id: number;
|
|
136
|
+
in_progress_text_head: string;
|
|
137
|
+
in_progress_text_tail: string;
|
|
138
|
+
in_progress_total_chars: number;
|
|
139
|
+
open_loops: Array<{
|
|
140
|
+
type: 'tool' | 'plan_step';
|
|
141
|
+
id: string;
|
|
142
|
+
name: string;
|
|
143
|
+
started_at: string;
|
|
144
|
+
}>;
|
|
145
|
+
last_event_ts: string;
|
|
146
|
+
last_checkpoint_ts: string;
|
|
147
|
+
stream_bytes_captured: number;
|
|
148
|
+
events_captured: number;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* In-progress checkpoint - saved every N seconds for crash recovery
|
|
152
|
+
*/
|
|
153
|
+
export interface StreamCheckpoint {
|
|
154
|
+
session_id: string;
|
|
155
|
+
turn_id: number;
|
|
156
|
+
checkpoint_ts: string;
|
|
157
|
+
text_head: string;
|
|
158
|
+
text_tail: string;
|
|
159
|
+
state: StreamState;
|
|
160
|
+
open_loops: Array<{
|
|
161
|
+
type: string;
|
|
162
|
+
id: string;
|
|
163
|
+
name: string;
|
|
164
|
+
started_at: string;
|
|
165
|
+
}>;
|
|
166
|
+
total_chars: number;
|
|
167
|
+
events_since_last_checkpoint: number;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Open loop - work started but not completed
|
|
171
|
+
*/
|
|
172
|
+
export interface OpenLoop {
|
|
173
|
+
type: 'tool' | 'plan_step' | 'user_request';
|
|
174
|
+
name: string;
|
|
175
|
+
status: 'in_progress' | 'blocked' | 'waiting';
|
|
176
|
+
started_at: string;
|
|
177
|
+
context?: string;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Work phase derived from activity patterns
|
|
181
|
+
*/
|
|
182
|
+
export type WorkPhase = 'Plan' | 'Implement' | 'Verify' | 'Fix' | 'Deploy';
|
|
183
|
+
/**
|
|
184
|
+
* WorkState Capsule - deterministic resume anchor for Time Machine
|
|
185
|
+
*
|
|
186
|
+
* This is the machine-derived state that guarantees perfect continuation.
|
|
187
|
+
* It's built from streaming capture data and injected by /continue.
|
|
188
|
+
*/
|
|
189
|
+
export interface WorkStateCapsule {
|
|
190
|
+
goal: string;
|
|
191
|
+
phase: WorkPhase;
|
|
192
|
+
next_step: string;
|
|
193
|
+
open_loops: OpenLoop[];
|
|
194
|
+
files_in_play: string[];
|
|
195
|
+
decisions_made: string[];
|
|
196
|
+
blockers?: string[];
|
|
197
|
+
last_good_output_tail: string;
|
|
198
|
+
continuation_instruction: string;
|
|
199
|
+
generated_at: string;
|
|
200
|
+
turn_id: number;
|
|
201
|
+
session_id: string;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Timeline event for Time Machine display
|
|
205
|
+
*/
|
|
206
|
+
export interface TimelineEvent {
|
|
207
|
+
turn_id: number;
|
|
208
|
+
timestamp: string;
|
|
209
|
+
phase: WorkPhase;
|
|
210
|
+
summary: string;
|
|
211
|
+
impact?: string;
|
|
212
|
+
tools_used: string[];
|
|
213
|
+
files_touched: string[];
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Evidence entry for audit trail
|
|
217
|
+
*/
|
|
218
|
+
export interface EvidenceEntry {
|
|
219
|
+
turn_id: number;
|
|
220
|
+
timestamp: string;
|
|
221
|
+
tool_events: ToolEvent[];
|
|
222
|
+
files_touched: string[];
|
|
223
|
+
diff_summary?: string;
|
|
224
|
+
transcript_line_uuid: string;
|
|
225
|
+
transcript_path: string;
|
|
226
|
+
raw_transcript_offset?: number;
|
|
227
|
+
}
|
package/dist/commands/run.js
CHANGED
|
@@ -44,6 +44,7 @@ const os = __importStar(require("os"));
|
|
|
44
44
|
const child_process_1 = require("child_process");
|
|
45
45
|
const state_1 = require("../utils/state");
|
|
46
46
|
const doctor_1 = require("./doctor");
|
|
47
|
+
const stream_tailer_1 = require("../capture/stream-tailer");
|
|
47
48
|
// Try to load node-pty (may fail on Node 24+)
|
|
48
49
|
let pty = null;
|
|
49
50
|
try {
|
|
@@ -510,9 +511,55 @@ async function run(options) {
|
|
|
510
511
|
(0, state_1.clearAutoClearFlag)();
|
|
511
512
|
// Track state
|
|
512
513
|
let currentSession = options.session || (0, state_1.getCurrentSessionName)();
|
|
514
|
+
// ════════════════════════════════════════════════════════════════════════════
|
|
515
|
+
// MULTI-SESSION SUPPORT: Register this process as an active session
|
|
516
|
+
// This prevents state collision when multiple Claude Code instances run
|
|
517
|
+
// ════════════════════════════════════════════════════════════════════════════
|
|
518
|
+
(0, state_1.registerActiveSession)('pending', // Session ID not yet known
|
|
519
|
+
currentSession || 'initializing', process.cwd());
|
|
520
|
+
dlog(`Registered active session (PID ${process.pid})`);
|
|
521
|
+
// Show active sessions count if verbose
|
|
522
|
+
if (verbose) {
|
|
523
|
+
const activeSessions = (0, state_1.getActiveSessions)();
|
|
524
|
+
if (activeSessions.length > 1) {
|
|
525
|
+
console.log(chalk_1.default.cyan(` 📊 Active ekkOS sessions: ${activeSessions.length}`));
|
|
526
|
+
}
|
|
527
|
+
}
|
|
513
528
|
let isAutoClearInProgress = false;
|
|
514
529
|
let transcriptPath = null;
|
|
515
530
|
let currentSessionId = null;
|
|
531
|
+
// Stream tailer for mid-turn context capture
|
|
532
|
+
let streamTailer = null;
|
|
533
|
+
const streamCacheDir = path.join(os.homedir(), '.ekkos', 'cache', 'sessions');
|
|
534
|
+
// Helper to start stream tailer when we have transcript path
|
|
535
|
+
function startStreamTailer(tPath, sId, sName) {
|
|
536
|
+
if (streamTailer)
|
|
537
|
+
return; // Already running
|
|
538
|
+
try {
|
|
539
|
+
streamTailer = new stream_tailer_1.StreamTailer({
|
|
540
|
+
transcriptPath: tPath,
|
|
541
|
+
sessionId: sId,
|
|
542
|
+
sessionName: sName,
|
|
543
|
+
cacheDir: streamCacheDir,
|
|
544
|
+
onEvent: (event) => {
|
|
545
|
+
dlog(`Stream event: ${event.kind} (turn ${event.turn_id || 'n/a'})`);
|
|
546
|
+
}
|
|
547
|
+
});
|
|
548
|
+
streamTailer.start();
|
|
549
|
+
dlog(`Stream tailer started for ${sName || sId}`);
|
|
550
|
+
}
|
|
551
|
+
catch (err) {
|
|
552
|
+
dlog(`Failed to start stream tailer: ${err.message}`);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
// Helper to stop stream tailer
|
|
556
|
+
function stopStreamTailer() {
|
|
557
|
+
if (streamTailer) {
|
|
558
|
+
streamTailer.stop();
|
|
559
|
+
streamTailer = null;
|
|
560
|
+
dlog('Stream tailer stopped');
|
|
561
|
+
}
|
|
562
|
+
}
|
|
516
563
|
// ══════════════════════════════════════════════════════════════════════════
|
|
517
564
|
// SESSION NAME TRACKING (from live TUI output)
|
|
518
565
|
// Claude prints: "· Turn N · groovy-koala-saves · 📅"
|
|
@@ -701,16 +748,26 @@ async function run(options) {
|
|
|
701
748
|
}
|
|
702
749
|
}
|
|
703
750
|
// PRIORITY 4: Persisted state (last resort)
|
|
751
|
+
// CRITICAL: Always validate sessionName - persisted state may have invalid names
|
|
752
|
+
// like "claude-plugins-official" from directory names or false positives
|
|
704
753
|
if (!sessionToRestore) {
|
|
705
754
|
const state = (0, state_1.getState)();
|
|
706
|
-
|
|
755
|
+
const persistedName = state?.sessionName || null;
|
|
707
756
|
const sessionId = state?.sessionId || null;
|
|
708
|
-
//
|
|
709
|
-
if (
|
|
710
|
-
sessionToRestore =
|
|
757
|
+
// Validate persisted name - only use if it passes word list validation
|
|
758
|
+
if (persistedName && isValidSessionName(persistedName)) {
|
|
759
|
+
sessionToRestore = persistedName;
|
|
760
|
+
dlog(`Using validated persisted state: ${sessionToRestore}`);
|
|
711
761
|
}
|
|
712
|
-
if (
|
|
713
|
-
|
|
762
|
+
else if (sessionId) {
|
|
763
|
+
// Derive from UUID if persisted name is invalid or missing
|
|
764
|
+
sessionToRestore = (0, state_1.uuidToWords)(sessionId);
|
|
765
|
+
if (persistedName) {
|
|
766
|
+
dlog(`Persisted name "${persistedName}" invalid, derived from UUID: ${sessionToRestore}`);
|
|
767
|
+
}
|
|
768
|
+
else {
|
|
769
|
+
dlog(`No persisted name, derived from UUID: ${sessionToRestore}`);
|
|
770
|
+
}
|
|
714
771
|
}
|
|
715
772
|
}
|
|
716
773
|
const sessionDisplay = sessionToRestore || 'unknown-session';
|
|
@@ -796,18 +853,35 @@ async function run(options) {
|
|
|
796
853
|
outputBuffer = outputBuffer.slice(-2000);
|
|
797
854
|
}
|
|
798
855
|
// Try to extract transcript path from output (Claude shows it on startup)
|
|
799
|
-
const transcriptMatch = data.match(/transcript[_\s]?(?:path)?[:\s]+([^\s\n]+\.
|
|
856
|
+
const transcriptMatch = data.match(/transcript[_\s]?(?:path)?[:\s]+([^\s\n]+\.jsonl?)/i);
|
|
800
857
|
if (transcriptMatch) {
|
|
801
858
|
transcriptPath = transcriptMatch[1];
|
|
802
859
|
dlog(`Detected transcript: ${transcriptPath}`);
|
|
860
|
+
// Start tailer if we have session ID
|
|
861
|
+
if (currentSessionId && transcriptPath) {
|
|
862
|
+
startStreamTailer(transcriptPath, currentSessionId, currentSession || undefined);
|
|
863
|
+
}
|
|
803
864
|
}
|
|
804
865
|
// Try to extract session ID from output (fallback - Claude rarely prints this)
|
|
805
866
|
const sessionMatch = data.match(/session[_\s]?(?:id)?[:\s]+([a-f0-9-]{36})/i);
|
|
806
867
|
if (sessionMatch) {
|
|
807
868
|
currentSessionId = sessionMatch[1];
|
|
808
869
|
currentSession = (0, state_1.uuidToWords)(currentSessionId);
|
|
870
|
+
// Update THIS process's session entry (not global state.json)
|
|
871
|
+
(0, state_1.updateCurrentProcessSession)(currentSessionId, currentSession);
|
|
872
|
+
// Also update global state for backwards compatibility
|
|
809
873
|
(0, state_1.updateState)({ sessionId: currentSessionId, sessionName: currentSession });
|
|
810
874
|
dlog(`Session detected from UUID: ${currentSession}`);
|
|
875
|
+
// Try to find/construct transcript path from session ID
|
|
876
|
+
if (!transcriptPath) {
|
|
877
|
+
const encodedCwd = process.cwd().replace(/\//g, '-').replace(/^-/, '');
|
|
878
|
+
const possibleTranscript = path.join(os.homedir(), '.claude', 'projects', encodedCwd, `${currentSessionId}.jsonl`);
|
|
879
|
+
if (fs.existsSync(possibleTranscript)) {
|
|
880
|
+
transcriptPath = possibleTranscript;
|
|
881
|
+
dlog(`Found transcript from session ID: ${transcriptPath}`);
|
|
882
|
+
startStreamTailer(transcriptPath, currentSessionId, currentSession || undefined);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
811
885
|
}
|
|
812
886
|
// ════════════════════════════════════════════════════════════════════════
|
|
813
887
|
// SESSION NAME DETECTION (PRIMARY METHOD)
|
|
@@ -829,8 +903,37 @@ async function run(options) {
|
|
|
829
903
|
lastSeenSessionAt = Date.now();
|
|
830
904
|
currentSession = lastSeenSessionName;
|
|
831
905
|
observedSessionThisRun = true; // Mark that we've seen a session in THIS process
|
|
906
|
+
// Update THIS process's session entry (not global state.json)
|
|
907
|
+
(0, state_1.updateCurrentProcessSession)(currentSessionId || 'unknown', currentSession);
|
|
908
|
+
// Also update global state for backwards compatibility
|
|
832
909
|
(0, state_1.updateState)({ sessionName: currentSession });
|
|
833
910
|
dlog(`Session detected from status line: ${currentSession} (observedSessionThisRun=true)`);
|
|
911
|
+
// Try to start stream tailer - scan for matching transcript file
|
|
912
|
+
if (!streamTailer) {
|
|
913
|
+
const encodedCwd = process.cwd().replace(/\//g, '-').replace(/^-/, '');
|
|
914
|
+
const projectDir = path.join(os.homedir(), '.claude', 'projects', encodedCwd);
|
|
915
|
+
try {
|
|
916
|
+
const files = fs.readdirSync(projectDir);
|
|
917
|
+
// Find most recent .jsonl file (likely current session)
|
|
918
|
+
const jsonlFiles = files
|
|
919
|
+
.filter(f => f.endsWith('.jsonl'))
|
|
920
|
+
.map(f => ({
|
|
921
|
+
name: f,
|
|
922
|
+
path: path.join(projectDir, f),
|
|
923
|
+
mtime: fs.statSync(path.join(projectDir, f)).mtimeMs
|
|
924
|
+
}))
|
|
925
|
+
.sort((a, b) => b.mtime - a.mtime);
|
|
926
|
+
if (jsonlFiles.length > 0) {
|
|
927
|
+
transcriptPath = jsonlFiles[0].path;
|
|
928
|
+
currentSessionId = jsonlFiles[0].name.replace('.jsonl', '');
|
|
929
|
+
dlog(`Found transcript from project scan: ${transcriptPath}`);
|
|
930
|
+
startStreamTailer(transcriptPath, currentSessionId, currentSession);
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
catch {
|
|
934
|
+
// Project dir might not exist yet
|
|
935
|
+
}
|
|
936
|
+
}
|
|
834
937
|
}
|
|
835
938
|
else {
|
|
836
939
|
// Same session, just update timestamp
|
|
@@ -851,6 +954,9 @@ async function run(options) {
|
|
|
851
954
|
lastSeenSessionAt = Date.now();
|
|
852
955
|
currentSession = lastSeenSessionName;
|
|
853
956
|
observedSessionThisRun = true; // Mark that we've seen a session in THIS process
|
|
957
|
+
// Update THIS process's session entry (not global state.json)
|
|
958
|
+
(0, state_1.updateCurrentProcessSession)(currentSessionId || 'unknown', currentSession);
|
|
959
|
+
// Also update global state for backwards compatibility
|
|
854
960
|
(0, state_1.updateState)({ sessionName: currentSession });
|
|
855
961
|
dlog(`Session detected from generic match: ${currentSession} (observedSessionThisRun=true)`);
|
|
856
962
|
}
|
|
@@ -874,6 +980,8 @@ async function run(options) {
|
|
|
874
980
|
// Handle PTY exit
|
|
875
981
|
shell.onExit(({ exitCode }) => {
|
|
876
982
|
(0, state_1.clearAutoClearFlag)();
|
|
983
|
+
stopStreamTailer(); // Stop stream capture
|
|
984
|
+
(0, state_1.unregisterActiveSession)(); // Remove from active sessions registry
|
|
877
985
|
// Restore terminal
|
|
878
986
|
if (process.stdin.isTTY) {
|
|
879
987
|
process.stdin.setRawMode(false);
|
|
@@ -886,6 +994,8 @@ async function run(options) {
|
|
|
886
994
|
// Cleanup on exit signals
|
|
887
995
|
const cleanup = () => {
|
|
888
996
|
(0, state_1.clearAutoClearFlag)();
|
|
997
|
+
stopStreamTailer(); // Stop stream capture
|
|
998
|
+
(0, state_1.unregisterActiveSession)(); // Remove from active sessions registry
|
|
889
999
|
if (process.stdin.isTTY) {
|
|
890
1000
|
process.stdin.setRawMode(false);
|
|
891
1001
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ekkos stream - Stream capture status and management
|
|
3
|
+
*
|
|
4
|
+
* Shows live status of stream capture for debugging and support.
|
|
5
|
+
*/
|
|
6
|
+
interface StreamStatusOptions {
|
|
7
|
+
session?: string;
|
|
8
|
+
watch?: boolean;
|
|
9
|
+
json?: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Display stream status
|
|
13
|
+
*/
|
|
14
|
+
export declare function streamStatus(options: StreamStatusOptions): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* List all sessions with stream data
|
|
17
|
+
*/
|
|
18
|
+
export declare function streamList(): void;
|
|
19
|
+
export {};
|