@hyperdrive.bot/paseo-server 0.3.11 → 0.3.12

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 (68) hide show
  1. package/dist/server/server/agent/providers/claude/transport/pty-query.d.ts +92 -10
  2. package/dist/server/server/agent/providers/claude/transport/pty-query.js +615 -38
  3. package/dist/server/server/relay-transport.js +36 -5
  4. package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-bridge-9f03d060da06e8838a4e0fdd5c067757.js → desktop-attachment-bridge-e6e0f92f1a2959279a7c3b2b50bf1df3.js} +5 -5
  5. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-e6e0f92f1a2959279a7c3b2b50bf1df3.js.br +0 -0
  6. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-e6e0f92f1a2959279a7c3b2b50bf1df3.js.gz +0 -0
  7. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-e6e0f92f1a2959279a7c3b2b50bf1df3.js.map.br +0 -0
  8. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-e6e0f92f1a2959279a7c3b2b50bf1df3.js.map.gz +0 -0
  9. package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-store-d0d9dffa612bf12bf551c5e513c28691.js → desktop-attachment-store-d5c93939344c993e52d655ccf8942928.js} +3 -3
  10. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-d5c93939344c993e52d655ccf8942928.js.br +0 -0
  11. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-d5c93939344c993e52d655ccf8942928.js.gz +0 -0
  12. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-d5c93939344c993e52d655ccf8942928.js.map.br +0 -0
  13. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-d5c93939344c993e52d655ccf8942928.js.map.gz +0 -0
  14. package/dist/server/web-ui/_expo/static/js/web/{index-5a54792f78b8475572ccfac9808dd926.js → index-853ef1a7fc9c9b7a39577b79564e0896.js} +164 -163
  15. package/dist/server/web-ui/_expo/static/js/web/index-853ef1a7fc9c9b7a39577b79564e0896.js.br +0 -0
  16. package/dist/server/web-ui/_expo/static/js/web/index-853ef1a7fc9c9b7a39577b79564e0896.js.gz +0 -0
  17. package/dist/server/web-ui/_expo/static/js/web/index-853ef1a7fc9c9b7a39577b79564e0896.js.map.br +0 -0
  18. package/dist/server/web-ui/_expo/static/js/web/{index-5a54792f78b8475572ccfac9808dd926.js.map.gz → index-853ef1a7fc9c9b7a39577b79564e0896.js.map.gz} +0 -0
  19. package/dist/server/web-ui/_expo/static/js/web/{indexeddb-attachment-store-54584275ea7a32061741c119074ff13f.js → indexeddb-attachment-store-35fb4ddfe925b1fb6b7a6c1953b21621.js} +3 -3
  20. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-35fb4ddfe925b1fb6b7a6c1953b21621.js.br +0 -0
  21. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-35fb4ddfe925b1fb6b7a6c1953b21621.js.gz +0 -0
  22. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-35fb4ddfe925b1fb6b7a6c1953b21621.js.map.br +0 -0
  23. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-35fb4ddfe925b1fb6b7a6c1953b21621.js.map.gz +0 -0
  24. package/dist/server/web-ui/_expo/static/js/web/{native-file-attachment-store-b53f2ba81a9777f6f6d04a98b0a12c33.js → native-file-attachment-store-8602ccac919e2b56f2e9a252dd06483e.js} +5 -5
  25. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-8602ccac919e2b56f2e9a252dd06483e.js.br +0 -0
  26. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-8602ccac919e2b56f2e9a252dd06483e.js.gz +0 -0
  27. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-8602ccac919e2b56f2e9a252dd06483e.js.map.br +0 -0
  28. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-8602ccac919e2b56f2e9a252dd06483e.js.map.gz +0 -0
  29. package/dist/server/web-ui/_expo/static/js/web/{profiler-7b2011c26cedb58cc00c02a7c25fc0a0.js → profiler-b3dd30ba0a88aece50e7e403785f34ba.js} +11 -11
  30. package/dist/server/web-ui/_expo/static/js/web/profiler-b3dd30ba0a88aece50e7e403785f34ba.js.br +0 -0
  31. package/dist/server/web-ui/_expo/static/js/web/profiler-b3dd30ba0a88aece50e7e403785f34ba.js.gz +0 -0
  32. package/dist/server/web-ui/_expo/static/js/web/profiler-b3dd30ba0a88aece50e7e403785f34ba.js.map.br +0 -0
  33. package/dist/server/web-ui/_expo/static/js/web/profiler-b3dd30ba0a88aece50e7e403785f34ba.js.map.gz +0 -0
  34. package/dist/server/web-ui/_expo/static/js/web/{startRecording-1b57837c4c358ef963a1392d9d96354b.js → startRecording-fd9fa11e24a3b8d94e5161aae7f42a5d.js} +60 -60
  35. package/dist/server/web-ui/_expo/static/js/web/startRecording-fd9fa11e24a3b8d94e5161aae7f42a5d.js.br +0 -0
  36. package/dist/server/web-ui/_expo/static/js/web/startRecording-fd9fa11e24a3b8d94e5161aae7f42a5d.js.gz +0 -0
  37. package/dist/server/web-ui/_expo/static/js/web/startRecording-fd9fa11e24a3b8d94e5161aae7f42a5d.js.map.br +0 -0
  38. package/dist/server/web-ui/_expo/static/js/web/{startRecording-1b57837c4c358ef963a1392d9d96354b.js.map.gz → startRecording-fd9fa11e24a3b8d94e5161aae7f42a5d.js.map.gz} +0 -0
  39. package/dist/server/web-ui/index.html +1 -1
  40. package/dist/server/web-ui/index.html.br +0 -0
  41. package/dist/server/web-ui/index.html.gz +0 -0
  42. package/package.json +6 -6
  43. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-9f03d060da06e8838a4e0fdd5c067757.js.br +0 -0
  44. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-9f03d060da06e8838a4e0fdd5c067757.js.gz +0 -0
  45. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-9f03d060da06e8838a4e0fdd5c067757.js.map.br +0 -0
  46. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-9f03d060da06e8838a4e0fdd5c067757.js.map.gz +0 -0
  47. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-d0d9dffa612bf12bf551c5e513c28691.js.br +0 -0
  48. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-d0d9dffa612bf12bf551c5e513c28691.js.gz +0 -0
  49. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-d0d9dffa612bf12bf551c5e513c28691.js.map.br +0 -0
  50. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-d0d9dffa612bf12bf551c5e513c28691.js.map.gz +0 -0
  51. package/dist/server/web-ui/_expo/static/js/web/index-5a54792f78b8475572ccfac9808dd926.js.br +0 -0
  52. package/dist/server/web-ui/_expo/static/js/web/index-5a54792f78b8475572ccfac9808dd926.js.gz +0 -0
  53. package/dist/server/web-ui/_expo/static/js/web/index-5a54792f78b8475572ccfac9808dd926.js.map.br +0 -0
  54. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-54584275ea7a32061741c119074ff13f.js.br +0 -0
  55. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-54584275ea7a32061741c119074ff13f.js.gz +0 -0
  56. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-54584275ea7a32061741c119074ff13f.js.map.br +0 -0
  57. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-54584275ea7a32061741c119074ff13f.js.map.gz +0 -0
  58. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-b53f2ba81a9777f6f6d04a98b0a12c33.js.br +0 -0
  59. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-b53f2ba81a9777f6f6d04a98b0a12c33.js.gz +0 -0
  60. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-b53f2ba81a9777f6f6d04a98b0a12c33.js.map.br +0 -0
  61. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-b53f2ba81a9777f6f6d04a98b0a12c33.js.map.gz +0 -0
  62. package/dist/server/web-ui/_expo/static/js/web/profiler-7b2011c26cedb58cc00c02a7c25fc0a0.js.br +0 -0
  63. package/dist/server/web-ui/_expo/static/js/web/profiler-7b2011c26cedb58cc00c02a7c25fc0a0.js.gz +0 -0
  64. package/dist/server/web-ui/_expo/static/js/web/profiler-7b2011c26cedb58cc00c02a7c25fc0a0.js.map.br +0 -0
  65. package/dist/server/web-ui/_expo/static/js/web/profiler-7b2011c26cedb58cc00c02a7c25fc0a0.js.map.gz +0 -0
  66. package/dist/server/web-ui/_expo/static/js/web/startRecording-1b57837c4c358ef963a1392d9d96354b.js.br +0 -0
  67. package/dist/server/web-ui/_expo/static/js/web/startRecording-1b57837c4c358ef963a1392d9d96354b.js.gz +0 -0
  68. package/dist/server/web-ui/_expo/static/js/web/startRecording-1b57837c4c358ef963a1392d9d96354b.js.map.br +0 -0
