agents-can-communicate 0.10.4 → 0.11.1

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 (98) hide show
  1. package/README.md +29 -21
  2. package/bin/acc-indicator.mjs +5 -0
  3. package/bin/entrypoints/acc-antigravity-relay.mjs +2 -2
  4. package/bin/entrypoints/acc-hook.mjs +4 -24
  5. package/bin/entrypoints/acc-mcp.mjs +8 -6
  6. package/bin/entrypoints/acc.mjs +22 -11
  7. package/bin/entrypoints/antigravity-relay-binding.mjs +1 -1
  8. package/docs/CAPABILITIES.md +3 -0
  9. package/docs/CLI.md +34 -7
  10. package/docs/MCP.md +42 -2
  11. package/docs/PROTOCOL.md +19 -0
  12. package/docs/STATUS_INDICATOR.md +133 -0
  13. package/docs/TROUBLESHOOTING.md +2 -2
  14. package/docs/WHY_ACC.md +14 -8
  15. package/node_modules/@agents-can-communicate/adapter-antigravity/package.json +1 -1
  16. package/node_modules/@agents-can-communicate/adapter-antigravity/plugin/plugin.json +1 -1
  17. package/node_modules/@agents-can-communicate/adapter-antigravity/plugin/skills/acc/SKILL.md +29 -5
  18. package/node_modules/@agents-can-communicate/adapter-antigravity/src/adapter.mjs +3 -0
  19. package/node_modules/@agents-can-communicate/adapter-antigravity/src/indicator-install.mjs +80 -0
  20. package/node_modules/@agents-can-communicate/adapter-antigravity/src/indicator-render.mjs +8 -0
  21. package/node_modules/@agents-can-communicate/adapter-antigravity/src/install.mjs +7 -4
  22. package/node_modules/@agents-can-communicate/adapter-claude-code/package.json +1 -1
  23. package/node_modules/@agents-can-communicate/adapter-claude-code/plugin/hooks/indicator.mjs +83 -0
  24. package/node_modules/@agents-can-communicate/adapter-claude-code/plugin/skills/acc/SKILL.md +29 -5
  25. package/node_modules/@agents-can-communicate/adapter-claude-code/src/adapter.mjs +1 -0
  26. package/node_modules/@agents-can-communicate/adapter-claude-code/src/install.mjs +16 -5
  27. package/node_modules/@agents-can-communicate/adapter-codex/package.json +1 -1
  28. package/node_modules/@agents-can-communicate/adapter-codex/plugin/skills/acc/SKILL.md +29 -5
  29. package/node_modules/@agents-can-communicate/adapter-gemini-cli/extension/gemini-extension.json +1 -1
  30. package/node_modules/@agents-can-communicate/adapter-gemini-cli/extension/skills/acc/SKILL.md +29 -5
  31. package/node_modules/@agents-can-communicate/adapter-gemini-cli/package.json +1 -1
  32. package/node_modules/@agents-can-communicate/adapter-grok/package.json +1 -1
  33. package/node_modules/@agents-can-communicate/adapter-grok/plugin/skills/acc/SKILL.md +29 -5
  34. package/node_modules/@agents-can-communicate/adapter-grok/src/adapter.mjs +4 -0
  35. package/node_modules/@agents-can-communicate/adapter-grok/src/indicator-install.mjs +30 -0
  36. package/node_modules/@agents-can-communicate/adapter-grok/src/indicator.mjs +23 -0
  37. package/node_modules/@agents-can-communicate/adapter-grok/src/install.mjs +9 -5
  38. package/node_modules/@agents-can-communicate/adapter-kimi/package.json +1 -1
  39. package/node_modules/@agents-can-communicate/adapter-kimi/plugin/skills/acc/SKILL.md +29 -5
  40. package/node_modules/@agents-can-communicate/adapter-kimi/src/adapter.mjs +4 -0
  41. package/node_modules/@agents-can-communicate/adapter-kimi/src/indicator-install.mjs +30 -0
  42. package/node_modules/@agents-can-communicate/adapter-kimi/src/indicator.mjs +17 -0
  43. package/node_modules/@agents-can-communicate/adapter-kimi/src/install.mjs +12 -6
  44. package/node_modules/@agents-can-communicate/adapter-sdk/package.json +1 -1
  45. package/node_modules/@agents-can-communicate/adapter-sdk/src/hook-shim.mjs +1 -0
  46. package/node_modules/@agents-can-communicate/adapter-sdk/src/index.mjs +5 -1
  47. package/node_modules/@agents-can-communicate/adapter-sdk/src/indicator-command.mjs +14 -0
  48. package/node_modules/@agents-can-communicate/adapter-sdk/src/indicator-text.mjs +13 -0
  49. package/node_modules/@agents-can-communicate/adapter-sdk/src/native-attempt-writer.mjs +1 -1
  50. package/node_modules/@agents-can-communicate/adapter-sdk/src/offer-observation-order.mjs +12 -0
  51. package/node_modules/@agents-can-communicate/adapter-sdk/src/offer-observation-writer.mjs +37 -0
  52. package/node_modules/@agents-can-communicate/adapter-sdk/src/offer-observation.mjs +47 -0
  53. package/node_modules/@agents-can-communicate/adapter-sdk/src/process-table.mjs +40 -27
  54. package/node_modules/@agents-can-communicate/adapter-sdk/src/toml-indicator.mjs +141 -0
  55. package/node_modules/@agents-can-communicate/adapter-sdk/src/toml-scan.mjs +99 -0
  56. package/node_modules/@agents-can-communicate/cli/package.json +8 -1
  57. package/node_modules/@agents-can-communicate/cli/src/adapter-catalog.mjs +33 -0
  58. package/node_modules/@agents-can-communicate/cli/src/args.mjs +5 -3
  59. package/node_modules/@agents-can-communicate/cli/src/claim-command.mjs +64 -0
  60. package/node_modules/@agents-can-communicate/cli/src/help.mjs +17 -11
  61. package/node_modules/@agents-can-communicate/cli/src/index.mjs +1 -0
  62. package/node_modules/@agents-can-communicate/cli/src/indicator-command.mjs +65 -0
  63. package/node_modules/@agents-can-communicate/cli/src/indicator-previous-command.mjs +84 -0
  64. package/node_modules/@agents-can-communicate/cli/src/indicator-previous-windows.mjs +8 -0
  65. package/node_modules/@agents-can-communicate/cli/src/indicator.mjs +112 -0
  66. package/node_modules/@agents-can-communicate/cli/src/install-command.mjs +4 -0
  67. package/node_modules/@agents-can-communicate/cli/src/main.mjs +38 -110
  68. package/node_modules/@agents-can-communicate/cli/src/managed-runtime/entry.mjs +19 -0
  69. package/node_modules/@agents-can-communicate/cli/src/managed-runtime/launchers.mjs +5 -3
  70. package/node_modules/@agents-can-communicate/cli/src/native-session-diagnostics.mjs +1 -1
  71. package/node_modules/@agents-can-communicate/cli/src/recorded-text.mjs +32 -0
  72. package/node_modules/@agents-can-communicate/core/package.json +1 -1
  73. package/node_modules/@agents-can-communicate/core/src/claim-selectors.mjs +62 -0
  74. package/node_modules/@agents-can-communicate/core/src/claims.mjs +88 -81
  75. package/node_modules/@agents-can-communicate/core/src/next-turn-delivery.mjs +2 -1
  76. package/node_modules/@agents-can-communicate/core/src/sessions.mjs +5 -2
  77. package/node_modules/@agents-can-communicate/core/src/sync.mjs +2 -1
  78. package/node_modules/@agents-can-communicate/delivery-router/package.json +1 -1
  79. package/node_modules/@agents-can-communicate/delivery-router/src/router.mjs +19 -7
  80. package/node_modules/@agents-can-communicate/hook-runner/package.json +1 -1
  81. package/node_modules/@agents-can-communicate/hook-runner/src/client-pid.mjs +23 -11
  82. package/node_modules/@agents-can-communicate/hook-runner/src/runner.mjs +66 -26
  83. package/node_modules/@agents-can-communicate/installer/package.json +3 -2
  84. package/node_modules/@agents-can-communicate/installer/src/apply.mjs +3 -0
  85. package/node_modules/@agents-can-communicate/installer/src/ownership.mjs +2 -1
  86. package/node_modules/@agents-can-communicate/installer/src/plan.mjs +11 -2
  87. package/node_modules/@agents-can-communicate/mcp-server/package.json +1 -1
  88. package/node_modules/@agents-can-communicate/mcp-server/src/claim-tools.mjs +56 -0
  89. package/node_modules/@agents-can-communicate/mcp-server/src/input-validator.mjs +9 -0
  90. package/node_modules/@agents-can-communicate/mcp-server/src/server.mjs +7 -8
  91. package/node_modules/@agents-can-communicate/mcp-server/src/tools.mjs +27 -9
  92. package/node_modules/@agents-can-communicate/protocol/package.json +1 -1
  93. package/node_modules/@agents-can-communicate/protocol/src/index.mjs +1 -0
  94. package/node_modules/@agents-can-communicate/storage-filesystem/package.json +3 -2
  95. package/node_modules/@agents-can-communicate/storage-filesystem/src/index.mjs +1 -1
  96. package/node_modules/@agents-can-communicate/storage-filesystem/src/session-read.mjs +13 -0
  97. package/node_modules/@agents-can-communicate/storage-filesystem/src/state-reads.mjs +24 -7
  98. package/package.json +3 -1
