@0xmaxma/claude-gateway 1.3.25 → 1.3.31
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/README.md +47 -1
- package/config.template.json +6 -2
- package/dist/agent/incident-store.d.ts +89 -0
- package/dist/agent/incident-store.d.ts.map +1 -0
- package/dist/agent/incident-store.js +299 -0
- package/dist/agent/incident-store.js.map +1 -0
- package/dist/agent/incident.d.ts +156 -0
- package/dist/agent/incident.d.ts.map +1 -0
- package/dist/agent/incident.js +177 -0
- package/dist/agent/incident.js.map +1 -0
- package/dist/agent/recovery-executor.d.ts +117 -0
- package/dist/agent/recovery-executor.d.ts.map +1 -0
- package/dist/agent/recovery-executor.js +168 -0
- package/dist/agent/recovery-executor.js.map +1 -0
- package/dist/agent/recovery-policy.d.ts +97 -0
- package/dist/agent/recovery-policy.d.ts.map +1 -0
- package/dist/agent/recovery-policy.js +164 -0
- package/dist/agent/recovery-policy.js.map +1 -0
- package/dist/agent/runner.d.ts +44 -0
- package/dist/agent/runner.d.ts.map +1 -1
- package/dist/agent/runner.js +272 -2
- package/dist/agent/runner.js.map +1 -1
- package/dist/agent/safe-mode.d.ts +61 -0
- package/dist/agent/safe-mode.d.ts.map +1 -0
- package/dist/agent/safe-mode.js +102 -0
- package/dist/agent/safe-mode.js.map +1 -0
- package/dist/agent/triage.d.ts +94 -0
- package/dist/agent/triage.d.ts.map +1 -0
- package/dist/agent/triage.js +209 -0
- package/dist/agent/triage.js.map +1 -0
- package/dist/agent/turn-trace.d.ts +120 -0
- package/dist/agent/turn-trace.d.ts.map +1 -0
- package/dist/agent/turn-trace.js +122 -0
- package/dist/agent/turn-trace.js.map +1 -0
- package/dist/api/gateway-router.d.ts +21 -0
- package/dist/api/gateway-router.d.ts.map +1 -1
- package/dist/api/gateway-router.js +58 -17
- package/dist/api/gateway-router.js.map +1 -1
- package/dist/config/migrator.d.ts +4 -0
- package/dist/config/migrator.d.ts.map +1 -1
- package/dist/config/migrator.js +60 -3
- package/dist/config/migrator.js.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/session/process.d.ts +18 -0
- package/dist/session/process.d.ts.map +1 -1
- package/dist/session/process.js +61 -1
- package/dist/session/process.js.map +1 -1
- package/dist/shell/claude-pty-shell.js +59 -0
- package/dist/shell/claude-pty-shell.js.map +1 -1
- package/dist/shell/control-channel.d.ts +74 -0
- package/dist/shell/control-channel.d.ts.map +1 -0
- package/dist/shell/control-channel.js +114 -0
- package/dist/shell/control-channel.js.map +1 -0
- package/dist/types.d.ts +21 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/web-ui.d.ts.map +1 -1
- package/dist/ui/web-ui.js +103 -2
- package/dist/ui/web-ui.js.map +1 -1
- package/mcp/tools/skills/handlers.ts +4 -2
- package/mcp/tools/telegram/receiver-server.ts +163 -0
- package/mcp/tools/telegram/typing.ts +124 -0
- package/package.json +3 -1
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Control channel (Epic #195, Phase 3b — item B2).
|
|
4
|
+
*
|
|
5
|
+
* The gateway's recovery executor can ask the PTY wrapper to press a specific
|
|
6
|
+
* key into the interactive TUI — the raw keystrokes the wrapper otherwise only
|
|
7
|
+
* generates internally (a single Enter, a menu digit, an arrow). These reach the
|
|
8
|
+
* wrapper as a NEW stdin message type `{"type":"control","key":...}`, kept
|
|
9
|
+
* distinct from a `type:"user"` message turn so control keystrokes are never
|
|
10
|
+
* confused with prompt text.
|
|
11
|
+
*
|
|
12
|
+
* The vocabulary is CLOSED and validated here, for the same reason the triage
|
|
13
|
+
* schema is closed: the only keystrokes the wrapper will ever emit on behalf of
|
|
14
|
+
* the gateway are the ones in `CONTROL_KEYS`. A malformed or unknown control
|
|
15
|
+
* message is rejected, so no arbitrary byte sequence can be injected into the
|
|
16
|
+
* PTY via this path. This module is pure (parse + map to keystrokes); the
|
|
17
|
+
* wrapper performs the actual `host.writeRaw` and the screen-gated Enter.
|
|
18
|
+
*/
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.MAX_PTY_INPUT_BYTES = exports.MAX_CONTROL_OPTION = exports.KEY_DOWN = exports.KEY_UP = exports.KEY_ENTER = exports.KEY_ESC = exports.CONTROL_KEYS = void 0;
|
|
21
|
+
exports.parseControlCommand = parseControlCommand;
|
|
22
|
+
exports.keystrokesFor = keystrokesFor;
|
|
23
|
+
exports.isAcceptablePtyInput = isAcceptablePtyInput;
|
|
24
|
+
exports.shouldRoutePtyInput = shouldRoutePtyInput;
|
|
25
|
+
/** Closed set of control keys the gateway may request. */
|
|
26
|
+
exports.CONTROL_KEYS = ['esc', 'esc-esc', 'enter', 'up', 'down', 'select-option'];
|
|
27
|
+
// VT100 keystroke sequences — identical to the ones the wrapper already emits
|
|
28
|
+
// internally (menu-probe arrows, handleMenuReply digit/Enter), so a control key
|
|
29
|
+
// is indistinguishable from a user pressing it.
|
|
30
|
+
exports.KEY_ESC = '\x1b';
|
|
31
|
+
exports.KEY_ENTER = '\r';
|
|
32
|
+
exports.KEY_UP = '\x1b[A';
|
|
33
|
+
exports.KEY_DOWN = '\x1b[B';
|
|
34
|
+
/**
|
|
35
|
+
* Upper bound for a select-option index. Capped at 9 to match the triage schema:
|
|
36
|
+
* the wrapper selects by typing the digit, which is only unambiguous single-char,
|
|
37
|
+
* so a two-digit index could type a wrong immediate selection. Menus are short.
|
|
38
|
+
*/
|
|
39
|
+
exports.MAX_CONTROL_OPTION = 9;
|
|
40
|
+
const KEY_SET = new Set(exports.CONTROL_KEYS);
|
|
41
|
+
/**
|
|
42
|
+
* Parse and validate a raw stdin control object into a closed ControlCommand,
|
|
43
|
+
* or null if it cannot be trusted. Never throws. `select-option` requires a
|
|
44
|
+
* bounded positive-integer `option`; anything else is rejected.
|
|
45
|
+
*/
|
|
46
|
+
function parseControlCommand(obj) {
|
|
47
|
+
const key = obj['key'];
|
|
48
|
+
if (typeof key !== 'string' || !KEY_SET.has(key))
|
|
49
|
+
return null;
|
|
50
|
+
if (key === 'select-option') {
|
|
51
|
+
const opt = obj['option'];
|
|
52
|
+
if (typeof opt !== 'number' ||
|
|
53
|
+
!Number.isInteger(opt) ||
|
|
54
|
+
opt < 1 ||
|
|
55
|
+
opt > exports.MAX_CONTROL_OPTION) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
return { key: 'select-option', option: opt };
|
|
59
|
+
}
|
|
60
|
+
return { key: key };
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The raw keystroke sequence(s) a control command maps to. For select-option
|
|
64
|
+
* this is just the digit — the wrapper sends Enter separately, gated on the
|
|
65
|
+
* menu still being on screen (a TUI may confirm on the digit alone), mirroring
|
|
66
|
+
* the existing menu-selection flow.
|
|
67
|
+
*/
|
|
68
|
+
function keystrokesFor(cmd) {
|
|
69
|
+
switch (cmd.key) {
|
|
70
|
+
case 'esc':
|
|
71
|
+
return [exports.KEY_ESC];
|
|
72
|
+
case 'esc-esc':
|
|
73
|
+
return [exports.KEY_ESC, exports.KEY_ESC];
|
|
74
|
+
case 'enter':
|
|
75
|
+
return [exports.KEY_ENTER];
|
|
76
|
+
case 'up':
|
|
77
|
+
return [exports.KEY_UP];
|
|
78
|
+
case 'down':
|
|
79
|
+
return [exports.KEY_DOWN];
|
|
80
|
+
case 'select-option':
|
|
81
|
+
return [String(cmd.option)];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Interactive terminal input (Issue #201). Unlike the closed control vocabulary,
|
|
86
|
+
* input-mode carries arbitrary raw keystroke bytes so a viewer can type any key.
|
|
87
|
+
* Access is gated at the gateway (auth + the localhost-default `gateway.bind`);
|
|
88
|
+
* these pure helpers bound and validate a single frame, and are reused on both
|
|
89
|
+
* sides of the pipe (the gateway WS handler and the PTY wrapper) so the two never
|
|
90
|
+
* drift on what counts as an acceptable frame.
|
|
91
|
+
*/
|
|
92
|
+
exports.MAX_PTY_INPUT_BYTES = 8192;
|
|
93
|
+
/**
|
|
94
|
+
* True when `data` is a non-empty string within the per-frame byte bound. The
|
|
95
|
+
* bound is measured in real UTF-8 bytes (not UTF-16 code units), so multi-byte
|
|
96
|
+
* input (emoji, non-Latin scripts) is capped at the same byte budget that will
|
|
97
|
+
* actually be written to the PTY.
|
|
98
|
+
*/
|
|
99
|
+
function isAcceptablePtyInput(data, maxBytes = exports.MAX_PTY_INPUT_BYTES) {
|
|
100
|
+
return (typeof data === 'string' &&
|
|
101
|
+
data.length > 0 &&
|
|
102
|
+
Buffer.byteLength(data, 'utf8') <= maxBytes);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Whether one inbound WebSocket frame should be routed into the live PTY.
|
|
106
|
+
* Requires a text (non-binary) frame and an acceptable payload; binary frames
|
|
107
|
+
* and oversized/empty payloads are dropped. Pure — no IO. (Whether a browser
|
|
108
|
+
* sends input at all is a client-side choice via the viewer's mode toggle;
|
|
109
|
+
* access to the socket is gated upstream by auth + `gateway.bind`.)
|
|
110
|
+
*/
|
|
111
|
+
function shouldRoutePtyInput(isBinary, data, maxBytes = exports.MAX_PTY_INPUT_BYTES) {
|
|
112
|
+
return !isBinary && isAcceptablePtyInput(data, maxBytes);
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=control-channel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"control-channel.js","sourceRoot":"","sources":["../../src/shell/control-channel.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;GAgBG;;;AAmCH,kDAgBC;AAQD,sCAeC;AAkBD,oDASC;AASD,kDAMC;AAlHD,0DAA0D;AAC7C,QAAA,YAAY,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,eAAe,CAAU,CAAA;AAU/F,8EAA8E;AAC9E,gFAAgF;AAChF,gDAAgD;AACnC,QAAA,OAAO,GAAG,MAAM,CAAA;AAChB,QAAA,SAAS,GAAG,IAAI,CAAA;AAChB,QAAA,MAAM,GAAG,QAAQ,CAAA;AACjB,QAAA,QAAQ,GAAG,QAAQ,CAAA;AAEhC;;;;GAIG;AACU,QAAA,kBAAkB,GAAG,CAAC,CAAA;AAEnC,MAAM,OAAO,GAAwB,IAAI,GAAG,CAAC,oBAAY,CAAC,CAAA;AAE1D;;;;GAIG;AACH,SAAgB,mBAAmB,CAAC,GAA4B;IAC9D,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAA;IACtB,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAA;IAC7D,IAAI,GAAG,KAAK,eAAe,EAAE,CAAC;QAC5B,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAA;QACzB,IACE,OAAO,GAAG,KAAK,QAAQ;YACvB,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC;YACtB,GAAG,GAAG,CAAC;YACP,GAAG,GAAG,0BAAkB,EACxB,CAAC;YACD,OAAO,IAAI,CAAA;QACb,CAAC;QACD,OAAO,EAAE,GAAG,EAAE,eAAe,EAAE,MAAM,EAAE,GAAG,EAAE,CAAA;IAC9C,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,GAAiB,EAAE,CAAA;AACnC,CAAC;AAED;;;;;GAKG;AACH,SAAgB,aAAa,CAAC,GAAmB;IAC/C,QAAQ,GAAG,CAAC,GAAG,EAAE,CAAC;QAChB,KAAK,KAAK;YACR,OAAO,CAAC,eAAO,CAAC,CAAA;QAClB,KAAK,SAAS;YACZ,OAAO,CAAC,eAAO,EAAE,eAAO,CAAC,CAAA;QAC3B,KAAK,OAAO;YACV,OAAO,CAAC,iBAAS,CAAC,CAAA;QACpB,KAAK,IAAI;YACP,OAAO,CAAC,cAAM,CAAC,CAAA;QACjB,KAAK,MAAM;YACT,OAAO,CAAC,gBAAQ,CAAC,CAAA;QACnB,KAAK,eAAe;YAClB,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAA;IAC/B,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACU,QAAA,mBAAmB,GAAG,IAAI,CAAA;AAEvC;;;;;GAKG;AACH,SAAgB,oBAAoB,CAClC,IAAa,EACb,WAAmB,2BAAmB;IAEtC,OAAO,CACL,OAAO,IAAI,KAAK,QAAQ;QACxB,IAAI,CAAC,MAAM,GAAG,CAAC;QACf,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,QAAQ,CAC5C,CAAA;AACH,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,mBAAmB,CACjC,QAAiB,EACjB,IAAa,EACb,WAAmB,2BAAmB;IAEtC,OAAO,CAAC,QAAQ,IAAI,oBAAoB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;AAC1D,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -136,6 +136,14 @@ export interface GatewayConfig {
|
|
|
136
136
|
gateway: {
|
|
137
137
|
logDir: string;
|
|
138
138
|
timezone: string;
|
|
139
|
+
/**
|
|
140
|
+
* Network interface the HTTP/WebSocket server binds to. Defaults to
|
|
141
|
+
* "127.0.0.1" (localhost-only) so the dashboard and API are not exposed to
|
|
142
|
+
* the local network out of the box. Set to "0.0.0.0" to expose all
|
|
143
|
+
* interfaces (e.g. behind a trusted reverse proxy). The `GATEWAY_BIND` env
|
|
144
|
+
* var, when set, takes precedence over this field.
|
|
145
|
+
*/
|
|
146
|
+
bind?: string;
|
|
139
147
|
models?: ModelConfig[];
|
|
140
148
|
api?: {
|
|
141
149
|
keys: ApiKey[];
|
|
@@ -145,6 +153,19 @@ export interface GatewayConfig {
|
|
|
145
153
|
* false = interactive backend: claude TUI under the claude-pty-shell PTY wrapper.
|
|
146
154
|
*/
|
|
147
155
|
headless?: boolean;
|
|
156
|
+
/**
|
|
157
|
+
* Self-healing recovery (Epic #195, Phase 3). When `autoRecover` is true the
|
|
158
|
+
* turn-trace watchdog may auto-execute a whitelisted recovery action
|
|
159
|
+
* (keystroke, session/receiver restart, safe-mode fallback, guarded resend)
|
|
160
|
+
* for a stalled turn. Default false — detection, incident logging, and
|
|
161
|
+
* notification still run when disabled; only live action execution is gated,
|
|
162
|
+
* so the feature ships dark and the operator opts in when ready. Safe-mode
|
|
163
|
+
* auto-fallback on hard PTY failure is independent of this flag (it is always
|
|
164
|
+
* reversible and never presses keys).
|
|
165
|
+
*/
|
|
166
|
+
selfHealing?: {
|
|
167
|
+
autoRecover?: boolean;
|
|
168
|
+
};
|
|
148
169
|
/** Global history retention/cleanup defaults */
|
|
149
170
|
history?: HistoryConfig & {
|
|
150
171
|
cleanupHour?: number;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/ui/web-ui.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web-ui.d.ts","sourceRoot":"","sources":["../../src/ui/web-ui.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,SAAK,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"web-ui.d.ts","sourceRoot":"","sources":["../../src/ui/web-ui.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,SAAK,GAAG,MAAM,CAu3B5D"}
|
package/dist/ui/web-ui.js
CHANGED
|
@@ -119,6 +119,22 @@ function generateDashboardHtml(dashToken = '') {
|
|
|
119
119
|
}
|
|
120
120
|
.pty-close:hover { color: #fc8181; }
|
|
121
121
|
.pty-refresh:hover { color: #63b3ed; }
|
|
122
|
+
/* Keyboard-focus outline on the viewer (it is tabindex focusable so PageUp/
|
|
123
|
+
PageDown reach the terminal); keep it subtle rather than the default ring. */
|
|
124
|
+
#pty-terminal:focus, #pty-terminal:focus-visible { outline: 1px solid #2d3748; }
|
|
125
|
+
.pty-mode-toggle {
|
|
126
|
+
background: none;
|
|
127
|
+
border: 1px solid #2d3748;
|
|
128
|
+
border-radius: 4px;
|
|
129
|
+
color: #718096;
|
|
130
|
+
cursor: pointer;
|
|
131
|
+
font-size: 0.72rem;
|
|
132
|
+
padding: 1px 7px;
|
|
133
|
+
margin-right: 6px;
|
|
134
|
+
}
|
|
135
|
+
.pty-mode-toggle:hover { color: #63b3ed; border-color: #3d4a5f; }
|
|
136
|
+
/* Active (input) mode — clearly signals the viewer now types into the PTY. */
|
|
137
|
+
.pty-mode-toggle.input-active { color: #0d1117; background: #63b3ed; border-color: #63b3ed; font-weight: 600; }
|
|
122
138
|
/* Fixed-size terminal viewport — the server PTY runs at 200x50, so the
|
|
123
139
|
viewer must NOT resize to the panel (that mismatch is what garbles the
|
|
124
140
|
output). We render at the native size and pan horizontally if the 200-col
|
|
@@ -233,13 +249,16 @@ function generateDashboardHtml(dashToken = '') {
|
|
|
233
249
|
in view when streaming. -->
|
|
234
250
|
<div class="pty-viewer" id="pty-viewer">
|
|
235
251
|
<div class="pty-viewer-header">
|
|
236
|
-
<span>
|
|
252
|
+
<span><span id="pty-title-text">Terminal Viewer</span> — <span class="agent-label" id="pty-agent-label"></span><span class="session-label" id="pty-session-label"></span></span>
|
|
237
253
|
<span>
|
|
254
|
+
<button class="pty-mode-toggle" id="pty-mode-toggle-btn" title="Toggle input mode (type into the live terminal)">⌨ View</button>
|
|
238
255
|
<button class="pty-refresh" id="pty-refresh-btn" title="Refresh (reconnect & redraw)">↺</button>
|
|
239
256
|
<button class="pty-close" id="pty-close-btn" title="Close">✕</button>
|
|
240
257
|
</span>
|
|
241
258
|
</div>
|
|
242
|
-
|
|
259
|
+
<!-- tabindex makes the viewer keyboard-focusable so PageUp/PageDown reach it
|
|
260
|
+
even in read-only view mode (xterm stdin is disabled there). -->
|
|
261
|
+
<div id="pty-terminal" tabindex="0"></div>
|
|
243
262
|
</div>
|
|
244
263
|
|
|
245
264
|
<!-- Sessions — full width (session-centric, flat list) -->
|
|
@@ -350,6 +369,11 @@ function generateDashboardHtml(dashToken = '') {
|
|
|
350
369
|
// multi-byte char into noise — decode as UTF-8 with {stream:true} so sequences
|
|
351
370
|
// split across WebSocket frames are reassembled instead of corrupted.
|
|
352
371
|
let utf8Decoder = null;
|
|
372
|
+
// Interactive input mode (Issue #201). When on, keystrokes typed into the
|
|
373
|
+
// terminal are streamed to the live PTY over the same WebSocket. Off by
|
|
374
|
+
// default (read-only mirror); the viewer flips it on via the mode toggle.
|
|
375
|
+
let ptyInputMode = false;
|
|
376
|
+
let ptyOnDataDisposable = null;
|
|
353
377
|
|
|
354
378
|
// The agent's TUI enables mouse tracking (DECSET 1000/1002/1003/1006...).
|
|
355
379
|
// While those modes are active, xterm.js forwards wheel/click events to the
|
|
@@ -373,6 +397,9 @@ function generateDashboardHtml(dashToken = '') {
|
|
|
373
397
|
// Append the session id after the agent name, e.g. "claude-founder · 3c01897c…".
|
|
374
398
|
document.getElementById('pty-session-label').textContent = sessionId ? ' \\u00b7 ' + sessionId : '';
|
|
375
399
|
document.getElementById('pty-viewer').style.display = 'block';
|
|
400
|
+
// Always (re)open a fresh session in read-only view mode; the mode toggle
|
|
401
|
+
// lets the viewer switch into interactive input on demand.
|
|
402
|
+
setPtyInputMode(false);
|
|
376
403
|
|
|
377
404
|
if (!term) {
|
|
378
405
|
term = new Terminal({
|
|
@@ -488,12 +515,53 @@ function generateDashboardHtml(dashToken = '') {
|
|
|
488
515
|
// are about to close intentionally, so it does not schedule a new one.
|
|
489
516
|
if (ptyReconnectTimer) { clearTimeout(ptyReconnectTimer); ptyReconnectTimer = null; }
|
|
490
517
|
ptyReconnectAttempts = 0;
|
|
518
|
+
setPtyInputMode(false); // always leave input mode when closing/switching
|
|
491
519
|
if (ptyWs) { ptyWs.onclose = null; ptyWs.onerror = null; ptyWs.close(); ptyWs = null; }
|
|
492
520
|
currentPtyAgent = null;
|
|
493
521
|
currentPtySession = null;
|
|
494
522
|
document.getElementById('pty-viewer').style.display = 'none';
|
|
495
523
|
}
|
|
496
524
|
|
|
525
|
+
// Switch the viewer between read-only mirror and interactive input. In input
|
|
526
|
+
// mode the terminal accepts stdin and every keystroke (printable chars,
|
|
527
|
+
// Enter, arrows, Ctrl-combos, Esc) is streamed to the live PTY over the WS,
|
|
528
|
+
// like a real terminal; the title and toggle reflect the active mode.
|
|
529
|
+
function setPtyInputMode(on) {
|
|
530
|
+
if (!term) on = false;
|
|
531
|
+
ptyInputMode = !!on;
|
|
532
|
+
const toggleBtn = document.getElementById('pty-mode-toggle-btn');
|
|
533
|
+
const titleEl = document.getElementById('pty-title-text');
|
|
534
|
+
if (term) term.options.disableStdin = !ptyInputMode;
|
|
535
|
+
// Detach any previous onData listener before (re)attaching, so toggling
|
|
536
|
+
// off — or toggling on twice — never leaves a duplicate keystroke stream.
|
|
537
|
+
if (ptyOnDataDisposable) { ptyOnDataDisposable.dispose(); ptyOnDataDisposable = null; }
|
|
538
|
+
if (ptyInputMode && term) {
|
|
539
|
+
ptyOnDataDisposable = term.onData(function(data) {
|
|
540
|
+
if (ptyWs && ptyWs.readyState === WebSocket.OPEN) ptyWs.send(data);
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
if (titleEl) titleEl.textContent = ptyInputMode ? 'Interactive Terminal' : 'Terminal Viewer';
|
|
544
|
+
if (toggleBtn) {
|
|
545
|
+
toggleBtn.innerHTML = ptyInputMode ? '\\u2328 Input' : '\\u2328 View';
|
|
546
|
+
toggleBtn.classList.toggle('input-active', ptyInputMode);
|
|
547
|
+
toggleBtn.title = ptyInputMode
|
|
548
|
+
? 'Input mode — keystrokes go to the live terminal (click for read-only)'
|
|
549
|
+
: 'Toggle input mode (type into the live terminal)';
|
|
550
|
+
}
|
|
551
|
+
if (ptyInputMode && term) {
|
|
552
|
+
term.focus(); // typing goes to xterm's textarea
|
|
553
|
+
} else {
|
|
554
|
+
// View mode: focus the container (tabindex) so PageUp/PageDown reach our
|
|
555
|
+
// key handler instead of scrolling the browser page.
|
|
556
|
+
const host = document.getElementById('pty-terminal');
|
|
557
|
+
if (host) host.focus();
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
function togglePtyInputMode() {
|
|
562
|
+
setPtyInputMode(!ptyInputMode);
|
|
563
|
+
}
|
|
564
|
+
|
|
497
565
|
// Refresh: force a clean reconnect of the CURRENT session. The server replays
|
|
498
566
|
// a freshly-serialized screen frame on subscribe, so this redraws from a clean
|
|
499
567
|
// xterm state — a manual escape hatch if the live stream ever drifts.
|
|
@@ -505,8 +573,41 @@ function generateDashboardHtml(dashToken = '') {
|
|
|
505
573
|
await openPtyViewer(agentId, sessionId);
|
|
506
574
|
}
|
|
507
575
|
|
|
576
|
+
// Page Up / Page Down keys (Issue #201): the alt-screen mirror keeps no
|
|
577
|
+
// scrollback of its own, so a physical PageUp/PageDown key is forwarded to the
|
|
578
|
+
// live TUI — which holds the history and scrolls itself. In read-only view mode
|
|
579
|
+
// xterm's stdin is disabled, so without this those keys would just scroll the
|
|
580
|
+
// browser page; here we intercept ONLY these two keys (never printable input)
|
|
581
|
+
// and send them to the PTY, so the user can page through earlier output without
|
|
582
|
+
// enabling the interactive keyboard. In input mode xterm already forwards them
|
|
583
|
+
// via onData, so we skip to avoid double-send.
|
|
584
|
+
//
|
|
585
|
+
// The listener is attached to the document, NOT the viewer container: xterm renders
|
|
586
|
+
// its own focusable helpers inside #pty-terminal, and with disableStdin the
|
|
587
|
+
// container rarely holds focus reliably (a reconnect or stray click drops it),
|
|
588
|
+
// so a container-scoped keydown silently missed the keys. Gating on the viewer
|
|
589
|
+
// being open + view mode keeps it from hijacking PageUp elsewhere on the page,
|
|
590
|
+
// and we bail when focus is in a real text field so form paging still works.
|
|
591
|
+
// \\x1b[5~ = PageUp, \\x1b[6~ = PageDown.
|
|
592
|
+
function forwardPageKey(e) {
|
|
593
|
+
if (e.key !== 'PageUp' && e.key !== 'PageDown') return;
|
|
594
|
+
if (ptyInputMode) return; // input mode: xterm.onData already sends it
|
|
595
|
+
// Only while THIS viewer is actually open with a live socket.
|
|
596
|
+
const viewer = document.getElementById('pty-viewer');
|
|
597
|
+
if (!viewer || viewer.style.display === 'none') return;
|
|
598
|
+
if (!ptyWs || ptyWs.readyState !== WebSocket.OPEN) return;
|
|
599
|
+
// Don't steal paging from a genuine editable field (none in view mode today,
|
|
600
|
+
// but keep the guard so the document-level listener stays well-behaved).
|
|
601
|
+
const t = e.target;
|
|
602
|
+
if (t && (t.tagName === 'INPUT' || (t.tagName === 'TEXTAREA' && !t.disabled) || t.isContentEditable)) return;
|
|
603
|
+
e.preventDefault();
|
|
604
|
+
ptyWs.send(e.key === 'PageUp' ? '\\x1b[5~' : '\\x1b[6~');
|
|
605
|
+
}
|
|
606
|
+
document.addEventListener('keydown', forwardPageKey);
|
|
607
|
+
|
|
508
608
|
document.getElementById('pty-close-btn').addEventListener('click', closePtyViewer);
|
|
509
609
|
document.getElementById('pty-refresh-btn').addEventListener('click', function() { void refreshPtyViewer(); });
|
|
610
|
+
document.getElementById('pty-mode-toggle-btn').addEventListener('click', togglePtyInputMode);
|
|
510
611
|
|
|
511
612
|
// Event delegation for Live buttons (avoids inline onclick + HTML injection)
|
|
512
613
|
document.getElementById('sessions-tbody').addEventListener('click', function(e) {
|
package/dist/ui/web-ui.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web-ui.js","sourceRoot":"","sources":["../../src/ui/web-ui.ts"],"names":[],"mappings":";;AAIA,
|
|
1
|
+
{"version":3,"file":"web-ui.js","sourceRoot":"","sources":["../../src/ui/web-ui.ts"],"names":[],"mappings":";;AAIA,sDAu3BC;AA33BD;;;GAGG;AACH,SAAgB,qBAAqB,CAAC,SAAS,GAAG,EAAE;IAClD,MAAM,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC3E,OAAO;;;;;qCAK4B,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA+2BtC,CAAC;AACT,CAAC"}
|
|
@@ -161,8 +161,10 @@ export async function installSkill(params: InstallSkillParams): Promise<string>
|
|
|
161
161
|
throw new Error(`SKILL.md exceeds ${MAX_SKILL_SIZE / 1024}KB limit (${(content.length / 1024).toFixed(1)}KB)`);
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
-
// Parse frontmatter to extract name
|
|
165
|
-
|
|
164
|
+
// Parse frontmatter to extract name. Import compiled dist/, not raw src/ —
|
|
165
|
+
// src/ is not published (files: ["mcp/"]), so a src/ import throws "Cannot find
|
|
166
|
+
// module" on installed packages. Enforced by mcp-no-src-imports.test.ts.
|
|
167
|
+
const { extractFrontmatter } = await import('../../../dist/skills/parser.js');
|
|
166
168
|
const extracted = extractFrontmatter(content);
|
|
167
169
|
if (!extracted) {
|
|
168
170
|
throw new Error('Invalid SKILL.md: no valid YAML frontmatter found.');
|
|
@@ -28,7 +28,15 @@ import { randomBytes } from 'crypto'
|
|
|
28
28
|
import { readFileSync, writeFileSync, mkdirSync, readdirSync, rmSync, statSync, renameSync, realpathSync, chmodSync, existsSync } from 'fs'
|
|
29
29
|
import { homedir } from 'os'
|
|
30
30
|
import { join, extname, sep } from 'path'
|
|
31
|
+
import { execFileSync } from 'child_process'
|
|
31
32
|
import { createWorkingStateManager, drainOrphanForwards } from './typing'
|
|
33
|
+
// Import compiled dist/, not raw src/ — src/ is not published (files: ["mcp/"]),
|
|
34
|
+
// so a src/ import crashes this bun-run receiver on installed packages (the bug
|
|
35
|
+
// that silenced every bot on systemd installs). Enforced by
|
|
36
|
+
// tests/unit/mcp-no-src-imports.test.ts.
|
|
37
|
+
import { formatTurnIncident, type TurnIncident } from '../../../dist/agent/turn-trace.js'
|
|
38
|
+
import { createIncidentStore } from '../../../dist/agent/incident-store.js'
|
|
39
|
+
import type { RecoveryOutcome } from '../../../dist/agent/incident.js'
|
|
32
40
|
import { initDedupDir, isDuplicate as _isDuplicate, pruneDedup as _pruneDedup } from './dedup'
|
|
33
41
|
import { hasMarkdown, toTelegramHtml, migrateAccess } from './pure'
|
|
34
42
|
|
|
@@ -104,6 +112,70 @@ let botUsername = ''
|
|
|
104
112
|
|
|
105
113
|
const TYPING_DIR = join(STATE_DIR, 'typing')
|
|
106
114
|
|
|
115
|
+
// ─── Incident store (Epic #195, Phase 2) ────────────────────────────────────
|
|
116
|
+
// Persist turn-trace stalls as scrubbed on-disk bundles, deduped by fingerprint
|
|
117
|
+
// (stage + failure class + CLI version) with escalation. The store owns all
|
|
118
|
+
// disk IO; the pure decision logic lives in src/agent/incident.ts.
|
|
119
|
+
const INCIDENTS_DIR = join(homedir(), '.claude-gateway', 'incidents')
|
|
120
|
+
|
|
121
|
+
// The Claude CLI version is part of the fingerprint. Resolve it once and cache
|
|
122
|
+
// it — a new version is a new fingerprint, and the receiver is restarted when
|
|
123
|
+
// the CLI is updated, so a per-process cache is safe.
|
|
124
|
+
let cachedCliVersion: string | null = null
|
|
125
|
+
function getCliVersion(): string {
|
|
126
|
+
if (cachedCliVersion !== null) return cachedCliVersion
|
|
127
|
+
try {
|
|
128
|
+
const out = execFileSync('claude', ['--version'], {
|
|
129
|
+
encoding: 'utf8',
|
|
130
|
+
timeout: 5000,
|
|
131
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
132
|
+
})
|
|
133
|
+
const m = out.trim().match(/^(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)/)
|
|
134
|
+
cachedCliVersion = m ? m[1] : 'unknown'
|
|
135
|
+
} catch {
|
|
136
|
+
cachedCliVersion = 'unknown'
|
|
137
|
+
}
|
|
138
|
+
return cachedCliVersion
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Gateway version, best-effort, for manifest context only (not fingerprinted).
|
|
142
|
+
function readGatewayVersion(): string {
|
|
143
|
+
for (const rel of ['../../../package.json', '../../package.json']) {
|
|
144
|
+
try {
|
|
145
|
+
const raw = readFileSync(join(__dirname, rel), 'utf8')
|
|
146
|
+
const v = (JSON.parse(raw) as { version?: string }).version
|
|
147
|
+
if (typeof v === 'string' && v.length > 0) return v
|
|
148
|
+
} catch {
|
|
149
|
+
// try next candidate
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return 'unknown'
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const incidentStore = createIncidentStore({
|
|
156
|
+
dir: INCIDENTS_DIR,
|
|
157
|
+
fs: { mkdirSync, writeFileSync, readFileSync, existsSync, readdirSync, rmSync },
|
|
158
|
+
now: () => Date.now(),
|
|
159
|
+
channel: 'telegram',
|
|
160
|
+
gatewayVersion: readGatewayVersion(),
|
|
161
|
+
getCliVersion,
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
// Prune old bundles at startup and daily thereafter (retention is enforced in
|
|
165
|
+
// the store; this just triggers it periodically).
|
|
166
|
+
try {
|
|
167
|
+
incidentStore.prune()
|
|
168
|
+
} catch {
|
|
169
|
+
// Non-fatal: a prune failure must not stop the receiver from serving.
|
|
170
|
+
}
|
|
171
|
+
setInterval(() => {
|
|
172
|
+
try {
|
|
173
|
+
incidentStore.prune()
|
|
174
|
+
} catch {
|
|
175
|
+
/* non-fatal */
|
|
176
|
+
}
|
|
177
|
+
}, 24 * 60 * 60 * 1000).unref()
|
|
178
|
+
|
|
107
179
|
const typingManager = createWorkingStateManager(
|
|
108
180
|
TYPING_DIR,
|
|
109
181
|
{
|
|
@@ -117,8 +189,99 @@ const typingManager = createWorkingStateManager(
|
|
|
117
189
|
]),
|
|
118
190
|
},
|
|
119
191
|
{ mkdirSync, writeFileSync, existsSync, rmSync, readFileSync, statSync },
|
|
192
|
+
// Turn-trace watchdog sink (Epic #195, Phase 2): persist a scrubbed incident
|
|
193
|
+
// bundle, then notify the affected chat only when the escalation rules say so
|
|
194
|
+
// (quiet on the first stall, louder once a fingerprint repeats). Any failure
|
|
195
|
+
// here is swallowed — incident bookkeeping must never break the live channel.
|
|
196
|
+
(incident, evidence) => {
|
|
197
|
+
process.stderr.write(`telegram channel: ${formatTurnIncident(incident)}\n`)
|
|
198
|
+
try {
|
|
199
|
+
const result = incidentStore.record(incident, evidence)
|
|
200
|
+
if (result.escalation.notify) {
|
|
201
|
+
void notifyIncident(incident.chatId, result)
|
|
202
|
+
incidentStore.markNotified(result.id, result.escalation.level)
|
|
203
|
+
}
|
|
204
|
+
// Cross-process recovery bridge (Epic #195, Phase 3b): for stages whose
|
|
205
|
+
// recovery lives in the runner (session/CLI), ask it to attempt recovery
|
|
206
|
+
// and persist the outcome. Fire-and-forget — recovery must never block the
|
|
207
|
+
// channel, and it is a no-op unless the operator enabled autoRecover.
|
|
208
|
+
void attemptRecover(incident, result.id)
|
|
209
|
+
} catch (err) {
|
|
210
|
+
process.stderr.write(
|
|
211
|
+
`telegram channel: incident persist failed: ${String(err)}\n`,
|
|
212
|
+
)
|
|
213
|
+
}
|
|
214
|
+
},
|
|
120
215
|
)
|
|
121
216
|
|
|
217
|
+
// Stages whose recovery must run in the runner process (live session control):
|
|
218
|
+
// session injection, CLI startup, and no-output progress wedges. Inbound
|
|
219
|
+
// (channel ingress) and delivery/dispatch (transport) are receiver-side and are
|
|
220
|
+
// not bridged here.
|
|
221
|
+
const RUNNER_RECOVERABLE_STAGES: ReadonlySet<string> = new Set(['inject', 'startup', 'progress'])
|
|
222
|
+
|
|
223
|
+
// A stable-per-turn key for the runner's intervention budget. Uses the stalled
|
|
224
|
+
// stage's start second (at − sinceMs), so repeated detections of the SAME wedged
|
|
225
|
+
// turn share a budget while a genuinely new turn gets a fresh one.
|
|
226
|
+
function recoveryTurnKey(incident: TurnIncident): string {
|
|
227
|
+
const startSec = Math.round((incident.at - incident.sinceMs) / 1000)
|
|
228
|
+
return `${incident.chatId}:${startSec}`
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Ask the runner to attempt recovery for a session/CLI-stage stall, then persist
|
|
232
|
+
// the returned outcome to the incident bundle. Best-effort and non-blocking.
|
|
233
|
+
async function attemptRecover(incident: TurnIncident, incidentId: string): Promise<void> {
|
|
234
|
+
if (!CALLBACK_URL_BASE) return
|
|
235
|
+
if (!RUNNER_RECOVERABLE_STAGES.has(incident.stage)) return
|
|
236
|
+
try {
|
|
237
|
+
const res = await fetch(CALLBACK_URL_BASE + '/recover', {
|
|
238
|
+
method: 'POST',
|
|
239
|
+
headers: { 'Content-Type': 'application/json' },
|
|
240
|
+
body: JSON.stringify({
|
|
241
|
+
incidentId,
|
|
242
|
+
chatId: incident.chatId,
|
|
243
|
+
stage: incident.stage,
|
|
244
|
+
failureClass: incident.failureClass,
|
|
245
|
+
turnKey: recoveryTurnKey(incident),
|
|
246
|
+
}),
|
|
247
|
+
})
|
|
248
|
+
if (!res.ok) return
|
|
249
|
+
const data = (await res.json()) as { ok?: boolean; outcome?: RecoveryOutcome }
|
|
250
|
+
if (data.ok && data.outcome) {
|
|
251
|
+
incidentStore.appendRecovery(incidentId, data.outcome)
|
|
252
|
+
}
|
|
253
|
+
} catch (err) {
|
|
254
|
+
process.stderr.write(`telegram channel: recover POST failed: ${String(err)}\n`)
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Short, content-free notice for a stalled turn. No message text or chat id is
|
|
259
|
+
// echoed back — only the pipeline stage and (on repeat) the occurrence count.
|
|
260
|
+
async function notifyIncident(
|
|
261
|
+
chatId: string,
|
|
262
|
+
result: { escalation: { level: string }; occurrences: number; manifest: { stage: string } },
|
|
263
|
+
): Promise<void> {
|
|
264
|
+
const stage = result.manifest.stage
|
|
265
|
+
let text: string
|
|
266
|
+
if (result.escalation.level === 'investigate') {
|
|
267
|
+
text =
|
|
268
|
+
`⚠️ Recurring stall detected at the "${stage}" stage ` +
|
|
269
|
+
`(${result.occurrences}× recently). This looks like a persistent issue — ` +
|
|
270
|
+
`it has been logged for investigation.`
|
|
271
|
+
} else {
|
|
272
|
+
// Neutral wording: automatic recovery only runs when the operator has
|
|
273
|
+
// enabled gateway.selfHealing.autoRecover (off by default), and the receiver
|
|
274
|
+
// cannot see that runner-side flag — so do not promise it here.
|
|
275
|
+
text =
|
|
276
|
+
`⚠️ A turn stalled at the "${stage}" stage and has been logged.`
|
|
277
|
+
}
|
|
278
|
+
try {
|
|
279
|
+
await bot.api.sendMessage(chatId, text)
|
|
280
|
+
} catch {
|
|
281
|
+
// Best-effort notify; the incident is already persisted regardless.
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
122
285
|
type PendingEntry = {
|
|
123
286
|
senderId: string
|
|
124
287
|
chatId: string
|