@@ -28,6 +28,15 @@ export declare class PtyQuery implements AsyncGenerator<SDKMessage, void> {
28
28
  private done;
29
29
  private readonly readyPromise;
30
30
  private offReadyData;
31
+ /**
32
+ * Cancels the readiness gate and its timers.
33
+ *
34
+ * Teardown MUST call this. A query closed before the gate settles used to leave its
35
+ * deadline interval running, so a session that attached and detached in the same
36
+ * millisecond still logged "readiness gate hit its timeout" a full minute later, warning
37
+ * about a terminal nobody was waiting on and leaking a timer per closed session.
38
+ */
39
+ private cancelReadiness;
31
40
  private turnEndTimer;
32
41
  private lastStopReason;
33
42
  private lastUsage;
@@ -36,6 +45,20 @@ export declare class PtyQuery implements AsyncGenerator<SDKMessage, void> {
36
45
  private readonly stallTimeoutMs;
37
46
  private stallTimer;
38
47
  private turnInFlight;
48
+ private terminalTail;
49
+ private offTerminalTap;
50
+ private readonly startedAt;
51
+ private recordingPath;
52
+ private recordingBytes;
53
+ private ptyBytesTotal;
54
+ private ptyBytesAtLastBeat;
55
+ private lastMeaningfulLine;
56
+ private lastTranscriptAt;
57
+ private heartbeatTimer;
58
+ private readySettledBy;
59
+ /** Last time the TUI footer said a turn was running. 0 = never seen. */
60
+ private lastBusyAt;
61
+ private interruptPromptAt;
39
62
  constructor(opts: PtyQueryOptions);
40
63
  private emit;
41
64
  next(): Promise<IteratorResult<SDKMessage, void>>;
@@ -44,13 +67,44 @@ export declare class PtyQuery implements AsyncGenerator<SDKMessage, void> {
44
67
  [Symbol.asyncIterator](): AsyncGenerator<SDKMessage, void>;
45
68
  private finish;
46
69
  private runInputLoop;
70
+ /**
71
+ * The message the user sees when the terminal would not take their prompt.
72
+ *
73
+ * Only reachable while the query is still live (teardown breaks out before this), so it
74
+ * always describes a message that genuinely did not land and that only the user can
75
+ * resend. Shaped as a normal result so it renders in the timeline rather than being
76
+ * buried in the daemon log.
77
+ */
78
+ private buildSubmitFailedResult;
47
79
  /**
48
80
  * Press Enter to submit the composed prompt, and CONFIRM the turn actually started by
49
- * watching the transcript grow claude appends the user message to <sid>.jsonl the
50
- * instant it accepts a turn. During boot the TUI intermittently swallows the first Enter
51
- * (a "what's new" notice / MCP-auth warning steals focus), so retry until it takes.
81
+ * watching for the USER LINE claude appends to <sid>.jsonl the instant it accepts a turn.
82
+ * During boot the TUI intermittently swallows the first Enter (a "what's new" notice /
83
+ * MCP-auth warning steals focus), so retry until it takes.
84
+ *
85
+ * The confirmation used to be `transcriptSize() > before`, which is any growth at all.
86
+ * That is not specific to the turn starting: claude writes `attachment`, `last-prompt`
87
+ * and other bookkeeping lines on its own schedule, so a swallowed Enter that happened to
88
+ * coincide with unrelated writes read as success. Observed in production 2026-08-01: a
89
+ * session logged 157 consecutive `attachment` lines and NOT ONE `user` line, yet
90
+ * submitTurn returned on the first attempt. The prompt stayed unsent in the TUI composer,
91
+ * paseo set turnInFlight and waited on a turn that had never begun, and the agent showed
92
+ * a spinner until the liveness backstop fired ten minutes later. The retry loop below was
93
+ * always right; the thing it was checking was not.
52
94
  */
95
+ /**
96
+ * Dismiss the post-interrupt modal if the terminal is showing one. ESC is only sent on a
97
+ * recent sighting: on an idle prompt it is harmless, but on a live turn it would interrupt
98
+ * real work, so a stale marker must never trigger it.
99
+ */
100
+ private clearInterruptPrompt;
53
101
  private submitTurn;
102
+ /**
103
+ * True once a real `user` line has been appended past `offset`. Reads only the bytes
104
+ * added since then, so it stays cheap on a transcript that can reach tens of MB.
105
+ * `isMeta` user lines are claude's own bookkeeping and do not mean a turn started.
106
+ */
107
+ private sawUserLineSince;
54
108
  private transcriptSize;
55
109
  private onTranscriptMessage;
56
110
  private scheduleTurnEndCheck;
@@ -68,16 +122,44 @@ export declare class PtyQuery implements AsyncGenerator<SDKMessage, void> {
68
122
  * the reader as a fresh turn.
69
123
  */
70
124
  private onTurnStalled;
71
- private buildResult;
72
125
  /**
73
- * A non-success `result` for a stalled turn. agent.ts's `appendResultEvents()` turns any
74
- * `subtype !== "success"` into a `turn_failed` carrying `errors.join("\n")`, which is what
75
- * puts a real message in front of the user.
126
+ * Append terminal output to the rolling tail.
127
+ *
128
+ * Scrubbed and filtered on the way IN, not on the way out, because the TUI's spinner
129
+ * redraws at a few hundred bytes/second: a raw buffer holds only a second or two of
130
+ * history and would evict the one line worth reading. Keeping only lines that carry
131
+ * letters or digits means a message like "Compacting conversation…" survives minutes of
132
+ * animation. Verified against a real stall: the raw tail was 163 chars of pure spinner.
133
+ */
134
+ /**
135
+ * True when the rolling tail's last frame looks like an input box waiting for typing.
76
136
  *
77
- * Wording matters: `isAbortError()` suppresses results whose errors match /\baborted\b/i,
78
- * and `buildTurnFailedEvent()` scrapes /\bcode\s+(\d+)\b/i for an exit code. Avoid both so
79
- * this neither gets swallowed nor reports a phantom exit code.
137
+ * Deliberately requires the busy marker to be ABSENT rather than trusting the prompt
138
+ * markers alone: the working footer renders as `… · esc to interrupt · ← for agents`, so
139
+ * "for agents" on its own is present in both states and would read a mid-turn terminal
140
+ * as idle.
80
141
  */
142
+ private looksIdle;
143
+ private appendTerminalTail;
144
+ /** Open `$PASEO_HOME/pty-recordings/<sessionId>.log`. Best-effort: never fail a session. */
145
+ private openRecording;
146
+ private recordLine;
147
+ private safeSize;
148
+ /**
149
+ * While a turn is outstanding, emit one line every {@link LIVENESS_HEARTBEAT_MS} with
150
+ * enough state to tell the failure modes apart without waiting for the stall budget:
151
+ * terminal bytes since the last beat (0 means the TUI is frozen, not thinking), seconds
152
+ * since the transcript last grew, and the last meaningful line on screen.
153
+ */
154
+ private startHeartbeat;
155
+ private stopHeartbeat;
156
+ private beat;
157
+ /**
158
+ * The tail as readable text: ANSI/OSC sequences dropped and runs of whitespace collapsed,
159
+ * because a raw TUI capture is mostly cursor movement and redraw padding.
160
+ */
161
+ private readTerminalTail;
162
+ private buildResult;
81
163
  private buildStalledResult;
82
164
  interrupt(): Promise<void>;
83
165
  setPermissionMode(): Promise<void>;