@kdonev/termscape 0.1.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 (139) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +288 -0
  3. package/dist/agents/env.d.ts +36 -0
  4. package/dist/agents/env.d.ts.map +1 -0
  5. package/dist/agents/env.js +61 -0
  6. package/dist/agents/env.js.map +1 -0
  7. package/dist/agents/profiles.d.ts +45 -0
  8. package/dist/agents/profiles.d.ts.map +1 -0
  9. package/dist/agents/profiles.js +123 -0
  10. package/dist/agents/profiles.js.map +1 -0
  11. package/dist/agents/resolve.d.ts +16 -0
  12. package/dist/agents/resolve.d.ts.map +1 -0
  13. package/dist/agents/resolve.js +71 -0
  14. package/dist/agents/resolve.js.map +1 -0
  15. package/dist/agents/router.d.ts +29 -0
  16. package/dist/agents/router.d.ts.map +1 -0
  17. package/dist/agents/router.js +83 -0
  18. package/dist/agents/router.js.map +1 -0
  19. package/dist/agents/tokens.d.ts +21 -0
  20. package/dist/agents/tokens.d.ts.map +1 -0
  21. package/dist/agents/tokens.js +39 -0
  22. package/dist/agents/tokens.js.map +1 -0
  23. package/dist/agents/wiring.d.ts +30 -0
  24. package/dist/agents/wiring.d.ts.map +1 -0
  25. package/dist/agents/wiring.js +110 -0
  26. package/dist/agents/wiring.js.map +1 -0
  27. package/dist/browser.d.ts +13 -0
  28. package/dist/browser.d.ts.map +1 -0
  29. package/dist/browser.js +34 -0
  30. package/dist/browser.js.map +1 -0
  31. package/dist/cli.d.ts +3 -0
  32. package/dist/cli.d.ts.map +1 -0
  33. package/dist/cli.js +200 -0
  34. package/dist/cli.js.map +1 -0
  35. package/dist/db/index.d.ts +14 -0
  36. package/dist/db/index.d.ts.map +1 -0
  37. package/dist/db/index.js +24 -0
  38. package/dist/db/index.js.map +1 -0
  39. package/dist/db/migrations.d.ts +15 -0
  40. package/dist/db/migrations.d.ts.map +1 -0
  41. package/dist/db/migrations.js +176 -0
  42. package/dist/db/migrations.js.map +1 -0
  43. package/dist/db/store.d.ts +71 -0
  44. package/dist/db/store.d.ts.map +1 -0
  45. package/dist/db/store.js +341 -0
  46. package/dist/db/store.js.map +1 -0
  47. package/dist/hub.d.ts +188 -0
  48. package/dist/hub.d.ts.map +1 -0
  49. package/dist/hub.js +636 -0
  50. package/dist/hub.js.map +1 -0
  51. package/dist/hub.tgz +0 -0
  52. package/dist/mcp/server.d.ts +31 -0
  53. package/dist/mcp/server.d.ts.map +1 -0
  54. package/dist/mcp/server.js +66 -0
  55. package/dist/mcp/server.js.map +1 -0
  56. package/dist/paths.d.ts +27 -0
  57. package/dist/paths.d.ts.map +1 -0
  58. package/dist/paths.js +31 -0
  59. package/dist/paths.js.map +1 -0
  60. package/dist/protocol/address.d.ts +15 -0
  61. package/dist/protocol/address.d.ts.map +1 -0
  62. package/dist/protocol/address.js +39 -0
  63. package/dist/protocol/address.js.map +1 -0
  64. package/dist/protocol/domain.d.ts +151 -0
  65. package/dist/protocol/domain.d.ts.map +1 -0
  66. package/dist/protocol/domain.js +104 -0
  67. package/dist/protocol/domain.js.map +1 -0
  68. package/dist/protocol/index.d.ts +7 -0
  69. package/dist/protocol/index.d.ts.map +1 -0
  70. package/dist/protocol/index.js +7 -0
  71. package/dist/protocol/index.js.map +1 -0
  72. package/dist/protocol/inject.d.ts +29 -0
  73. package/dist/protocol/inject.d.ts.map +1 -0
  74. package/dist/protocol/inject.js +40 -0
  75. package/dist/protocol/inject.js.map +1 -0
  76. package/dist/protocol/mcp-tools.d.ts +45 -0
  77. package/dist/protocol/mcp-tools.d.ts.map +1 -0
  78. package/dist/protocol/mcp-tools.js +46 -0
  79. package/dist/protocol/mcp-tools.js.map +1 -0
  80. package/dist/protocol/peer.d.ts +304 -0
  81. package/dist/protocol/peer.d.ts.map +1 -0
  82. package/dist/protocol/peer.js +183 -0
  83. package/dist/protocol/peer.js.map +1 -0
  84. package/dist/protocol/ws.d.ts +416 -0
  85. package/dist/protocol/ws.d.ts.map +1 -0
  86. package/dist/protocol/ws.js +119 -0
  87. package/dist/protocol/ws.js.map +1 -0
  88. package/dist/remote/deployer.d.ts +78 -0
  89. package/dist/remote/deployer.d.ts.map +1 -0
  90. package/dist/remote/deployer.js +216 -0
  91. package/dist/remote/deployer.js.map +1 -0
  92. package/dist/remote/enroll.d.ts +14 -0
  93. package/dist/remote/enroll.d.ts.map +1 -0
  94. package/dist/remote/enroll.js +244 -0
  95. package/dist/remote/enroll.js.map +1 -0
  96. package/dist/remote/join-script.d.ts +29 -0
  97. package/dist/remote/join-script.d.ts.map +1 -0
  98. package/dist/remote/join-script.js +709 -0
  99. package/dist/remote/join-script.js.map +1 -0
  100. package/dist/remote/join.d.ts +19 -0
  101. package/dist/remote/join.d.ts.map +1 -0
  102. package/dist/remote/join.js +195 -0
  103. package/dist/remote/join.js.map +1 -0
  104. package/dist/remote/lan.d.ts +45 -0
  105. package/dist/remote/lan.d.ts.map +1 -0
  106. package/dist/remote/lan.js +105 -0
  107. package/dist/remote/lan.js.map +1 -0
  108. package/dist/remote/peer-serve.d.ts +27 -0
  109. package/dist/remote/peer-serve.d.ts.map +1 -0
  110. package/dist/remote/peer-serve.js +274 -0
  111. package/dist/remote/peer-serve.js.map +1 -0
  112. package/dist/remote/peer.d.ts +62 -0
  113. package/dist/remote/peer.d.ts.map +1 -0
  114. package/dist/remote/peer.js +250 -0
  115. package/dist/remote/peer.js.map +1 -0
  116. package/dist/remote/registry.d.ts +104 -0
  117. package/dist/remote/registry.d.ts.map +1 -0
  118. package/dist/remote/registry.js +359 -0
  119. package/dist/remote/registry.js.map +1 -0
  120. package/dist/remote/tarball.d.ts +9 -0
  121. package/dist/remote/tarball.d.ts.map +1 -0
  122. package/dist/remote/tarball.js +22 -0
  123. package/dist/remote/tarball.js.map +1 -0
  124. package/dist/server.d.ts +54 -0
  125. package/dist/server.d.ts.map +1 -0
  126. package/dist/server.js +438 -0
  127. package/dist/server.js.map +1 -0
  128. package/dist/session/manager.d.ts +104 -0
  129. package/dist/session/manager.d.ts.map +1 -0
  130. package/dist/session/manager.js +421 -0
  131. package/dist/session/manager.js.map +1 -0
  132. package/dist/session/pty.d.ts +114 -0
  133. package/dist/session/pty.d.ts.map +1 -0
  134. package/dist/session/pty.js +300 -0
  135. package/dist/session/pty.js.map +1 -0
  136. package/package.json +49 -0
  137. package/web/assets/index-B2JtCtHa.css +1 -0
  138. package/web/assets/index-BOqZOoep.js +107 -0
  139. package/web/index.html +13 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 kdonev
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,288 @@
1
+ # Termscape
2
+
3
+ Run a crew of AI coding agents on one infinite canvas, and let them talk to
4
+ each other.
5
+
6
+ Each terminal window on the canvas runs an agent CLI wired to an MCP server the
7
+ hub exposes. Agents can look each other up, send each other messages, spawn
8
+ helpers into their workspace, and check on each other's terminals. A message
9
+ from one agent is delivered by typing it into the other's terminal, immediately.
10
+
11
+ Local-first: the hub runs on your machine, binds loopback only, and the UI is a
12
+ browser tab. Other machines run the same hub as a daemon and appear on the same
13
+ canvas.
14
+
15
+ ## Getting started
16
+
17
+ ```bash
18
+ npx @kdonev/termscape
19
+ ```
20
+
21
+ That starts the hub and opens the canvas in your browser — pass `--no-open`
22
+ if you would rather it did not; the URL is printed either way. Nothing is
23
+ installed system-wide: state lives in `~/.termscape`, and deleting that
24
+ directory is the uninstall.
25
+
26
+ Slide out the **machines** panel: every machine, the workspaces on it, and
27
+ the agents in each. Point a workspace at a folder there, and start an agent
28
+ in it.
29
+
30
+ - **Scroll** to pan, **Ctrl/⌘ + scroll** to zoom, **Ctrl/⌘ + 1** to fit,
31
+ **Ctrl/⌘ + 2** to zoom to one terminal
32
+ - A **quick flick** of the zoom — a fast pinch, or a fast spin of the wheel —
33
+ navigates instead of zooming: in over a terminal maximizes it, out steps
34
+ back to the workspace around it and then to everything. Zooming at any
35
+ ordinary pace is left alone
36
+ - Below 60% zoom terminals become preview cards — zoom in to interact
37
+ - Clicking an agent in the panel brings the canvas to it
38
+
39
+ ## Requirements
40
+
41
+ - Node 22 or newer
42
+ - An agent CLI on your `PATH` — [Claude Code](https://claude.com/claude-code)
43
+ is the profile that ships configured
44
+ - macOS, Windows, or Linux
45
+
46
+ Everything native is prebuilt on all three platforms, so no compiler is
47
+ needed.
48
+
49
+ ## How it fits together
50
+
51
+ ```
52
+ Browser (canvas, xterm.js)
53
+ │ WebSocket: JSON control + binary PTY frames
54
+ Hub (Node)
55
+ │ node-pty ── agent CLI processes
56
+ │ MCP over HTTP ── the tools agents call
57
+ │ SQLite ── workspaces, layout, sessions, screens
58
+ │ hub↔hub WebSocket, either direction
59
+ Remote hub (same binary, --headless)
60
+ ```
61
+
62
+ Agents never talk to each other directly. They call `send_message` on their own
63
+ hub; the hub does the delivery, locally or by forwarding to a peer. That is why
64
+ an agent addresses a peer on another machine exactly as it addresses one in the
65
+ next window.
66
+
67
+ ## Adding another machine
68
+
69
+ Start the hub so the other machine can see it, then let that machine come to
70
+ you:
71
+
72
+ ```bash
73
+ npx @kdonev/termscape --listen lan
74
+ ```
75
+
76
+ (From a clone that is `npm run dev -- --listen lan`, or
77
+ `npm run dev -w @termscape/hub -- --listen lan` if you are calling the
78
+ workspace directly — npm needs the `--` to hand flags to the hub rather than
79
+ reading them itself.)
80
+
81
+ The hub prints an `enroll:` URL alongside the usual one. Open it **on the
82
+ machine you want to add** and run the command it shows:
83
+
84
+ ```bash
85
+ curl -fsSL http://studio:7777/join.sh | sh # macOS, Linux
86
+ irm http://studio:7777/join.ps1 | iex # Windows
87
+ ```
88
+
89
+ Both halves of that URL are chosen to be typeable, because the join page is the
90
+ one address you have to carry to another machine and enter by hand:
91
+
92
+ - **The host** is this machine's own name when that name actually resolves to
93
+ the address the hub bound — checked, not assumed. Windows resolves bare names
94
+ over LLMNR/NetBIOS and macOS/Linux over mDNS, and neither is guaranteed, so
95
+ the hub prints the numeric URL underneath as a fallback and the machines
96
+ panel offers it too. The canvas itself is reachable by name as well, token and all,
97
+ which is how you open it on a second screen or a phone.
98
+ - **The port** is the first free one from `7777, 4242, 7333, 3333, ...`.
99
+ `--port <n>` overrides it; `--port 0` takes whatever the OS hands out.
100
+
101
+ That installs the hub into `~/.termscape` there and connects it back. The machine
102
+ appears in the **machines** panel with a node of its own, and a workspace added
103
+ under that node runs its agents over there — same addresses, same
104
+ `send_message`, same canvas.
105
+
106
+ The installer works out what is missing before it changes anything:
107
+
108
+ - **Node 22.** If the machine has none, or an older one, it fetches a private
109
+ copy into `~/.termscape/node` — checksum-verified against nodejs.org's own
110
+ `SHASUMS256.txt`, since it is a binary about to be executed. Private rather
111
+ than system-wide, so it needs no administrator rights, no package manager,
112
+ and no fresh shell to pick up a PATH change; uninstalling is deleting the
113
+ directory. A copy already there is reused.
114
+ - **Native modules.** It prefers prebuilt binaries for `node-pty` and
115
+ `better-sqlite3`, falls back to compiling, and if neither works tells you
116
+ exactly which toolchain to install.
117
+
118
+ If the machine does not appear, the installer says why rather than reporting
119
+ success: a spent or expired key, a version gap, or a hub that exited. It waits
120
+ for the canvas to actually accept the machine, not merely for the hub to start
121
+ listening. `~/.termscape/hub.log` on that machine has the detail.
122
+
123
+ Re-running the join command on a machine that already joined is the supported
124
+ way to update or repair it: it stops the hub running there, replaces the
125
+ install, and rejoins with the token it already holds — or, if you had removed
126
+ that host from the canvas, with the fresh key the command carries. Removing a
127
+ machine from the panel stops its hub too, so it is not left running a daemon
128
+ that belongs to nobody — and takes the workspaces and agents on it with it,
129
+ which the panel says before it does it.
130
+
131
+ A re-join is quick after the first one: it keeps the dependency tree already
132
+ installed there unless the dependencies, the Node version, or the platform
133
+ have actually changed, and checks that tree really loads before trusting it.
134
+
135
+ Two things worth knowing:
136
+
137
+ - `--listen` is opt-in and off by default. With it, your hub is reachable on
138
+ that network, and anyone who can load the join page can attach a machine to
139
+ your canvas. Every other route still requires the token.
140
+ - Each download carries a single-use key that expires in 15 minutes. Once a
141
+ machine has joined it keeps a durable token in `~/.termscape/host-token` and
142
+ rejoins by itself after a reboot or a dropped link — its agents keep running
143
+ in the meantime.
144
+
145
+ **If you can't stand at the other machine**, the panel's *deploy over ssh* tab
146
+ does the reverse: it connects with your SSH agent or a key, installs the hub
147
+ over SFTP, starts it bound to that machine's loopback, and reaches it through a
148
+ tunnel. Same protocol, opposite direction.
149
+
150
+ ## Tools agents get
151
+
152
+ | Tool | What it does |
153
+ |---|---|
154
+ | `whoami` | your address, workspace and working directory |
155
+ | `list_agents` | everyone on the canvas, across every host, and whether they are busy |
156
+ | `send_message` | type a message into another agent's terminal, right now |
157
+ | `spawn_agent` | start a helper in your workspace, with an optional first task |
158
+ | `read_screen` | look at another agent's terminal without interrupting it |
159
+ | `set_status` | label your own window so the human can see what you are doing |
160
+ | `stop_agent` | stop an agent you spawned |
161
+
162
+ Every agent is also given a brief explaining its address, its peers, and that
163
+ text arriving as `[from <address>] ...` is a colleague rather than the human.
164
+
165
+ ## Agent profiles
166
+
167
+ An agent CLI is configuration, not code. Built-ins are `claude` and `shell`
168
+ (a plain terminal, no agent wiring). Override or add profiles in
169
+ `~/.termscape/agents.toml`:
170
+
171
+ ```toml
172
+ [my-agent]
173
+ command = "my-cli"
174
+ args = ["--mcp-config", "{{mcp_config_path}}"]
175
+ status = "heuristic" # or "hooks", for exact turn boundaries
176
+ ready_hint = "[$#>%] ?$" # prompt regex, for the idle indicator
177
+ inject = "bracketed" # bracketed paste, or "raw"
178
+ ```
179
+
180
+ ## State and restart
181
+
182
+ SQLite at `~/.termscape/state.db` holds everything needed to redraw the canvas
183
+ and relaunch every agent. It deliberately does not hold conversation history —
184
+ Claude Code already keeps that, and we store the pointer to it.
185
+
186
+ Kill the hub and start it again: the canvas comes back with its window
187
+ positions, its zoom, and each terminal's last screen, with the sessions marked
188
+ stopped. **Resume** relaunches an agent with `--resume`, continuing its prior
189
+ conversation.
190
+
191
+ Two consequences worth knowing:
192
+
193
+ - Only the **last screen** of each terminal survives a restart. Scrollback above
194
+ it is not persisted. (While the hub is running, full scrollback is held in
195
+ memory and replayed when you zoom back into a window.)
196
+ - Resume relaunches in the **same working directory**, because that is how
197
+ Claude Code finds a conversation. Move the folder and resume starts fresh.
198
+
199
+ ## Remote machines
200
+
201
+ Add a machine in the panel. The hub is copied over SSH, installed, and started as a
202
+ detached daemon bound to the remote machine's loopback interface, reached only
203
+ through an SSH tunnel. Because it is a daemon and not an `ssh` subprocess,
204
+ remote agents keep running when the connection drops, and reattach with their
205
+ state when it comes back.
206
+
207
+ The remote host needs Node 22+ and a toolchain able to build `node-pty` and
208
+ `better-sqlite3`.
209
+
210
+ ## Security
211
+
212
+ Agents can type into each other's terminals and spawn more agents. That is the
213
+ feature, and it is the risk surface: an agent that reads a hostile repository
214
+ could be talked into sending an attacker's text to a peer.
215
+
216
+ - The hub binds `127.0.0.1` only, never a network interface. Remote hubs too.
217
+ - Every agent gets its own bearer token. The sender of a message is taken from
218
+ that token, never from the arguments, so attribution cannot be forged.
219
+ - Messages are length-capped, rate-limited per sender, and always arrive with a
220
+ visible `[from <address>]` prefix.
221
+ - Every delivery attempt is recorded with its outcome and shown in the message
222
+ log. Nothing is delivered invisibly.
223
+ - `spawn_agent` is capped per workspace, so a confused agent cannot recurse the
224
+ machine to death.
225
+ - An agent may only stop agents it spawned.
226
+ - `--dangerously-skip-permissions` is never a default.
227
+
228
+ ## Development
229
+
230
+ From a clone, rather than the published package:
231
+
232
+ ```bash
233
+ git clone https://github.com/kdonev/termscape.git
234
+ cd termscape
235
+ npm install
236
+ npm run build
237
+ npm run dev # hub with the built UI
238
+ ```
239
+
240
+ If `npm install` or `npm ci` tries to compile `better-sqlite3` and fails for
241
+ want of a C++ toolchain, install this way instead:
242
+
243
+ ```bash
244
+ npm ci --ignore-scripts && npm rebuild node-pty
245
+ ```
246
+
247
+ Any install that reads `package-lock.json` misses better-sqlite3's
248
+ `gypfile: false` and runs `node-gyp` on a module that already ships working
249
+ prebuilds. Skipping install scripts avoids that; the rebuild puts back the one
250
+ native build that is real, which is a no-op except on Linux. This is what CI
251
+ does. It does not affect anyone installing the published package.
252
+
253
+ ```bash
254
+ npm test # unit + integration, no LLM required
255
+ npm run typecheck
256
+ npm run dev:web # vite dev server, expects a hub on :7777
257
+ ```
258
+
259
+ The integration tests spawn real PTYs and drive the real MCP endpoint, so
260
+ `npm test` genuinely exercises message delivery and cross-host routing.
261
+
262
+ ### Known quirks
263
+
264
+ - On Windows, node-pty prints `AttachConsole failed` to stderr when killing a
265
+ PTY from a process with no console attached (notably under the test runner).
266
+ It is noise from a helper process and does not affect behaviour.
267
+
268
+ ### Releasing
269
+
270
+ The repo is a workspace of three private packages; what gets published is a
271
+ single package assembled by `packages/hub/scripts/pack-npm.mjs` — the hub,
272
+ the built UI it serves, and `@termscape/protocol` bundled inside it.
273
+
274
+ ```bash
275
+ npm run pack:npm # build everything, then stage and pack the tarball
276
+ ```
277
+
278
+ Tagging `v<version>` runs `.github/workflows/release.yml`, which refuses a
279
+ tag that disagrees with `packages/hub/package.json`, installs the packed
280
+ tarball on macOS, Windows and Linux and checks each one starts and serves the
281
+ canvas, and only then publishes to npm with provenance. Bump the version in
282
+ `packages/hub/package.json` **and** `HUB_VERSION` in `packages/hub/src/hub.ts`
283
+ together — peer compatibility is gated on the constant, and a test fails if
284
+ the two drift.
285
+
286
+ ## License
287
+
288
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Environment sanitizing for spawned agents.
3
+ *
4
+ * Agents inherit the hub's environment so they can find their tools and
5
+ * credentials. But when the hub itself is launched from inside an agent CLI —
6
+ * which is not exotic; it is how you would develop this app — that parent's
7
+ * private session state is in the environment too, and inheriting it is
8
+ * actively harmful:
9
+ *
10
+ * CLAUDE_CODE_CHILD_SESSION marks the child as a sub-session, which turns
11
+ * transcript saving OFF. Since --resume reads
12
+ * that transcript, inheriting this silently
13
+ * breaks the resume feature entirely.
14
+ * CLAUDE_CODE_MESSAGING_SOCKET / _TOKEN
15
+ * the parent session's private IPC channel. A
16
+ * spawned agent must not be handed it.
17
+ * CLAUDE_CODE_SESSION_ID / _HOST_SESSION_ID / CLAUDE_PID
18
+ * identify the parent run; a child adopting them
19
+ * confuses session bookkeeping on both sides.
20
+ *
21
+ * So anything that identifies the *parent agent process* is stripped, while
22
+ * ordinary user configuration (PATH, HOME, ANTHROPIC_API_KEY, proxy settings)
23
+ * is passed through untouched.
24
+ */
25
+ export declare function shouldStrip(name: string): boolean;
26
+ /**
27
+ * Base environment for a spawned agent: the hub's environment minus the
28
+ * parent-session variables, plus the profile's own overrides.
29
+ *
30
+ * Profile overrides win, so a profile can deliberately re-add something that
31
+ * would otherwise be stripped.
32
+ */
33
+ export declare function buildAgentEnv(base: NodeJS.ProcessEnv, overrides?: Record<string, string>): Record<string, string>;
34
+ /** Names that were removed, for logging and for the tests to assert on. */
35
+ export declare function strippedNames(base: NodeJS.ProcessEnv): string[];
36
+ //# sourceMappingURL=env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/agents/env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAYH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAIjD;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,CAAC,UAAU,EACvB,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GACrC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQxB;AAED,2EAA2E;AAC3E,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,EAAE,CAE/D"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Environment sanitizing for spawned agents.
3
+ *
4
+ * Agents inherit the hub's environment so they can find their tools and
5
+ * credentials. But when the hub itself is launched from inside an agent CLI —
6
+ * which is not exotic; it is how you would develop this app — that parent's
7
+ * private session state is in the environment too, and inheriting it is
8
+ * actively harmful:
9
+ *
10
+ * CLAUDE_CODE_CHILD_SESSION marks the child as a sub-session, which turns
11
+ * transcript saving OFF. Since --resume reads
12
+ * that transcript, inheriting this silently
13
+ * breaks the resume feature entirely.
14
+ * CLAUDE_CODE_MESSAGING_SOCKET / _TOKEN
15
+ * the parent session's private IPC channel. A
16
+ * spawned agent must not be handed it.
17
+ * CLAUDE_CODE_SESSION_ID / _HOST_SESSION_ID / CLAUDE_PID
18
+ * identify the parent run; a child adopting them
19
+ * confuses session bookkeeping on both sides.
20
+ *
21
+ * So anything that identifies the *parent agent process* is stripped, while
22
+ * ordinary user configuration (PATH, HOME, ANTHROPIC_API_KEY, proxy settings)
23
+ * is passed through untouched.
24
+ */
25
+ /** Exact names that must never reach a spawned agent. */
26
+ const STRIP_EXACT = new Set(['CLAUDECODE', 'CLAUDE_PID', 'CLAUDE_EFFORT']);
27
+ /** Prefixes whose whole family is parent-session state. */
28
+ const STRIP_PREFIXES = [
29
+ 'CLAUDE_CODE_',
30
+ 'CLAUDE_AGENT_SDK_',
31
+ 'CLAUDE_PREVIEW_',
32
+ ];
33
+ export function shouldStrip(name) {
34
+ const upper = name.toUpperCase();
35
+ if (STRIP_EXACT.has(upper))
36
+ return true;
37
+ return STRIP_PREFIXES.some((p) => upper.startsWith(p));
38
+ }
39
+ /**
40
+ * Base environment for a spawned agent: the hub's environment minus the
41
+ * parent-session variables, plus the profile's own overrides.
42
+ *
43
+ * Profile overrides win, so a profile can deliberately re-add something that
44
+ * would otherwise be stripped.
45
+ */
46
+ export function buildAgentEnv(base, overrides = {}) {
47
+ const out = {};
48
+ for (const [k, v] of Object.entries(base)) {
49
+ if (v === undefined)
50
+ continue;
51
+ if (shouldStrip(k))
52
+ continue;
53
+ out[k] = v;
54
+ }
55
+ return { ...out, ...overrides };
56
+ }
57
+ /** Names that were removed, for logging and for the tests to assert on. */
58
+ export function strippedNames(base) {
59
+ return Object.keys(base).filter(shouldStrip).sort();
60
+ }
61
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/agents/env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,yDAAyD;AACzD,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,YAAY,EAAE,YAAY,EAAE,eAAe,CAAC,CAAC,CAAC;AAE3E,2DAA2D;AAC3D,MAAM,cAAc,GAAG;IACrB,cAAc;IACd,mBAAmB;IACnB,iBAAiB;CAClB,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IACjC,IAAI,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACxC,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AACzD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAC3B,IAAuB,EACvB,YAAoC,EAAE;IAEtC,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1C,IAAI,CAAC,KAAK,SAAS;YAAE,SAAS;QAC9B,IAAI,WAAW,CAAC,CAAC,CAAC;YAAE,SAAS;QAC7B,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACb,CAAC;IACD,OAAO,EAAE,GAAG,GAAG,EAAE,GAAG,SAAS,EAAE,CAAC;AAClC,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,aAAa,CAAC,IAAuB;IACnD,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE,CAAC;AACtD,CAAC"}
@@ -0,0 +1,45 @@
1
+ import type { InjectMode } from '../protocol/index.js';
2
+ /**
3
+ * An agent profile describes how to launch one kind of CLI and how to talk to
4
+ * it. Adding a new agent CLI should be a config change, not a code change.
5
+ */
6
+ export interface AgentProfile {
7
+ id: string;
8
+ description: string;
9
+ command: string;
10
+ args: string[];
11
+ env: Record<string, string>;
12
+ /** false = plain terminal: no MCP wiring, no brief, no agent identity. */
13
+ mcp: boolean;
14
+ /** How busy/idle is determined. */
15
+ status: 'hooks' | 'heuristic';
16
+ /** Regex matched against the last non-empty line when status = heuristic. */
17
+ readyHint?: string;
18
+ inject: InjectMode;
19
+ /**
20
+ * Argument template used to bring a session back with its prior
21
+ * conversation. `{{uuid}}` is replaced with agent_session_uuid. When absent,
22
+ * the profile is not resumable and restarts clean.
23
+ */
24
+ resumeArgs?: string[];
25
+ }
26
+ /**
27
+ * Built-in profiles. All Claude Code flags here are verified against the CLI:
28
+ * --mcp-config, --strict-mcp-config, --session-id, --settings,
29
+ * --append-system-prompt-file, --resume.
30
+ */
31
+ export declare const BUILTIN_PROFILES: Record<string, AgentProfile>;
32
+ export declare class ProfileRegistry {
33
+ private profiles;
34
+ constructor(profiles?: Record<string, AgentProfile>);
35
+ /** Built-ins, overlaid with ~/.termscape/agents.toml if present. */
36
+ static load(): ProfileRegistry;
37
+ get(id: string): AgentProfile | null;
38
+ require(id: string): AgentProfile;
39
+ list(): AgentProfile[];
40
+ isResumable(id: string): boolean;
41
+ }
42
+ /** Replace `{{key}}` placeholders. Unknown placeholders are left untouched. */
43
+ export declare function template(input: string, vars: Record<string, string>): string;
44
+ export declare function templateAll(args: string[], vars: Record<string, string>): string[];
45
+ //# sourceMappingURL=profiles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profiles.d.ts","sourceRoot":"","sources":["../../src/agents/profiles.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGtD;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,0EAA0E;IAC1E,GAAG,EAAE,OAAO,CAAC;IACb,mCAAmC;IACnC,MAAM,EAAE,OAAO,GAAG,WAAW,CAAC;IAC9B,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,UAAU,CAAC;IACnB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAOD;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CA8CzD,CAAC;AAEF,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAA+B;gBAEnC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC;IAInD,oEAAoE;IACpE,MAAM,CAAC,IAAI,IAAI,eAAe;IA8B9B,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;IAIpC,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY;IAMjC,IAAI,IAAI,YAAY,EAAE;IAItB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;CAIjC;AAED,+EAA+E;AAC/E,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAI5E;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,EAAE,CAElF"}
@@ -0,0 +1,123 @@
1
+ import { readFileSync, existsSync } from 'node:fs';
2
+ import { platform } from 'node:process';
3
+ import { parse as parseToml } from 'smol-toml';
4
+ import { paths } from '../paths.js';
5
+ function defaultShell() {
6
+ if (platform === 'win32')
7
+ return process.env.COMSPEC ?? 'powershell.exe';
8
+ return process.env.SHELL ?? '/bin/bash';
9
+ }
10
+ /**
11
+ * Built-in profiles. All Claude Code flags here are verified against the CLI:
12
+ * --mcp-config, --strict-mcp-config, --session-id, --settings,
13
+ * --append-system-prompt-file, --resume.
14
+ */
15
+ export const BUILTIN_PROFILES = {
16
+ claude: {
17
+ id: 'claude',
18
+ description: 'Claude Code, wired to the hub MCP endpoint',
19
+ command: 'claude',
20
+ args: [
21
+ '--mcp-config',
22
+ '{{mcp_config_path}}',
23
+ '--strict-mcp-config',
24
+ '--session-id',
25
+ '{{session_uuid}}',
26
+ '--settings',
27
+ '{{settings_path}}',
28
+ '--append-system-prompt-file',
29
+ '{{brief_path}}',
30
+ ],
31
+ env: {},
32
+ mcp: true,
33
+ status: 'hooks',
34
+ inject: 'bracketed',
35
+ // Resume swaps --session-id for --resume; everything else is re-templated
36
+ // identically, and crucially the session is relaunched in the same cwd,
37
+ // because Claude Code keys its conversation store by working directory.
38
+ resumeArgs: [
39
+ '--mcp-config',
40
+ '{{mcp_config_path}}',
41
+ '--strict-mcp-config',
42
+ '--resume',
43
+ '{{session_uuid}}',
44
+ '--settings',
45
+ '{{settings_path}}',
46
+ '--append-system-prompt-file',
47
+ '{{brief_path}}',
48
+ ],
49
+ },
50
+ shell: {
51
+ id: 'shell',
52
+ description: 'Plain terminal, no agent wiring',
53
+ command: defaultShell(),
54
+ args: [],
55
+ env: {},
56
+ mcp: false,
57
+ status: 'heuristic',
58
+ readyHint: '[$#>%] ?$',
59
+ inject: 'raw',
60
+ },
61
+ };
62
+ export class ProfileRegistry {
63
+ profiles;
64
+ constructor(profiles) {
65
+ this.profiles = profiles ?? { ...BUILTIN_PROFILES };
66
+ }
67
+ /** Built-ins, overlaid with ~/.termscape/agents.toml if present. */
68
+ static load() {
69
+ const merged = { ...BUILTIN_PROFILES };
70
+ const file = paths.profiles();
71
+ if (existsSync(file)) {
72
+ try {
73
+ const raw = parseToml(readFileSync(file, 'utf8'));
74
+ for (const [id, v] of Object.entries(raw)) {
75
+ if (typeof v !== 'object' || v === null)
76
+ continue;
77
+ const base = merged[id];
78
+ merged[id] = {
79
+ id,
80
+ description: v.description ?? base?.description ?? id,
81
+ command: v.command ?? base?.command ?? id,
82
+ args: v.args ?? base?.args ?? [],
83
+ env: v.env ?? base?.env ?? {},
84
+ mcp: v.mcp ?? base?.mcp ?? true,
85
+ status: v.status ?? base?.status ?? 'heuristic',
86
+ readyHint: v.ready_hint ?? v.readyHint ?? base?.readyHint,
87
+ inject: v.inject ?? base?.inject ?? 'bracketed',
88
+ resumeArgs: v.resume_args ?? v.resumeArgs ?? base?.resumeArgs,
89
+ };
90
+ }
91
+ }
92
+ catch (err) {
93
+ // A broken config must not take the hub down; fall back to built-ins.
94
+ console.error(`[profiles] ignoring ${file}: ${err.message}`);
95
+ }
96
+ }
97
+ return new ProfileRegistry(merged);
98
+ }
99
+ get(id) {
100
+ return this.profiles[id] ?? null;
101
+ }
102
+ require(id) {
103
+ const p = this.get(id);
104
+ if (!p)
105
+ throw new Error(`unknown agent profile "${id}"`);
106
+ return p;
107
+ }
108
+ list() {
109
+ return Object.values(this.profiles);
110
+ }
111
+ isResumable(id) {
112
+ const p = this.get(id);
113
+ return !!p?.resumeArgs;
114
+ }
115
+ }
116
+ /** Replace `{{key}}` placeholders. Unknown placeholders are left untouched. */
117
+ export function template(input, vars) {
118
+ return input.replace(/\{\{(\w+)\}\}/g, (whole, key) => key in vars ? vars[key] : whole);
119
+ }
120
+ export function templateAll(args, vars) {
121
+ return args.map((a) => template(a, vars));
122
+ }
123
+ //# sourceMappingURL=profiles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profiles.js","sourceRoot":"","sources":["../../src/agents/profiles.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /** Absolute path to `command`, or null when it is not on PATH. */
2
+ export declare function which(command: string): string | null;
3
+ export interface ResolvedCommand {
4
+ argv: string[];
5
+ /** The executable that was found, before any shell wrapping. */
6
+ resolved: string;
7
+ }
8
+ /**
9
+ * Turn a profile's (command, args) into an argv node-pty can actually spawn.
10
+ *
11
+ * Windows batch shims (.cmd/.bat) are not executable images, so CreateProcess
12
+ * refuses them. Many CLIs installed via npm are exactly that, so those get
13
+ * wrapped in `cmd.exe /c`.
14
+ */
15
+ export declare function resolveCommand(command: string, args: string[]): ResolvedCommand;
16
+ //# sourceMappingURL=resolve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/agents/resolve.ts"],"names":[],"mappings":"AA4BA,kEAAkE;AAClE,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAuBpD;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,gEAAgE;IAChE,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,eAAe,CAgB/E"}