agents-can-communicate 0.1.15 → 0.1.17

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 (19) hide show
  1. package/node_modules/@agents-can-communicate/adapter-claude-code/package.json +1 -1
  2. package/node_modules/@agents-can-communicate/adapter-claude-code/plugin/skills/acc/SKILL.md +7 -3
  3. package/node_modules/@agents-can-communicate/adapter-codex/package.json +1 -1
  4. package/node_modules/@agents-can-communicate/adapter-codex/plugin/skills/acc/SKILL.md +7 -3
  5. package/node_modules/@agents-can-communicate/adapter-gemini-cli/extension/skills/acc/SKILL.md +7 -3
  6. package/node_modules/@agents-can-communicate/adapter-gemini-cli/package.json +1 -1
  7. package/node_modules/@agents-can-communicate/adapter-kimi/package.json +1 -1
  8. package/node_modules/@agents-can-communicate/adapter-kimi/plugin/skills/acc/SKILL.md +7 -3
  9. package/node_modules/@agents-can-communicate/adapter-sdk/package.json +1 -1
  10. package/node_modules/@agents-can-communicate/adapter-sdk/src/context-projector.mjs +57 -17
  11. package/node_modules/@agents-can-communicate/cli/package.json +1 -1
  12. package/node_modules/@agents-can-communicate/cli/src/doctor-command.mjs +15 -3
  13. package/node_modules/@agents-can-communicate/core/package.json +1 -1
  14. package/node_modules/@agents-can-communicate/hook-runner/package.json +1 -1
  15. package/node_modules/@agents-can-communicate/installer/package.json +1 -1
  16. package/node_modules/@agents-can-communicate/mcp-server/package.json +1 -1
  17. package/node_modules/@agents-can-communicate/protocol/package.json +1 -1
  18. package/node_modules/@agents-can-communicate/storage-filesystem/package.json +1 -1
  19. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/adapter-claude-code",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -73,14 +73,18 @@ to the command that answers it:
73
73
  - [request_stalled] message_x you asked and nobody is there -> ask someone else
74
74
  ```
75
75
 
76
- A turn is written to a byte budget, so it can end with
76
+ A turn is written to a byte budget, so it can end with one of these:
77
77
 
78
78
  ```text
79
79
  - +2 not shown, over budget; read them with `acc sync --scope full --json`
80
+ - ⚠ 1 message(s) addressed to you did not fit; run `acc sync --scope full --json`
80
81
  ```
81
82
 
82
- Run that. Two things were addressed to you and the turn had no room for them; they are
83
- not gone, and nobody will repeat them.
83
+ Run the sync. Both mean something addressed to you had no room this turn; it is not gone,
84
+ and nobody will repeat it. The `⚠` line is the one that has cost the most - a peer's
85
+ message, sometimes the very decision that unblocks you, held behind a reminder about your
86
+ own lapsed claim. When you see it, pull before anything else. And never tell your human you
87
+ are blocked on a peer without pulling first: the answer may already be queued.
84
88
 
85
89
  ## Work someone asked of you
86
90
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/adapter-codex",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -73,14 +73,18 @@ to the command that answers it:
73
73
  - [request_stalled] message_x you asked and nobody is there -> ask someone else
74
74
  ```
75
75
 
76
- A turn is written to a byte budget, so it can end with
76
+ A turn is written to a byte budget, so it can end with one of these:
77
77
 
78
78
  ```text
79
79
  - +2 not shown, over budget; read them with `acc sync --scope full --json`
80
+ - ⚠ 1 message(s) addressed to you did not fit; run `acc sync --scope full --json`
80
81
  ```
81
82
 
82
- Run that. Two things were addressed to you and the turn had no room for them; they are
83
- not gone, and nobody will repeat them.
83
+ Run the sync. Both mean something addressed to you had no room this turn; it is not gone,
84
+ and nobody will repeat it. The `⚠` line is the one that has cost the most - a peer's
85
+ message, sometimes the very decision that unblocks you, held behind a reminder about your
86
+ own lapsed claim. When you see it, pull before anything else. And never tell your human you
87
+ are blocked on a peer without pulling first: the answer may already be queued.
84
88
 
85
89
  ## Work someone asked of you
86
90
 
@@ -73,14 +73,18 @@ to the command that answers it:
73
73
  - [request_stalled] message_x you asked and nobody is there -> ask someone else
74
74
  ```
75
75
 
76
- A turn is written to a byte budget, so it can end with
76
+ A turn is written to a byte budget, so it can end with one of these:
77
77
 
78
78
  ```text
79
79
  - +2 not shown, over budget; read them with `acc sync --scope full --json`
80
+ - ⚠ 1 message(s) addressed to you did not fit; run `acc sync --scope full --json`
80
81
  ```
81
82
 
82
- Run that. Two things were addressed to you and the turn had no room for them; they are
83
- not gone, and nobody will repeat them.
83
+ Run the sync. Both mean something addressed to you had no room this turn; it is not gone,
84
+ and nobody will repeat it. The `⚠` line is the one that has cost the most - a peer's
85
+ message, sometimes the very decision that unblocks you, held behind a reminder about your
86
+ own lapsed claim. When you see it, pull before anything else. And never tell your human you
87
+ are blocked on a peer without pulling first: the answer may already be queued.
84
88
 
85
89
  ## Work someone asked of you
86
90
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/adapter-gemini-cli",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/adapter-kimi",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -73,14 +73,18 @@ to the command that answers it:
73
73
  - [request_stalled] message_x you asked and nobody is there -> ask someone else
74
74
  ```
