@0xmaxma/claude-gateway 1.2.32 → 1.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 (45) hide show
  1. package/README.md +23 -4
  2. package/config.template.json +5 -5
  3. package/dist/api/router.d.ts.map +1 -1
  4. package/dist/api/router.js +2 -4
  5. package/dist/api/router.js.map +1 -1
  6. package/dist/apps/agent-manager.d.ts.map +1 -1
  7. package/dist/apps/agent-manager.js +0 -1
  8. package/dist/apps/agent-manager.js.map +1 -1
  9. package/dist/config/watcher.d.ts.map +1 -1
  10. package/dist/config/watcher.js +21 -4
  11. package/dist/config/watcher.js.map +1 -1
  12. package/dist/index.js +8 -3
  13. package/dist/index.js.map +1 -1
  14. package/dist/session/process.d.ts.map +1 -1
  15. package/dist/session/process.js +32 -5
  16. package/dist/session/process.js.map +1 -1
  17. package/dist/shell/args.d.ts +22 -0
  18. package/dist/shell/args.d.ts.map +1 -0
  19. package/dist/shell/args.js +105 -0
  20. package/dist/shell/args.js.map +1 -0
  21. package/dist/shell/claude-pty-shell.d.ts +3 -0
  22. package/dist/shell/claude-pty-shell.d.ts.map +1 -0
  23. package/dist/shell/claude-pty-shell.js +407 -0
  24. package/dist/shell/claude-pty-shell.js.map +1 -0
  25. package/dist/shell/emitter.d.ts +36 -0
  26. package/dist/shell/emitter.d.ts.map +1 -0
  27. package/dist/shell/emitter.js +85 -0
  28. package/dist/shell/emitter.js.map +1 -0
  29. package/dist/shell/pty-host.d.ts +21 -0
  30. package/dist/shell/pty-host.d.ts.map +1 -0
  31. package/dist/shell/pty-host.js +102 -0
  32. package/dist/shell/pty-host.js.map +1 -0
  33. package/dist/shell/screen.d.ts +44 -0
  34. package/dist/shell/screen.d.ts.map +1 -0
  35. package/dist/shell/screen.js +89 -0
  36. package/dist/shell/screen.js.map +1 -0
  37. package/dist/shell/tailer.d.ts +64 -0
  38. package/dist/shell/tailer.d.ts.map +1 -0
  39. package/dist/shell/tailer.js +181 -0
  40. package/dist/shell/tailer.js.map +1 -0
  41. package/dist/types.d.ts +7 -1
  42. package/dist/types.d.ts.map +1 -1
  43. package/mcp/tools/telegram/dedup.ts +46 -0
  44. package/mcp/tools/telegram/receiver-server.ts +25 -0
  45. package/package.json +3 -1
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.sanitizeUserText = sanitizeUserText;
37
+ exports.translateArgs = translateArgs;
38
+ const crypto = __importStar(require("crypto"));
39
+ /**
40
+ * User text from channels (Telegram etc.) is untrusted and goes into a PTY:
41
+ * strip every C0 control char except \n and \t (notably ESC — a crafted
42
+ * message must not be able to inject terminal key sequences), plus DEL.
43
+ * \r is normalized to \n so it cannot submit the TUI input early.
44
+ */
45
+ function sanitizeUserText(text) {
46
+ return text
47
+ .replace(/\r\n/g, '\n')
48
+ .replace(/\r/g, '\n')
49
+ // eslint-disable-next-line no-control-regex
50
+ .replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, '');
51
+ }
52
+ /** Headless-only flags the wrapper consumes (claude interactive must not see them). */
53
+ const CONSUME_FLAGS = new Set(['--print', '-p', '--verbose', '--include-partial-messages']);
54
+ /** Headless-only flags with a value — consume both tokens. */
55
+ const CONSUME_FLAGS_WITH_VALUE = new Set(['--input-format', '--output-format']);
56
+ /** Flags with a value that pass through to interactive claude. */
57
+ const PASS_FLAGS_WITH_VALUE = new Set(['--model', '--mcp-config', '--session-id', '--permission-mode']);
58
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
59
+ /**
60
+ * Translate the arg vector the gateway builds for headless claude
61
+ * (see SessionProcess.buildArgs) into args for interactive claude.
62
+ * Unknown flags pass through so agentConfig.claude.extraFlags keeps working.
63
+ */
64
+ function translateArgs(argv) {
65
+ const claudeArgs = [];
66
+ let sessionId = '';
67
+ let model = '';
68
+ for (let i = 0; i < argv.length; i++) {
69
+ const arg = argv[i];
70
+ if (CONSUME_FLAGS.has(arg))
71
+ continue;
72
+ if (CONSUME_FLAGS_WITH_VALUE.has(arg)) {
73
+ i++;
74
+ continue;
75
+ }
76
+ // Built-in below — consume here so it is never duplicated.
77
+ if (arg === '--dangerously-skip-permissions')
78
+ continue;
79
+ if (PASS_FLAGS_WITH_VALUE.has(arg)) {
80
+ const value = argv[i + 1];
81
+ if (value === undefined)
82
+ throw new Error(`missing value for ${arg}`);
83
+ if (arg === '--model')
84
+ model = value;
85
+ if (arg === '--session-id') {
86
+ if (!UUID_RE.test(value))
87
+ throw new Error(`--session-id is not a UUID: ${value}`);
88
+ sessionId = value;
89
+ }
90
+ claudeArgs.push(arg, value);
91
+ i++;
92
+ continue;
93
+ }
94
+ claudeArgs.push(arg);
95
+ }
96
+ if (!sessionId) {
97
+ sessionId = crypto.randomUUID();
98
+ claudeArgs.push('--session-id', sessionId);
99
+ }
100
+ // Built-in: the wrapper always runs claude with permissions skipped,
101
+ // matching the gateway's headless backend (no config flag anymore).
102
+ claudeArgs.push('--dangerously-skip-permissions');
103
+ return { claudeArgs, sessionId, model };
104
+ }
105
+ //# sourceMappingURL=args.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args.js","sourceRoot":"","sources":["../../src/shell/args.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAQA,4CAMC;AAyBD,sCAoCC;AA3ED,+CAAiC;AAEjC;;;;;GAKG;AACH,SAAgB,gBAAgB,CAAC,IAAY;IAC3C,OAAO,IAAI;SACR,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC;SACtB,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC;QACrB,4CAA4C;SAC3C,OAAO,CAAC,mCAAmC,EAAE,EAAE,CAAC,CAAC;AACtD,CAAC;AAWD,uFAAuF;AACvF,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,4BAA4B,CAAC,CAAC,CAAC;AAC5F,8DAA8D;AAC9D,MAAM,wBAAwB,GAAG,IAAI,GAAG,CAAC,CAAC,gBAAgB,EAAE,iBAAiB,CAAC,CAAC,CAAC;AAChF,kEAAkE;AAClE,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,cAAc,EAAE,cAAc,EAAE,mBAAmB,CAAC,CAAC,CAAC;AAExG,MAAM,OAAO,GAAG,iEAAiE,CAAC;AAElF;;;;GAIG;AACH,SAAgB,aAAa,CAAC,IAAc;IAC1C,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,IAAI,SAAS,GAAG,EAAE,CAAC;IACnB,IAAI,KAAK,GAAG,EAAE,CAAC;IAEf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,IAAI,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QACrC,IAAI,wBAAwB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAAC,CAAC,EAAE,CAAC;YAAC,SAAS;QAAC,CAAC;QACzD,2DAA2D;QAC3D,IAAI,GAAG,KAAK,gCAAgC;YAAE,SAAS;QACvD,IAAI,qBAAqB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACnC,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1B,IAAI,KAAK,KAAK,SAAS;gBAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,GAAG,EAAE,CAAC,CAAC;YACrE,IAAI,GAAG,KAAK,SAAS;gBAAE,KAAK,GAAG,KAAK,CAAC;YACrC,IAAI,GAAG,KAAK,cAAc,EAAE,CAAC;gBAC3B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;oBAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,KAAK,EAAE,CAAC,CAAC;gBAClF,SAAS,GAAG,KAAK,CAAC;YACpB,CAAC;YACD,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YAC5B,CAAC,EAAE,CAAC;YACJ,SAAS;QACX,CAAC;QACD,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;IAED,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,SAAS,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;QAChC,UAAU,CAAC,IAAI,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC;IAC7C,CAAC;IAED,qEAAqE;IACrE,oEAAoE;IACpE,UAAU,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;IAElD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=claude-pty-shell.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-pty-shell.d.ts","sourceRoot":"","sources":["../../src/shell/claude-pty-shell.ts"],"names":[],"mappings":""}
@@ -0,0 +1,407 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ /**
38
+ * claude-pty-shell — runs the *interactive* Claude Code TUI inside a PTY
39
+ * while speaking the gateway's headless stream-json protocol on stdio.
40
+ *
41
+ * Drop-in usage (no gateway code changes):
42
+ * CLAUDE_BIN="node /path/to/dist/shell/claude-pty-shell.js"
43
+ *
44
+ * Design: planning-60-pty-shell-wrapper.md. Text source of truth is the
45
+ * session transcript JSONL (streamed mid-turn = message-level streaming);
46
+ * the PTY screen is used only for busy/idle/dialog liveness signals.
47
+ */
48
+ const fs = __importStar(require("fs"));
49
+ const readline = __importStar(require("readline"));
50
+ const args_1 = require("./args");
51
+ const screen_1 = require("./screen");
52
+ const pty_host_1 = require("./pty-host");
53
+ const tailer_1 = require("./tailer");
54
+ const emitter_1 = require("./emitter");
55
+ const POLL_MS = 200;
56
+ const STARTUP_QUIET_MS = 600;
57
+ // How often to touch the heartbeat file during an active turn (PTY mode keepalive).
58
+ // Must be well under the receiver's STALLED_TIMEOUT_MS (300s) to prevent false warnings.
59
+ const HEARTBEAT_INTERVAL_MS = 60000;
60
+ const SUBMIT_ENTER_DELAY_MS = 300;
61
+ const SUBMIT_RETRY_AFTER_MS = 4000;
62
+ const MAX_ENTER_RETRIES = 2;
63
+ const FALLBACK_IDLE_QUIET_MS = 2000;
64
+ const DIALOG_ACTION_COOLDOWN_MS = 2000;
65
+ const STARTUP_TIMEOUT_MS = 120000;
66
+ const WATCHDOG_MS = process.env.PTY_SHELL_WATCHDOG_MS
67
+ ? Number(process.env.PTY_SHELL_WATCHDOG_MS) || (30 * 60 * 1000)
68
+ : 30 * 60 * 1000;
69
+ // Set PTY_SHELL_SKIP_DIALOG_DISMISS=1 to disable all TUI dialog auto-dismiss.
70
+ // Use when a new Claude Code version changes TUI text and dialog patterns break.
71
+ const SKIP_DIALOG_DISMISS = process.env.PTY_SHELL_SKIP_DIALOG_DISMISS === '1';
72
+ // Set PTY_SHELL_NO_BRACKETED_PASTE=1 if the Claude Code TUI ever disables bracketed
73
+ // paste mode. Without bracketed paste, a newline inside the user's message would
74
+ // submit the input early. sanitizeUserText() strips CR so the '\r' sent after the
75
+ // text is the only submit trigger — safe in both modes.
76
+ const NO_BRACKETED_PASTE = process.env.PTY_SHELL_NO_BRACKETED_PASTE === '1';
77
+ const DEBUG = process.env.PTY_SHELL_DEBUG === '1';
78
+ function logError(msg) {
79
+ process.stderr.write(`[pty-shell] ERROR ${msg}\n`);
80
+ }
81
+ function logWarn(msg) {
82
+ process.stderr.write(`[pty-shell] WARN ${msg}\n`);
83
+ }
84
+ function logDebug(msg) {
85
+ if (DEBUG)
86
+ process.stderr.write(`[pty-shell] DEBUG ${msg}\n`);
87
+ }
88
+ class Driver {
89
+ constructor() {
90
+ this.ready = false;
91
+ this.exiting = false;
92
+ this.startedAt = Date.now();
93
+ this.queue = [];
94
+ this.turn = null;
95
+ this.lastDialogActionAt = 0;
96
+ this.tickTimer = null;
97
+ this.screen = new screen_1.ScreenModel();
98
+ this.emitter = new emitter_1.ProtocolEmitter();
99
+ this.args = (0, args_1.translateArgs)(process.argv.slice(2));
100
+ // CLAUDE_REAL_BIN may be multi-word (e.g. "node /path/cli.js"), same as CLAUDE_BIN.
101
+ this.realBinParts = (process.env.CLAUDE_REAL_BIN ?? 'claude').split(' ');
102
+ // ---- periodic liveness poll ----------------------------------------------
103
+ this.lastDumpAt = 0;
104
+ this.lastHeartbeatAt = 0;
105
+ // Path to the receiver's heartbeat file (set via PTY_SHELL_HEARTBEAT_PATH env var).
106
+ // Written periodically during active turns so the stalled detector doesn't fire
107
+ // on long sub-agent tasks where the PTY is busy but no transcript lines are emitted.
108
+ this.heartbeatPath = process.env.PTY_SHELL_HEARTBEAT_PATH ?? null;
109
+ }
110
+ start() {
111
+ const [realBin, ...realBinArgs] = this.realBinParts;
112
+ logDebug(`session=${this.args.sessionId} bin=${this.realBinParts.join(' ')} args=${this.args.claudeArgs.join(' ')}`);
113
+ this.host = new pty_host_1.PtyHost(realBin, [...realBinArgs, ...this.args.claudeArgs], {
114
+ cols: this.screen.cols,
115
+ rows: this.screen.rows,
116
+ cwd: process.cwd(),
117
+ onData: (d) => this.screen.write(d),
118
+ onExit: (code) => this.onChildExit(code),
119
+ });
120
+ this.tailer = new tailer_1.TranscriptTailer(process.cwd(), this.args.sessionId, {
121
+ onAssistant: (record) => this.onAssistant(record),
122
+ onTurnEnd: (durationMs) => this.onTurnEnd(durationMs),
123
+ onError: (err) => logError(`tailer: ${err.message}`),
124
+ });
125
+ this.tailer.start();
126
+ this.attachStdin();
127
+ this.attachSignals();
128
+ this.tickTimer = setInterval(() => this.tick(), POLL_MS);
129
+ }
130
+ // ---- stdin: gateway → wrapper -------------------------------------------
131
+ attachStdin() {
132
+ const rl = readline.createInterface({ input: process.stdin });
133
+ rl.on('line', (line) => {
134
+ if (!line.trim())
135
+ return;
136
+ let obj;
137
+ try {
138
+ obj = JSON.parse(line);
139
+ }
140
+ catch {
141
+ logWarn(`ignoring non-JSON stdin line (${line.length} bytes)`);
142
+ return;
143
+ }
144
+ if (obj.type !== 'user') {
145
+ logDebug(`ignoring stdin message type=${String(obj.type)}`);
146
+ return;
147
+ }
148
+ const message = obj.message;
149
+ let text = '';
150
+ if (typeof message?.content === 'string') {
151
+ text = message.content;
152
+ }
153
+ else if (Array.isArray(message?.content)) {
154
+ text = message.content
155
+ .filter((b) => b.type === 'text' && typeof b.text === 'string')
156
+ .map((b) => b.text)
157
+ .join('\n');
158
+ }
159
+ const sanitized = (0, args_1.sanitizeUserText)(text);
160
+ if (!sanitized.trim()) {
161
+ logWarn('user turn empty after sanitization — answering with error result');
162
+ this.emitter.emitResult({
163
+ sessionId: this.args.sessionId, isError: true,
164
+ text: 'empty user message', durationMs: 0, usage: null,
165
+ });
166
+ return;
167
+ }
168
+ this.queue.push(sanitized);
169
+ this.trySubmit();
170
+ });
171
+ rl.on('close', () => {
172
+ // Gateway is gone; no point running a TUI for nobody.
173
+ logWarn('stdin closed — shutting down');
174
+ this.shutdown(0);
175
+ });
176
+ }
177
+ attachSignals() {
178
+ // Gateway interrupt() sends SIGINT → translate to ESC (interrupts the TUI turn).
179
+ process.on('SIGINT', () => {
180
+ if (this.turn) {
181
+ logWarn('SIGINT → sending ESC to interrupt current turn');
182
+ this.host.writeRaw('\x1b');
183
+ }
184
+ });
185
+ process.on('SIGTERM', () => {
186
+ logDebug('SIGTERM → killing claude');
187
+ this.shutdown(0);
188
+ });
189
+ }
190
+ // ---- transcript events: claude → gateway --------------------------------
191
+ onAssistant(record) {
192
+ const usage = record.message.usage;
193
+ if (usage)
194
+ this.emitter.emitMessageStartShim(usage, this.args.sessionId);
195
+ const text = this.emitter.emitAssistant(record, this.args.sessionId);
196
+ if (this.turn) {
197
+ this.turn.sawAssistant = true;
198
+ this.turn.lastProgressAt = Date.now();
199
+ if (text)
200
+ this.turn.texts.push(text);
201
+ if (usage)
202
+ this.turn.usage = usage;
203
+ }
204
+ else {
205
+ logDebug('assistant record outside an active turn (emitted anyway)');
206
+ }
207
+ }
208
+ onTurnEnd(durationMs) {
209
+ logDebug(`turn_duration record (${durationMs}ms)`);
210
+ if (this.turn)
211
+ this.finishTurn(false);
212
+ }
213
+ finishTurn(isError, errMsg) {
214
+ const turn = this.turn;
215
+ if (!turn)
216
+ return;
217
+ this.turn = null;
218
+ this.tailer.flush(); // drain any records written in the last poll window
219
+ const text = turn.texts.join('');
220
+ this.emitter.emitResult({
221
+ sessionId: this.args.sessionId,
222
+ isError,
223
+ text: isError ? (errMsg ?? text ?? 'unknown error') : text,
224
+ durationMs: Date.now() - turn.startedAt,
225
+ usage: turn.usage,
226
+ });
227
+ if (isError)
228
+ logError(`turn failed: ${errMsg ?? '(no detail)'}`);
229
+ this.trySubmit();
230
+ }
231
+ // ---- turn submission -----------------------------------------------------
232
+ trySubmit() {
233
+ if (!this.ready || this.turn || this.queue.length === 0 || this.exiting)
234
+ return;
235
+ const text = this.queue.shift();
236
+ const now = Date.now();
237
+ this.turn = {
238
+ startedAt: now,
239
+ submittedAt: 0,
240
+ enterRetries: 0,
241
+ sawBusy: false,
242
+ sawAssistant: false,
243
+ lastProgressAt: now,
244
+ texts: [],
245
+ usage: null,
246
+ dialogEscapes: 0,
247
+ recordsAtStart: this.tailer.seenRecords,
248
+ };
249
+ void this.typeAndSubmit(text);
250
+ }
251
+ async typeAndSubmit(text) {
252
+ if (NO_BRACKETED_PASTE) {
253
+ // Fallback: sanitizeUserText() strips all CR, so '\r' below is the only
254
+ // submit trigger — safe for multiline text without bracketed paste.
255
+ await this.host.writeChunked(text);
256
+ }
257
+ else {
258
+ // Bracketed paste prevents early submission on newlines inside the text.
259
+ // \r must be a separate delayed write or the TUI treats it as part of the paste.
260
+ await this.host.writeChunked(`\x1b[200~${text}\x1b[201~`);
261
+ }
262
+ await new Promise((r) => setTimeout(r, SUBMIT_ENTER_DELAY_MS));
263
+ this.host.writeRaw('\r');
264
+ if (this.turn)
265
+ this.turn.submittedAt = Date.now();
266
+ }
267
+ tick() {
268
+ if (this.exiting)
269
+ return;
270
+ const now = Date.now();
271
+ if (DEBUG && now - this.lastDumpAt > 2000) {
272
+ this.lastDumpAt = now;
273
+ const txt = this.screen.text();
274
+ logDebug(`state ready=${this.ready} turn=${!!this.turn} quiet=${this.screen.quietMs()}ms busy=${this.screen.isBusy()} prompt=${this.screen.hasPrompt()} screenlen=${txt.replace(/\s/g, '').length}`);
275
+ }
276
+ if (!this.ready) {
277
+ if (this.screen.hasPrompt() && !this.screen.isBusy() && this.screen.quietMs() >= STARTUP_QUIET_MS) {
278
+ this.ready = true;
279
+ logDebug('TUI ready');
280
+ this.emitter.emitInit(this.args.sessionId, this.args.model, process.cwd());
281
+ this.trySubmit();
282
+ return;
283
+ }
284
+ this.maybeHandleDialog();
285
+ if (now - this.startedAt > STARTUP_TIMEOUT_MS) {
286
+ logError(`claude TUI did not become ready within startup timeout; screen:\n${this.screen.text()}`);
287
+ this.shutdown(1);
288
+ }
289
+ return;
290
+ }
291
+ const turn = this.turn;
292
+ if (!turn || turn.submittedAt === 0)
293
+ return;
294
+ // Touch heartbeat so the receiver's stalled detector doesn't fire during
295
+ // long sub-agent tasks where the PTY is busy but no JSON lines are emitted.
296
+ if (this.heartbeatPath && now - this.lastHeartbeatAt >= HEARTBEAT_INTERVAL_MS) {
297
+ this.lastHeartbeatAt = now;
298
+ try {
299
+ fs.writeFileSync(this.heartbeatPath, String(now));
300
+ }
301
+ catch { }
302
+ }
303
+ if (this.screen.consumeBusySeen() || this.screen.isBusy()) {
304
+ turn.sawBusy = true;
305
+ turn.lastProgressAt = now;
306
+ return;
307
+ }
308
+ // Not busy. Possible: still rendering, swallowed Enter, dialog, or done
309
+ // (turn_duration normally ends the turn before we get here).
310
+ this.maybeHandleDialog();
311
+ if (!turn.sawBusy
312
+ && now - turn.submittedAt > SUBMIT_RETRY_AFTER_MS
313
+ && this.screen.hasPrompt()
314
+ && this.screen.quietMs() > 1500
315
+ && this.tailer.seenRecords === turn.recordsAtStart) {
316
+ // Only retry if no new records have appeared since this turn started —
317
+ // a delta > 0 means claude already started writing output.
318
+ if (turn.enterRetries < MAX_ENTER_RETRIES) {
319
+ turn.enterRetries++;
320
+ turn.submittedAt = now;
321
+ logWarn(`Enter appears swallowed — retry ${turn.enterRetries}/${MAX_ENTER_RETRIES}`);
322
+ this.host.writeRaw('\r');
323
+ }
324
+ else {
325
+ this.finishTurn(true, 'failed to submit turn to the TUI input');
326
+ }
327
+ return;
328
+ }
329
+ // Fallback end-of-turn (e.g. interrupted turn never writes turn_duration):
330
+ // ran → idle prompt → quiet, and we already streamed assistant output.
331
+ if (turn.sawBusy && turn.sawAssistant
332
+ && this.screen.hasPrompt()
333
+ && this.screen.quietMs() >= FALLBACK_IDLE_QUIET_MS) {
334
+ logDebug('fallback idle detection ended the turn');
335
+ this.finishTurn(false);
336
+ return;
337
+ }
338
+ if (now - turn.lastProgressAt > WATCHDOG_MS) {
339
+ this.finishTurn(true, `no progress for ${WATCHDOG_MS}ms — giving up`);
340
+ this.shutdown(1);
341
+ }
342
+ }
343
+ maybeHandleDialog() {
344
+ if (SKIP_DIALOG_DISMISS)
345
+ return;
346
+ const now = Date.now();
347
+ if (now - this.lastDialogActionAt < DIALOG_ACTION_COOLDOWN_MS)
348
+ return;
349
+ if (this.screen.quietMs() < 500)
350
+ return; // wait until the dialog is fully drawn
351
+ const dialog = this.screen.detectDialog();
352
+ if (!dialog)
353
+ return;
354
+ this.lastDialogActionAt = now;
355
+ switch (dialog) {
356
+ case 'bypass-permissions':
357
+ // --dangerously-skip-permissions is built into the wrapper, so the
358
+ // confirmation dialog is always accepted on the operator's behalf.
359
+ logWarn('accepting Bypass Permissions dialog (per built-in --dangerously-skip-permissions)');
360
+ this.host.writeRaw('2');
361
+ break;
362
+ case 'trust-folder':
363
+ // The gateway only ever runs claude in its own agent workspaces.
364
+ logWarn('accepting workspace trust dialog');
365
+ this.host.writeRaw('\r');
366
+ break;
367
+ case 'unknown-select':
368
+ if (!this.turn)
369
+ break;
370
+ this.turn.dialogEscapes++;
371
+ logError(`unexpected dialog during turn (escape ${this.turn.dialogEscapes}/2):\n${this.screen.text()}`);
372
+ if (this.turn.dialogEscapes <= 2) {
373
+ this.host.writeRaw('\x1b');
374
+ }
375
+ else {
376
+ this.finishTurn(true, 'blocked by an unexpected TUI dialog');
377
+ }
378
+ break;
379
+ }
380
+ }
381
+ // ---- lifecycle ------------------------------------------------------------
382
+ onChildExit(code) {
383
+ if (this.exiting) {
384
+ process.exit(code);
385
+ return;
386
+ }
387
+ logError(`claude exited unexpectedly (code ${code})`);
388
+ if (this.turn)
389
+ this.finishTurn(true, `claude exited (code ${code})`);
390
+ this.exiting = true;
391
+ this.tailer.stop();
392
+ process.exit(code);
393
+ }
394
+ shutdown(code) {
395
+ if (this.exiting)
396
+ return;
397
+ this.exiting = true;
398
+ if (this.tickTimer)
399
+ clearInterval(this.tickTimer);
400
+ this.tailer.stop();
401
+ this.host.kill();
402
+ // PtyHost.onExit will exit(child code); this is the safety net.
403
+ setTimeout(() => process.exit(code), 1500).unref();
404
+ }
405
+ }
406
+ new Driver().start();
407
+ //# sourceMappingURL=claude-pty-shell.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-pty-shell.js","sourceRoot":"","sources":["../../src/shell/claude-pty-shell.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import type { AssistantRecord, UsageInfo } from './tailer';
2
+ /**
3
+ * Synthesizes the stream-json events the gateway's SessionProcess stdout
4
+ * parser consumes (src/session/process.ts). Every assistant event is emitted
5
+ * as a FINAL message (top-level stop_reason set): the parser then appends the
6
+ * full text as a fresh delta and resets its partial tracking, which is what
7
+ * makes mid-turn (message-level streaming) emission safe.
8
+ */
9
+ export declare class ProtocolEmitter {
10
+ private readonly out;
11
+ constructor(out?: NodeJS.WritableStream);
12
+ private writeLine;
13
+ emitInit(sessionId: string, model: string, cwd: string): void;
14
+ /**
15
+ * Context-size shim: the gateway reads usage from stream_event/message_start
16
+ * to display context %. Transcript assistant records carry the same usage,
17
+ * so replay it. Emitted before each assistant event; the gateway keeps the
18
+ * latest value and applies it at result time.
19
+ */
20
+ emitMessageStartShim(usage: UsageInfo, sessionId: string): void;
21
+ /**
22
+ * Emit one transcript assistant record as a final assistant event.
23
+ * Thinking blocks are stripped (the gateway only consumes text and
24
+ * tool_use blocks; thinking content must not leak into chat history).
25
+ * Returns the text contained in the record, '' if none.
26
+ */
27
+ emitAssistant(record: AssistantRecord, sessionId: string): string;
28
+ emitResult(opts: {
29
+ sessionId: string;
30
+ isError: boolean;
31
+ text: string;
32
+ durationMs: number;
33
+ usage: UsageInfo | null;
34
+ }): void;
35
+ }
36
+ //# sourceMappingURL=emitter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emitter.d.ts","sourceRoot":"","sources":["../../src/shell/emitter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE3D;;;;;;GAMG;AACH,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,GAAG;gBAAH,GAAG,GAAE,MAAM,CAAC,cAA+B;IAExE,OAAO,CAAC,SAAS;IAIjB,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAW7D;;;;;OAKG;IACH,oBAAoB,CAAC,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAiB/D;;;;;OAKG;IACH,aAAa,CAAC,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;IAmBjE,UAAU,CAAC,IAAI,EAAE;QACf,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,OAAO,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;KACzB,GAAG,IAAI;CAYT"}