agents-can-communicate 0.4.1 → 0.4.3

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 (57) hide show
  1. package/README.md +17 -4
  2. package/docs/ARCHITECTURE.md +7 -1
  3. package/docs/CLI.md +23 -3
  4. package/docs/CONFIGURATION.md +25 -0
  5. package/docs/GETTING_STARTED.md +17 -5
  6. package/docs/PROTOCOL.md +4 -0
  7. package/docs/RELEASING.md +1 -1
  8. package/docs/SECURITY_MODEL.md +7 -0
  9. package/docs/TROUBLESHOOTING.md +60 -7
  10. package/docs/UPGRADING.md +36 -19
  11. package/node_modules/@agents-can-communicate/adapter-claude-code/package.json +1 -1
  12. package/node_modules/@agents-can-communicate/adapter-claude-code/src/adapter.mjs +3 -3
  13. package/node_modules/@agents-can-communicate/adapter-claude-code/src/channel.mjs +2 -4
  14. package/node_modules/@agents-can-communicate/adapter-claude-code/src/install.mjs +10 -0
  15. package/node_modules/@agents-can-communicate/adapter-claude-code/src/native-delivery.mjs +3 -1
  16. package/node_modules/@agents-can-communicate/adapter-codex/package.json +1 -1
  17. package/node_modules/@agents-can-communicate/adapter-codex/src/app-server-client.mjs +1 -1
  18. package/node_modules/@agents-can-communicate/adapter-codex/src/config-block.mjs +4 -88
  19. package/node_modules/@agents-can-communicate/adapter-codex/src/install.mjs +36 -15
  20. package/node_modules/@agents-can-communicate/adapter-codex/src/live-permissions.mjs +110 -0
  21. package/node_modules/@agents-can-communicate/adapter-codex/src/native-delivery.mjs +2 -1
  22. package/node_modules/@agents-can-communicate/adapter-codex/src/permission-ownership.mjs +109 -0
  23. package/node_modules/@agents-can-communicate/adapter-codex/src/toml-scan.mjs +99 -0
  24. package/node_modules/@agents-can-communicate/adapter-gemini-cli/extension/gemini-extension.json +1 -1
  25. package/node_modules/@agents-can-communicate/adapter-gemini-cli/package.json +1 -1
  26. package/node_modules/@agents-can-communicate/adapter-grok/package.json +1 -1
  27. package/node_modules/@agents-can-communicate/adapter-kimi/package.json +1 -1
  28. package/node_modules/@agents-can-communicate/adapter-sdk/package.json +1 -1
  29. package/node_modules/@agents-can-communicate/adapter-sdk/src/channel-directory.mjs +8 -0
  30. package/node_modules/@agents-can-communicate/adapter-sdk/src/index.mjs +3 -0
  31. package/node_modules/@agents-can-communicate/adapter-sdk/src/native-attempt-writer.mjs +64 -0
  32. package/node_modules/@agents-can-communicate/adapter-sdk/src/native-attempt.mjs +65 -0
  33. package/node_modules/@agents-can-communicate/adapter-sdk/src/native-vocabulary.mjs +1 -0
  34. package/node_modules/@agents-can-communicate/cli/package.json +1 -1
  35. package/node_modules/@agents-can-communicate/cli/src/doctor-command.mjs +19 -52
  36. package/node_modules/@agents-can-communicate/cli/src/install-command.mjs +23 -45
  37. package/node_modules/@agents-can-communicate/cli/src/main.mjs +3 -1
  38. package/node_modules/@agents-can-communicate/cli/src/native-delivery-status.mjs +88 -0
  39. package/node_modules/@agents-can-communicate/cli/src/native-session-diagnostics.mjs +64 -0
  40. package/node_modules/@agents-can-communicate/core/package.json +1 -1
  41. package/node_modules/@agents-can-communicate/core/src/receipts.mjs +1 -0
  42. package/node_modules/@agents-can-communicate/delivery-router/package.json +1 -1
  43. package/node_modules/@agents-can-communicate/delivery-router/src/router.mjs +1 -1
  44. package/node_modules/@agents-can-communicate/hook-runner/package.json +1 -1
  45. package/node_modules/@agents-can-communicate/hook-runner/src/native-attempt.mjs +43 -0
  46. package/node_modules/@agents-can-communicate/hook-runner/src/runner.mjs +17 -27
  47. package/node_modules/@agents-can-communicate/installer/package.json +1 -1
  48. package/node_modules/@agents-can-communicate/installer/src/apply.mjs +2 -0
  49. package/node_modules/@agents-can-communicate/installer/src/delivery-diagnostics.mjs +36 -0
  50. package/node_modules/@agents-can-communicate/installer/src/detect.mjs +28 -12
  51. package/node_modules/@agents-can-communicate/installer/src/index.mjs +3 -1
  52. package/node_modules/@agents-can-communicate/installer/src/live-policy.mjs +10 -3
  53. package/node_modules/@agents-can-communicate/installer/src/plan.mjs +12 -2
  54. package/node_modules/@agents-can-communicate/mcp-server/package.json +1 -1
  55. package/node_modules/@agents-can-communicate/protocol/package.json +1 -1
  56. package/node_modules/@agents-can-communicate/storage-filesystem/package.json +1 -1
  57. package/package.json +1 -1
