appback-remoteagent 0.13.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 (46) hide show
  1. package/.env.example +39 -0
  2. package/LICENSE +21 -0
  3. package/README.md +371 -0
  4. package/bin/remoteagent.js +2 -0
  5. package/dist/adapters/claude-adapter.js +78 -0
  6. package/dist/adapters/codex-adapter.js +241 -0
  7. package/dist/adapters/provider-adapter.js +1 -0
  8. package/dist/adapters/shell-adapter.js +44 -0
  9. package/dist/adapters/windows-shell.js +111 -0
  10. package/dist/bot.js +2135 -0
  11. package/dist/config.js +170 -0
  12. package/dist/index.js +534 -0
  13. package/dist/secret-helper.js +24 -0
  14. package/dist/services/agent-memory-service.js +737 -0
  15. package/dist/services/bot-management-service.js +626 -0
  16. package/dist/services/bridge-service.js +807 -0
  17. package/dist/services/local-ui-service.js +533 -0
  18. package/dist/services/provider-setup-service.js +284 -0
  19. package/dist/services/remote-shell-service.js +97 -0
  20. package/dist/store/file-store.js +690 -0
  21. package/dist/telegram-fetch.js +85 -0
  22. package/dist/types.js +1 -0
  23. package/docs/ARCHITECTURE.md +170 -0
  24. package/docs/COKACDIR_NOTES.md +79 -0
  25. package/docs/ERROR_NORMALIZATION.md +46 -0
  26. package/docs/MINI_APP.md +112 -0
  27. package/docs/MVP.md +108 -0
  28. package/docs/OPERATIONS.md +181 -0
  29. package/docs/RELEASING.md +87 -0
  30. package/docs/SESSION_DIRECTORY_PLAN.md +506 -0
  31. package/package.json +47 -0
  32. package/scripts/bump-version.sh +23 -0
  33. package/scripts/finish-claude-login.sh +48 -0
  34. package/scripts/install-claude.sh +6 -0
  35. package/scripts/install-codex.sh +8 -0
  36. package/scripts/install.ps1 +51 -0
  37. package/scripts/install.sh +101 -0
  38. package/scripts/mock-adapter.sh +7 -0
  39. package/scripts/restart-after-bot-op.sh +118 -0
  40. package/scripts/selftest-telegram-update.mjs +359 -0
  41. package/scripts/start-claude-login.sh +4 -0
  42. package/scripts/start.ps1 +39 -0
  43. package/scripts/start.sh +54 -0
  44. package/scripts/stop.ps1 +40 -0
  45. package/scripts/stop.sh +39 -0
  46. package/tsconfig.json +20 -0
