xiaotime 0.2.0 → 0.3.0

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.
Files changed (44) hide show
  1. package/dist/__tests__/approval_menu.test.d.ts +15 -0
  2. package/dist/__tests__/approval_menu.test.d.ts.map +1 -0
  3. package/dist/__tests__/approval_menu.test.js +107 -0
  4. package/dist/__tests__/approval_menu.test.js.map +1 -0
  5. package/dist/__tests__/server_tool_render.test.d.ts +17 -0
  6. package/dist/__tests__/server_tool_render.test.d.ts.map +1 -0
  7. package/dist/__tests__/server_tool_render.test.js +74 -0
  8. package/dist/__tests__/server_tool_render.test.js.map +1 -0
  9. package/dist/__tests__/settings.test.d.ts +16 -0
  10. package/dist/__tests__/settings.test.d.ts.map +1 -0
  11. package/dist/__tests__/settings.test.js +289 -0
  12. package/dist/__tests__/settings.test.js.map +1 -0
  13. package/dist/__tests__/tools.test.d.ts +17 -0
  14. package/dist/__tests__/tools.test.d.ts.map +1 -0
  15. package/dist/__tests__/tools.test.js +381 -0
  16. package/dist/__tests__/tools.test.js.map +1 -0
  17. package/dist/auth.d.ts.map +1 -1
  18. package/dist/auth.js +6 -2
  19. package/dist/auth.js.map +1 -1
  20. package/dist/config.d.ts +19 -0
  21. package/dist/config.d.ts.map +1 -1
  22. package/dist/config.js +24 -1
  23. package/dist/config.js.map +1 -1
  24. package/dist/display.d.ts +19 -0
  25. package/dist/display.d.ts.map +1 -1
  26. package/dist/display.js +23 -0
  27. package/dist/display.js.map +1 -1
  28. package/dist/settings.d.ts +109 -0
  29. package/dist/settings.d.ts.map +1 -0
  30. package/dist/settings.js +332 -0
  31. package/dist/settings.js.map +1 -0
  32. package/dist/tools.d.ts +11 -3
  33. package/dist/tools.d.ts.map +1 -1
  34. package/dist/tools.js +96 -33
  35. package/dist/tools.js.map +1 -1
  36. package/dist/ui_state.d.ts +134 -0
  37. package/dist/ui_state.d.ts.map +1 -0
  38. package/dist/ui_state.js +460 -0
  39. package/dist/ui_state.js.map +1 -0
  40. package/dist/ws.d.ts +5 -0
  41. package/dist/ws.d.ts.map +1 -1
  42. package/dist/ws.js +99 -66
  43. package/dist/ws.js.map +1 -1
  44. package/package.json +5 -2
