@zgeoff/atc 2.8.1 → 2.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -2
- package/package.json +1 -1
- package/src/client/daemon-client.ts +10 -0
package/README.md
CHANGED
|
@@ -118,8 +118,18 @@ installs in detail.
|
|
|
118
118
|
## Beyond the keyboard
|
|
119
119
|
|
|
120
120
|
- `atc mcp` exposes the fleet as MCP tools, so an agent can spawn, drive, and read other agents. A
|
|
121
|
-
session spawned this way lists under the session that spawned it and is killed with it.
|
|
122
|
-
|
|
121
|
+
session spawned this way lists under the session that spawned it and is killed with it. Each agent
|
|
122
|
+
keeps its own MCP config, so register the server once per agent you run:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
claude mcp add --scope user atc -- atc mcp
|
|
126
|
+
codex mcp add atc -- atc mcp
|
|
127
|
+
grok mcp add atc -- atc mcp
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
A Claude or Codex session that is already running loads the server only after it restarts. A
|
|
131
|
+
running Grok session loads it when you press `r` in its `/mcps` list.
|
|
132
|
+
|
|
123
133
|
- A Claude session takes messages from other tools. `atc_session_message` queues one, and the
|
|
124
134
|
session reads it in a new turn, or inside the turn it is running. `atc_message_get` returns the
|
|
125
135
|
reply once that turn ends. The [protocol](./docs/architecture/protocol.md#messages) covers the
|
package/package.json
CHANGED
|
@@ -30,6 +30,10 @@ export class DaemonClient {
|
|
|
30
30
|
|
|
31
31
|
private socket: { end: () => void } | null = null;
|
|
32
32
|
|
|
33
|
+
// Set once the connection ends, so a request sent afterwards rejects at
|
|
34
|
+
// once instead of waiting on a response that can never arrive.
|
|
35
|
+
private closedReason: string | null = null;
|
|
36
|
+
|
|
33
37
|
static async open(socketPath: string): Promise<DaemonClient> {
|
|
34
38
|
const client = new DaemonClient();
|
|
35
39
|
|
|
@@ -65,6 +69,10 @@ export class DaemonClient {
|
|
|
65
69
|
m: string,
|
|
66
70
|
p?: Readonly<Record<string, unknown>>,
|
|
67
71
|
): Promise<Readonly<Record<string, unknown>>> {
|
|
72
|
+
if (this.closedReason !== null) {
|
|
73
|
+
return Promise.reject(new DaemonError('internal', this.closedReason));
|
|
74
|
+
}
|
|
75
|
+
|
|
68
76
|
const id = this.nextID++;
|
|
69
77
|
const resolvers = Promise.withResolvers<Readonly<Record<string, unknown>>>();
|
|
70
78
|
|
|
@@ -135,6 +143,8 @@ export class DaemonClient {
|
|
|
135
143
|
}
|
|
136
144
|
|
|
137
145
|
private drainPending(reason: string): void {
|
|
146
|
+
this.closedReason ??= reason;
|
|
147
|
+
|
|
138
148
|
for (const [id, waiter] of this.pending) {
|
|
139
149
|
this.pending.delete(id);
|
|
140
150
|
waiter.reject(new DaemonError('internal', reason));
|