75
75
 
76
- A turn is written to a byte budget, so it can end with
76
+ A turn is written to a byte budget, so it can end with one of these:
77
77
 
78
78
  ```text
79
79
  - +2 not shown, over budget; read them with `acc sync --scope full --json`
80
+ - ⚠ 1 message(s) addressed to you did not fit; run `acc sync --scope full --json`
80
81
  ```
81
82
 
82
- Run that. Two things were addressed to you and the turn had no room for them; they are
83
- not gone, and nobody will repeat them.
83
+ Run the sync. Both mean something addressed to you had no room this turn; it is not gone,
84
+ and nobody will repeat it. The `⚠` line is the one that has cost the most - a peer's
85
+ message, sometimes the very decision that unblocks you, held behind a reminder about your
86
+ own lapsed claim. When you see it, pull before anything else. And never tell your human you
87
+ are blocked on a peer without pulling first: the answer may already be queued.
84
88
 
85
89
  ## Work someone asked of you
86
90
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/adapter-sdk",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -6,7 +6,10 @@ const DEFAULT_BUDGET_BYTES = 6_000;
6
6
  // said only that something had been withheld, and nothing anywhere - not the
7
7
  // skills, not the docs - said how to see it. A turn that reports a thing the
8
8
  // reader cannot reach is how an agent ends up inventing its own way in.
9
- const NOTE_RESERVE = 80;
9
+ // Enough for the longest over-budget note - the escalated "message did not fit"
10
+ // line, which is longer than the plain "+N not shown" it replaces. Kept small
11
+ // enough that the note still fits beside a header at the smallest budgets.
12
+ const NOTE_RESERVE = 90;
10
13
  const FENCE = "```";
11
14
  // A peer cannot close a block it cannot name. The fence carries a marker that
12
15
  // is stripped from peer content, so forged delimiters stay inside the block.