@@ -64,19 +64,43 @@ Do this once, not every turn. Update it only when the scope or mode materially
64
64
  changes. `--hint` is important: it lets ACC match your plan against a peer's
65
65
  claim. Intent is awareness, not permission.
66
66
 
67
- Before changing shared files, claim the smallest useful resource:
67
+ Before changing shared files, claim the smallest useful resources in one operation:
68
68
 
69
69
  ```bash
70
- {{ACC}} claim --resource 'file:packages/core/**' --reason "porting the store"
70
+ {{ACC}} claim --resource 'file:packages/core/**' \
71
+ --resource 'file:packages/protocol/**' --reason "porting the claim model"
71
72
  ```
72
73
 
73
- Exit 5 means a conflict. Do not work around it silently. Narrow your scope,
74
- contact the owner, or ask the human. Give a claim back explicitly when useful:
74
+ Repeat `--resource` for an atomic batch, or supply it once for one claim.
75
+ Shared mode, enforcement, reason, and lease apply to every resource. Duplicate resources after
76
+ normalization are rejected. Exit 5 means a conflict: no claim is created or
77
+ renewed. Batch `details.conflicts` names blocked resources and their holders.
78
+ Narrow your scope, contact the owner, or ask the human. Repeating a successful
79
+ claim command renews your existing claims on those resources.
80
+
81
+ Release selected claims when useful:
75
82
 
76
83
  ```bash
77
- {{ACC}} release --resource 'file:packages/core/**'
84
+ {{ACC}} release --resource 'file:packages/core/**' \
85
+ --resource 'file:packages/protocol/**'
78
86
  ```
