Skip to content

Commit 76e4567

Browse files
authored
Deprecate CLI standalone experience and adopt full client/server model for this client (#2199)
**Deprecate standalone CLI experience** This PR removes the standalone (in-process) CLI mode and makes the CLI exclusively a thin client over the agent server via WebSocket RPC. Starting the CLI alone will automatically trigger agent-server startup in a new window (or connect to an existing one if it exists). It also adds server lifecycle management features to make the server-first model ergonomic. **Key changes** **Remove standalone interactive command** - Deleted [ts/packages/cli/src/commands/interactive.ts](vscode-webview://1o48rp7rdr60cpilngp5dms8tvlq1h8f0158a5o23usnfvp78ej7/ts/packages/cli/src/commands/interactive.ts) (231 lines), which created a full in-process dispatcher. Users now always go through the agent server via connect. **Improve server spawn behavior (connect command)** - --hidden: spawns the agent server without a visible window (background mode on Windows via windowsHide; visible window is now the default so users can see server output). - --idle-timeout <seconds>: instructs the server to shut itself down after N seconds with no connected clients, enabling ephemeral/scripted use cases. - --memory: starts an ephemeral session that is automatically deleted on exit. **Server-side idle shutdown** - [ts/packages/agentServer/server/src/server.ts](vscode-webview://1o48rp7rdr60cpilngp5dms8tvlq1h8f0158a5o23usnfvp78ej7/ts/packages/agentServer/server/src/server.ts): tracks active connection count and schedules a setTimeout shutdown when it drops to zero (if --idle-timeout is set). **New CLI server subcommands** - server status ([ts/packages/cli/src/commands/server/status.ts](vscode-webview://1o48rp7rdr60cpilngp5dms8tvlq1h8f0158a5o23usnfvp78ej7/ts/packages/cli/src/commands/server/status.ts)): checks whether the agent server is running on a given port. - server stop ([ts/packages/cli/src/commands/server/stop.ts](vscode-webview://1o48rp7rdr60cpilngp5dms8tvlq1h8f0158a5o23usnfvp78ej7/ts/packages/cli/src/commands/server/stop.ts)): gracefully stops the running agent server. **Client API improvements** - isServerRunning is now exported from the client package for use by CLI subcommands. - ensureAgentServer / spawnAgentServer accept hidden and idleTimeout parameters. - Windows spawn path now tries PowerShell 7 (pwsh.exe at full path) before falling back to powershell.exe. <img width="399" height="195" alt="image" src="https://github.com/user-attachments/assets/57bd6537-127b-4266-a6f6-d45345ee8cd9" /> <img width="449" height="143" alt="image" src="https://github.com/user-attachments/assets/83009f20-cf91-4e58-ac52-5469a9015fa0" />
1 parent b3288d7 commit 76e4567

File tree

25 files changed

+1144
-754
lines changed

25 files changed

+1144
-754
lines changed

ts/.vscode/launch.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,11 @@
4949
{
5050
"type": "node",
5151
"request": "launch",
52-
"name": "CLI interactive",
52+
"name": "CLI connect",
5353
"skipFiles": ["<node_internals>/**"],
5454
"cwd": "${workspaceFolder}/packages/cli",
5555
"program": "./bin/run.js",
56-
"args": ["interactive"],
56+
"args": ["connect"],
5757
"console": "integratedTerminal",
5858
"outFiles": ["${workspaceFolder}/**/*.js"]
5959
},
@@ -76,11 +76,11 @@
7676
{
7777
"type": "node",
7878
"request": "launch",
79-
"name": "CLI (dev) interactive",
79+
"name": "CLI (dev) connect",
8080
"skipFiles": ["<node_internals>/**"],
8181
"cwd": "${workspaceFolder}/packages/cli",
8282
"program": "./bin/dev.js",
83-
"args": ["interactive"],
83+
"args": ["connect"],
8484
"runtimeArgs": [
8585
"--loader",
8686
"ts-node/esm",
@@ -92,11 +92,11 @@
9292
{
9393
"type": "node",
9494
"request": "launch",
95-
"name": "CLI (dev) interactive [intergrated terminal]",
95+
"name": "CLI (dev) connect [integrated terminal]",
9696
"skipFiles": ["<node_internals>/**"],
9797
"cwd": "${workspaceFolder}/packages/cli",
9898
"program": "./bin/dev.js",
99-
"args": ["interactive"],
99+
"args": ["connect"],
100100
"runtimeArgs": [
101101
"--loader",
102102
"ts-node/esm",

ts/CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ Detail architecture descriptions are located in the **`docs/architecture`** dire
5959
- **`packages/knowPro/`** — Structured RAG implementation for conversational memory.
6060
- **`packages/agents/`** — All application agents (player, calendar, email, list, browser, etc.).
6161
- **`packages/shell/`** — Electron GUI app.
62-
- **`packages/cli/`** — Console app.
62+
- **`packages/cli/`** — Console app (connected-mode only; all commands route through `agent-server` via WebSocket RPC).
6363

6464
### Agent plugin structure
6565

ts/README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ Also, you can go to the shell directory `./packages/shell` and start from there.
175175
[TypeAgent CLI](./packages/cli) provides a console based _interactive agents_ with _natural language interfaces_ experience. Additional console command is available to explore different part of TypeAgent functionalities.
176176

177177
- Run `pnpm run cli` to get the available command
178-
- Run `pnpm run cli -- interactive` will start the interactive prompt
178+
- Run `pnpm run cli -- connect` will start the interactive prompt (connecting to the agent server via WebSocket RPC)
179179

180180
Also, you can go to the CLI directory `./packages/cli` and start from there. Please see instruction in TypeAgent CLI's [README.md](./packages/cli/README.md) for more options and detail.
181181

@@ -277,13 +277,13 @@ If you open this directory as a workspace in VSCode, multiple launch task is def
277277

278278
Common Debug Launch Task:
279279

280-
- CLI interactive - `./package/cli/bin/run.js interactive`
281-
- CLI (dev) interactive - `./package/cli/bin/dev.js interactive` with a new command prompt
282-
- CLI (dev) interactive [Integrated Terminal] - `./bin/dev.js interactive` using VSCode terminal (needed for WSL)
280+
- CLI connect - `./package/cli/bin/run.js connect`
281+
- CLI (dev) connect - `./package/cli/bin/dev.js connect` with a new command prompt
282+
- CLI (dev) connect [Integrated Terminal] - `./bin/dev.js connect` using VSCode terminal (needed for WSL)
283283

284284
#### Attaching to running sessions
285285

286-
To attaching to an existing session with TypeAgent CLI's interactive mode or TypeAgent Shell, you can start inspector by issuing the command `@debug` and use the VSCode `Attach` debugger launch task to attach.
286+
To attaching to an existing session with TypeAgent CLI's connect mode or TypeAgent Shell, you can start inspector by issuing the command `@debug` and use the VSCode `Attach` debugger launch task to attach.
287287

288288
#### TypeAgent Shell Browser Process
289289

@@ -298,7 +298,7 @@ The project uses [debug](https://www.npmjs.com/package/debug) package to enable
298298
For example (in Linux), to trace the GPT prompt that get sent when running the interactive CLI.
299299

300300
```bash
301-
DEBUG=typeagent:prompt packages/cli/bin/run.js interactive
301+
DEBUG=typeagent:prompt packages/cli/bin/run.js connect
302302
```
303303

304304
**Option 2**: In the shell or CLI's interactive mode, you can issue the command `@trace <pattern>` to add to the list of namespace. Use "-" or "-\*" to disable all the trace.

ts/docs/architecture/agentServerSessions.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ agent-cli connect # connect to the 'CLI' session (created
357357
agent-cli connect --resume # resume the last used session
358358
agent-cli connect --session <id> # connect to a specific session by ID
359359
agent-cli connect --port <port> # connect to a server on a non-default port (default: 8999)
360+
agent-cli connect --hidden # start the server hidden (no visible window)
360361
```
361362

362363
By default (no flags), `connect` targets a session named `"CLI"`. It calls `listSessions("CLI")` and joins the first match, or calls `createSession("CLI")` if none exists.
@@ -365,8 +366,21 @@ Pass `--resume` / `-r` to instead resume the last used session, whose ID is pers
365366

366367
Pass `--session` / `-s <id>` to connect to a specific session by UUID. This takes priority over `--resume` if both are provided; errors propagate as-is without the recovery prompt.
367368

369+
Pass `--hidden` to start the agent server without a visible window. Default is a visible window for interactive use.
370+
368371
On every successful connection the connected session ID is written to `~/.typeagent/cli-state.json` for use by future `--resume` invocations.
369372

373+
#### `run` — non-interactive commands
374+
375+
`agent-cli run request`, `run translate`, and `run explain` each accept `--session <id>` / `-s` to target a specific session. If omitted, they use the find-or-create `"CLI"` session. The server is started hidden by default for non-interactive commands; use `--show` to get a visible window.
376+
377+
#### `server` — manage the server process
378+
379+
```bash
380+
agent-cli server status # show whether the server is running
381+
agent-cli server stop # send a graceful shutdown to the running server
382+
```
383+
370384
#### `sessions` topic — session CRUD
371385

372386
| Command | RPC call |

ts/docs/architecture/completion.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -888,7 +888,7 @@ needs shadow candidates".
888888

889889
## CLI integration
890890

891-
The CLI (`packages/cli/src/commands/interactive.ts`) follows the same
891+
The CLI (`packages/cli/src/commands/connect.ts`) follows the same
892892
contract but with simpler plumbing:
893893

894894
1. Sends full input and a `direction` (always `"forward"` for tab-completion,

ts/packages/agentServer/README.md

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -105,17 +105,20 @@ Session dispatchers are automatically evicted from memory after 5 minutes with n
105105
## Connection lifecycle
106106

107107
```
108-
Client calls ensureAndConnectDispatcher(clientIO, port)
108+
Client calls ensureAgentServer(port, hidden)
109109
110-
├─ Is server already listening on ws://localhost:<port>?
111-
│ └─ No → spawnAgentServer() — detached child process, survives parent exit
110+
└─ Is server already listening on ws://localhost:<port>?
111+
└─ No → spawnAgentServer() — detached child process, survives parent exit
112+
hidden=true suppresses the terminal/window
113+
114+
Client calls connectAgentServer(url)
112115
113116
├─ Open WebSocket → create RPC channels
114117
115-
├─ Send joinSession({ clientType, filter }) on agent-server channel
118+
├─ Send joinSession({ sessionId, clientType, filter }) on agent-server channel
116119
│ └─ Server assigns connectionId, returns { connectionId, sessionId }
117120
118-
└─ Return Dispatcher RPC proxy to caller
121+
└─ Return AgentServerConnection (call .joinSession() to get a Dispatcher proxy)
119122
```
120123

121124
On disconnect, the server removes all of that connection's sessions from its routing table.
@@ -142,10 +145,29 @@ Chat UI (renderer) ↔ IPC ↔ Main process ↔ WebSocket ↔ agentServer
142145

143146
## CLI integration
144147

145-
The CLI ([`packages/cli/src/commands/connect.ts`](../cli/src/commands/connect.ts)) always uses remote connection. It calls `ensureAndConnectDispatcher()`, which auto-spawns the server if not already running, then enters an interactive readline loop.
148+
The CLI ([`packages/cli/`](../cli/)) always uses remote connection via WebSocket.
146149

147150
```
148-
Terminal ↔ EnhancedConsoleClientIO ↔ WebSocket ↔ agentServer
151+
Terminal ↔ ConsoleClientIO ↔ WebSocket ↔ agentServer
152+
```
153+
154+
### `agent-cli connect` (interactive)
155+
156+
`connect` calls `ensureAgentServer(port, hidden, idleTimeout)` to auto-spawn the server if needed, then calls `connectAgentServer()` and `joinSession()` directly. By default the spawned server window is visible; pass `--hidden` to suppress it. Pass `--idle-timeout <seconds>` to enable idle shutdown when spawning (default: `0`, server stays alive indefinitely).
157+
158+
### `agent-cli run` (non-interactive)
159+
160+
The `run request`, `run translate`, and `run explain` subcommands also call `ensureAgentServer()` — but default to **hidden** (no window), with `--show` to opt into a visible window. All three support `--session <id>` to target a specific session instead of the default `"CLI"` session. When spawning, passes `--idle-timeout 600` so the server exits 10 minutes after the last client disconnects.
161+
162+
### `agent-cli replay`
163+
164+
`replay` always creates an ephemeral session (`cli-replay-<uuid>`) and deletes it on exit. Defaults to hidden; `--show` to opt in. Also passes `--idle-timeout 600` when spawning.
165+
166+
### `agent-cli server`
167+
168+
```bash
169+
agent-cli server status # check whether the server is running
170+
agent-cli server stop # send a graceful shutdown via RPC
149171
```
150172

151173
---
@@ -161,17 +183,18 @@ Shell launches → createDispatcher() in-process → no server involved
161183
**Shell or CLI — server already running**
162184

163185
```
164-
Client → ensureAndConnectDispatcher(port=8999)
165-
→ server already running → connect → joinSession() → Dispatcher proxy
186+
Client → ensureAgentServer(port=8999, hidden)
187+
→ server already running → no-op
188+
Client → connectAgentServer() → joinSession() → Dispatcher proxy
166189
```
167190

168191
**Shell or CLI — server not yet running**
169192

170193
```
171-
Client → ensureAndConnectDispatcher(port=8999)
172-
→ server not found → spawnAgentServer()
194+
Client → ensureAgentServer(port=8999, hidden, idleTimeout)
195+
→ server not found → spawnAgentServer() (hidden or visible window)
173196
→ poll until ready (60 s timeout)
174-
→ connect → joinSession() → Dispatcher proxy
197+
Client → connectAgentServer() → joinSession() → Dispatcher proxy
175198
```
176199

177200
**Headless server**
@@ -182,6 +205,13 @@ pnpm --filter agent-server start
182205
→ any number of Shell/CLI clients can connect and share sessions
183206
```
184207

208+
**Stopping the server**
209+
210+
```bash
211+
agent-cli server stop # via CLI (recommended)
212+
pnpm --filter agent-server stop # via pnpm script
213+
```
214+
185215
---
186216

187217
## Session persistence

ts/packages/agentServer/client/README.md

Lines changed: 54 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -40,33 +40,72 @@ await connection.close();
4040
| `deleteSession(sessionId)` | Delete a session and its persisted data |
4141
| `close()` | Close the WebSocket connection |
4242

43-
### `ensureAndConnectDispatcher(clientIO, port?, options?, onDisconnect?)`
43+
### `ensureAgentServer(port?, hidden?, idleTimeout?)`
4444

45-
Convenience wrapper that auto-spawns the server if needed and joins a session, returning a `Dispatcher` directly. Used by Shell and CLI.
45+
Ensures the agentServer is running, spawning it if needed.
4646

47-
1. Checks whether a server is already listening on `ws://localhost:<port>` (default 8999).
48-
2. If not, calls `spawnAgentServer()` to start it as a detached child process.
47+
1. Calls `isServerRunning(url)` to check whether a server is already listening.
48+
2. If not, calls `spawnAgentServer(hidden, idleTimeout)` to start it as a detached child process.
4949
3. Polls until the server is ready (500 ms interval, 60 s timeout).
50-
4. Calls `connectDispatcher()` and returns the `Dispatcher` proxy.
5150

5251
```typescript
53-
const dispatcher = await ensureAndConnectDispatcher(
54-
clientIO,
55-
8999,
56-
{ clientType: "shell" },
57-
() => {
58-
console.error("Disconnected");
59-
process.exit(1);
60-
},
61-
);
52+
// Start hidden with 10-minute idle shutdown — used by non-interactive CLI commands
53+
await ensureAgentServer(8999, true, 600);
6254

63-
await dispatcher.processCommand("help");
55+
// Start in a visible window, no idle shutdown — used by interactive connect
56+
await ensureAgentServer(8999, false);
57+
58+
const connection = await connectAgentServer("ws://localhost:8999");
59+
```
60+
61+
| Parameter | Type | Default | Description |
62+
| ------------- | --------- | ------- | ------------------------------------------------------------------------------------ |
63+
| `port` | `number` | `8999` | Port to check and spawn on |
64+
| `hidden` | `boolean` | `false` | When spawning, suppress the terminal/window (`true` = hidden) |
65+
| `idleTimeout` | `number` | `0` | Pass `--idle-timeout` to the spawned server; `0` disables (server runs indefinitely) |
66+
67+
### `isServerRunning(url)`
68+
69+
Returns `true` if a server is already listening at the given WebSocket URL.
70+
71+
```typescript
72+
if (await isServerRunning("ws://localhost:8999")) {
73+
console.log("Server is up");
74+
}
6475
```
6576

6677
### `stopAgentServer(port?)`
6778

6879
Connects to the running server on the given port and sends a `shutdown()` RPC.
6980

81+
### `ensureAndConnectSession(clientIO, port?, options?, onDisconnect?, hidden?, idleTimeout?)`
82+
83+
Convenience wrapper: ensures the server is running, connects, and joins a session in one call. Returns a `SessionDispatcher` directly.
84+
85+
```typescript
86+
const session = await ensureAndConnectSession(
87+
clientIO,
88+
8999,
89+
{ sessionId },
90+
onDisconnect,
91+
true,
92+
600,
93+
);
94+
```
95+
96+
| Parameter | Type | Default | Description |
97+
| -------------- | -------------------------- | ------------ | ----------------------------------------------------- |
98+
| `clientIO` | `ClientIO` | _(required)_ | Client IO implementation |
99+
| `port` | `number` | `8999` | Port to connect to |
100+
| `options` | `DispatcherConnectOptions` | `undefined` | Session join options (e.g. `sessionId`) |
101+
| `onDisconnect` | `() => void` | `undefined` | Called when the WebSocket disconnects |
102+
| `hidden` | `boolean` | `false` | Suppress terminal/window when spawning |
103+
| `idleTimeout` | `number` | `0` | Pass `--idle-timeout` to spawned server; `0` disables |
104+
105+
### `ensureAndConnectDispatcher(clientIO, port?, options?, onDisconnect?)` _(deprecated)_
106+
107+
Convenience wrapper that auto-spawns the server if needed and joins a session, returning a `Dispatcher` directly. Prefer calling `ensureAgentServer()` + `connectAgentServer()` + `joinSession()` separately for full control.
108+
70109
### `connectDispatcher(clientIO, url, options?, onDisconnect?)` _(deprecated)_
71110

72111
Backward-compatible wrapper: connects and immediately joins a session, returning a `Dispatcher`. Use `connectAgentServer()` for full multi-session support.

0 commit comments

Comments
 (0)