@@ -0,0 +1,460 @@
1
+ "use strict";
2
+ /**
3
+ * Session-UI state machine for the xiaotime dev CLI.
4
+ *
5
+ * SPRINT-CLI-STATE-MACHINE-1 (#6163 / closes #6127) shipped the original
6
+ * state machine + raw-mode approval prompt. That fix eliminated the
7
+ * defaults-to-N half of the "yy" double-echo bug but the visible-yy half
8
+ * persisted because `readline.createInterface({ terminal: true })` attaches
9
+ * its own keypress handler to stdin that echoes characters via its own
10
+ * stdout writes; `rl.pause()` stops `line` events but does NOT detach that
11
+ * echo path, and `setRawMode(true)` only suppresses kernel-level echo, not
12
+ * readline's.
13
+ *
14
+ * SPRINT-CLI-APPROVAL-MENU-1 (#6509) replaces `promptApproval`'s `[y/N]`
15
+ * one-shot prompt with `promptApprovalMenu` — a three-option numbered menu
16
+ * (Run / Run + allowlist / Reject + feedback). The rl is explicitly
17
+ * **closed and recreated** around the menu render so its keypress echo
18
+ * physically can't fire (the rl object is gone for the duration of the
19
+ * menu). Persistent close listeners survive the recreation via
20
+ * `onRlClose()` — callers that need a stable close hook register through
21
+ * that instead of `getRl().on("close", ...)`.
22
+ *
23
+ * The state machine has four states:
24
+ *
25
+ * IDLE — at the `you:` prompt, awaiting user input.
26
+ * GENERATING — model is streaming tokens (or about to). Spinner.
27
+ * RUNNING_TOOL — a server-side tool is running. Spinner.
28
+ * AWAITING_APPROVAL — user must navigate the approval menu for a
29
+ * client-side tool. Main rl is closed; raw stdin
30
+ * captures keystrokes.
31
+ *
32
+ * The WS handler in `ws.ts` is the sole driver. Transitions:
33
+ *
34
+ * IDLE -- user line received -> GENERATING
35
+ * GENERATING -- text_delta -> GENERATING (refresh)
36
+ * GENERATING -- tool_call (server) -> RUNNING_TOOL
37
+ * GENERATING -- tool_call (client+approval) -> AWAITING_APPROVAL
38
+ * AWAITING_APPROVAL -- menu selection -> RUNNING_TOOL
39
+ * RUNNING_TOOL -- tool_result sent -> GENERATING
40
+ * GENERATING -- message_stop -> IDLE
41
+ * ANY -- error -> IDLE
42
+ */
43
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
44
+ if (k2 === undefined) k2 = k;
45
+ var desc = Object.getOwnPropertyDescriptor(m, k);
46
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
47
+ desc = { enumerable: true, get: function() { return m[k]; } };
48
+ }
49
+ Object.defineProperty(o, k2, desc);
50
+ }) : (function(o, m, k, k2) {
51
+ if (k2 === undefined) k2 = k;
52
+ o[k2] = m[k];
53
+ }));
54
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
55
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
56
+ }) : function(o, v) {
57
+ o["default"] = v;
58
+ });
59
+ var __importStar = (this && this.__importStar) || (function () {
60
+ var ownKeys = function(o) {
61
+ ownKeys = Object.getOwnPropertyNames || function (o) {
62
+ var ar = [];
63
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
64
+ return ar;
65
+ };
66
+ return ownKeys(o);
67
+ };
68
+ return function (mod) {
69
+ if (mod && mod.__esModule) return mod;
70
+ var result = {};
71
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
72
+ __setModuleDefault(result, mod);
73
+ return result;
74
+ };
75
+ })();
76
+ var __importDefault = (this && this.__importDefault) || function (mod) {
77
+ return (mod && mod.__esModule) ? mod : { "default": mod };
78
+ };
79
+ Object.defineProperty(exports, "__esModule", { value: true });
80
+ exports.SessionUI = void 0;
81
+ const readline = __importStar(require("readline"));
82
+ const chalk_1 = __importDefault(require("chalk"));
83
+ const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
84
+ const SPINNER_INTERVAL_MS = 100;
85
+ const ELAPSED_THRESHOLD_MS = 3000; // show elapsed time after this
86
+ const MENU_OPTIONS = [
87
+ "Run",
88
+ "Run and don't ask again",
89
+ "Reject and tell Claude why",
90
+ ];
91
+ const MENU_HINT = "(1-3, ↑↓ Enter, Esc to reject)";
92
+ class SessionUI {
93
+ state = "idle";
94
+ spinnerTimer = null;
95
+ spinnerFrame = 0;
96
+ spinnerStartedAt = 0;
97
+ spinnerLabel = "";
98
+ // True only while the spinner has written something to the line and
99
+ // we owe a clear. Set on first frame, cleared on stopSpinner. Lets
100
+ // text_delta callers know they need to clear the spinner line
101
+ // before printing the first token.
102
+ spinnerLineDirty = false;
103
+ rl;
104
+ lineListener = null;
105
+ /**
106
+ * Close-listener callbacks that should survive rl recreations. The
107
+ * approval-menu path closes + recreates `rl` to physically detach
108
+ * readline's keypress echo. ws.ts registers its "Session paused"
109
+ * resume hint here so it stays attached across recreations.
110
+ */
111
+ closeListeners = [];
112
+ constructor() {
113
+ this.rl = this._makeRl();
114
+ }
115
+ /** Hand the underlying readline to callers that need it for cleanup. */
116
+ getRl() {
117
+ return this.rl;
118
+ }
119
+ /**
120
+ * Register a callback to fire when the rl reports a non-suppressed
121
+ * `close` event (the only one users observe is Ctrl+C at the main
122
+ * prompt — close-during-approval is suppressed via removeAllListeners
123
+ * before `rl.close()`). Callbacks are re-attached on every rl
124
+ * recreation so they outlive `promptApprovalMenu`.
125
+ */
126
+ onRlClose(listener) {
127
+ this.closeListeners.push(listener);
128
+ this.rl.on("close", listener);
129
+ }
130
+ /** Set the explicit current state. Drives spinner start/stop. */
131
+ setState(next) {
132
+ if (next === this.state)
133
+ return;
134
+ const prev = this.state;
135
+ this.state = next;
136
+ // Transition out of any spinner state.
137
+ if (prev === "generating" || prev === "running_tool") {
138
+ this.stopSpinner();
139
+ }
140
+ // Transition in.
141
+ if (next === "generating") {
142
+ this.startSpinner("thinking");
143
+ }
144
+ else if (next === "running_tool") {
145
+ this.startSpinner("running tool");
146
+ }
147
+ // `awaiting_approval` / `idle` => no spinner. Approval-menu path
148
+ // takes over stdin in `promptApprovalMenu`.
149
+ }
150
+ getState() {
151
+ return this.state;
152
+ }
153
+ /** Wait for one line of user input on the main rl. */
154
+ promptLine() {
155
+ return new Promise((resolve) => {
156
+ // Drop any previous one-shot listener that didn't fire.
157
+ if (this.lineListener) {
158
+ this.rl.off("line", this.lineListener);
159
+ }
160
+ const listener = (line) => {
161
+ this.lineListener = null;
162
+ resolve(line.trim());
163
+ };
164
+ this.lineListener = listener;
165
+ this.rl.once("line", listener);
166
+ });
167
+ }
168
+ /**
169
+ * Three-option numbered approval menu. Replaces the pre-#6509
170
+ * `[y/N]` one-shot prompt.
171
+ *
172
+ * Visual:
173
+ * ❯ 1. Run
174
+ * 2. Run and don't ask again
175
+ * 3. Reject and tell Claude why
176
+ * (1-3, ↑↓ Enter, Esc to reject)
177
+ *
178
+ * Controls:
179
+ * - Number key 1/2/3 — one-shot select
180
+ * - Arrow Up/Down — move focus
181
+ * - Enter — select focused
182
+ * - Esc — equivalent to option 3 (reject)
183
+ * - Ctrl+C — reject + propagate SIGINT (cancels session)
184
+ *
185
+ * The rl is closed before the menu render and recreated after. This
186
+ * physically removes readline's keypress echo from stdin for the
187
+ * duration of the menu — the bug fix the #6163 patch attempted via
188
+ * `rl.pause()` (which only stops `line` events, not the keypress
189
+ * echo). Persistent close listeners are stashed in
190
+ * `this.closeListeners` and re-attached on recreate; the close event
191
+ * triggered by THIS close() is suppressed via removeAllListeners
192
+ * before the call so it doesn't fire the "Session paused" hint.
193
+ *
194
+ * For option 3, after the menu resolves the recreated rl prompts
195
+ * once for a free-form rejection reason (line-mode). Empty input is
196
+ * allowed.
197
+ *
198
+ * The returned `allowlistRequested: true` (option 2) is a signal to
199
+ * the caller — PR2 wires it to write the pattern to
200
+ * `~/.xiaotime/settings.json`. PR1 callers may ignore it.
201
+ */
202
+ async promptApprovalMenu(toolHeader) {
203
+ this.setState("awaiting_approval");
204
+ if (toolHeader) {
205
+ process.stdout.write(toolHeader);
206
+ }
207
+ // Recreate the rl in `finally` so it ALWAYS lands — even if the
208
+ // no-TTY bail-out fires inside `_renderMenuAndGetSelection`. The
209
+ // next `promptLine` call needs a live rl regardless of how the
210
+ // menu resolved.
211
+ let selectedIdx;
212
+ try {
213
+ selectedIdx = await this._renderMenuAndGetSelection();
214
+ }
215
+ finally {
216
+ this.rl = this._makeRl();
217
+ }
218
+ // -1 → bail-out from `_renderMenuAndGetSelection` because stdin is
219
+ // not a TTY (CI / piped invocation / test runner). Skip the
220
+ // rejection-reason readline prompt because nothing would feed it.
221
+ if (selectedIdx === -1) {
222
+ return { approved: false, rejectReason: "(no TTY)" };
223
+ }
224
+ if (selectedIdx === 0) {
225
+ process.stdout.write(chalk_1.default.green(" ✓ Approved\n"));
226
+ return { approved: true, allowlistRequested: false };
227
+ }
228
+ if (selectedIdx === 1) {
229
+ process.stdout.write(chalk_1.default.green(" ✓ Approved (allowlist requested)\n"));
230
+ return { approved: true, allowlistRequested: true };
231
+ }
232
+ // selectedIdx === 2 — rejection. Prompt for free-form reason via
233
+ // the recreated rl (line-mode, single line, empty allowed).
234
+ process.stdout.write(chalk_1.default.yellow(" Reason (Enter to send empty): "));
235
+ const reason = await new Promise((resolve) => {
236
+ this.rl.once("line", (line) => resolve(line.trim()));
237
+ });
238
+ return { approved: false, rejectReason: reason };
239
+ }
240
+ // ── Menu internals ───────────────────────────────────────────────
241
+ _makeRl() {
242
+ const rl = readline.createInterface({
243
+ input: process.stdin,
244
+ output: process.stdout,
245
+ terminal: true,
246
+ });
247
+ for (const l of this.closeListeners) {
248
+ rl.on("close", l);
249
+ }
250
+ return rl;
251
+ }
252
+ async _renderMenuAndGetSelection() {
253
+ // Suppress the close-listener side effects for this internal
254
+ // close — we don't want the "Session paused" hint firing
255
+ // mid-approval. Stash the listeners on this.closeListeners so
256
+ // _makeRl can re-attach them after the menu resolves.
257
+ this.rl.removeAllListeners("close");
258
+ this.rl.close();
259
+ const stdin = process.stdin;
260
+ // Bail BEFORE rendering the menu if stdin isn't a TTY. setRawMode
261
+ // can silently no-op on non-TTY stdin in some environments
262
+ // (vitest, piped invocation) — in that case the data listener
263
+ // would attach but never receive bytes, hanging the caller
264
+ // indefinitely. -1 sentinel tells promptApprovalMenu to skip the
265
+ // rejection-reason prompt (which would also hang).
266
+ if (!stdin.isTTY) {
267
+ process.stdout.write(chalk_1.default.red("Rejected (no TTY)\n"));
268
+ return -1;
269
+ }
270
+ const wasRaw = stdin.isRaw === true;
271
+ try {
272
+ stdin.setRawMode(true);
273
+ }
274
+ catch {
275
+ // Belt + suspenders — isTTY guard above should cover this, but a
276
+ // mid-session TTY loss could surface here.
277
+ process.stdout.write(chalk_1.default.red("Rejected (no TTY)\n"));
278
+ return -1;
279
+ }
280
+ stdin.resume();
281
+ let focusedIdx = 0;
282
+ this._renderMenu(focusedIdx);
283
+ // #6532 CR-r1: function-level finally guarantees onData removal +
284
+ // setRawMode restore even if the Promise body throws or the
285
+ // process is signalled. The previous design relied on every
286
+ // `finish()` call doing the cleanup, leaving leak windows when
287
+ // onData itself threw or when an awaiter rejected without
288
+ // routing through finish().
289
+ let onData = null;
290
+ try {
291
+ return await new Promise((resolve, reject) => {
292
+ const finish = (idx) => {
293
+ this._clearMenu();
294
+ resolve(idx);
295
+ };
296
+ onData = (chunk) => {
297
+ try {
298
+ const s = chunk.toString();
299
+ // Ctrl+C → reject + propagate SIGINT so the WS handler's
300
+ // close path runs and the session ends cleanly.
301
+ if (s.includes("\x03")) {
302
+ finish(2);
303
+ process.kill(process.pid, "SIGINT");
304
+ return;
305
+ }
306
+ // Allowlisted escape-prefixed sequences. Esc alone (no
307
+ // `[`) → option 3 (reject). Arrow up/down rotate focus.
308
+ // Any OTHER `\x1b`-prefixed input is explicitly rejected
309
+ // (logged to stderr at debug level + ignored) per #6532
310
+ // CR-r1: previously such sequences silently no-op'd,
311
+ // which is currently safe due to the no-echo policy but
312
+ // would become a terminal-injection vector if a future
313
+ // diagnostic change started echoing unknown input.
314
+ if (s.charCodeAt(0) === 0x1b) {
315
+ if (s === "\x1b") {
316
+ finish(2);
317
+ return;
318
+ }
319
+ if (s === "\x1b[A") {
320
+ focusedIdx =
321
+ (focusedIdx - 1 + MENU_OPTIONS.length) % MENU_OPTIONS.length;
322
+ this._rerenderMenu(focusedIdx);
323
+ return;
324
+ }
325
+ if (s === "\x1b[B") {
326
+ focusedIdx = (focusedIdx + 1) % MENU_OPTIONS.length;
327
+ this._rerenderMenu(focusedIdx);
328
+ return;
329
+ }
330
+ // Unrecognized escape sequence — log + ignore. Use the
331
+ // hex form so a malicious paste of bell/CSI bytes is
332
+ // not re-rendered through stderr.
333
+ const hex = Array.from(chunk)
334
+ .map((b) => b.toString(16).padStart(2, "0"))
335
+ .join(" ");
336
+ process.stderr.write(chalk_1.default.dim(`\n[approval-menu] ignored unrecognized escape: ${hex}\n`));
337
+ return;
338
+ }
339
+ // Number-key one-shot selectors.
340
+ if (s === "1" || s === "2" || s === "3") {
341
+ finish(Number(s) - 1);
342
+ return;
343
+ }
344
+ // Enter on focused row.
345
+ if (s === "\r" || s === "\n") {
346
+ finish(focusedIdx);
347
+ return;
348
+ }
349
+ // Anything else — ignore. No echo, no bounce. The visible
350
+ // menu stays put so the user can try again.
351
+ }
352
+ catch (err) {
353
+ reject(err);
354
+ }
355
+ };
356
+ stdin.on("data", onData);
357
+ });
358
+ }
359
+ finally {
360
+ if (onData) {
361
+ stdin.removeListener("data", onData);
362
+ }
363
+ try {
364
+ stdin.setRawMode(wasRaw);
365
+ }
366
+ catch {
367
+ /* setRawMode can throw if stdin lost its TTY mid-session. */
368
+ }
369
+ }
370
+ }
371
+ /** Total lines the menu occupies: one per option + one hint line. */
372
+ _menuLineCount() {
373
+ return MENU_OPTIONS.length + 1;
374
+ }
375
+ _renderMenu(focusedIdx) {
376
+ for (let i = 0; i < MENU_OPTIONS.length; i++) {
377
+ const marker = i === focusedIdx ? chalk_1.default.cyan("❯") : " ";
378
+ const numText = chalk_1.default.cyan(`${i + 1}.`);
379
+ process.stdout.write(` ${marker} ${numText} ${MENU_OPTIONS[i]}\n`);
380
+ }
381
+ process.stdout.write(chalk_1.default.dim(` ${MENU_HINT}\n`));
382
+ }
383
+ _rerenderMenu(focusedIdx) {
384
+ // Move cursor up to top of menu, clear each line, redraw.
385
+ const lines = this._menuLineCount();
386
+ process.stdout.write(`\x1b[${lines}A`);
387
+ for (let i = 0; i < MENU_OPTIONS.length; i++) {
388
+ process.stdout.write("\x1b[K");
389
+ const marker = i === focusedIdx ? chalk_1.default.cyan("❯") : " ";
390
+ const numText = chalk_1.default.cyan(`${i + 1}.`);
391
+ process.stdout.write(` ${marker} ${numText} ${MENU_OPTIONS[i]}\n`);
392
+ }
393
+ process.stdout.write("\x1b[K");
394
+ process.stdout.write(chalk_1.default.dim(` ${MENU_HINT}\n`));
395
+ }
396
+ _clearMenu() {
397
+ const lines = this._menuLineCount();
398
+ process.stdout.write(`\x1b[${lines}A`);
399
+ for (let i = 0; i < lines; i++) {
400
+ process.stdout.write("\x1b[K");
401
+ if (i < lines - 1)
402
+ process.stdout.write("\n");
403
+ }
404
+ // Cursor left at start of the (now-cleared) first menu line so
405
+ // the post-selection echo lands there cleanly.
406
+ process.stdout.write(`\x1b[${lines - 1}A\r`);
407
+ }
408
+ // ── Spinner internals ────────────────────────────────────────────
409
+ startSpinner(label) {
410
+ this.spinnerLabel = label;
411
+ this.spinnerFrame = 0;
412
+ this.spinnerStartedAt = Date.now();
413
+ this.spinnerLineDirty = false;
414
+ this.spinnerTimer = setInterval(() => this.renderSpinnerFrame(), SPINNER_INTERVAL_MS);
415
+ // Render the first frame immediately so there's no perceptible
416
+ // delay between state-set and visible feedback.
417
+ this.renderSpinnerFrame();
418
+ }
419
+ renderSpinnerFrame() {
420
+ const frame = SPINNER_FRAMES[this.spinnerFrame % SPINNER_FRAMES.length];
421
+ const elapsed = Date.now() - this.spinnerStartedAt;
422
+ const elapsedStr = elapsed >= ELAPSED_THRESHOLD_MS
423
+ ? chalk_1.default.dim(` (${Math.floor(elapsed / 1000)}s)`)
424
+ : "";
425
+ // Clear-to-end-of-line (`\x1b[K`) after the spinner content
426
+ // rather than trailing spaces — robust against terminals where
427
+ // the last frame was longer than the current one (the trailing
428
+ // spaces approach left orphaned chars on shrinking labels).
429
+ process.stdout.write(`\r${chalk_1.default.cyan(frame)} ${chalk_1.default.dim(this.spinnerLabel)}${elapsedStr}\x1b[K`);
430
+ this.spinnerLineDirty = true;
431
+ this.spinnerFrame++;
432
+ }
433
+ stopSpinner() {
434
+ if (this.spinnerTimer) {
435
+ clearInterval(this.spinnerTimer);
436
+ this.spinnerTimer = null;
437
+ }
438
+ if (this.spinnerLineDirty) {
439
+ // Clear the spinner line so the next print doesn't overlap.
440
+ process.stdout.write("\r\x1b[K");
441
+ this.spinnerLineDirty = false;
442
+ }
443
+ }
444
+ /** Called by the text_delta renderer the first time a real model
445
+ * token arrives during a `generating` state. Clears the spinner so
446
+ * the token prints cleanly, but leaves the state at `generating`
447
+ * (token streaming continues without re-spinning). */
448
+ onFirstToken() {
449
+ if (this.spinnerLineDirty) {
450
+ process.stdout.write("\r\x1b[K");
451
+ this.spinnerLineDirty = false;
452
+ }
453
+ if (this.spinnerTimer) {
454
+ clearInterval(this.spinnerTimer);
455
+ this.spinnerTimer = null;
456
+ }
457
+ }
458
+ }
459
+ exports.SessionUI = SessionUI;
460
+ //# sourceMappingURL=ui_state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui_state.js","sourceRoot":"","sources":["../src/ui_state.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,mDAAqC;AACrC,kDAA0B;AAY1B,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAC1E,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAChC,MAAM,oBAAoB,GAAG,IAAI,CAAC,CAAC,+BAA+B;AAElE,MAAM,YAAY,GAA0B;IAC1C,KAAK;IACL,yBAAyB;IACzB,4BAA4B;CAC7B,CAAC;AACF,MAAM,SAAS,GAAG,gCAAgC,CAAC;AAEnD,MAAa,SAAS;IACZ,KAAK,GAAa,MAAM,CAAC;IACzB,YAAY,GAA0B,IAAI,CAAC;IAC3C,YAAY,GAAG,CAAC,CAAC;IACjB,gBAAgB,GAAG,CAAC,CAAC;IACrB,YAAY,GAAG,EAAE,CAAC;IAC1B,oEAAoE;IACpE,mEAAmE;IACnE,8DAA8D;IAC9D,mCAAmC;IAC3B,gBAAgB,GAAG,KAAK,CAAC;IAEzB,EAAE,CAAqB;IACvB,YAAY,GAAoC,IAAI,CAAC;IAC7D;;;;;OAKG;IACK,cAAc,GAAsB,EAAE,CAAC;IAE/C;QACE,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;IAED,wEAAwE;IACxE,KAAK;QACH,OAAO,IAAI,CAAC,EAAE,CAAC;IACjB,CAAC;IAED;;;;;;OAMG;IACH,SAAS,CAAC,QAAoB;QAC5B,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAChC,CAAC;IAED,iEAAiE;IACjE,QAAQ,CAAC,IAAc;QACrB,IAAI,IAAI,KAAK,IAAI,CAAC,KAAK;YAAE,OAAO;QAChC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC;QACxB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAElB,uCAAuC;QACvC,IAAI,IAAI,KAAK,YAAY,IAAI,IAAI,KAAK,cAAc,EAAE,CAAC;YACrD,IAAI,CAAC,WAAW,EAAE,CAAC;QACrB,CAAC;QAED,iBAAiB;QACjB,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;YAC1B,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;QAChC,CAAC;aAAM,IAAI,IAAI,KAAK,cAAc,EAAE,CAAC;YACnC,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC,CAAC;QACpC,CAAC;QACD,iEAAiE;QACjE,4CAA4C;IAC9C,CAAC;IAED,QAAQ;QACN,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,sDAAsD;IACtD,UAAU;QACR,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,wDAAwD;YACxD,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;gBACtB,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;YACzC,CAAC;YACD,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAE,EAAE;gBAChC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;gBACzB,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;YACvB,CAAC,CAAC;YACF,IAAI,CAAC,YAAY,GAAG,QAAQ,CAAC;YAC7B,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiCG;IACH,KAAK,CAAC,kBAAkB,CAAC,UAAmB;QAC1C,IAAI,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC;QAEnC,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACnC,CAAC;QAED,gEAAgE;QAChE,iEAAiE;QACjE,+DAA+D;QAC/D,iBAAiB;QACjB,IAAI,WAAmB,CAAC;QACxB,IAAI,CAAC;YACH,WAAW,GAAG,MAAM,IAAI,CAAC,0BAA0B,EAAE,CAAC;QACxD,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC3B,CAAC;QAED,mEAAmE;QACnE,4DAA4D;QAC5D,kEAAkE;QAClE,IAAI,WAAW,KAAK,CAAC,CAAC,EAAE,CAAC;YACvB,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC;QACvD,CAAC;QAED,IAAI,WAAW,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,eAAK,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC;YACpD,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,CAAC;QACvD,CAAC;QACD,IAAI,WAAW,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,eAAK,CAAC,KAAK,CAAC,sCAAsC,CAAC,CACpD,CAAC;YACF,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC;QACtD,CAAC;QACD,iEAAiE;QACjE,4DAA4D;QAC5D,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,eAAK,CAAC,MAAM,CAAC,kCAAkC,CAAC,CACjD,CAAC;QACF,MAAM,MAAM,GAAG,MAAM,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,EAAE;YACnD,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACvD,CAAC,CAAC,CAAC;QACH,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC;IACnD,CAAC;IAED,oEAAoE;IAE5D,OAAO;QACb,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC;YAClC,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,QAAQ,EAAE,IAAI;SACf,CAAC,CAAC;QACH,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACpC,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACpB,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;IAEO,KAAK,CAAC,0BAA0B;QACtC,6DAA6D;QAC7D,yDAAyD;QACzD,8DAA8D;QAC9D,sDAAsD;QACtD,IAAI,CAAC,EAAE,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;QACpC,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;QAEhB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC5B,kEAAkE;QAClE,2DAA2D;QAC3D,8DAA8D;QAC9D,2DAA2D;QAC3D,iEAAiE;QACjE,mDAAmD;QACnD,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC,CAAC;YACvD,OAAO,CAAC,CAAC,CAAC;QACZ,CAAC;QAED,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,KAAK,IAAI,CAAC;QACpC,IAAI,CAAC;YACH,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;QAAC,MAAM,CAAC;YACP,iEAAiE;YACjE,2CAA2C;YAC3C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC,CAAC;YACvD,OAAO,CAAC,CAAC,CAAC;QACZ,CAAC;QACD,KAAK,CAAC,MAAM,EAAE,CAAC;QAEf,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;QAE7B,kEAAkE;QAClE,4DAA4D;QAC5D,4DAA4D;QAC5D,+DAA+D;QAC/D,0DAA0D;QAC1D,4BAA4B;QAC5B,IAAI,MAAM,GAAqC,IAAI,CAAC;QACpD,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBACnD,MAAM,MAAM,GAAG,CAAC,GAAW,EAAE,EAAE;oBAC7B,IAAI,CAAC,UAAU,EAAE,CAAC;oBAClB,OAAO,CAAC,GAAG,CAAC,CAAC;gBACf,CAAC,CAAC;gBAEF,MAAM,GAAG,CAAC,KAAa,EAAE,EAAE;oBACzB,IAAI,CAAC;wBACH,MAAM,CAAC,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;wBAE3B,yDAAyD;wBACzD,gDAAgD;wBAChD,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;4BACvB,MAAM,CAAC,CAAC,CAAC,CAAC;4BACV,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;4BACpC,OAAO;wBACT,CAAC;wBAED,uDAAuD;wBACvD,wDAAwD;wBACxD,yDAAyD;wBACzD,wDAAwD;wBACxD,qDAAqD;wBACrD,wDAAwD;wBACxD,uDAAuD;wBACvD,mDAAmD;wBACnD,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;4BAC7B,IAAI,CAAC,KAAK,MAAM,EAAE,CAAC;gCACjB,MAAM,CAAC,CAAC,CAAC,CAAC;gCACV,OAAO;4BACT,CAAC;4BACD,IAAI,CAAC,KAAK,QAAQ,EAAE,CAAC;gCACnB,UAAU;oCACR,CAAC,UAAU,GAAG,CAAC,GAAG,YAAY,CAAC,MAAM,CAAC,GAAG,YAAY,CAAC,MAAM,CAAC;gCAC/D,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;gCAC/B,OAAO;4BACT,CAAC;4BACD,IAAI,CAAC,KAAK,QAAQ,EAAE,CAAC;gCACnB,UAAU,GAAG,CAAC,UAAU,GAAG,CAAC,CAAC,GAAG,YAAY,CAAC,MAAM,CAAC;gCACpD,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;gCAC/B,OAAO;4BACT,CAAC;4BACD,uDAAuD;4BACvD,qDAAqD;4BACrD,kCAAkC;4BAClC,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;iCAC1B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;iCAC3C,IAAI,CAAC,GAAG,CAAC,CAAC;4BACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,eAAK,CAAC,GAAG,CACP,kDAAkD,GAAG,IAAI,CAC1D,CACF,CAAC;4BACF,OAAO;wBACT,CAAC;wBAED,iCAAiC;wBACjC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;4BACxC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;4BACtB,OAAO;wBACT,CAAC;wBAED,wBAAwB;wBACxB,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;4BAC7B,MAAM,CAAC,UAAU,CAAC,CAAC;4BACnB,OAAO;wBACT,CAAC;wBAED,0DAA0D;wBAC1D,4CAA4C;oBAC9C,CAAC;oBAAC,OAAO,GAAG,EAAE,CAAC;wBACb,MAAM,CAAC,GAAG,CAAC,CAAC;oBACd,CAAC;gBACH,CAAC,CAAC;gBAEF,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YAC3B,CAAC,CAAC,CAAC;QACL,CAAC;gBAAS,CAAC;YACT,IAAI,MAAM,EAAE,CAAC;gBACX,KAAK,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACvC,CAAC;YACD,IAAI,CAAC;gBACH,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;YAC3B,CAAC;YAAC,MAAM,CAAC;gBACP,6DAA6D;YAC/D,CAAC;QACH,CAAC;IACH,CAAC;IAED,qEAAqE;IAC7D,cAAc;QACpB,OAAO,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC;IACjC,CAAC;IAEO,WAAW,CAAC,UAAkB;QACpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7C,MAAM,MAAM,GAAG,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,eAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;YACxD,MAAM,OAAO,GAAG,eAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACxC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,MAAM,IAAI,OAAO,IAAI,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACtE,CAAC;QACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,KAAK,SAAS,IAAI,CAAC,CAAC,CAAC;IACtD,CAAC;IAEO,aAAa,CAAC,UAAkB;QACtC,0DAA0D;QAC1D,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;QACpC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,KAAK,GAAG,CAAC,CAAC;QACvC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAC/B,MAAM,MAAM,GAAG,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,eAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;YACxD,MAAM,OAAO,GAAG,eAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACxC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,MAAM,IAAI,OAAO,IAAI,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACtE,CAAC;QACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC/B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,KAAK,SAAS,IAAI,CAAC,CAAC,CAAC;IACtD,CAAC;IAEO,UAAU;QAChB,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;QACpC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,KAAK,GAAG,CAAC,CAAC;QACvC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAC/B,IAAI,CAAC,GAAG,KAAK,GAAG,CAAC;gBAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAChD,CAAC;QACD,+DAA+D;QAC/D,+CAA+C;QAC/C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC;IAC/C,CAAC;IAED,oEAAoE;IAE5D,YAAY,CAAC,KAAa;QAChC,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;QAC1B,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC;QACtB,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACnC,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;QAC9B,IAAI,CAAC,YAAY,GAAG,WAAW,CAC7B,GAAG,EAAE,CAAC,IAAI,CAAC,kBAAkB,EAAE,EAC/B,mBAAmB,CACpB,CAAC;QACF,+DAA+D;QAC/D,gDAAgD;QAChD,IAAI,CAAC,kBAAkB,EAAE,CAAC;IAC5B,CAAC;IAEO,kBAAkB;QACxB,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,YAAY,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;QACxE,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,gBAAgB,CAAC;QACnD,MAAM,UAAU,GACd,OAAO,IAAI,oBAAoB;YAC7B,CAAC,CAAC,eAAK,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC;YAChD,CAAC,CAAC,EAAE,CAAC;QACT,4DAA4D;QAC5D,+DAA+D;QAC/D,+DAA+D;QAC/D,4DAA4D;QAC5D,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,KAAK,eAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,eAAK,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,UAAU,QAAQ,CAC5E,CAAC;QACF,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC7B,IAAI,CAAC,YAAY,EAAE,CAAC;IACtB,CAAC;IAEO,WAAW;QACjB,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YACjC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QAC3B,CAAC;QACD,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC1B,4DAA4D;YAC5D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YACjC,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;QAChC,CAAC;IACH,CAAC;IAED;;;0DAGsD;IACtD,YAAY;QACV,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YACjC,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;QAChC,CAAC;QACD,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YACjC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QAC3B,CAAC;IACH,CAAC;CACF;AAzZD,8BAyZC"}
package/dist/ws.d.ts CHANGED
@@ -1,5 +1,10 @@
1
1
  /**
2
2
  * WebSocket connection and main message loop.
3
+ *
4
+ * SPRINT-CLI-STATE-MACHINE-1 (#6163 / closes #6127) — drives the
5
+ * SessionUI state machine from incoming WS events so the user gets
6
+ * a spinner while the model is generating / a tool is running, and
7
+ * approval prompts don't race the main rl on keystrokes.
3
8
  */
4
9
  export declare function runSession(sessionId: string): Promise<void>;
5
10
  //# sourceMappingURL=ws.d.ts.map
package/dist/ws.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ws.d.ts","sourceRoot":"","sources":["../src/ws.ts"],"names":[],"mappings":"AAAA;;GAEG;AAeH,wBAAsB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA0HjE"}
1
+ {"version":3,"file":"ws.d.ts","sourceRoot":"","sources":["../src/ws.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAgBH,wBAAsB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgMjE"}