package/README.md CHANGED
@@ -65,6 +65,12 @@ then restart your clients from the project directory. In Codex, check `/plugins`
65
65
  review the current ACC definitions in `/hooks`; changed hooks may need fresh trust.
66
66
  [Getting started](docs/GETTING_STARTED.md) covers activation and preserved sandbox settings.
67
67
 
68
+ For Codex live delivery on Apple Silicon macOS, installation also configures outgoing
69
+ local socket access on Codex 0.153.4 or newer when using default workspace permissions.
70
+ Custom policies are preserved. If its local service is missing, doctor gives the command
71
+ `codex app-server daemon start`; then open a new Codex session. Doctor reports receiving
72
+ channel state and outgoing permission configuration separately.
73
+
68
74
  Open two sessions and give them ordinary tasks, as above. Look for an agent discovering a
69
75
  peer, checking who is changing a file, asking about a shared dependency, or replying to a
70
76
  review request.
@@ -73,8 +79,8 @@ Run `acc doctor` from the project if a peer is missing. A directory containing A
73
79
  state, commonly your home directory, cannot be used as a workspace; start the client in a
74
80
  project directory. See [Troubleshooting](docs/TROUBLESHOOTING.md).
75
81
 
76
- Already using ACC? Follow the [upgrade guide](docs/UPGRADING.md), including the 0.4.0 →
77
- 0.4.1 update and the data-format boundary when moving from 0.3.1.
82
+ Already using ACC? Follow the [upgrade guide](docs/UPGRADING.md), including the 0.4.x →
83
+ 0.4.3 update and the data-format boundary when moving from 0.3.1.
78
84
 
79
85
  ## When messages arrive
80
86
 
@@ -95,9 +101,16 @@ mutations. It adds no automatic peer-message injection or idle delivery. A reloc
95
101
  **Optional live delivery can start a turn in an idle Codex or Claude Code session.** It is
96
102
  experimental, off by default, and can spend model tokens. On Apple Silicon Macs, Codex
97
103
  0.152.1 or newer requires an already-running LocalDaemon and a verified session;
98
- Claude Code 2.1.258 or newer requires zsh and shows its development-channel warning at
99
- startup. Messages arriving mid-turn wait for the turn to finish. The receiving session's
104
+ Claude Code 2.1.258 or newer requires zsh and client-side Channels activation; check its
105
+ startup notice for ACC and accept the development warning when shown. An MCP connection
106
+ alone does not verify inbound delivery. Messages arriving mid-turn wait for the turn to
107
+ finish. The receiving session's
100
108
  opt-in policy and current reachability determine whether delivery can proceed.
109
+ `acc install` reports each client's delivery state and can save Codex consent before its
110
+ service is available. `acc doctor` also names each session’s last native binding result,
111
+ including missing launch consent, an unidentified client process or a failed handshake.
112
+ It distinguishes a disabled policy from an unavailable service or a missing live channel
113
+ in the current project.
101
114
 
102
115
  A Codex thread retained by LocalDaemon can receive opted-in messages after its terminal
103
116
  exits. Turning ACC delivery off prevents new native offers; already accepted queue entries
@@ -68,7 +68,13 @@ livePolicy · opaqueEndpointRef · leaseUntil
68
68
 
69
69
  Core validates identity and expiry but never interprets the opaque endpoint. That remains
70
70
  inside the owning adapter. `acc status` reports available modes, policy, reachability, and
71
- lease without exposing the endpoint.
71
+ lease without exposing the endpoint. The hook runner also replaces one optional native
72
+ attempt diagnostic beside its session-owner file: closed policy/process/handshake
73
+ metadata with a timestamp, never vendor output. Doctor joins it only to the current open
74
+ generation and reports it separately from transport and receipt facts. It is not journalled
75
+ or projected into agent context; session restart replaces it and SessionEnd attempts bounded
76
+ cleanup. Doctor ignores closed or superseded generations even if cleanup could not finish. Diagnostic disk I/O runs in an
77
+ unreferenced worker, so a stalled write cannot hold the hook process open.
72
78
 
73
79
  ## Certified capability versus current reachability
74
80
 
package/docs/CLI.md CHANGED
@@ -239,8 +239,9 @@ external AI client. An addressed handoff requires acknowledgement; a room handof
239
239
  `--delivery off|actionable|all` is a per-client recipient policy request, not a capability
240
240
  switch, and the default is `off`. `--adapter` is repeatable to name several clients. An
241
241
  explicit `--delivery` applies uniformly and never prompts; omitting it on an interactive
242
- terminal asks one default-No question per eligible client, and on a non-interactive run or a
243
- `--dry-run` it keeps fresh clients off. A recorded opt-in is kept on upgrade. If the detected
242
+ terminal asks one default-No question per supported client. Codex can save consent while
243
+ its local service is unavailable or has no loaded session; this does not activate delivery.
244
+ A non-interactive run or a `--dry-run` keeps fresh clients off. A recorded opt-in is kept on upgrade. If the detected
244
245
  client cannot receive native delivery - unsupported, below the captured minimum, a
245
246
  prerelease, known-bad, a wrong platform, or an unsupported shell - installation keeps the
246
247
  effective policy off and prints the reason. Claude Code shell activation writes an owned
@@ -248,7 +249,26 @@ zsh PATH block and a shim that `exec`s the real client; `ACC_BYPASS=1` bypasses
248
249
  activation. Codex LocalDaemon delivery uses recorded installation consent without changing