79
87
 
88
+ Choose exactly one selector family: repeated `--resource`, repeated `--claim`,
89
+ or `--all`. Duplicate selectors after normalization are rejected. A missing or
90
+ foreign explicit target fails without releasing any claims. Repeating an explicit release after its targets were removed is an error.
91
+ Batch release accepts no force-release authority.
92
+
93
+ To release all your claims while keeping your session and intent open:
94
+
95
+ ```bash
96
+ {{ACC}} release --all
97
+ ```
98
+
99
+ This selects only your session's current claims in its workspace. An empty set
100
+ succeeds. Each retry selects the current set and can release newly acquired claims.
101
+ Use `work --clear` to clear intent, `ack` to acknowledge a message, and `finish`
102
+ to record a handoff and close your ACC presence.
103
+
80
104
  ## Communicate only when it changes another agent's work
81
105
 
82
106
  Send a message for a dependency, conflict, direct question, decision, or
@@ -10,6 +10,7 @@ import { detectAntigravity, doctorAntigravity, installAntigravity, planAntigravi
10
10
  import { bindNativeSession, nativeActivationHint, offerMessage, planNativeActivation,
11
11
  probeNativeDelivery, refreshNativeSession } from "./native-delivery.mjs";
12
12
  import { PROTOCOL_CONTRACT } from "./relay-endpoint.mjs";
13
+ import { renderAntigravityIndicator } from "./indicator-render.mjs";
13
14
 
14
15
  // The version this client has been captured on. Nothing earlier was measured,
15
16
  // and later releases - this client ships every few days - are judged by this
@@ -63,6 +64,8 @@ export function createAntigravityAdapter() {
63
64
  return defineAdapter({
64
65
  id: "antigravity",
65
66
  displayName: "Antigravity CLI",
67
+ statusIndicator: { minimumVersion: "1.0.6", reload: "start a new CLI session",
68
+ renderText: renderAntigravityIndicator },
66
69
  // What the official installer puts on PATH, and what a version probe has to
67
70
  // spawn: `agy --version` answers `1.2.7`. Presence liveness also walks the
68
71
  // hook's process ancestry for this basename to learn the client's own pid.
@@ -0,0 +1,80 @@
1
+ import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { defaultIndicator, shellQuote, shortPath, windowsHookCommand, writeForeignJson }
4
+ from "@agents-can-communicate/adapter-sdk";
5
+ import { agySettingsPath } from "./allow-rule.mjs";
6
+
7
+ const io = { readFile, writeFile, mkdir };
8
+ const load = async file => {
9
+ try { return JSON.parse(await readFile(file, "utf8")); }
10
+ catch (error) { if (error.code === "ENOENT") return null; throw error; }
11
+ };
12
+ const markerPath = ({ dataHome, home }) => path.join(dataHome ?? path.join(home, ".gemini", "config"),
13
+ "acc", "adapter-antigravity", "indicator.json");
14
+
15
+ /** Own only the wrapper command and the fields ACC actually changed. A later
16
+ * user edit wins; the original status line is restored only where still ours. */
17
+ export async function configureIndicator(context, enabled) {
18
+ const file = agySettingsPath(context.home), marker = markerPath(context);
19
+ const saved = await load(marker);
20
+ if (!enabled && !saved) return [];
21
+ const existing = await load(file);
22
+ if (saved && (saved.schemaVersion !== 1 || typeof saved.installed?.command !== "string"
23
+ || !Array.isArray(saved.owned) || !saved.owned.every(key => typeof key === "string"))) {
24
+ throw new Error("ACC status-line ownership is invalid; keep the user's settings and run acc doctor");
25
+ }
26
+ if (!enabled) {
27
+ if (!saved) return [];
28
+ if (existing?.statusLine?.command === saved.installed.command) {
29
+ const current = { ...existing.statusLine };
30
+ for (const key of saved.owned) {
31
+ const value = saved.installed[key];
32
+ if (JSON.stringify(current[key]) !== JSON.stringify(value)) continue;
33
+ if (Object.hasOwn(saved.previous ?? {}, key)) current[key] = saved.previous[key];
34
+ else delete current[key];
35
+ }
36
+ const next = { ...existing };
37
+ if (Object.keys(current).length) next.statusLine = current;
38
+ else if (saved.previous !== null) next.statusLine = saved.previous;
39
+ else delete next.statusLine;
40
+ if (saved.createdFile && Object.keys(next).length === 0) await rm(file, { force: true });
41
+ else await writeForeignJson(file, next, io);
42
+ }
43
+ await rm(marker, { force: true });
44
+ return [file];
45
+ }
46
+ const ours = saved && existing?.statusLine?.command === saved.installed.command;
47
+ // Keep the marker after a user replacement or removal, so later updates do
48
+ // not mistake it for a first install. Explicit disable clears this history.
49
+ if (saved && !ours) return [];
50
+ const previous = ours ? saved.previous : existing?.statusLine ?? null;
51
+ if (previous !== null && (previous.type !== "command" || typeof previous.command !== "string")) {
52
+ throw new Error("ACC cannot compose this statusLine type; keep it and configure the indicator manually");
53
+ }
54
+ const node = context.node ?? process.execPath;
55
+ const indicator = context.indicatorRunner ?? defaultIndicator();
56
+ // Each path is one shell argument. The user's old shell program stays in a
57
+ // JSON record; interpolating it into this command would change its quoting.
58
+ let command;
59
+ if ((context.hostPlatform ?? process.platform) === "win32") {
60
+ const shim = path.join(context.home, ".gemini", "config", "acc", "indicator.mjs");
61
+ await mkdir(path.dirname(shim), { recursive: true });
62
+ await writeFile(shim, `import { spawnSync } from "node:child_process";\n`
63
+ + `const child = spawnSync(${JSON.stringify(node)}, ${JSON.stringify([indicator,
64
+ "--adapter", "antigravity", "--previous", marker])}, {stdio:"inherit",windowsHide:true});\n`
65
+ + `process.exitCode = child.status ?? 0;\n`);
66
+ command = windowsHookCommand("unquoted", { node, shim: await shortPath(shim), args: [] }).trimEnd();
67
+ } else command = [node, indicator, "--adapter", "antigravity", "--previous", marker]
68
+ .map(shellQuote).join(" ");
69
+ const installed = ours ? { ...existing.statusLine, command }
70
+ : { ...previous, type: "command", command, enabled: true,
71
+ stack_with_default: previous?.stack_with_default ?? true };
72
+ const owned = ours ? saved.owned.filter(key =>
73
+ JSON.stringify(existing.statusLine[key]) === JSON.stringify(saved.installed[key]))
74
+ : Object.keys(installed).filter(key => JSON.stringify(installed[key]) !== JSON.stringify(previous?.[key]));
75
+ await mkdir(path.dirname(marker), { recursive: true });
76
+ await writeFile(marker, JSON.stringify({ schemaVersion: 1, previous, installed, owned,
77
+ createdFile: saved?.createdFile ?? existing === null }) + "\n");
78
+ await writeForeignJson(file, { ...existing, statusLine: installed }, io);
79
+ return [file];
80
+ }
@@ -0,0 +1,8 @@
1
+ // Antigravity consumes ANSI from a command whose stdout is a pipe, not a TTY.
2
+ // Foreground and intensity affect only the glyph. Never set a background.
3
+ export function renderAntigravityIndicator(report) {
4
+ const rgb = report.health === "ready" ? "44;122;57"
5
+ : report.health === "problem" ? "150;108;30" : "102;102;102";
6
+ return report.label.replace(/^ACC ([●!…])/u,
7
+ (_, glyph) => `ACC \x1b[22;1;38;2;${rgb}m${glyph}\x1b[22;39m`);
8
+ }
@@ -5,7 +5,7 @@ import path from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import { promisify } from "node:util";
7
7
 
8
- import { bakeSkillCommand, blankJson, defaultAntigravityRelay, isShellWord, mergeEnv, ownVersion,
8
+ import { bakeSkillCommand, blankJson, compareVersionOrder, versionOrder, defaultAntigravityRelay, isShellWord, mergeEnv, ownVersion,
9
9
  removeIfEmpty, shellQuote, shortPath, stampPluginVersion, windowsHookCommand, writeCliShim,
10
10
  writeForeignJson, writeHookShim, writeNodeShim }
11
11
  from "@agents-can-communicate/adapter-sdk";
@@ -15,6 +15,7 @@ import { agySettingsPath, cliWrapperPath, ensureAllowRule, inspectAllowRule, ins
15
15
  withdrawAllowRule } from "./allow-rule.mjs";
16
16
  import { ensureDesktopRule, inspectDesktopRule, withdrawDesktopRule } from "./desktop-allow-rule.mjs";
17
17
  import { relayShimName, relayStartCommand, runningRelays, stopRelays } from "./relays.mjs";
18
+ import { configureIndicator } from "./indicator-install.mjs";
18
19
 
19
20
  const run = promisify(execFile);
20
21
 
@@ -425,8 +426,10 @@ export async function installAntigravity(context) {
425
426
  const allow = await ensureAllowRule(context);
426
427
  // Antigravity 2.0 keeps grants of its own, read only where it has run.
427
428
  const desktop = await ensureDesktopRule(context);
429
+ const indicatorChanges = await configureIndicator(context, context.indicator === "on"
430
+ && compareVersionOrder(versionOrder(context.clientVersion), versionOrder("1.0.6")) >= 0);
428
431
  const changes = [shimDir(home), file, pluginInstallPath(home), vendorManifestPath(home),
429
- ...allow.changes, ...desktop.changes];
432
+ ...allow.changes, ...desktop.changes, ...indicatorChanges];
430
433
 
431
434
  const diagnostics = [...allow.diagnostics, ...desktop.diagnostics];
432
435
  const needsAction = [...allow.needsAction, ...desktop.needsAction];
@@ -495,7 +498,7 @@ export async function installAntigravity(context) {
495
498
  */
496
499
  export async function uninstallAntigravity(context) {
497
500
  const { home, keep = [] } = context;
498
- const changes = [];
501
+ const changes = await configureIndicator(context, false);
499
502
  const diagnostics = [];
500
503
  // Nothing may keep running once ACC is gone. A relay holds a live session
501
504
  // endpoint in memory, so it is stopped here rather than left to find out.
@@ -744,7 +747,7 @@ export function planAntigravityInstall(context) {
744
747
  // match: a wrapper path that needs quotes gets none.
745
748
  const plugin = [{ path: pluginInstallPath(context.home), kind: "merge" },
746
749
  { path: vendorManifestPath(context.home), kind: "merge" },
747
- ...(isShellWord(cliWrapperPath(context.home, context.hostPlatform))
750
+ ...(context.indicator === "on" || isShellWord(cliWrapperPath(context.home, context.hostPlatform))
748
751
  ? [{ path: agySettingsPath(context.home), kind: "merge" }] : [])];
749
752
  if (locationChoice(context) !== null) {
750
753
  return [shim, ...plugin,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/adapter-claude-code",
3
- "version": "0.10.4",
3
+ "version": "0.11.1",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -0,0 +1,83 @@
1
+ // Interpreter and read-only entrypoint are baked by the installer. No prompts,
2
+ // transcript access, model turns, ACC writes or transport probes are needed.
3
+ const NODE = __ACC_NODE__;
4
+ const INDICATOR = __ACC_INDICATOR__;
5
+ // The reader answers at the latest 1.5 s after its modules load. Inside a loaded
6
+ // Claude the child's start alone took up to 1.3 s, so a shorter bound killed
7
+ // reads that would have answered and printed a false problem.
8
+ const READ_TIMEOUT_MS = 5000;
9
+ // A read that did not happen says nothing about this chat. Only a run of them
10
+ // replaces the last observed state.
11
+ const READ_FAILURES = ["indicator_unavailable", "state_unreadable"];
12
+ const FAILED_READS_SHOWN = 3;
13
+
14
+ let report = { label: "ACC …", health: "starting", detail: "Reading ACC state." };
15
+ let busy = false, sessionId = null, startedAt = 0, lastRead = 0, announced = null, failedReads = 0;
16
+
17
+ const failedRead = slow => ({ label: "ACC !", health: "problem", reasonCode: "indicator_unavailable",
18
+ ...slow ? {
19
+ detail: "The ACC indicator did not answer within five seconds.",
20
+ action: "Run /acc-status to read it again; a busy machine can delay the answer.",
21
+ } : {
22
+ detail: "The ACC indicator could not read this session's state.",
23
+ action: "Run acc install --adapter claude_code --indicator on, then /reload-plugins.",
24
+ } });
25
+
26
+ async function refresh($) {
27
+ if (busy) return;
28
+ const id = await $.session.id();
29
+ const now = await $.clock.now();
30
+ if (id !== sessionId) {
31
+ sessionId = id; startedAt = now; lastRead = 0; announced = null; failedReads = 0;
32
+ report = { label: "ACC …", health: "starting", detail: "Reading ACC state." };
33
+ }
34
+ if (now - lastRead < (now - startedAt < 5000 ? 1000 : 5000)) return;
35
+ lastRead = now; busy = true;
36
+ let next;
37
+ try {
38
+ const value = await $.process.run([NODE, INDICATOR, "--adapter", "claude_code",
39
+ "--native-session", id, "--json"], { timeoutMs: READ_TIMEOUT_MS });
40
+ next = JSON.parse(value.stdout);
41
+ } catch {
42
+ next = failedRead(await $.clock.now() - now >= READ_TIMEOUT_MS);
43
+ } finally { busy = false; }
44
+ if (await $.session.id() !== id) return;
45
+ failedReads = READ_FAILURES.includes(next.reasonCode) ? failedReads + 1 : 0;
46
+ if (next.reasonCode === "not_registered" && now - startedAt < 5000) {
47
+ report = { label: "ACC …", health: "starting",
48
+ detail: "Waiting up to five seconds for the session hooks to register ACC." };
49
+ } else if (failedReads === 0 || failedReads >= FAILED_READS_SHOWN) report = next;
50
+ if (report.health === "problem" && report.reasonCode !== announced) {
51
+ await $.ui.log([report.detail, report.action, "Details: /acc-status"].filter(Boolean).join(" "));
52
+ announced = report.reasonCode;
53
+ } else if (report.health === "ready") announced = null;
54
+ $.ui.invalidate("ui.render");
55
+ }
56
+ export function register(on) {
57
+ on("session.start", async ($, e, next) => {
58
+ $.clock.every(1000, async () => { await refresh($); });
59
+ await refresh($);
60
+ await $.command.register({ name: "acc-status", immediate: true,
61
+ description: "Explain this chat's ACC indicator and its next recovery step" });
62
+ return next(e);
63
+ });
64
+ on("command.run", { command: "acc-status" }, async ($) => {
65
+ lastRead = 0;
66
+ await refresh($);
67
+ return { text: [report.label, report.detail, report.action].filter(Boolean).join("\n") };
68
+ });
69
+ on("ui.render", { component: "SessionMode" }, async ($, e, next) => {
70
+ const { Box, Text } = $.ui.resolve(e);
71
+ const symbol = report.health === "ready" ? "●" : report.health === "problem" ? "!" : "…";
72
+ const color = report.health === "ready" ? "#2c7a39" : report.health === "problem" ? "warning" : "inactive";
73
+ const qualifier = ["turn", "inbox"].includes(report.reception) ? ` · ${report.reception}` : "";
74
+ // Native mode strings are all dimmed. Keep their rendering intact and put
75
+ // only ACC's glyph in its own non-dim Text. Match Antigravity's ready green
76
+ // exactly instead of allowing Claude's success theme color to desaturate it.
77
+ return Box({ flexDirection: "row", children: [await next(e),
78
+ Text({ color: "inactive", children: [" ACC "] }),
79
+ Text({ color, bold: true, dimColor: false, children: [symbol] }),
80
+ ...(qualifier ? [Text({ color: "inactive", children: [qualifier] })] : []),
81
+ ] });
82
+ });
83
+ }
@@ -57,19 +57,43 @@ Do this once, not every turn. Update it only when the scope or mode materially
57
57
  changes. `--hint` is important: it lets ACC match your plan against a peer's
58
58
  claim. Intent is awareness, not permission.
59
59
 
60
- Before changing shared files, claim the smallest useful resource:
60
+ Before changing shared files, claim the smallest useful resources in one operation:
61
61
 
62
62
  ```bash
63
- {{ACC}} claim --resource 'file:packages/core/**' --reason "porting the store"
63
+ {{ACC}} claim --resource 'file:packages/core/**' \
64
+ --resource 'file:packages/protocol/**' --reason "porting the claim model"
64
65
  ```
65
66
 
66
- Exit 5 means a conflict. Do not work around it silently. Narrow your scope,
67
- contact the owner, or ask the human. Give a claim back explicitly when useful:
67
+ Repeat `--resource` for an atomic batch, or supply it once for one claim.
68
+ Shared mode, enforcement, reason, and lease apply to every resource. Duplicate resources after
69
+ normalization are rejected. Exit 5 means a conflict: no claim is created or
70
+ renewed. Batch `details.conflicts` names blocked resources and their holders.
71
+ Narrow your scope, contact the owner, or ask the human. Repeating a successful
72
+ claim command renews your existing claims on those resources.
73
+
74
+ Release selected claims when useful:
68
75
 
69
76
  ```bash
70
- {{ACC}} release --resource 'file:packages/core/**'
77
+ {{ACC}} release --resource 'file:packages/core/**' \
78
+ --resource 'file:packages/protocol/**'
71
79
  ```
72
80
 
81
+ Choose exactly one selector family: repeated `--resource`, repeated `--claim`,
82
+ or `--all`. Duplicate selectors after normalization are rejected. A missing or
83
+ foreign explicit target fails without releasing any claims. Repeating an explicit release after its targets were removed is an error.
84
+ Batch release accepts no force-release authority.
85
+
86
+ To release all your claims while keeping your session and intent open:
87
+
88
+ ```bash
89
+ {{ACC}} release --all
90
+ ```
91
+
92
+ This selects only your session's current claims in its workspace. An empty set
93
+ succeeds. Each retry selects the current set and can release newly acquired claims.
94
+ Use `work --clear` to clear intent, `ack` to acknowledge a message, and `finish`
95
+ to record a handoff and close your ACC presence.
96
+
73
97
  ## Communicate only when it changes another agent's work
74
98
 
75
99
  Send a message for a dependency, conflict, direct question, decision, or
@@ -34,6 +34,7 @@ export function createClaudeCodeAdapter() {
34
34
  return defineAdapter({
35
35
  id: "claude_code",
36
36
  displayName: "Claude Code",
37
+ statusIndicator: { minimumVersion: "2.1.287", reload: "run /reload-plugins in the open session" },
37
38
  // The binary this client actually installs. Probed for a version to
38
39
  // decide whether the client is on this machine, so it has to be the
39
40
  // real command rather than the adapter id: `2.1.233 (Claude Code)`.
@@ -7,7 +7,7 @@ import path from "node:path";
7
7
  import { AccError, EXIT } from "@agents-can-communicate/protocol";
8
8
  import { fileURLToPath } from "node:url";
9
9
 
10
- import { acccreatedFile, bakeSkillCommand, blankJson,
10
+ import { acccreatedFile, bakeSkillCommand, blankJson, defaultIndicator, compareVersionOrder, versionOrder,
11
11
  mergeOwnedEntries, ownedEntries,
12
12
  keepVersions, ownVersion, stampPluginVersion,
13
13
  removeIfEmpty,
@@ -181,7 +181,7 @@ async function execFormHooks(file, node) {
181
181
  }
182
182
 
183
183
  /** A plugin tree with the shim written and the skill's command baked in. */
184
- async function layOutPlugin(target, { runner, node, cli, hostPlatform }) {
184
+ async function layOutPlugin(target, { runner, node, cli, hostPlatform, indicator, indicatorRunner, clientVersion }) {
185
185
  await rm(target, { recursive: true, force: true });
186
186
  await cp(bundle, target, { recursive: true });
187
187
  // The skill ships with a placeholder where the command belongs: `acc` is not
@@ -194,6 +194,15 @@ async function layOutPlugin(target, { runner, node, cli, hostPlatform }) {
194
194
  await writeHookShim({ dir: path.join(target, "hooks"), adapterId: "claude_code",
195
195
  runner, node, platform: hostPlatform });
196
196
  if (hostPlatform === "win32") await execFormHooks(path.join(target, "hooks", "hooks.json"), node);
197
+ if (indicator === "on" && compareVersionOrder(versionOrder(clientVersion), versionOrder("2.1.287")) >= 0) {
198
+ const hooksFile = path.join(target, "hooks", "hooks.json");
199
+ const hooks = await readJson(hooksFile, {});
200
+ await writeJson(hooksFile, { ...hooks, modules: ["./indicator.mjs"] });
201
+ const moduleFile = path.join(target, "hooks", "indicator.mjs");
202
+ const source = await readFile(moduleFile, "utf8");
203
+ await writeFile(moduleFile, source.replace("__ACC_NODE__", JSON.stringify(node))
204
+ .replace("__ACC_INDICATOR__", JSON.stringify(indicatorRunner ?? defaultIndicator())));
205
+ } else await rm(path.join(target, "hooks", "indicator.mjs"), { force: true });
197
206
  // The copy the client reads says which ACC wrote it. The shipped manifest
198
207
  // carries no version, so there is nothing in the repository to fall out of
199
208
  // step - which is how every client came to report 0.1.6 while running 0.1.9.
@@ -202,7 +211,8 @@ async function layOutPlugin(target, { runner, node, cli, hostPlatform }) {
202
211
  }
203
212
 
204
213
  export async function installClaudePlugin({ configDir, runner, cli, keepPreviousVersion = null,
205
- node = process.execPath, now = new Date(), hostPlatform = process.platform }) {
214
+ node = process.execPath, now = new Date(), hostPlatform = process.platform,
215
+ indicator = "off", indicatorRunner, clientVersion }) {
206
216
  // Everything this will merge into, read before a byte is written. A settings
207
217
  // file that will not parse used to be discovered after the plugin tree was
208
218
  // already on disk, and the install then failed with nineteen files left
@@ -219,12 +229,13 @@ export async function installClaudePlugin({ configDir, runner, cli, keepPrevious
219
229
  const source = sourceDir(configDir);
220
230
  const cached = cachePath(configDir, version);
221
231
 
222
- await layOutPlugin(source, { runner, node, cli, hostPlatform });
232
+ const layout = { runner, node, cli, hostPlatform, indicator, indicatorRunner, clientVersion };
233
+ await layOutPlugin(source, layout);
223
234
  await writeJson(marketplaceFile(configDir), marketplaceManifest());
224
235
  // The copy the client runs from. Written here rather than asking the user to
225
236
  // run `claude plugin install`, exactly as the Codex adapter does, because the
226
237
  // command's only effect is this copy plus the two registry entries below.
227
- await layOutPlugin(cached, { runner, node, cli, hostPlatform });
238
+ await layOutPlugin(cached, layout);
228
239
  // The copy just written, plus the one an upgrade moved off. A client caches a
229
240
  // plugin under its version, so every upgrade would otherwise leave the previous
230
241
  // release's tree beside this one - invisible while the version never moved,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/adapter-codex",
3
- "version": "0.10.4",
3
+ "version": "0.11.1",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -76,19 +76,43 @@ Do this once, not every turn. Update it only when the scope or mode materially
76
76
  changes. `--hint` is important: it lets ACC match your plan against a peer's
77
77
  claim. Intent is awareness, not permission.
78
78
 
79
- Before changing shared files, claim the smallest useful resource:
79
+ Before changing shared files, claim the smallest useful resources in one operation:
80
80
 
81
81
  ```bash
82
- {{ACC}} claim --resource 'file:packages/core/**' --reason "porting the store"
82
+ {{ACC}} claim --resource 'file:packages/core/**' \
83
+ --resource 'file:packages/protocol/**' --reason "porting the claim model"
83
84
  ```
84
85
 
85
- Exit 5 means a conflict. Do not work around it silently. Narrow your scope,
86
- contact the owner, or ask the human. Give a claim back explicitly when useful:
86
+ Repeat `--resource` for an atomic batch, or supply it once for one claim.
87
+ Shared mode, enforcement, reason, and lease apply to every resource. Duplicate resources after
88
+ normalization are rejected. Exit 5 means a conflict: no claim is created or
89
+ renewed. Batch `details.conflicts` names blocked resources and their holders.
90
+ Narrow your scope, contact the owner, or ask the human. Repeating a successful
91
+ claim command renews your existing claims on those resources.
92
+
93
+ Release selected claims when useful:
87
94
 
88
95
  ```bash
89
- {{ACC}} release --resource 'file:packages/core/**'
96
+ {{ACC}} release --resource 'file:packages/core/**' \
97
+ --resource 'file:packages/protocol/**'
90
98
  ```
91
99
 
100
+ Choose exactly one selector family: repeated `--resource`, repeated `--claim`,
101
+ or `--all`. Duplicate selectors after normalization are rejected. A missing or
102
+ foreign explicit target fails without releasing any claims. Repeating an explicit release after its targets were removed is an error.
103
+ Batch release accepts no force-release authority.
104
+
105
+ To release all your claims while keeping your session and intent open:
106
+
107
+ ```bash
108
+ {{ACC}} release --all
109
+ ```
110
+
111
+ This selects only your session's current claims in its workspace. An empty set
112
+ succeeds. Each retry selects the current set and can release newly acquired claims.
113
+ Use `work --clear` to clear intent, `ack` to acknowledge a message, and `finish`
114
+ to record a handoff and close your ACC presence.
115
+
92
116
  ## Communicate only when it changes another agent's work
93
117
 
94
118
  Send a message for a dependency, conflict, direct question, decision, or
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agents-can-communicate",
3
- "version": "0.10.4",
3
+ "version": "0.11.1",
4
4
  "description": "Coordinate this Gemini CLI session with other AI agent sessions working in the same workspace.",
5
5
  "contextFileName": "skills/acc/SKILL.md"
6
6
  }
@@ -57,19 +57,43 @@ Do this once, not every turn. Update it only when the scope or mode materially
57
57
  changes. `--hint` is important: it lets ACC match your plan against a peer's
58
58
  claim. Intent is awareness, not permission.
59
59
 
60
- Before changing shared files, claim the smallest useful resource:
60
+ Before changing shared files, claim the smallest useful resources in one operation:
61
61
 
62
62
  ```bash
63
- {{ACC}} claim --resource 'file:packages/core/**' --reason "porting the store"
63
+ {{ACC}} claim --resource 'file:packages/core/**' \
64
+ --resource 'file:packages/protocol/**' --reason "porting the claim model"
64
65
  ```
65
66
 
66
- Exit 5 means a conflict. Do not work around it silently. Narrow your scope,
67
- contact the owner, or ask the human. Give a claim back explicitly when useful:
67
+ Repeat `--resource` for an atomic batch, or supply it once for one claim.
68
+ Shared mode, enforcement, reason, and lease apply to every resource. Duplicate resources after
69
+ normalization are rejected. Exit 5 means a conflict: no claim is created or
70
+ renewed. Batch `details.conflicts` names blocked resources and their holders.
71
+ Narrow your scope, contact the owner, or ask the human. Repeating a successful
72
+ claim command renews your existing claims on those resources.
73
+
74
+ Release selected claims when useful:
68
75
 
69
76
  ```bash
70
- {{ACC}} release --resource 'file:packages/core/**'
77
+ {{ACC}} release --resource 'file:packages/core/**' \
78
+ --resource 'file:packages/protocol/**'
71
79
  ```
72
80
 
81
+ Choose exactly one selector family: repeated `--resource`, repeated `--claim`,
82
+ or `--all`. Duplicate selectors after normalization are rejected. A missing or
83
+ foreign explicit target fails without releasing any claims. Repeating an explicit release after its targets were removed is an error.
84
+ Batch release accepts no force-release authority.
85
+
86
+ To release all your claims while keeping your session and intent open:
87
+
88
+ ```bash
89
+ {{ACC}} release --all
90
+ ```
91
+
92
+ This selects only your session's current claims in its workspace. An empty set
93
+ succeeds. Each retry selects the current set and can release newly acquired claims.
94
+ Use `work --clear` to clear intent, `ack` to acknowledge a message, and `finish`
95
+ to record a handoff and close your ACC presence.
96
+
73
97
  ## Communicate only when it changes another agent's work
74
98
 
75
99
  Send a message for a dependency, conflict, direct question, decision, or
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/adapter-gemini-cli",
3
- "version": "0.10.4",
3
+ "version": "0.11.1",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/adapter-grok",
3
- "version": "0.10.4",
3
+ "version": "0.11.1",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -73,19 +73,43 @@ Do this once, not every turn. Update it only when the scope or mode materially
73
73
  changes. `--hint` is important: it lets ACC match your plan against a peer's
74
74
  claim. Intent is awareness, not permission.
75
75
 
76
- Before changing shared files, claim the smallest useful resource:
76
+ Before changing shared files, claim the smallest useful resources in one operation:
77
77
 
78
78
  ```bash
79
- {{ACC}} claim --resource 'file:packages/core/**' --reason "porting the store"
79
+ {{ACC}} claim --resource 'file:packages/core/**' \
80
+ --resource 'file:packages/protocol/**' --reason "porting the claim model"
80
81
  ```
81
82
 
82
- Exit 5 means a conflict. Do not work around it silently. Narrow your scope,
83
- contact the owner, or ask the human. Give a claim back explicitly when useful:
83
+ Repeat `--resource` for an atomic batch, or supply it once for one claim.
84
+ Shared mode, enforcement, reason, and lease apply to every resource. Duplicate resources after
85
+ normalization are rejected. Exit 5 means a conflict: no claim is created or
86
+ renewed. Batch `details.conflicts` names blocked resources and their holders.
87
+ Narrow your scope, contact the owner, or ask the human. Repeating a successful
88
+ claim command renews your existing claims on those resources.
89
+
90
+ Release selected claims when useful:
84
91
 
85
92
  ```bash
86
- {{ACC}} release --resource 'file:packages/core/**'
93
+ {{ACC}} release --resource 'file:packages/core/**' \
94
+ --resource 'file:packages/protocol/**'
87
95
  ```
88
96
 
97
+ Choose exactly one selector family: repeated `--resource`, repeated `--claim`,
98
+ or `--all`. Duplicate selectors after normalization are rejected. A missing or
99
+ foreign explicit target fails without releasing any claims. Repeating an explicit release after its targets were removed is an error.
100
+ Batch release accepts no force-release authority.
101
+
102
+ To release all your claims while keeping your session and intent open:
103
+
104
+ ```bash
105
+ {{ACC}} release --all
106
+ ```
107
+
108
+ This selects only your session's current claims in its workspace. An empty set
109
+ succeeds. Each retry selects the current set and can release newly acquired claims.
110
+ Use `work --clear` to clear intent, `ack` to acknowledge a message, and `finish`
111
+ to record a handoff and close your ACC presence.
112
+
89
113
  ## Communicate only when it changes another agent's work
90
114
 
91
115
  Send a message for a dependency, conflict, direct question, decision, or
@@ -1,3 +1,5 @@
1
+ import { preflightGrokIndicator } from "./indicator-install.mjs";
2
+ import { grokIndicator } from "./indicator.mjs";
1
3
  import { defineAdapter, projectContext, projectContextResult }
2
4
  from "@agents-can-communicate/adapter-sdk";
3
5
  import certification from "../certification.json" with { type: "json" };
@@ -22,6 +24,7 @@ export const GROK_VERSION = "1.0.13";
22
24
  export function createGrokAdapter() {
23
25
  return defineAdapter({
24
26
  id: "grok",
27
+ statusIndicator: grokIndicator,
25
28
  displayName: "Grok",
26
29
  // Native Mach-O at ~/.grok/bin/grok. `ps -o comm=` on 1.0.13 reports `grok`.
27
30
  client: { command: "grok", certificationName: "grok", versionArgs: ["--version"] },
@@ -41,6 +44,7 @@ export function createGrokAdapter() {
41
44
  planInstall: context => planGrokInstall(forClient(context)),
42
45
  detect: context => detectGrok(forClient(context)),
43
46
  install: context => installGrokHooks(forClient(context)),
47
+ preflightUninstall: context => preflightGrokIndicator(forClient(context)),
44
48
  uninstall: context => uninstallGrokHooks(forClient(context)),
45
49
 
46
50
  doctor: async context => {