@@ -167,11 +170,24 @@ export function projectContext(sync, { budgetBytes = DEFAULT_BUDGET_BYTES } = {}
167
170
  const claims = sync.claims ?? [];
168
171
 
169
172
  // Every entry is a group that appears whole or not at all. Single-line groups
170
- // may still be truncated - there is no fence in them to leave open.
173
+ // may still be truncated - there is no fence in them to leave open. `message`
174
+ // is carried so a dropped message can be counted apart from a dropped
175
+ // reminder: the two are not the same news.
176
+ //
177
+ // A peer message sits after "act now" attention (a direct request, an imminent
178
+ // conflict: priority <= 2) and ahead of standing reminders. The order is the
179
+ // fix for a real starvation: an expired-claim line (priority 6) regenerates
180
+ // from state every turn, while a message is delivered once and its receipt
181
+ // then stops it appearing - so a reminder that never clears must not keep
182
+ // pushing a one-time message into the over-budget overflow, turn after turn,
183
+ // where two agents each lost their most important message to it.
184
+ const urgent = attention.filter(item => item.priority <= 2);
185
+ const info = attention.filter(item => item.priority > 2);
171
186
  const required = [
172
- ...attentionLines(attention).map(line => [line]),
173
- ...claimLines(claims).map(line => [line]),
174
- ...peerBlocks(messages),
187
+ ...attentionLines(urgent).map(line => ({ lines: [line], message: false })),
188
+ ...peerBlocks(messages).map(block => ({ lines: block, message: true })),
189
+ ...attentionLines(info).map(line => ({ lines: [line], message: false })),
190
+ ...claimLines(claims).map(line => ({ lines: [line], message: false })),
175
191
  ];
176
192
  // Solo costs nothing: a lone session pays no visible price, and "no peers" is
177
193
  // still a cost when injected into every turn. But this is decided after the
@@ -198,27 +214,51 @@ export function projectContext(sync, { budgetBytes = DEFAULT_BUDGET_BYTES } = {}
198
214
  // Reserved so the note below always fits. Without it the projection could run
199
215
  // out of room to say that it ran out of room.
200
216
  const ceiling = budgetBytes - NOTE_RESERVE;
201
- let dropped = 0;
217
+ let droppedOther = 0;
218
+ let droppedMessages = 0;
219
+ const drop = group => { if (group.message) droppedMessages += 1; else droppedOther += 1; };
202
220
  for (const group of required) {
203
- if (group.length === 1) {
204
- const candidate = truncate(group[0], Math.max(0, ceiling - used - 1));
205
- if (candidate === "" || used + bytes(candidate) + 1 > ceiling) { dropped += 1; continue; }
221
+ const block = group.lines;
222
+ if (block.length === 1) {
223
+ const candidate = truncate(block[0], Math.max(0, ceiling - used - 1));
224
+ if (candidate === "" || used + bytes(candidate) + 1 > ceiling) { drop(group); continue; }
206
225
  lines.push(candidate);
207
226
  used += bytes(candidate) + 1;
208
227
  continue;
209
228
  }
210
- const size = group.reduce((total, line) => total + bytes(line) + 1, 0);
229
+ const size = block.reduce((total, line) => total + bytes(line) + 1, 0);
211
230
  // Skipped rather than stopped at: the groups are ordered by priority, and a
212
231
  // large message must not hide the shorter ones behind it.
213
- if (used + size > ceiling) { dropped += 1; continue; }
214
- lines.push(...group);
232
+ if (used + size > ceiling) { drop(group); continue; }
233
+ lines.push(...block);
215
234
  used += size;
216
235
  }
217
- if (dropped > 0) {
218
- const note = `- +${dropped} not shown, over budget; read them with `
219
- + "`acc sync --scope full --json`";
220
- lines.push(note);
221
- used += bytes(note) + 1;
236
+ // A dropped message is louder than a dropped reminder: "+N not shown" read as
237
+ // noise to two agents who each lost their most important message to it, so a
238
+ // message that did not fit says so specifically and names the command that
239
+ // recovers it. One note either way, escalated when a message is among the loss.
240
+ // The note is guarded against the budget, not merely reserved for: at a
241
+ // pathologically small budget the header alone can leave less room than the
242
+ // note needs, and a projection that overran the very budget it exists to
243
+ // respect is the bug this whole function is careful about. If the full note
244
+ // will not fit, the shortest imperative that does is still not silence.
245
+ const pushNote = note => {
246
+ const short = "- ⚠ over budget; `acc sync --scope full --json`";
247
+ for (const candidate of [note, short]) {
248
+ if (used + bytes(candidate) + 1 <= budgetBytes) {
249
+ lines.push(candidate);
250
+ used += bytes(candidate) + 1;
251
+ return;
252
+ }
253
+ }
254
+ };
255
+ if (droppedMessages > 0) {
256
+ // No count of the other drops: `--scope full` recovers everything.
257
+ pushNote(`- ⚠ ${droppedMessages} message(s) addressed to you did not fit; `
258
+ + "run `acc sync --scope full --json`");
259
+ } else if (droppedOther > 0) {
260
+ pushNote(`- +${droppedOther} not shown, over budget; read them with `
261
+ + "`acc sync --scope full --json`");
222
262
  }
223
263
 
224
264
  let shown = 0;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/cli",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -134,10 +134,18 @@ async function diagnoseAdapters({ options, runtime }) {
134
134
  // trust prompt, most of all. It goes where a person reads, not into --json.
135
135
  remediation.push(...(entry.needsAction ?? []));
136
136
  const installed = record.installs.find(one => one.adapterId === entry.adapterId);
137
- const stale = staleInstall({ recorded: installed?.accVersion ?? null, running });
137
+ const bundleVersion = installed?.accVersion ?? null;
138
+ const stale = staleInstall({ recorded: bundleVersion, running });
138
139
  if (stale !== null) {
140
+ // Names the skills and manifests, not "the plugin". Updating the npm
141
+ // package replaces the CLI and the hook runtime the client's shim points
142
+ // at, so the runner can already be current - `wired` says whether it is -
143
+ // while the skills and manifests copied into the client stay at whatever
144
+ // acc last ran `acc install`. Calling the whole plugin stale reads as a
145
+ // stale runtime and contradicts a `wired` that says otherwise.
139
146
  remediation.push(`acc install --adapter ${entry.adapterId}`
140
- + ` # plugin is ${stale.recorded}, acc is ${stale.running}`);
147
+ + ` # skills and manifests here are from ${stale.recorded}, acc is ${stale.running}`
148
+ + ` - reinstall to refresh the bundle`);
141
149
  }
142
150
  // Read from the wiring rather than from the record. An ACC old enough not to
143
151
  // know the record's version field still rewrites that record - blank - while
@@ -149,7 +157,11 @@ async function diagnoseAdapters({ options, runtime }) {
149
157
  remediation.push(`acc install --adapter ${entry.adapterId}`
150
158
  + ` # wired to acc ${wired}, this is ${running}`);
151
159
  }
152
- return { ...entry, stale, wired, owned: { modified: owned.modified,
160
+ // `wired` is the version of the runner the client executes; `bundleVersion`
161
+ // is the acc that copied the skills and manifests into it. They diverge after
162
+ // an npm upgrade with no `acc install`, and reporting both is what makes the
163
+ // divergence legible rather than hidden behind a single reassuring number.
164
+ return { ...entry, stale, wired, bundleVersion, owned: { modified: owned.modified,
153
165
  missing: owned.missing, intact: owned.intact.length }, remediation };
154
166
  }));
155
167
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/core",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/hook-runner",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/installer",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": { ".": "./src/index.mjs" },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/mcp-server",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/protocol",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/storage-filesystem",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agents-can-communicate",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "type": "module",
5
5
  "description": "Local-first coordination for independently opened AI agent sessions.",
6
6
  "keywords": [