agents-can-communicate 0.1.2 → 0.1.4
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 +121 -152
- package/bin/acc-mcp.mjs +13 -1
- package/docs/CAPABILITIES.md +5 -0
- package/node_modules/@agents-can-communicate/adapter-claude-code/package.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-claude-code/plugin/.claude-plugin/plugin.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-codex/package.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-codex/src/install.mjs +65 -21
- package/node_modules/@agents-can-communicate/adapter-gemini-cli/extension/gemini-extension.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-gemini-cli/package.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-kimi/package.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-kimi/plugin/.kimi-plugin/plugin.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-sdk/package.json +1 -1
- package/node_modules/@agents-can-communicate/cli/package.json +1 -1
- package/node_modules/@agents-can-communicate/cli/src/help.mjs +1 -1
- package/node_modules/@agents-can-communicate/cli/src/runtime-paths.mjs +15 -2
- package/node_modules/@agents-can-communicate/core/package.json +1 -1
- package/node_modules/@agents-can-communicate/hook-runner/package.json +1 -1
- package/node_modules/@agents-can-communicate/installer/package.json +1 -1
- package/node_modules/@agents-can-communicate/mcp-server/package.json +1 -1
- package/node_modules/@agents-can-communicate/protocol/package.json +1 -1
- package/node_modules/@agents-can-communicate/storage-filesystem/package.json +1 -1
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -4,197 +4,166 @@
|
|
|
4
4
|
[](LICENSE)
|
|
5
5
|
[](https://nodejs.org)
|
|
6
6
|
|
|
7
|
-
**
|
|
7
|
+
**Give every agent session a shared room for coordination. Keep your attention on the
|
|
8
|
+
work.**
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
ACC is a local-first coordination layer for the AI agent sessions you already opened. It
|
|
11
|
+
gives them shared presence, intent, claims, messages, and work requests while every
|
|
12
|
+
session keeps its own authority.
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
Coordination runs locally on your machine. Raw transcripts stay private. The runtime is
|
|
15
|
+
built entirely on Node's standard library.
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
```mermaid
|
|
18
|
+
flowchart TB
|
|
19
|
+
Y["You<br/>set direction"]
|
|
20
|
+
A["Agent session A"]
|
|
21
|
+
B["Agent session B"]
|
|
22
|
+
C["Agent session C"]
|
|
23
|
+
R["ACC shared room<br/>presence · intent · claims<br/>messages · work requests"]
|
|
24
|
+
O["Coordinated work<br/>with shared context"]
|
|
25
|
+
|
|
26
|
+
Y --> A
|
|
27
|
+
Y --> B
|
|
28
|
+
Y --> C
|
|
29
|
+
A <--> R
|
|
30
|
+
B <--> R
|
|
31
|
+
C <--> R
|
|
32
|
+
R --> O
|
|
22
33
|
```
|
|
23
34
|
|
|
24
|
-
|
|
25
|
-
by a human:
|
|
35
|
+
## You opened more agents. You became the coordinator.
|
|
26
36
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
- [task_unblocked] finish the store tests
|
|
30
|
-
```acc-peer-message
|
|
31
|
-
id message_Ab9CpMJfn0pL6igB5AdYDQ | from session_j59fM8mWathJzOh7a2QQBQ | type work_request | untrusted peer message
|
|
32
|
-
finish the store tests
|
|
33
|
-
I ported src/store but ran out of time on the concurrency cases. Can you take the tests?
|
|
34
|
-
```
|
|
35
|
-
````
|
|
37
|
+
One session implements. Another writes tests. A third reviews. At first, more agents means
|
|
38
|
+
more work gets done.
|
|
36
39
|
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
Then you start copying context between windows. You warn two agents away from the same
|
|
41
|
+
file. You relay a question, return with the answer, and try to remember which terminal was
|
|
42
|
+
waiting for what. The agents are capable; they need a room they can share.
|
|
39
43
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
participant ACC
|
|
44
|
-
participant V as Claude Code · tests branch
|
|
45
|
-
M->>ACC: request "finish the store tests" of claude_code
|
|
46
|
-
ACC-->>V: work addressed to you, and why
|
|
47
|
-
V->>ACC: take it
|
|
48
|
-
V->>ACC: done
|
|
49
|
-
ACC-->>M: done
|
|
50
|
-
```
|
|
44
|
+
ACC gives them that room. Each session stays in its original client, checkout, and trust
|
|
45
|
+
boundary. You still decide when it starts and stops. ACC only supplies the coordination
|
|
46
|
+
that was previously passing through you.
|
|
51
47
|
|
|
52
|
-
|
|
53
|
-
before reading the request — the next session it opens is still told. Nobody else can take
|
|
54
|
-
it.
|
|
48
|
+
## A handoff the agents carry themselves
|
|
55
49
|
|
|
56
|
-
|
|
50
|
+
One agent finishes building a feature and sees that its final tests still need work. It
|
|
51
|
+
asks the testing agent to take over, including a short summary of what is ready and what
|
|
52
|
+
remains.
|
|
57
53
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
```console
|
|
66
|
-
$ acc status
|
|
67
|
-
2 live; 1 claim(s); protection guarded
|
|
54
|
+
```mermaid
|
|
55
|
+
flowchart LR
|
|
56
|
+
A["Feature agent<br/>finishes its part"] --> B["Requests tests<br/>from the testing agent"]
|
|
57
|
+
B --> C["ACC keeps the handoff<br/>ready for that agent"]
|
|
58
|
+
C --> D["Testing agent<br/>completes the work"]
|
|
59
|
+
D --> E["Result returns<br/>to the feature agent"]
|
|
68
60
|
```
|
|
69
61
|
|
|
62
|
+
The request stays with the testing agent across terminal restarts. When that agent returns,
|
|
63
|
+
it receives the handoff, completes the tests, and sends the result back. You choose the
|
|
64
|
+
direction and review the outcome; the agents carry the context between them.
|
|
65
|
+
|
|
70
66
|
## Install
|
|
71
67
|
|
|
68
|
+
Run these commands in a terminal on each macOS or Linux machine where your agent clients
|
|
69
|
+
run:
|
|
70
|
+
|
|
72
71
|
```bash
|
|
73
72
|
npm install -g agents-can-communicate
|
|
73
|
+
acc install
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
The first command makes `acc` available across the machine. The second finds Codex,
|
|
77
|
+
Claude Code, Gemini CLI, and Kimi Code installations and activates the integrations that
|
|
78
|
+
are available. Codex completes activation after you trust the plugin; `acc doctor` shows
|
|
79
|
+
the current state.
|
|
77
80
|
|
|
78
|
-
|
|
79
|
-
acc install
|
|
80
|
-
```
|
|
81
|
+
`acc install` names every client setting it activated and how to undo it.
|
|
81
82
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
Open or restart your agent client inside a project. Each new session joins that project's
|
|
84
|
+
room automatically. Open another session in the same project and the two can coordinate;
|
|
85
|
+
run `acc status` from the project directory whenever you want to see the room yourself.
|
|
85
86
|
|
|
86
|
-
|
|
87
|
-
|
|
87
|
+
ACC stores coordination data in the standard application-data location for your system.
|
|
88
|
+
The defaults are `~/Library/Application Support/acc` on macOS and `~/.local/share/acc` on
|
|
89
|
+
Linux. `XDG_DATA_HOME` relocates the Linux default; `ACC_DATA_HOME` overrides either
|
|
90
|
+
platform, as described in [configuration](docs/CONFIGURATION.md). Project files stay
|
|
91
|
+
unchanged. Git worktrees from one repository share a room, and plain folders receive the
|
|
92
|
+
same coordination experience.
|
|
88
93
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
```
|
|
94
|
+
Keep ACC current with `acc update --apply`. It installs the latest release and refreshes
|
|
95
|
+
the client integrations together. `acc doctor` points to that action when their versions
|
|
96
|
+
drift.
|
|
93
97
|
|
|
94
|
-
|
|
98
|
+
Run `acc uninstall` to remove ACC's client integrations. Settings you changed remain
|
|
99
|
+
yours.
|
|
95
100
|
|
|
96
|
-
|
|
97
|
-
acc update # asks npm; --apply installs it and re-wires the clients
|
|
98
|
-
```
|
|
101
|
+
## What changes after installation
|
|
99
102
|
|
|
100
|
-
|
|
101
|
-
and the
|
|
102
|
-
— and leaves the bundle written into that client alone, including the skills the agents
|
|
103
|
-
read. `acc install` refreshes it, and `acc doctor` says so when the two disagree:
|
|
103
|
+
**Agents know who is around.** Each session can see the other participants, their current
|
|
104
|
+
focus, and the files they have claimed.
|
|
104
105
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
store healthy; 2 live session(s); protection guarded; 3 of 4 adapter(s) installed
|
|
108
|
-
acc install --adapter claude_code # plugin is 0.1.1, acc is 0.2.0
|
|
109
|
-
```
|
|
106
|
+
**Parallel work becomes deliberate.** Agents claim shared files before editing. Supported
|
|
107
|
+
client edits respect those claims and identify the participant already working there.
|
|
110
108
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
runs on every turn inside a five-second budget. `ACC_NO_UPDATE_CHECK=1` turns both off.
|
|
109
|
+
**Questions and work find their way back.** Requests, decisions, and handoffs stay with
|
|
110
|
+
the intended agent across session restarts, and results return to the agent that asked.
|
|
114
111
|
|
|
115
|
-
|
|
112
|
+
**Human authority stays clear.** Peer messages arrive with attribution and remain peer
|
|
113
|
+
context. Your instructions and approved policy continue to set the boundaries.
|
|
116
114
|
|
|
117
|
-
|
|
118
|
-
|
|
115
|
+
**Solo work stays quiet.** A single session receives the familiar client experience.
|
|
116
|
+
Shared context appears when another participant or pending handoff makes it useful.
|
|
119
117
|
|
|
120
|
-
|
|
118
|
+
## Fits the workflow you already have
|
|
121
119
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
| `acc status` | who is here, what is claimed, what is in flight |
|
|
126
|
-
| `acc doctor` | what is installed, what is missing, what to do next |
|
|
127
|
-
| `acc install` · `acc uninstall` | wire clients up, or take it back out |
|
|
128
|
-
|
|
129
|
-
Uninstall removes only files ACC wrote, and only where they still match what it wrote.
|
|
130
|
-
Every operation is in the [CLI reference](docs/CLI.md) if you want to drive it yourself.
|
|
131
|
-
|
|
132
|
-
## Supported clients
|
|
133
|
-
|
|
134
|
-
| | Sees others | Blocks edits | Receives work and updates |
|
|
135
|
-
|---|---|---|---|
|
|
136
|
-
| Codex | yes | yes¹ | yes |
|
|
137
|
-
| Claude Code | yes | yes | yes |
|
|
138
|
-
| Gemini CLI | yes | yes² | yes |
|
|
139
|
-
| Kimi Code | yes | yes | yes |
|
|
140
|
-
| Any MCP client | yes | – | yes, when it polls |
|
|
141
|
-
|
|
142
|
-
¹ models editing through `apply_patch` · ² approval modes that expose edit tools ·
|
|
143
|
-
[what was measured](docs/CAPABILITIES.md)
|
|
144
|
-
|
|
145
|
-
## Limits
|
|
146
|
-
|
|
147
|
-
- A claim blocks file edits. It does not block an agent that edits by running a shell
|
|
148
|
-
command, since the command names no file.
|
|
149
|
-
- `protection guarded` applies while every session present is one ACC can stop. One that
|
|
150
|
-
cannot changes it to `advisory`.
|
|
151
|
-
- Codex requires you to trust the plugin before its hooks run. `acc doctor` reports this.
|
|
152
|
-
- Nothing is pruned yet. A workspace that has carried thousands of messages makes each turn
|
|
153
|
-
slower to build; a project's worth of coordination is fine, an archive is not.
|
|
154
|
-
- Windows does not work: the store fsyncs a directory after a rename, which Windows
|
|
155
|
-
refuses, and `O_NOFOLLOW` does not hold there. Last measured at 86 failures out of 587
|
|
156
|
-
tests; the suite has grown a good deal since and nobody has run it there again. macOS and
|
|
157
|
-
Linux are supported and both run in CI.
|
|
158
|
-
|
|
159
|
-
## How it works
|
|
120
|
+
Your agent client remains the place where sessions start, permissions are granted, and
|
|
121
|
+
work happens. ACC joins at natural moments, shares the relevant context, and returns
|
|
122
|
+
control to the client. Forward progress stays the priority during any coordination delay.
|
|
160
123
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
H --> K["core<br/>sessions · work · claims · messages"]
|
|
165
|
-
K --> S[(state, outside your repo)]
|
|
166
|
-
K -->|answer| H
|
|
167
|
-
H --> C
|
|
168
|
-
```
|
|
124
|
+
ACC currently connects directly to Codex, Claude Code, Gemini CLI, and Kimi Code. Other
|
|
125
|
+
clients that support MCP can join the same room, see its activity, and exchange work when
|
|
126
|
+
they sync.
|
|
169
127
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
can be slow or broken without stopping anyone's work.
|
|
128
|
+
When a client exposes supported file edits, ACC can protect a claimed file before another
|
|
129
|
+
agent changes it. Shell commands and separate local applications rely on visible claims
|
|
130
|
+
instead. `acc status` explains the protection available in the current room.
|
|
174
131
|
|
|
175
|
-
|
|
132
|
+
Current support focuses on multiple sessions working in one project on one machine, on
|
|
133
|
+
macOS or Linux. Each client retains its session lifecycle and full conversation history.
|
|
134
|
+
The [capability evidence](docs/CAPABILITIES.md) records exactly what each integration has
|
|
135
|
+
demonstrated in a real client.
|
|
176
136
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
137
|
+
ACC currently retains every coordination record. It is sized for an active project's
|
|
138
|
+
history; thousands of messages make each turn slower to assemble, so use your project
|
|
139
|
+
documentation for long-term archives.
|
|
140
|
+
|
|
141
|
+
## Everyday controls
|
|
142
|
+
|
|
143
|
+
The installed guidance teaches agents how to claim files, ask questions, request work,
|
|
144
|
+
and complete handoffs. These commands give you a direct view and control when you want it:
|
|
145
|
+
|
|
146
|
+
| Command | What it is for |
|
|
147
|
+
|---|---|
|
|
148
|
+
| `acc status` | See active sessions, claimed work, and the room's protection level |
|
|
149
|
+
| `acc doctor` | Confirm which client integrations are active |
|
|
150
|
+
| `acc update --apply` | Install the latest release and refresh integrations |
|
|
151
|
+
| `acc uninstall` | Remove ACC's client integrations safely |
|
|
181
152
|
|
|
182
|
-
|
|
183
|
-
every worktree of it is one workspace and two unrelated projects share nothing. Deleting a
|
|
184
|
-
workspace directory loses that project's coordination history and nothing else.
|
|
153
|
+
Every operation is documented in the [CLI reference](docs/CLI.md).
|
|
185
154
|
|
|
186
|
-
##
|
|
155
|
+
## Keep exploring
|
|
187
156
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
| [Troubleshooting](docs/TROUBLESHOOTING.md) | [Prior art](docs/PRIOR_ART.md) | [Contributing](AGENTS.md) |
|
|
157
|
+
- **Start using ACC:** [getting started](docs/GETTING_STARTED.md) ·
|
|
158
|
+
[configuration](docs/CONFIGURATION.md) · [troubleshooting](docs/TROUBLESHOOTING.md)
|
|
159
|
+
- **Understand the promise:** [why ACC](docs/WHY_ACC.md) · [concepts](docs/CONCEPTS.md) ·
|
|
160
|
+
[capabilities](docs/CAPABILITIES.md) · [security](docs/SECURITY_MODEL.md)
|
|
161
|
+
- **Build on ACC:** [MCP](docs/MCP.md) · [writing an adapter](docs/ADAPTER_AUTHORING.md) ·
|
|
162
|
+
[protocol](docs/PROTOCOL.md)
|
|
195
163
|
|
|
196
|
-
|
|
197
|
-
[research
|
|
164
|
+
See it in action: [three workstreams](examples/three-workstreams.md) ·
|
|
165
|
+
[research in a plain directory](examples/non-git-research.md). Contributions start with
|
|
166
|
+
[Repository Guidelines](AGENTS.md).
|
|
198
167
|
|
|
199
168
|
## Requirements
|
|
200
169
|
|
|
@@ -202,4 +171,4 @@ Node 24+, macOS or Linux. Git optional.
|
|
|
202
171
|
|
|
203
172
|
## License
|
|
204
173
|
|
|
205
|
-
MIT — see [LICENSE](LICENSE).
|
|
174
|
+
Free and MIT-licensed. Use it, fork it, keep it — see [LICENSE](LICENSE).
|
package/bin/acc-mcp.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { randomBytes } from "node:crypto";
|
|
3
3
|
|
|
4
|
-
import { createId } from "@agents-can-communicate/protocol";
|
|
4
|
+
import { EXIT, createId } from "@agents-can-communicate/protocol";
|
|
5
5
|
import { createCoordinationService } from "@agents-can-communicate/core";
|
|
6
6
|
import { openFilesystemStore } from "@agents-can-communicate/storage-filesystem";
|
|
7
7
|
import { createGitProbe, discoverWorkspace, platformDataHome, runtimePaths }
|
|
@@ -12,6 +12,18 @@ import { serve } from "@agents-can-communicate/mcp-server";
|
|
|
12
12
|
// randomness. The participant name comes from configuration, never from the
|
|
13
13
|
// client: the protocol says clientInfo is self-reported and must not drive
|
|
14
14
|
// behaviour, and the session is derived from this configuration alone.
|
|
15
|
+
// Nothing is read from the command line, so nothing may be passed on it. It
|
|
16
|
+
// used to accept and ignore anything: writing `acc-mcp --cwd <project>` - the
|
|
17
|
+
// habit `acc` teaches - started a server rooted wherever the client happened to
|
|
18
|
+
// launch it, alone in a workspace nobody else was in, with no warning at all.
|
|
19
|
+
if (process.argv.length > 2) {
|
|
20
|
+
process.stderr.write("acc-mcp takes no arguments. It is configured by environment:\n"
|
|
21
|
+
+ " ACC_MCP_PARTICIPANT who this server takes part as (default: mcp)\n"
|
|
22
|
+
+ " ACC_MCP_WORKSPACE the project it joins (default: the working directory)\n"
|
|
23
|
+
+ `refusing: ${process.argv.slice(2).join(" ")}\n`);
|
|
24
|
+
process.exit(EXIT.USAGE);
|
|
25
|
+
}
|
|
26
|
+
|
|
15
27
|
const participantId = process.env.ACC_MCP_PARTICIPANT ?? "mcp";
|
|
16
28
|
const clock = { now: () => new Date().toISOString() };
|
|
17
29
|
const ids = { next: kind => createId(kind, randomBytes) };
|
package/docs/CAPABILITIES.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Capabilities
|
|
2
2
|
|
|
3
|
+
Capability honesty is part of the product, not an implementation footnote. ACC coordinates
|
|
4
|
+
sessions it does not own, so the workspace can promise only what every session actually
|
|
5
|
+
exposes. One weaker participant lowers the reported protection level instead of inheriting
|
|
6
|
+
a stronger label from its peers.
|
|
7
|
+
|
|
3
8
|
What each harness was **observed** doing, on the versions named here. Nothing in this
|
|
4
9
|
table is inferred from documentation: every `yes` has a fixture captured from a real
|
|
5
10
|
session, and every `no` means it was not seen, not that it is impossible.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agents-can-communicate",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Coordinate this Codex session with other AI agent sessions working in the same workspace.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"keywords": ["coordination", "multi-agent", "claims", "handoff"],
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { cp, mkdir, readFile, rm, stat, writeFile } from "node:fs/promises";
|
|
1
|
+
import { cp, mkdir, readFile, rm, rmdir, stat, writeFile } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
|
|
@@ -11,22 +11,35 @@ import { AccError, EXIT } from "@agents-can-communicate/protocol";
|
|
|
11
11
|
const bundle = fileURLToPath(new URL("../plugin", import.meta.url));
|
|
12
12
|
const PLUGIN_NAME = "agents-can-communicate";
|
|
13
13
|
|
|
14
|
-
// The marketplace ACC owns
|
|
15
|
-
//
|
|
16
|
-
//
|
|
14
|
+
// The marketplace ACC owns, and its own root inside the agents home.
|
|
15
|
+
//
|
|
16
|
+
// Registering a separate one rather than joining the user's keeps the two
|
|
17
|
+
// apart. ACC used to write into `<home>/.agents/plugins/marketplace.json` -
|
|
18
|
+
// which is the marketplace this client discovers by itself, with no config
|
|
19
|
+
// entry at all, under whatever that manifest calls itself. So ACC merged its
|
|
20
|
+
// entry into someone else's marketplace and then enabled `…@acc-local`, an id
|
|
21
|
+
// this client never forms: `acc install` reported success and `codex plugin
|
|
22
|
+
// list` said `not installed`. Measured against Codex 0.147.0, then measured
|
|
23
|
+
// again to confirm a root of ACC's own is accepted and reported enabled.
|
|
17
24
|
const MARKETPLACE = "acc-local";
|
|
18
25
|
const QUALIFIED = `${PLUGIN_NAME}@${MARKETPLACE}`;
|
|
19
26
|
|
|
20
|
-
// A marketplace is a
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
// A marketplace is a root holding `.agents/plugins/marketplace.json`, and every
|
|
28
|
+
// `source.path` in that manifest - `./plugins/<name>` - is resolved by this
|
|
29
|
+
// client against the *root*, not against the manifest's directory. Measured:
|
|
30
|
+
// `codex plugin list` prints the path it resolved, and for a plugin the user
|
|
31
|
+
// installed themselves it printed `<root>/plugins/x` from an entry spelled
|
|
32
|
+
// `./plugins/x`. The comment that used to be here said the opposite, and ACC
|
|
33
|
+
// wrote its tree two directories below where the client then looked.
|
|
34
|
+
//
|
|
35
|
+
// The root is under `.agents/` rather than the home itself: `<home>/plugins/`
|
|
36
|
+
// is where this client would put it, and nothing of ACC's belongs at the top of
|
|
37
|
+
// somebody's home.
|
|
38
|
+
const marketplaceRoot = agentsHome => path.join(agentsHome, ".agents", MARKETPLACE);
|
|
39
|
+
const marketplacePath = agentsHome =>
|
|
40
|
+
path.join(marketplaceRoot(agentsHome), ".agents", "plugins", "marketplace.json");
|
|
41
|
+
const pluginPath = (agentsHome, name = PLUGIN_NAME) =>
|
|
42
|
+
path.join(marketplaceRoot(agentsHome), "plugins", name);
|
|
30
43
|
const configPath = codexHome => path.join(codexHome, "config.toml");
|
|
31
44
|
// Where `codex plugin add` leaves the copy it actually runs. All three
|
|
32
45
|
// components are ACC's own - the marketplace it created, the plugin name it
|
|
@@ -111,6 +124,11 @@ export async function installCodexPlugin({ home, agentsHome = home,
|
|
|
111
124
|
// plugin tree is laid down that nothing will then be able to remove.
|
|
112
125
|
const existing = await readJson(marketplacePath(agentsHome), { name: MARKETPLACE,
|
|
113
126
|
interface: { displayName: "Agents Can Communicate" }, plugins: [] });
|
|
127
|
+
// The name in the manifest, which is the one this client forms plugin ids
|
|
128
|
+
// from. ACC used its own regardless, so on a machine that already had a
|
|
129
|
+
// marketplace at this root - discovered without any config entry, under
|
|
130
|
+
// whatever its manifest calls itself - the id ACC enabled was one the client
|
|
131
|
+
// never forms, and the plugin sat there listed and not installed.
|
|
114
132
|
const before = await readFile(configPath(codexHome), "utf8").catch(() => "");
|
|
115
133
|
|
|
116
134
|
const target = pluginPath(agentsHome);
|
|
@@ -142,7 +160,7 @@ export async function installCodexPlugin({ home, agentsHome = home,
|
|
|
142
160
|
await writeTomlBlock(config, [
|
|
143
161
|
`[marketplaces.${MARKETPLACE}]`,
|
|
144
162
|
`source_type = "local"`,
|
|
145
|
-
`source = ${tomlString(agentsHome)}`,
|
|
163
|
+
`source = ${tomlString(marketplaceRoot(agentsHome))}`,
|
|
146
164
|
"",
|
|
147
165
|
`[plugins.${tomlString(QUALIFIED)}]`,
|
|
148
166
|
"enabled = true",
|
|
@@ -156,13 +174,26 @@ export async function installCodexPlugin({ home, agentsHome = home,
|
|
|
156
174
|
await rm(cached, { recursive: true, force: true });
|
|
157
175
|
await cp(target, cached, { recursive: true });
|
|
158
176
|
|
|
159
|
-
// The
|
|
160
|
-
//
|
|
177
|
+
// The plugin's own directory in the cache. Not the versioned one inside it,
|
|
178
|
+
// which goes stale the moment the version changes - and not the marketplace
|
|
179
|
+
// cache root above it, which belongs to whoever's marketplace this is: that
|
|
180
|
+
// root holds every plugin installed from it, and removing it took a plugin
|
|
181
|
+
// the user had installed themselves. Measured, on a real machine.
|
|
182
|
+
//
|
|
183
|
+
// The old comment here said the root was "what ACC owns", which was true only
|
|
184
|
+
// while ACC invented its own marketplace name and so had a root to itself.
|
|
161
185
|
// make the record stale the moment the plugin version changes.
|
|
162
|
-
return { ok: true, changes: [target, file, config,
|
|
186
|
+
return { ok: true, changes: [target, file, config, cachePath(codexHome)],
|
|
163
187
|
diagnostics: ["hooks require explicit trust in Codex before they run"] };
|
|
164
188
|
}
|
|
165
189
|
|
|
190
|
+
/** Remove each directory that is empty, in the order given. */
|
|
191
|
+
async function removeEmptyDirs(directories) {
|
|
192
|
+
for (const directory of directories) {
|
|
193
|
+
await rmdir(directory).catch(() => {});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
166
197
|
export async function uninstallCodexPlugin({ home, agentsHome = home,
|
|
167
198
|
codexHome = path.join(home, ".codex"), keep = [] }) {
|
|
168
199
|
const file = marketplacePath(agentsHome);
|
|
@@ -190,8 +221,20 @@ export async function uninstallCodexPlugin({ home, agentsHome = home,
|
|
|
190
221
|
return value?.name === MARKETPLACE && (value.plugins ?? []).length === 0;
|
|
191
222
|
} });
|
|
192
223
|
|
|
193
|
-
await removeInstalledTree(
|
|
224
|
+
await removeInstalledTree(cachePath(codexHome), keep);
|
|
194
225
|
await removeInstalledTree(pluginPath(agentsHome), keep);
|
|
226
|
+
// The directories ACC made to hold those, once nothing is in them. They are
|
|
227
|
+
// ACC's own - a marketplace root it created and the cache directory named
|
|
228
|
+
// after it - and an empty one left behind is litter in a home that did not
|
|
229
|
+
// have it. Anything the user put inside stops this: the directory is not
|
|
230
|
+
// empty, and it stays.
|
|
231
|
+
await removeEmptyDirs([
|
|
232
|
+
path.join(marketplaceRoot(agentsHome), "plugins"),
|
|
233
|
+
path.dirname(marketplacePath(agentsHome)),
|
|
234
|
+
path.dirname(path.dirname(marketplacePath(agentsHome))),
|
|
235
|
+
marketplaceRoot(agentsHome),
|
|
236
|
+
cacheRoot(codexHome),
|
|
237
|
+
]);
|
|
195
238
|
return { ok: true, changes, diagnostics: [] };
|
|
196
239
|
}
|
|
197
240
|
|
|
@@ -202,7 +245,8 @@ export async function detectCodex({ home, agentsHome = home,
|
|
|
202
245
|
const config = await readFile(configPath(codexHome), "utf8").catch(() => "");
|
|
203
246
|
const registered = config.includes(`[marketplaces.${MARKETPLACE}]`);
|
|
204
247
|
const enabled = config.includes(`[plugins."${QUALIFIED}"]`);
|
|
205
|
-
const cached = await stat(cachePath(codexHome))
|
|
248
|
+
const cached = await stat(cachePath(codexHome))
|
|
249
|
+
.then(() => true).catch(() => false);
|
|
206
250
|
return { ok: true, changes: [], diagnostics: [
|
|
207
251
|
published ? "acc plugin published in the marketplace" : "acc plugin not registered",
|
|
208
252
|
registered && enabled
|
|
@@ -228,7 +272,7 @@ export function planCodexInstall({ home, agentsHome = home,
|
|
|
228
272
|
codexHome = path.join(home, ".codex") }) {
|
|
229
273
|
return [
|
|
230
274
|
{ path: pluginPath(agentsHome), kind: "tree" },
|
|
231
|
-
{ path:
|
|
275
|
+
{ path: cachePath(codexHome), kind: "tree" },
|
|
232
276
|
{ path: marketplacePath(agentsHome), kind: "merge" },
|
|
233
277
|
{ path: configPath(codexHome), kind: "merge" },
|
|
234
278
|
];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agents-can-communicate",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Coordinate this Kimi Code session with other AI agent sessions working in the same workspace: shared presence, resource claims, typed messages, and handoffs.",
|
|
5
5
|
"skills": "./skills/",
|
|
6
6
|
"sessionStart": {
|
|
@@ -62,7 +62,7 @@ const DOCS = "https://github.com/automatis-tools/agents-can-communicate"
|
|
|
62
62
|
|
|
63
63
|
export function helpText() {
|
|
64
64
|
const width = Math.max(...Object.keys(COMMANDS).map(name => name.length)) + 4;
|
|
65
|
-
const lines = ["acc -
|
|
65
|
+
const lines = ["acc - coordinate the agent sessions you already opened", ""];
|
|
66
66
|
for (const { heading, commands } of describeCommands()) {
|
|
67
67
|
lines.push(heading);
|
|
68
68
|
for (const { name, summary } of commands) {
|
|
@@ -23,11 +23,24 @@ export function runtimePaths({ dataHome, workspaceId, workspaceRoots = [] }) {
|
|
|
23
23
|
// Enforced here rather than only asserted in a test, because "just put it in
|
|
24
24
|
// .agents next to the project" is the exact regression this design exists to
|
|
25
25
|
// prevent, and it would otherwise look like it works.
|
|
26
|
+
//
|
|
27
|
+
// The message names both paths and what to do, because the case a person
|
|
28
|
+
// actually meets is not the one this was written for. Running `acc` in a home
|
|
29
|
+
// directory makes that directory the workspace - it is no checkout, so
|
|
30
|
+
// discovery falls back to where you are - and the platform's own state
|
|
31
|
+
// directory is inside a home by definition. So `acc status` in `~` answered
|
|
32
|
+
// "runtime state must not live inside the workspace", which reads as a
|
|
33
|
+
// misconfiguration and tells the reader nothing they can act on.
|
|
26
34
|
for (const workspaceRoot of workspaceRoots) {
|
|
27
35
|
const relative = path.relative(workspaceRoot, root);
|
|
28
36
|
if (relative === "" || (!path.isAbsolute(relative) && !relative.startsWith(".."))) {
|
|
29
|
-
throw new AccError(EXIT.USAGE,
|
|
30
|
-
|
|
37
|
+
throw new AccError(EXIT.USAGE,
|
|
38
|
+
// The data home rather than the workspace's own directory inside it:
|
|
39
|
+
// that is the one a reader can move, and the one the remedy names.
|
|
40
|
+
`${workspaceRoot} holds ACC's own state at ${path.join(dataHome, "acc")}, `
|
|
41
|
+
+ "so it cannot be a workspace. Run acc inside a project, or point "
|
|
42
|
+
+ "ACC_DATA_HOME outside this directory.",
|
|
43
|
+
{ root, dataHome, workspaceRoot });
|
|
31
44
|
}
|
|
32
45
|
}
|
|
33
46
|
return Object.freeze(Object.fromEntries([["root", root],
|
package/package.json
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agents-can-communicate",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "
|
|
5
|
+
"description": "Local-first coordination for independently opened AI agent sessions.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"agents",
|
|
8
8
|
"coordination",
|
|
9
|
+
"local-first",
|
|
10
|
+
"agent-handoff",
|
|
9
11
|
"mcp",
|
|
10
12
|
"hooks",
|
|
11
13
|
"codex",
|