package/.env.example ADDED
@@ -0,0 +1,39 @@
1
+ TELEGRAM_BOT_TOKEN=your-telegram-bot-token
2
+ TELEGRAM_BOT_TOKENS=
3
+ TELEGRAM_MAIN_BOT_ID=
4
+ TELEGRAM_OWNER_ID=
5
+ TELEGRAM_MESSAGE_BATCH_MS=1500
6
+ TELEGRAM_AUTO_PROGRESS_MAX_TURNS=6
7
+ TELEGRAM_EMPTY_RESPONSE_RETRIES=1
8
+ TELEGRAM_RETRYABLE_ERROR_RETRIES=2
9
+ TELEGRAM_RETRYABLE_ERROR_DELAY_MS=5000
10
+ TELEGRAM_UNTAGGED_INTENT_RETRIES=2
11
+ ARTIFACT_CLEANUP_ENABLED=true
12
+ ARTIFACT_RETENTION_DAYS=30
13
+ ARTIFACT_CLEANUP_INTERVAL_MS=86400000
14
+ REMOTEAGENT_WATCHDOG_ENABLED=true
15
+ REMOTEAGENT_WATCHDOG_INTERVAL_MS=300000
16
+ REMOTEAGENT_WATCHDOG_CPU_PERCENT=90
17
+ REMOTEAGENT_WATCHDOG_MIN_AGE_MS=120000
18
+ DATA_DIR=
19
+ DEFAULT_WORKSPACE=
20
+ WORKSPACE_ROOT=
21
+ DEFAULT_MODE=codex
22
+ COMMAND_TIMEOUT_MS=600000
23
+ SETUP_COMMAND_TIMEOUT_MS=600000
24
+ CODEX_BIN=codex
25
+ CODEX_SANDBOX_MODE=
26
+ CODEX_COMMAND=
27
+ CODEX_INSTALL_COMMAND=
28
+ CLAUDE_BIN=claude
29
+ CLAUDE_COMMAND=
30
+ CLAUDE_PERMISSION_MODE=bypassPermissions
31
+ CLAUDE_INSTALL_COMMAND=
32
+ CLAUDE_LOGIN_START_COMMAND=
33
+ CLAUDE_LOGIN_FINISH_COMMAND=
34
+ LOCAL_UI_ENABLED=true
35
+ LOCAL_UI_HOST=127.0.0.1
36
+ LOCAL_UI_PORT=3794
37
+
38
+ REMOTEAGENT_SERVICE_NAME=remoteagent
39
+ BOT_RESTART_HELPER_PATH=
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 appback
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,371 @@
1
+ # RemoteAgent
2
+
3
+ RemoteAgent is a personal installable runtime for controlling coding sessions from Telegram, a terminal, and an optional Telegram Mini App.
4
+
5
+ It is built for one owner running their own agents on their own machine, then continuing that work remotely without introducing a hosted multi-user backend.
6
+
7
+ ## What it is
8
+
9
+ RemoteAgent is not a hosted SaaS and not a Telegram-only app.
10
+
11
+ It has three layers:
12
+
13
+ 1. **Runtime server** - the installed machine that actually runs Codex, Claude Code, shell commands, and file operations.
14
+ 2. **Telegram bot** - the default remote messaging interface.
15
+ 3. **Telegram Mini App** - an optional richer UI that opens inside Telegram and controls the same runtime.
16
+
17
+ The runtime machine is the source of truth. Telegram is the client.
18
+
19
+ ## What it does
20
+
21
+ RemoteAgent is currently organized around six core capabilities.
22
+
23
+ | Capability | What it means today | Status |
24
+ | --- | --- | --- |
25
+ | Telegram control | Telegram chat can start, attach, switch, inspect, and reset local sessions | Supported |
26
+ | Terminal control | The owner can run restricted remote shell commands from Telegram | Supported with restrictions |
27
+ | Telegram <-> Codex | A Telegram chat can start or attach to a Codex session and continue it | Supported |
28
+ | Telegram <-> Claude Code | A Telegram chat can start or attach to a Claude Code session and continue it | Supported |
29
+ | Telegram attachments | Telegram can send images, text, Markdown, PDF, Word documents, spreadsheet files, archives, and audio/voice inputs into the runtime | Supported |
30
+ | Telegram Mini App UI | A richer Telegram-native UI can sit on top of the same runtime and session model | Planned next |
31
+
32
+ ## Product direction
33
+
34
+ RemoteAgent is a self-hosted personal runtime, not a hosted SaaS.
35
+
36
+ The intended shape is:
37
+
38
+ 1. the machine running RemoteAgent is the source of truth
39
+ 2. Telegram chat is the baseline remote client for that runtime
40
+ 3. a Telegram Mini App is an optional UI layer over the same runtime
41
+ 4. Codex and Claude Code are provider adapters behind one local session model
42
+ 5. terminal control is an owner-only extension of that same runtime
43
+ 6. files sent from Telegram are materialized locally and then routed through the active session
44
+
45
+ This repository is optimized for continuity:
46
+
47
+ - start work on the machine
48
+ - continue from Telegram
49
+ - optionally open a Mini App for richer session controls
50
+ - come back and keep going from the same runtime-owned session state
51
+
52
+ ## Why a Mini App fits
53
+
54
+ A Telegram Mini App does **not** replace the runtime server.
55
+ It gives RemoteAgent a better control surface inside Telegram.
56
+
57
+ That means a Mini App can expose:
58
+
59
+ - session list and switching
60
+ - current provider and model
61
+ - recent logs and progress states
62
+ - stop and continue actions
63
+ - attachment history
64
+ - safer structured controls than raw slash commands
65
+
66
+ But the Mini App still depends on the installed RemoteAgent runtime and the local provider CLIs.
67
+
68
+ ## Current scope
69
+
70
+ In scope:
71
+
72
+ - one owner
73
+ - one installable local runtime
74
+ - local session persistence
75
+ - Telegram control
76
+ - Codex and Claude Code adapters
77
+ - restricted terminal control
78
+ - Telegram attachment intake
79
+ - future Telegram Mini App control UI for the same runtime
80
+
81
+ Out of scope:
82
+
83
+ - multi-tenant hosted backend
84
+ - account resale
85
+ - team-facing SaaS control plane
86
+ - pretending to mirror official desktop apps exactly
87
+ - making Telegram the actual execution backend
88
+
89
+ ## Current capabilities
90
+
91
+ ### 1. Telegram control
92
+
93
+ Telegram is the main remote control surface today.
94
+
95
+ Current command surface implemented in `src/bot.ts`:
96
+
97
+ | Command | What it does |
98
+ | --- | --- |
99
+ | `/start [codex|claude]` | Starts a fresh fixed-mode session in a new managed workspace under `WORKSPACE_ROOT` |
100
+ | `/help` | Shows the current command list |
101
+ | `/list` | Lists recent sessions |
102
+ | `/list -a` | Lists all sessions with active/unused status, managed workspace size, and last update time |
103
+ | `/new` | Creates and binds a new session using the saved default mode in a new managed workspace |
104
+ | `/switch <session>` | Rebinds this chat to an existing RemoteAgent session |
105
+ | `/status` | Shows current session, workspace, provider, and sandbox state |
106
+ | `/option retry <count>` | Sets the automatic continuation turn limit and persists it to `~/.remoteagent/.env` |
107
+ | `/option timeout <seconds>` | Sets the provider execution timeout and persists it to `~/.remoteagent/.env` |
108
+ | `/option intent <count>` | Sets retries for untagged intent-only provider replies and persists it to `~/.remoteagent/.env` |
109
+ | `/state` | Shows the session ledger that is injected as provider context |
110
+ | `/state clear` | Clears the current session ledger without deleting the session |
111
+ | `/state note <text>` | Adds an operator note to the session ledger |
112
+ | `/bots` | Lists the currently configured Telegram bots |
113
+ | `/bot add <token>` | Adds a conversation bot, restarts the runtime, and confirms the result after restart |
114
+ | `/bot doctor` | Checks configured Telegram bots and removes bots that Telegram reports as permanently dead |
115
+ | `/bot main <number\|@username\|id>` | Selects the main bot. If no valid main is configured, the oldest configured bot is used |
116
+ | `/bot remove <username\|id>` | Removes a configured Telegram bot, restarts the runtime, and confirms the result after restart |
117
+ | `/bot reload` | Restarts the runtime and confirms the result after restart |
118
+ | `/install codex\|claude` | Runs the configured provider install or update command for the bot owner |
119
+ | `/login codex` | Starts the Codex device-auth login flow and returns a browser URL when available |
120
+ | `/login claude [token]` | Starts or finishes the configured Claude Code login flow for the bot owner |
121
+ | `/reset` | Clears the current chat binding |
122
+ | `/batch start` | Starts manual batching of multiple text messages |
123
+ | `/batch send` | Sends the collected batch |
124
+ | `/batch done` | Alias for `/batch send` |
125
+ | `/batch cancel` | Discards the current batch |
126
+ | `/batch status` | Shows current batch state |
127
+
128
+ ### 2. Terminal control
129
+
130
+ Remote shell control is available through:
131
+
132
+ - `/! <command>`
133
+ - `/!cmd <command>`
134
+ - `/!bash <command>`
135
+
136
+ This is intentionally restricted.
137
+
138
+ Remote shell requires all of the following:
139
+
140
+ - private 1:1 Telegram chat
141
+ - sender matches `TELEGRAM_OWNER_ID`
142
+ - active Codex binding exists
143
+ - current Codex sandbox is `danger-full-access`
144
+
145
+ ### 3. Telegram and Codex
146
+
147
+ RemoteAgent supports both fresh Codex pairing and attach/resume.
148
+
149
+ Current Codex entry commands:
150
+
151
+ - `/start codex`
152
+ - `/attach codex <thread_id>`
153
+ - `/sandbox codex <read-only|workspace-write|danger-full-access>`
154
+
155
+ Current Codex behavior:
156
+
157
+ - fresh pairing from Telegram
158
+ - attach to existing `thread_id`
159
+ - continue the same Codex session across turns
160
+ - per-session sandbox selection
161
+
162
+ ### 4. Telegram and Claude Code
163
+
164
+ RemoteAgent also supports fresh Claude Code pairing and attach/resume.
165
+
166
+ Current Claude entry commands:
167
+
168
+ - `/start claude`
169
+ - `/attach claude <session_id>`
170
+
171
+ Current Claude behavior:
172
+
173
+ - fresh pairing from Telegram
174
+ - attach to existing `session_id`
175
+ - continue the same Claude Code session across turns
176
+ - optional owner-only install/login flow through `/install claude` and `/login claude [token]`
177
+
178
+ ### 5. Telegram attachments
179
+
180
+ Telegram attachments are written into the local runtime under `~/.remoteagent/uploads/telegram/<bot>/<chat>/...` and then routed through the active session. Artifact metadata is indexed at `~/.remoteagent/managed/artifacts.json`.
181
+
182
+ Attachments can be inspected with `/artifacts list` and cleaned manually with `/artifacts cleanup <days>`. RemoteAgent also runs periodic artifact cleanup when `ARTIFACT_CLEANUP_ENABLED=true`; by default it keeps 30 days and also removes old unindexed files under `uploads/telegram`.
183
+
184
+ Current supported attachment classes:
185
+
186
+ - photos
187
+ - image files
188
+ - text files
189
+ - Markdown files
190
+ - PDF documents
191
+ - Word documents (.docx, basic .doc intake)
192
+ - spreadsheet files (.xlsx, .xlsm, basic .xls intake)
193
+ - archive files
194
+ - voice messages
195
+ - audio files
196
+
197
+ Attachment handling is triggered from ordinary Telegram messages.
198
+ If the message contains a supported file or media payload, RemoteAgent downloads it, stores it locally, builds an attachment prompt, and sends that into the active provider session.
199
+
200
+ ### 6. Telegram Mini App
201
+
202
+ The Mini App is the next UI layer, not a second execution engine.
203
+
204
+ The Mini App should talk to the same runtime state used by the bot, including:
205
+
206
+ - session ids
207
+ - session bindings
208
+ - provider metadata
209
+ - event logs
210
+ - attachment history
211
+ - stop and continue controls
212
+
213
+ See [docs/MINI_APP.md](docs/MINI_APP.md) for the planned Mini App shape.
214
+
215
+ ## Provider support matrix
216
+
217
+ | Capability | Codex | Claude Code | OpenClaw |
218
+ | --- | --- | --- | --- |
219
+ | Fresh Telegram pairing | Yes | Yes | Planned |
220
+ | Attach to existing session | Yes | Yes | Planned |
221
+ | Resume same session across turns | Yes | Yes | Planned |
222
+ | Telegram-based remote shell participation | Yes | No | Planned |
223
+ | Per-session sandbox control from Telegram | Yes | No | Planned |
224
+ | Attachment routing through active session | Yes | Yes | Planned |
225
+ | Telegram Mini App control surface | Planned | Planned | Planned |
226
+ | Production adapter in this repo | Yes | Yes | No |
227
+
228
+ ## Release policy
229
+
230
+ Every production deployment must bump the package version using semantic versioning.
231
+
232
+ - `MAJOR`: breaking changes or migration-required runtime changes
233
+ - `MINOR`: new capabilities or non-breaking feature expansion
234
+ - `PATCH`: bug fixes, hardening, and maintenance updates
235
+
236
+ A change is not considered finished until it is committed and pushed.
237
+ A deployment on server 30 is not considered complete until machine 21's npm-installed runtime is updated as well.
238
+
239
+ See [docs/RELEASING.md](docs/RELEASING.md) for the release checklist and version bump commands.
240
+ See [docs/ERROR_NORMALIZATION.md](docs/ERROR_NORMALIZATION.md) for provider error classification and retry behavior.
241
+
242
+ ## Runtime layout
243
+
244
+ Installed runtime data lives in:
245
+
246
+ - Linux/macOS: `~/.remoteagent`
247
+ - Windows: `%USERPROFILE%\.remoteagent`
248
+
249
+ Typical directories and files include:
250
+
251
+ Managed workspaces created by `/start` without an explicit path live under `WORKSPACE_ROOT` and use random 8-character uid folder names, while public session ids like `S001` remain display-only ids.
252
+
253
+ - `.env`
254
+ - `logs/`
255
+ - `uploads/telegram/`
256
+ - `sessions/`
257
+ - `channels/telegram/`
258
+ - `state.json`
259
+
260
+ ## Environment
261
+
262
+ Useful runtime variables:
263
+
264
+ Provider install/login hooks are optional and are executed only from owner-only Telegram commands.
265
+
266
+ Recommended Linux hooks in this repo:
267
+
268
+ - `scripts/install-codex.sh`
269
+ - `scripts/install-claude.sh`
270
+ - `scripts/start-claude-login.sh`
271
+ - `scripts/finish-claude-login.sh`
272
+
273
+ - `TELEGRAM_BOT_TOKEN`
274
+ - `TELEGRAM_BOT_TOKENS`
275
+ - `TELEGRAM_OWNER_ID`
276
+ - `DEFAULT_WORKSPACE`
277
+ - `WORKSPACE_ROOT`
278
+ - `COMMAND_TIMEOUT_MS`
279
+ - `SETUP_COMMAND_TIMEOUT_MS`
280
+ - `ARTIFACT_CLEANUP_ENABLED`
281
+ - `ARTIFACT_RETENTION_DAYS`
282
+ - `ARTIFACT_CLEANUP_INTERVAL_MS`
283
+ - `CODEX_BIN`
284
+ - `CODEX_SANDBOX_MODE`
285
+ - `CODEX_INSTALL_COMMAND`
286
+ - `CLAUDE_BIN`
287
+ - `CLAUDE_COMMAND`
288
+ - `CLAUDE_PERMISSION_MODE`
289
+ - `CLAUDE_INSTALL_COMMAND`
290
+ - `CLAUDE_LOGIN_START_COMMAND`
291
+ - `CLAUDE_LOGIN_FINISH_COMMAND`
292
+ - `REMOTEAGENT_SERVICE_NAME`
293
+ - `BOT_RESTART_HELPER_PATH`
294
+ - `LOCAL_UI_ENABLED`
295
+ - `LOCAL_UI_HOST`
296
+ - `LOCAL_UI_PORT`
297
+
298
+ ## Quick start
299
+
300
+ ### Linux / macOS
301
+
302
+ ```bash
303
+ npm install -g appback-remoteagent
304
+ remoteagent-install
305
+ remoteagent-start
306
+ ```
307
+
308
+ `remoteagent-install` seeds provider install/login hook paths into `~/.remoteagent/.env` automatically, so `/install codex` and `/install claude` work on a fresh machine without manual hook wiring.
309
+
310
+ For one-line installs on a fresh machine:
311
+
312
+ ```bash
313
+ curl -fsSL https://raw.githubusercontent.com/appback/remoteagent/main/scripts/install.sh | bash
314
+ remoteagent-start
315
+ ```
316
+
317
+ The piped installer installs `appback-remoteagent` from npm. It does not deploy a Git checkout as the runtime.
318
+
319
+ ### Windows PowerShell
320
+
321
+ Native Windows service packaging is not finalized yet. For now, use WSL/Linux for production runtimes, or run the repository-local PowerShell scripts during development:
322
+
323
+ ```powershell
324
+ .\scripts\install.ps1
325
+ .\scripts\start.ps1
326
+ ```
327
+
328
+ The installer also writes default provider install/login hook paths into `%USERPROFILE%\.remoteagent\.env`.
329
+
330
+ After `/install codex` or `/install claude`, RemoteAgent now also checks whether the provider still needs authentication and tells the operator the next login step.
331
+
332
+ Then open Telegram and start with one of these common flows. `/start` without a mode uses the saved default mode once a provider has been started or attached at least once.
333
+
334
+ ```text
335
+ /start
336
+ /start codex
337
+ /start claude
338
+ /install codex
339
+ /install claude
340
+ /login codex
341
+ /login claude
342
+ /login claude <token>
343
+ /attach codex <thread_id>
344
+ /attach claude <session_id>
345
+ ```
346
+
347
+ Once a chat is bound, ordinary text messages continue the active session. Supported attachments can also be sent directly as normal Telegram messages.
348
+
349
+ ## Architecture and operations
350
+
351
+ High-level architecture: [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)
352
+
353
+ Mini App plan: [docs/MINI_APP.md](docs/MINI_APP.md)
354
+
355
+ MVP scope: [docs/MVP.md](docs/MVP.md)
356
+
357
+ Operational ownership and deployment rules: [docs/OPERATIONS.md](docs/OPERATIONS.md)
358
+
359
+ Reference notes about `cokacdir`: [docs/COKACDIR_NOTES.md](docs/COKACDIR_NOTES.md)
360
+
361
+ ## Development
362
+
363
+ ```bash
364
+ npm install
365
+ npm run check
366
+ npm run build
367
+ ```
368
+
369
+ ## License
370
+
371
+ This project is licensed under the MIT License. See [LICENSE](LICENSE).
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import "../dist/index.js";
@@ -0,0 +1,78 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { spawnWithPlatformShell } from "./windows-shell.js";
3
+ export class ClaudeAdapter {
4
+ claudeBin;
5
+ timeoutMs;
6
+ permissionMode;
7
+ constructor(claudeBin, timeoutMs, permissionMode) {
8
+ this.claudeBin = claudeBin;
9
+ this.timeoutMs = timeoutMs;
10
+ this.permissionMode = permissionMode;
11
+ }
12
+ async send(request) {
13
+ const sessionId = request.sessionId ?? randomUUID();
14
+ const args = this.buildArgs(request, sessionId);
15
+ const { stdout, stderr, code, timedOut } = await this.runClaude(args, request.cwd, request.remoteSessionId, request.publicSessionId);
16
+ if (code !== 0) {
17
+ throw new Error(this.formatProcessError(stdout, stderr, timedOut));
18
+ }
19
+ if (timedOut) {
20
+ throw new Error(this.formatTimeoutError());
21
+ }
22
+ const output = stdout.trim();
23
+ if (!output) {
24
+ throw new Error("Claude returned an empty response.");
25
+ }
26
+ return {
27
+ provider: "claude",
28
+ sessionId,
29
+ cwd: request.cwd,
30
+ output,
31
+ };
32
+ }
33
+ buildArgs(request, sessionId) {
34
+ const args = [
35
+ "--print",
36
+ "--output-format",
37
+ "text",
38
+ "--permission-mode",
39
+ this.permissionMode,
40
+ ];
41
+ if (request.model) {
42
+ args.push("--model", request.model);
43
+ }
44
+ if (request.sessionId) {
45
+ args.push("--resume", sessionId, request.message);
46
+ }
47
+ else {
48
+ args.push("--session-id", sessionId, request.message);
49
+ }
50
+ return args;
51
+ }
52
+ runClaude(args, cwd, remoteSessionId, publicSessionId) {
53
+ return spawnWithPlatformShell(this.claudeBin, args, cwd, this.currentTimeoutMs(), undefined, remoteSessionId, {
54
+ REMOTEAGENT_SESSION_ID: remoteSessionId,
55
+ REMOTEAGENT_PUBLIC_SESSION_ID: publicSessionId ?? "",
56
+ REMOTEAGENT_WORKSPACE: cwd,
57
+ });
58
+ }
59
+ formatProcessError(stdout, stderr, timedOut = false) {
60
+ const text = [stderr, stdout]
61
+ .map((value) => value.trim())
62
+ .filter(Boolean)
63
+ .join("\n")
64
+ .trim();
65
+ if (text) {
66
+ return text;
67
+ }
68
+ return timedOut
69
+ ? this.formatTimeoutError()
70
+ : "Claude execution failed without any output.";
71
+ }
72
+ formatTimeoutError() {
73
+ return `Claude timed out after ${Math.round(this.currentTimeoutMs() / 1000)}s without returning a final reply.`;
74
+ }
75
+ currentTimeoutMs() {
76
+ return typeof this.timeoutMs === "function" ? this.timeoutMs() : this.timeoutMs;
77
+ }
78
+ }