249
250
  ordinary launch arguments. Its opt-in remains active when shim variables are absent or
250
251
  bypassed; `acc install --adapter codex --delivery off` disables new native offers. ACC never
251
- starts or stops the vendor daemon. See [delivery consent](CONFIGURATION.md#keep-delivery-consent-user-owned).
252
+ starts or stops the vendor daemon. The install summary names each client's requested policy,
253
+ activation state and verified fallback. `doctor` separates protocol readiness, recorded
254
+ consent and a live channel in the current workspace, with a next step for missing activation.
255
+ A supported version or an installed plugin alone is not an active delivery channel.
256
+ `runtime: active` means ACC has a reachable local transport binding. Claude can still
257
+ block inbound Channels messages while its MCP server and tools remain connected;
258
+ doctor therefore also names the client-side startup check.
259
+ In doctor JSON, `nativeDelivery.activation` distinguishes missing launch setup from a
260
+ recorded setup (or `not_required` for a pre-existing service). `policy` is the installed
261
+ choice; `sessionPolicy` describes a native binding when one is visible. Existing Claude
262
+ sessions can retain their launch policy after a different choice is installed for new
263
+ sessions; Codex checks current recorded consent before new offers.
264
+ `nativeDelivery.sessions` lists each current session's identity, present transport state
265
+ and `lastAttempt`: timestamp, startup/turn event, effective policy and its source, whether
266
+ that policy was missing/invalid/off, whether a client process was identified, and the closed
267
+ handshake result/reason. `lastAttempt: null` means no usable attempt was observed for this
268
+ generation; it does not prove hooks are disabled. A past successful handshake is separate
269
+ from current transport reachability. ACC replaces this small diagnostic beside the
270
+ hook-owner file outside the repository; it never adds attempt history to agent context.
271
+ See [delivery consent](CONFIGURATION.md#keep-delivery-consent-user-owned).
252
272
 
253
273
  An initial `acc install` enables automatic updates. Reinstalling preserves an explicit
254
274
  `acc update --auto off` choice. A full uninstall pauses updates; reinstalling restores
@@ -144,6 +144,31 @@ consent from the installation record, not a shell-shim variable. Unavailable or
144
144
  sessions retain durable inbox fallback. Use `acc install --adapter codex --delivery off`
145
145
  to stop new native offers; bypassing a shim does not disable that recorded opt-in.
146
146
 
147
+ ### Codex outgoing permissions
148
+
149
+ Receiving a native message and sending from the agent's sandbox are separate operations.
150
+ On Codex 0.153.4 or newer on macOS arm64, live opt-in also configures outgoing access
151
+ for default workspace permissions. This happens even when the daemon is not yet available.
152
+ Installation, its preview, and the interactive consent question disclose this change.
153
+
154
+ ACC selects a permission profile named `acc-workspace`, extending `:workspace`. It grants
155
+ write access to the ACC state directory and allows only the local ACC channel directory
156
+ (`/tmp/acc-ch-<uid>`) and the Codex home control socket. The profile enables networking
157
+ through `features.network_proxy = true`, with no external domains allowed. The proxy and
158
+ socket grants must stay together: enabling networking without the proxy changes its scope.
159
+
160
+ An existing legacy workspace-write configuration is migrated only when its sole writable
161
+ root is ACC's state directory. Custom permission/configuration profiles, additional roots,
162
+ inline settings and uncaptured clients are preserved and reported as unverified. ACC does
163
+ not merge arbitrary security policies or verify overrides in an already running session.
164
+ For a custom policy, grant the same state and socket access through the proxy in the
165
+ client's effective workspace profile; do not combine it with legacy sandbox settings.
166
+
167
+ Restart Codex after changing permissions. Explicit delivery `off` or uninstall restores
168
+ the previous configuration only while every generated permission component is unchanged.
169
+ If any component was edited or another setting depends on it, ACC preserves the entire
170
+ bundle and reports it for review. Plugin registration can still be removed independently.
171
+
147
172
  ## Override local paths and identity
148
173
 
149
174
  Nothing in `acc.workspace.json` says where state is stored, and nothing there can — that is
@@ -15,7 +15,7 @@ pair or session-bound ACC MCP tools. See [CLI ownership](CLI.md#coordinate-from-
15
15
 
16
16
  ACC requires macOS or Linux and Node.js 24 or newer.
17
17
 
18
- Already using ACC? Follow the [upgrade guide](UPGRADING.md) for the 0.4.0 → 0.4.1
18
+ Already using ACC? Follow the [upgrade guide](UPGRADING.md) for the 0.4.x → 0.4.3
19
19
  update or the data-format boundary when upgrading from 0.3.1.
20
20
 
21
21
  ```bash
@@ -39,13 +39,25 @@ printed by the installer. In Codex, use `/plugins` to check ACC is enabled, then
39
39
  to review each ACC hook and enable/trust its current definition if needed. Restart the
40
40
  session after that review; changed hook definitions may require trust again.
41
41
 
42
- If the installer preserved your existing Codex sandbox settings, verify the named ACC
43
- state directory is in `sandbox_workspace_write.writable_roots` in the config it identifies.
42
+ For Codex live delivery, follow the outgoing-permission and local-service instructions
43
+ from install/doctor, then start a new session. Default workspace permissions can be
44
+ configured automatically on Codex 0.153.4 or newer on macOS arm64. Custom settings are
45
+ preserved; see [outgoing permissions](CONFIGURATION.md#codex-outgoing-permissions).
46
+ With legacy sandbox settings, the named ACC state directory must also be in
47
+ `sandbox_workspace_write.writable_roots` in the config the installer identifies.
44
48
  ACC keeps those user settings unchanged. Installed files alone do not establish that hooks
45
49
  are active; `acc doctor` leaves current readiness unverified and directs you to Codex.
46
50
 
47
- If you opt into Claude Code's experimental idle delivery, Claude also shows its own
48
- development-channel warning at every startup. The feature is off by default, can spend
51
+ Read the delivery summary for each client. Live delivery needs an explicit opt-in and a
52
+ verified channel in the current session. Codex can save your choice even when its local
53
+ service is not running yet. Declining uses the reported fallback: `acc inbox`, or next-turn
54
+ hooks only where the exact client version and platform are certified.
55
+
56
+ If you opt into Claude Code's experimental idle delivery, check Claude's Channels startup
57
+ notice for ACC and accept its development-channel warning when shown. If it reports Channels
58
+ unavailable or blocked, a connected MCP server does not make inbound delivery work;
59
+ see [troubleshooting](TROUBLESHOOTING.md#i-enabled-live-delivery-but-got-fallback).
60
+ The feature is off by default, can spend
49
61
  model tokens, and currently requires Apple Silicon macOS, zsh, and Claude Code 2.1.258 or
50
62
  newer. You do not need it for durable messages or supported next-turn delivery.
51
63
 
package/docs/PROTOCOL.md CHANGED
@@ -199,6 +199,10 @@ peer body into diagnostics.
199
199
  Receipt `offered` is committed only after the transport accepts bytes. A failed attempt
200
200
  leaves the receipt queued.
201
201
 
202
+ `transport_permission_denied` means the sender's OS or sandbox refused local transport
203
+ access (`EPERM` or `EACCES`). It is distinct from `recipient_unavailable` and remains a
204
+ failed offer with a queued receipt; raw OS error strings are not persisted.
205
+
202
206
  ## Inbox, reply, and acknowledgement
203
207
 
204
208
  Without an id, public `inbox` lists bounded summary pages for unresolved messages owned
package/docs/RELEASING.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Releasing
2
2
 
3
3
  Use this procedure to build one auditable npm artifact, verify that exact tarball, and keep
4
- its evidence tied to the commit that supplied its bytes. The package is currently `0.4.1`;
4
+ its evidence tied to the commit that supplied its bytes. The package is currently `0.4.3`;
5
5
  the commands derive the version from `package.json` so the filename cannot drift.
6
6
 
7
7
  ```mermaid
@@ -79,6 +79,13 @@ consent before offers. A loaded daemon thread can receive messages after its TUI
79
79
  exits. Delivery off and uninstall prevent new Codex submissions; a submission
80
80
  already accepted by the vendor queue cannot be withdrawn.
81
81
 
82
+ On captured Codex/macOS configurations, live opt-in also grants outgoing access to ACC's
83
+ state and local Unix sockets through a deny-by-default network proxy. Custom permission
84
+ policies remain user-owned. Selection, proxy and grants are restored together only while
85
+ unchanged; edited or newly referenced settings remain intact. See
86
+ [Codex outgoing permissions](CONFIGURATION.md#codex-outgoing-permissions). Configuration
87
+ readiness does not prove that an active session's overrides permit a live offer.
88
+
82
89
  ## Claims
83
90
 
84
91
  CLI claims default to advisory. Guarded enforcement must be requested explicitly and
@@ -94,13 +94,65 @@ For Codex, use your ordinary launch command with 0.152.1 or newer on Apple Silic
94
94
  macOS. Its LocalDaemon must already be running, and trusted hooks must establish
95
95
  the receiver's exact thread and workspace. Embedded sessions, an absent socket,
96
96
  ambiguous recipients or failed identity checks retain durable inbox access.
97
- `acc doctor` reports current eligibility. ACC preserves requested consent through
98
- a temporary daemon outage and does not start the daemon for you.
97
+ `acc doctor` reports readiness, consent and the current workspace's live channel separately.
98
+ `native_endpoint_unavailable` means the local service endpoint is missing or is not a safe socket;
99
+ `native_session_unavailable` means the service answered but has no loaded thread to probe.
100
+ An interactive install can save consent in either case. ACC preserves it through a temporary
101
+ outage and does not start the daemon for you.
102
+
103
+ On a supported Codex CLI, a missing daemon can be started with
104
+ `codex app-server daemon start`; open a new Codex session afterward. Doctor includes this
105
+ command when it detects the missing endpoint.
106
+
107
+ If a reply stays queued with `transport_permission_denied`, the sender's permissions
108
+ blocked local transport. This is distinct from an unavailable recipient. The message was
109
+ recorded successfully; the error does not mean it was read or acknowledged.
110
+ On Codex 0.153.4 or newer on macOS arm64, rerun `acc install --adapter codex` with existing
111
+ live consent (or add `--delivery actionable` to opt in), then start a new session.
112
+ Doctor's `outgoingDelivery` reports the installed permission configuration separately
113
+ from `nativeDelivery.runtime`: an active receiving channel does not establish outgoing
114
+ access. Custom policies and active-session overrides remain unverified; inspect the config
115
+ path doctor names and follow [outgoing permissions](CONFIGURATION.md#codex-outgoing-permissions).
116
+
117
+ Check `acc doctor --json` and `acc status --json` while both clients are open. If policy is
118
+ `off`, opt in with `acc install --adapter codex --delivery actionable` (or select another
119
+ adapter). This can spend model tokens. If policy is enabled but runtime is `waiting` and
120
+ `deliveryBindings` is empty, no live channel is bound in this workspace. Start a new client
121
+ session, check its integration prompts and re-run doctor. A healthy store, online peers,
122
+ or a connected MCP server does not by itself establish automatic delivery. `lifecycle:
123
+ manual` can also mean the current version has no certified session-end hook; it does not
124
+ prove that no hooks ran.
99
125
 
100
126
  For Claude Code, open a fresh interactive zsh after installation so its launcher
101
- is on PATH, and accept its visible development-channel warning. A failed channel
102
- connection may remain in Claude's `~/.claude/mcp-needs-auth-cache.json` for about
103
- fifteen minutes; remove only the `acc` entry and restart if that is the cause.
127
+ is on PATH. Check Claude's **Channels startup notice for ACC**, and accept the
128
+ development-channel warning when it appears. A successful bootstrap cache means the
129
+ executable passed ACC's compatibility probe. `/mcp` showing `connected` and two tools
130
+ means the MCP server connected. Even `runtime: active` in ACC's doctor JSON describes
131
+ the local transport; none of these proves that Claude enabled inbound channel messages.
132
+
133
+ If Claude says `--dangerously-load-development-channels ignored` or `Channels are not
134
+ currently available`, it has not enabled that delivery path. On a fresh 2.1.266 test
135
+ profile, the first launch showed those messages and the next launch showed the development
136
+ warning; restarting once can recheck availability, but is not a guaranteed fix. If it
137
+ remains unavailable, follow Claude's notice. Organization policy can also block Channels;
138
+ an administrator must enable them where required. ACC does not override that policy.
139
+ See [Claude's Channels documentation](https://code.claude.com/docs/en/channels).
140
+
141
+ If `deliveryBindings` is empty, ACC has not bound a local transport either. Read the
142
+ per-session lines in `acc doctor`, or `nativeDelivery.sessions[].lastAttempt` in JSON:
143
+
144
+ - An absent launch policy means that hook did not receive delivery consent, even if an
145
+ earlier bootstrap probe succeeded. For Claude, open a new terminal and client through
146
+ the installed launcher.
147
+ - `client_process_unknown` means ACC could not identify the client process. A new client
148
+ session repeats that lookup.
149
+ - `handshake_failed` or `handshake_timeout` means the session could not bind the local
150
+ channel. Check the client's integration/channel setup; the next ordinary turn retries.
151
+ - No attempt observed can mean no native hook ran, an older runtime wrote the owner, or
152
+ diagnostic persistence failed. Check hook activation and the runtime versions in doctor.
153
+
154
+ The timestamp describes the last attempt for that exact generation. A past successful
155
+ handshake does not establish a currently reachable channel or client-side admission.
104
156
 
105
157
  Closing a Codex terminal can leave its daemon thread loaded and eligible. Use
106
158
  `acc install --adapter codex --delivery off` to stop new ACC native offers.
@@ -115,8 +167,9 @@ definitions need review, and a trusted hook can still be disabled.
115
167
 
116
168
  `acc doctor` reports installed files separately from hook readiness, which it leaves
117
169
  unverified. A saved trust record cannot prove current activation. If installation preserved
118
- your own sandbox configuration, doctor also names the ACC state directory whose access
119
- you should check in `sandbox_workspace_write.writable_roots`.
170
+ your own legacy sandbox configuration, doctor also names the ACC state directory whose
171
+ access you should check in `sandbox_workspace_write.writable_roots`. Live delivery requires
172
+ local socket permissions as well; a writable state directory alone is insufficient.
120
173
 
121
174
  ## Gemini does not guard a write
122
175
 
package/docs/UPGRADING.md CHANGED
@@ -1,12 +1,13 @@
1
- # Upgrading to 0.4.1
1
+ # Upgrading to 0.4.3
2
2
 
3
- ## From 0.4.0
3
+ ## From 0.4.2, 0.4.1 or 0.4.0
4
4
 
5
- This patch keeps the existing workspace data format. It fixes Grok CLI ownership,
6
- relocated Grok profiles, automatic-update preferences after reinstall, and the warning
7
- when a client starts in a directory containing ACC's own state.
5
+ This patch keeps the existing workspace data format. It fixes outgoing native delivery
6
+ from Codex's sandbox, separates permission failures from unavailable recipients, and
7
+ shows outgoing setup alongside receiving-channel state in doctor. It also includes the
8
+ previous 0.4.x delivery diagnostics, session recovery and client integration fixes.
8
9
 
9
- Close the participating clients and persistent ACC MCP processes, then run:
10
+ Close participating clients and persistent ACC MCP processes, then run:
10
11
 
11
12
  ```bash
12
13
  acc update
@@ -14,17 +15,33 @@ acc version
14
15
  acc doctor
15
16
  ```
16
17
 
17
- After publication, `acc version` should report 0.4.1. A managed update refreshes the
18
- installed integrations and skills. Restart the clients and complete any hook/trust
19
- review they request. Existing managed installations activate the selected runtime
20
- through `acc update`; use the npm install steps below for pre-0.4 or unmanaged
21
- installations. When pinned to 0.4.0, select 0.4.1 or clear the pin first.
22
-
23
- In Grok, the refreshed skill runs public status through the terminal before its first
24
- owned command. The hook reminder after that result supplies the session's own CLI
25
- arguments. Grok still reads peer messages explicitly through inbox; this patch does not
26
- add external wake or certify guards. Start clients in a project directory, rather than
27
- in a home directory containing ACC state.
18
+ After publication, `acc version` should report 0.4.3. If a pin keeps an older version,
19
+ select 0.4.3 or clear it first. A managed update refreshes installed integrations and
20
+ skills; use the npm instructions below for unmanaged or pre-0.4 installations. Start
21
+ clients again and complete any hook/trust review they request. With existing live consent,
22
+ Codex 0.153.4 or newer on macOS arm64 receives local socket permissions when its workspace
23
+ policy is default or contains only ACC's legacy state root. Custom policies are preserved
24
+ and reported as unverified. See [outgoing permissions](CONFIGURATION.md#codex-outgoing-permissions).
25
+ If doctor names a missing local service, run `codex app-server daemon start` before opening
26
+ the new session.
27
+
28
+ Run `acc doctor` in the project after the new clients have started (or submitted a normal
29
+ turn). Its per-session lines now explain missing launch consent, an unidentified client
30
+ process and a failed or timed-out handshake. `nativeDelivery.sessions[].lastAttempt` in
31
+ `acc doctor --json` provides the same closed metadata and timestamp. Existing owners may
32
+ have no attempt record until a new hook runs; missing metadata does not prove hooks are
33
+ disabled. A previous successful handshake and a connected MCP server do not prove that
34
+ Claude admitted inbound Channels messages. See [delivery troubleshooting](TROUBLESHOOTING.md#i-enabled-live-delivery-but-got-fallback).
35
+
36
+ Upgrading preserves delivery consent. If doctor reports native delivery off and you want
37
+ automatic peer requests, use `acc install --adapter codex --delivery actionable` (or the
38
+ relevant adapter); this can spend model tokens. Codex can save that consent before its
39
+ local service/session becomes available. ACC does not start the vendor daemon, and it
40
+ keeps durable inbox access when no verified live channel is bound.
41
+
42
+ In Grok, public status supplies the session's own CLI arguments through the next tool
43
+ hook. Grok still uses explicit inbox reads; this patch adds no external wake or guards.
44
+ Start clients in a project directory, rather than a home directory containing ACC state.
28
45
 
29
46
  ## From 0.3.1
30
47
 
@@ -47,7 +64,7 @@ restores access; deleting or editing the record is not a remedy.
47
64
  2. Install the released package, then refresh the client integrations:
48
65
 
49
66
  ```bash
50
- npm install --global agents-can-communicate@0.4.1
67
+ npm install --global agents-can-communicate@0.4.3
51
68
  acc version
52
69
  acc install
53
70
  ```
@@ -97,7 +114,7 @@ acc update # download and apply, or report what is keeping it
97
114
  acc update --check # check without installing or changing update settings
98
115
  acc update --auto off # disable background updates
99
116
  acc update --auto on # enable them again
100
- acc update --pin 0.4.1 # stay on this exact stable version
117
+ acc update --pin 0.4.3 # stay on this exact stable version
101
118
  acc update --pin none # follow stable releases again
102
119
  ```
103
120
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/adapter-claude-code",
3
- "version": "0.4.1",
3
+ "version": "0.4.3",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -11,9 +11,9 @@ import { bindNativeSession, offerMessage, planNativeActivation, probeNativeDeliv
11
11
  export const CLAUDE_CODE_VERSION = "2.1.233";
12
12
  export const CLAUDE_CHANNEL_MINIMUM = "2.1.258";
13
13
  export const CLAUDE_DELIVERY_FALLBACK = Object.freeze({
14
- diagnostic: "Claude Code native delivery is off: the 2.1.252 capture stopped at the "
15
- + "development-channel security warning before the ACC MCP child started; messages "
16
- + "stay durable for certified next-turn delivery or acc inbox",
14
+ diagnostic: "Claude Code native delivery requires client-side Channels activation; "
15
+ + "a successful bootstrap or connected ACC MCP server does not prove inbound delivery "
16
+ + "is enabled. Messages remain durable for certified next-turn delivery or acc inbox",
17
17
  });
18
18
 
19
19
  /**
@@ -1,8 +1,8 @@
1
1
  import { randomBytes, timingSafeEqual } from "node:crypto";
2
2
  import { chmodSync, existsSync, mkdirSync, statSync, unlinkSync, writeFileSync } from "node:fs";
3
3
  import net from "node:net";
4
- import os from "node:os";
5
4
  import path from "node:path";
5
+ import { channelSocketDirectory } from "@agents-can-communicate/adapter-sdk";
6
6
 
7
7
  // The production ACC Channel: a stdio MCP server Claude Code spawns, plus a
8
8
  // session-scoped Unix endpoint the delivery router reaches. One envelope on the
@@ -39,8 +39,6 @@ const shortId = () => `endpoint_${randomBytes(16).toString("hex")}`;
39
39
  // while the registration - discoverable by the hook-resolved pid - stays under
40
40
  // the workspace. The registration records the socket's absolute path, so the
41
41
  // two are decoupled.
42
- const defaultSocketDir = () => path.join(os.tmpdir(),
43
- `acc-ch-${typeof process.getuid === "function" ? process.getuid() : "u"}`);
44
42
 
45
43
  /**
46
44
  * Compose a Channel over an endpoint directory and injected ACC callbacks.
@@ -49,7 +47,7 @@ const defaultSocketDir = () => path.join(os.tmpdir(),
49
47
  * ones backed by the real conversation service; a test supplies fakes. Neither
50
48
  * the socket path nor the nonce leaves through a return value or a log line.
51
49
  */
52
- export function createAccChannel({ endpointDir, socketDir = defaultSocketDir(), clientPid,
50
+ export function createAccChannel({ endpointDir, socketDir = channelSocketDirectory(), clientPid,
53
51
  protocolContract = PROTOCOL_CONTRACT, modes = CHANNEL_MODES, leaseMs = 60_000, routeReply,
54
52
  routeAck, refreshBinding = null, observe = () => {},
55
53
  clock = () => new Date().toISOString(), write, now = Date.now }) {
@@ -1,6 +1,9 @@
1
1
  import { cp, mkdir, readdir, readFile, rm, writeFile } from "node:fs/promises";
2
2
  import path from "node:path";
3
3
 
4
+ // Kept together above 300 lines: source and cache publication, vendor registry
5
+ // merges and their exact uninstall share one ownership transaction and helpers.
6
+
4
7
  import { AccError, EXIT } from "@agents-can-communicate/protocol";
5
8
  import { fileURLToPath } from "node:url";
6
9
 
@@ -19,6 +22,9 @@ const manifest = fileURLToPath(new URL("../plugin/.claude-plugin/plugin.json",
19
22
  const PLUGIN_NAME = "agents-can-communicate";
20
23
  const MARKETPLACE = "acc-local";
21
24
  const QUALIFIED = `${PLUGIN_NAME}@${MARKETPLACE}`;
25
+ const CHANNEL_ACTIVATION_CHECK = "Check Claude's Channels startup notice for ACC; "
26
+ + "an MCP connection does not verify inbound delivery. If Channels are unavailable "
27
+ + "or blocked, resolve that client warning before expecting live messages.";
22
28
 
23
29
  /**
24
30
  * How this client actually installs a plugin.
@@ -244,6 +250,7 @@ export async function installClaudePlugin({ configDir, runner, cli, preserveVers
244
250
  changes: [source, cached, marketplaceFile(configDir),
245
251
  knownMarketplacesPath(configDir), installedPluginsPath(configDir), file,
246
252
  ...(live ? [mcpPath(source), mcpPath(cached)] : [])],
253
+ needsAction: live ? [CHANNEL_ACTIVATION_CHECK] : [],
247
254
  diagnostics: live
248
255
  ? ["native channel wired; Claude's experimental development-channel warning still applies"]
249
256
  : [] };
@@ -290,7 +297,10 @@ export async function detectClaude({ configDir }) {
290
297
  const registered = Object.hasOwn(
291
298
  (await readJson(installedPluginsPath(configDir), { plugins: {} })).plugins ?? {},
292
299
  QUALIFIED);
300
+ const channelConfigured = enabled && registered
301
+ && (await readJson(mcpPath(sourceDir(configDir)), null))?.mcpServers?.["acc-channel"] != null;
293
302
  return { ok: true, changes: [],
303
+ needsAction: channelConfigured ? [CHANNEL_ACTIVATION_CHECK] : [],
294
304
  diagnostics: [enabled && registered
295
305
  ? "acc plugin registered and enabled"
296
306
  : "acc plugin not registered"] };
@@ -206,7 +206,9 @@ function sendEnvelope({ record, message, binding, connect, timeoutMs, rejected }
206
206
  const finish = value => { if (settled) return; settled = true; clearTimeout(timer);
207
207
  socket.destroy(); resolve(value); };
208
208
  const timer = setTimeout(() => finish(rejected("transport_error")), timeoutMs);
209
- socket.once("error", () => finish(rejected("recipient_unavailable")));
209
+ socket.once("error", error => finish(rejected(
210
+ ["EPERM", "EACCES"].includes(error.code)
211
+ ? "transport_permission_denied" : "recipient_unavailable")));
210
212
  socket.once("connect", () => {
211
213
  socket.write(`${JSON.stringify(envelope)}\n`);
212
214
  let buffer = "";
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/adapter-codex",
3
- "version": "0.4.1",
3
+ "version": "0.4.3",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -65,7 +65,7 @@ export async function probeCodexQueue(peer, { threadId, minimum = MINIMUM_VERSIO
65
65
  const loaded = await pageAll(peer, "thread/loaded/list", {});
66
66
  threadId = loaded.find(id => typeof id === "string" && id !== "");
67
67
  if (threadId === undefined) return { supported: false, serverVersion,
68
- reasonCode: "feature_probe_failed" };
68
+ reasonCode: "native_session_unavailable" };
69
69
  }
70
70
  queueEntries(await peer.request("thread/queue/list", { threadId }));
71
71
  } catch (error) {
@@ -3,10 +3,8 @@ import path from "node:path";
3
3
  import { BEGIN, END, renderBlock } from "@agents-can-communicate/adapter-sdk";
4
4
  import { AccError, EXIT } from "@agents-can-communicate/protocol";
5
5
 
6
- const unsafe = (reason = "unrecognized TOML declaration") => {
7
- throw new AccError(EXIT.CONFLICT, `cannot safely edit Codex config: ${reason}; `
8
- + "repair ambiguous TOML or ACC markers before retrying", { reason });
9
- };
6
+ import { statements, declaration, unsafe } from "./toml-scan.mjs";
7
+
10
8
  const ROOT = "# ACC sandbox writable_roots created with: ";
11
9
  export const sandboxOwnership = root => `${ROOT}${JSON.stringify(root)}`;
12
10
 
@@ -16,88 +14,6 @@ const OWNED = new Map([
16
14
  [JSON.stringify(["sandbox_workspace_write"]), ["writable_roots"]],
17
15
  ]);
18
16
 
19
- // A bounded lexical scan, not a TOML value parser. Newlines inside strings,
20
- // arrays and inline tables cannot introduce a header or a managed marker.
21
- function* statements(source) {
22
- let start = 0, code = "", quote = null;
23
- const stack = [];
24
- for (let i = 0; i < source.length;) {
25
- const char = source[i];
26
- if (quote) {
27
- if (quote[0] === '"' && char === "\\") {
28
- code += source.slice(i, i + 2); i += 2; continue;
29
- }
30
- if (source.startsWith(quote, i)) {
31
- let count = quote.length;
32
- if (quote.length === 3) {
33
- while (source[i + count] === quote[0]) count++;
34
- if (count > 5) unsafe("unsupported string quote delimiter");
35
- }
36
- code += source.slice(i, i + count); i += count; quote = null; continue;
37
- }
38
- if (quote.length === 1 && /[\r\n]/.test(char)) unsafe("newline in single-line string");
39
- code += char; i++; continue;
40
- }
41
- if (char === "#") {
42
- while (i < source.length && source[i] !== "\n") i++;
43
- continue;
44
- }
45
- if (char === '"' || char === "'") {
46
- quote = source.startsWith(char.repeat(3), i) ? char.repeat(3) : char;
47
- code += quote; i += quote.length; continue;
48
- }
49
- if (char === "[" || char === "{") stack.push(char);
50
- if (char === "]" || char === "}") {
51
- if (stack.pop() !== (char === "]" ? "[" : "{")) unsafe("mismatched collection delimiter");
52
- }
53
- code += char; i++;
54
- if (char === "\n" && stack.length === 0) {
55
- yield { raw: source.slice(start, i), code: code.trim() };
56
- start = i; code = "";
57
- }
58
- }
59
- if (quote || stack.length) unsafe(quote ? "unclosed string" : "unclosed collection");
60
- if (start < source.length) yield { raw: source.slice(start), code: code.trim() };
61
- }
62
-
63
- function decodeKey(key) {
64
- if (key[0] === "'") return key.slice(1, -1);
65
- if (key[0] !== '"') return key;
66
- return key.slice(1, -1).replace(/\\(U[\da-fA-F]{8}|u[\da-fA-F]{4}|[btnfr"\\])|\\./g,
67
- (match, escape) => {
68
- if (!escape) unsafe("unsupported quoted-key escape");
69
- if (/^[uU]/.test(escape)) {
70
- const point = Number.parseInt(escape.slice(1), 16);
71
- if (point > 0x10ffff || (point >= 0xd800 && point <= 0xdfff)) {
72
- unsafe("invalid quoted-key Unicode escape");
73
- }
74
- return String.fromCodePoint(point);
75
- }
76
- return ({ b: "\b", t: "\t", n: "\n", f: "\f", r: "\r", '"': '"', "\\": "\\" })[escape];
77
- });
78
- }
79
-
80
- function keyPath(code) {
81
- const keys = [];
82
- let rest = code.trimStart();
83
- for (;;) {
84
- const match = /^(?:[A-Za-z0-9_-]+|'[^'\r\n]*'|"(?:[^"\\\r\n]|\\[^\r\n])*")/.exec(rest);
85
- if (!match) unsafe("unrecognized TOML key");
86
- keys.push(decodeKey(match[0]));
87
- rest = rest.slice(match[0].length).trimStart();
88
- if (!rest.startsWith(".")) return { keys, rest };
89
- rest = rest.slice(1).trimStart();
90
- }
91
- }
92
-
93
- function declaration(code) {
94
- const header = code.startsWith("[");
95
- const array = header && code.startsWith("[[");
96
- const { keys, rest } = keyPath(header ? code.slice(array ? 2 : 1) : code);
97
- if (header ? rest !== (array ? "]]" : "]") : !rest.startsWith("=")) unsafe();
98
- return { keys, header, array, value: header ? null : rest.slice(1).trim() };
99
- }
100
-
101
17
  // An unchanged, newly generated sandbox has value provenance. A legacy or
102
18
  // edited sandbox belongs to the client as a whole and remains byte-preserved.
103
19
  function ownsSandbox(body) {
@@ -214,8 +130,8 @@ export async function readConfig(file) {
214
130
  });
215
131
  }
216
132
 
217
- export async function writeTomlBlock(file, body) {
218
- const { source } = inspectConfig(await readConfig(file), file);
133
+ export async function writeTomlBlock(file, body, preparedSource) {
134
+ const source = preparedSource ?? inspectConfig(await readConfig(file), file).source;
219
135
  const separator = source === "" || source.endsWith("\n") ? "" : "\n";
220
136
  await mkdir(path.dirname(file), { recursive: true });
221
137
  await writeFile(file, `${source}${separator}${renderBlock(body)}\n`);