agents-can-communicate 0.8.1 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/ADAPTER_AUTHORING.md +14 -0
- package/docs/CAPABILITIES.md +1 -1
- package/docs/CLI.md +16 -0
- package/docs/CONFIGURATION.md +73 -8
- package/docs/GETTING_STARTED.md +6 -3
- package/docs/HOW_IT_WORKS.md +3 -1
- package/docs/SECURITY_MODEL.md +12 -1
- package/docs/TROUBLESHOOTING.md +32 -5
- package/docs/UPGRADING.md +29 -1
- package/node_modules/@agents-can-communicate/adapter-antigravity/package.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-antigravity/plugin/plugin.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-antigravity/plugin/skills/acc/SKILL.md +7 -0
- package/node_modules/@agents-can-communicate/adapter-antigravity/src/adapter.mjs +3 -1
- package/node_modules/@agents-can-communicate/adapter-antigravity/src/allow-rule.mjs +204 -0
- package/node_modules/@agents-can-communicate/adapter-antigravity/src/install.mjs +45 -10
- package/node_modules/@agents-can-communicate/adapter-claude-code/package.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-claude-code/src/adapter.mjs +9 -0
- package/node_modules/@agents-can-communicate/adapter-claude-code/src/inbox-endpoint.mjs +3 -1
- package/node_modules/@agents-can-communicate/adapter-claude-code/src/inbox-observed-directories.mjs +62 -0
- package/node_modules/@agents-can-communicate/adapter-claude-code/src/inbox-socket-directories.mjs +41 -0
- package/node_modules/@agents-can-communicate/adapter-codex/package.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-codex/src/adapter.mjs +3 -0
- package/node_modules/@agents-can-communicate/adapter-codex/src/install.mjs +5 -4
- package/node_modules/@agents-can-communicate/adapter-codex/src/live-permissions.mjs +64 -12
- package/node_modules/@agents-can-communicate/adapter-gemini-cli/extension/gemini-extension.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-gemini-cli/package.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-grok/package.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-kimi/package.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-sdk/package.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-sdk/src/capabilities.mjs +7 -0
- package/node_modules/@agents-can-communicate/adapter-sdk/src/hook-shim.mjs +16 -2
- package/node_modules/@agents-can-communicate/adapter-sdk/src/index.mjs +1 -1
- package/node_modules/@agents-can-communicate/cli/package.json +1 -1
- package/node_modules/@agents-can-communicate/cli/src/doctor-command.mjs +9 -4
- package/node_modules/@agents-can-communicate/cli/src/install-command.mjs +11 -4
- package/node_modules/@agents-can-communicate/cli/src/main.mjs +44 -6
- package/node_modules/@agents-can-communicate/cli/src/native-session-diagnostics.mjs +20 -10
- package/node_modules/@agents-can-communicate/core/package.json +1 -1
- package/node_modules/@agents-can-communicate/core/src/status.mjs +12 -0
- package/node_modules/@agents-can-communicate/delivery-router/package.json +1 -1
- package/node_modules/@agents-can-communicate/hook-runner/package.json +1 -1
- package/node_modules/@agents-can-communicate/hook-runner/src/runner.mjs +9 -0
- package/node_modules/@agents-can-communicate/installer/package.json +1 -1
- package/node_modules/@agents-can-communicate/installer/src/detect.mjs +10 -3
- package/node_modules/@agents-can-communicate/installer/src/index.mjs +1 -0
- package/node_modules/@agents-can-communicate/installer/src/receiver-sockets.mjs +19 -0
- package/node_modules/@agents-can-communicate/mcp-server/package.json +1 -1
- package/node_modules/@agents-can-communicate/protocol/package.json +1 -1
- package/node_modules/@agents-can-communicate/storage-filesystem/package.json +1 -1
- package/node_modules/@agents-can-communicate/storage-filesystem/src/atomic-json.mjs +30 -4
- package/node_modules/@agents-can-communicate/storage-filesystem/src/safe-directory.mjs +56 -25
- package/node_modules/@agents-can-communicate/storage-filesystem/src/store.mjs +6 -2
- package/package.json +1 -1
|
@@ -29,6 +29,7 @@ export function createExampleAdapter() {
|
|
|
29
29
|
detect, install, uninstall, doctor,
|
|
30
30
|
planInstall, // what install would write
|
|
31
31
|
preflightUninstall, // optional read-only removal validation
|
|
32
|
+
inboundSockets, // optional: socket paths a live sender connects to
|
|
32
33
|
normalizeHook, // client payload -> normalised event
|
|
33
34
|
renderContext, // SyncResult -> text
|
|
34
35
|
renderContextResult, // text + ids of complete rendered groups
|
|
@@ -227,6 +228,19 @@ the refreshed lease. Refresh is not a heartbeat and cannot extend presence beyon
|
|
|
227
228
|
its own expiry. Optional `retireNativeSession()` cleans adapter-owned endpoint state
|
|
228
229
|
after confirmed core retirement; it must remain bounded and fail open for hooks.
|
|
229
230
|
|
|
231
|
+
An adapter whose `offerMessage()` connects to a Unix socket in the recipient's session
|
|
232
|
+
declares where those sockets live with the optional `inboundSockets(context)`. It returns
|
|
233
|
+
absolute paths, directories or sockets, derived from `context.env`, `context.platform` and
|
|
234
|
+
the client homes in the context. It runs synchronously, once per install, doctor or refresh
|
|
235
|
+
command, and must never throw. It may read the adapter's own records under
|
|
236
|
+
`context.stateRoot` when a session can bind outside what the environment implies. Claude Code
|
|
237
|
+
reads its endpoint records there, and keeps each read bounded. The installer
|
|
238
|
+
composes every known adapter's declaration into `context.receiverSockets`. An adapter whose
|
|
239
|
+
client sandboxes the sender's shell allows exactly that list, and reports its outgoing
|
|
240
|
+
permissions configured only while every entry is allowed. It never names another vendor's
|
|
241
|
+
paths itself. Codex does this in its permission profile. Declare a new receiving transport
|
|
242
|
+
here, or every Codex sender gets `transport_permission_denied` against it.
|
|
243
|
+
|
|
230
244
|
A package-shipped passing Codex installed-hook capture additionally references its
|
|
231
245
|
complete real product matrix through the selected provenance record's
|
|
232
246
|
`productEvidence: { fixture, sha256 }`. Package verification checks the actual file,
|
package/docs/CAPABILITIES.md
CHANGED
|
@@ -71,7 +71,7 @@ The limitations belong next to the adapters they affect:
|
|
|
71
71
|
|
|
72
72
|
| Adapter | Exact limitation and evidence |
|
|
73
73
|
|---|---|
|
|
74
|
-
| Antigravity CLI | 1.2.7 on darwin-arm64, captured in print mode, and every later release by the forward rule. Only `SessionStart`, `PreInvocation`, `PostInvocation` and `Stop` load; `SessionEnd`, `PreToolUse` and `PostToolUse` are accepted into the config file and silently dropped, so there is no tool guard and no session-end deregistration - a session goes offline by presence age or an explicit `acc finish`. Payloads carry no `hook_event_name`, so each registered command passes its own event name. The end-of-turn `Stop` continuation reaches the model and is a bounded nudge, not a gate: ACC continues a turn at most once and fails open, and the client caps consecutive continuations itself (vendor 1.1.9). `agy agentapi send-message` can wake an idle session - captured - but only with that session's language-server address and CSRF token, which exist in the agent's own shell and in no hook. ACC does not take that token, so live push and reply routing are false. A peer message that arrives while the model writes its last answer is carried by the `Stop` continuation instead. A write that parses can register nothing, so install and doctor read `agy -p "/hooks"` back instead of trusting the file. Live push (1.2.7, darwin-arm64, TUI only, experimental, recorded opt-in) runs through a relay the agent starts once per conversation from its own shell - the only process holding the session endpoint - after ACC's context asks it to, up to three times while none is serving; the operator approves that command at the client's permission prompt. An idle session wakes; a busy one sees the message after its running answer, or at the next model invocation when the turn waits on a tool. Print mode and the first session in a folder trusted at that launch get no relay. |
|
|
74
|
+
| Antigravity CLI | 1.2.7 on darwin-arm64, captured in print mode, and every later release by the forward rule. Only `SessionStart`, `PreInvocation`, `PostInvocation` and `Stop` load; `SessionEnd`, `PreToolUse` and `PostToolUse` are accepted into the config file and silently dropped, so there is no tool guard and no session-end deregistration - a session goes offline by presence age or an explicit `acc finish`. Payloads carry no `hook_event_name`, so each registered command passes its own event name. The end-of-turn `Stop` continuation reaches the model and is a bounded nudge, not a gate: ACC continues a turn at most once and fails open, and the client caps consecutive continuations itself (vendor 1.1.9). `agy agentapi send-message` can wake an idle session - captured - but only with that session's language-server address and CSRF token, which exist in the agent's own shell and in no hook. ACC does not take that token, so live push and reply routing are false. A peer message that arrives while the model writes its last answer is carried by the `Stop` continuation instead. A write that parses can register nothing, so install and doctor read `agy -p "/hooks"` back instead of trusting the file. Live push (1.2.7, darwin-arm64, TUI only, experimental, recorded opt-in) runs through a relay the agent starts once per conversation from its own shell - the only process holding the session endpoint - after ACC's context asks it to, up to three times while none is serving; the operator approves that command at the client's permission prompt. An idle session wakes; a busy one sees the message after its running answer, or at the next model invocation when the turn waits on a tool. Print mode and the first session in a folder trusted at that launch get no relay. The client asks before every shell command (1.2.12), so install always adds the prefix rule `command(<wrapper>)` to the client's settings to let the woken agent's ACC commands run without that prompt. A woken session answered with no prompt under that rule on 1.2.12 (2026-09-28); print mode with it has not been captured. |
|
|
75
75
|
| Codex | Next-turn context, captured on 0.147.0, requires plugin trust. The observed stock 0.153.4 upgrade from ACC 0.3.1 to 0.4 required fresh review of five modified hook definitions; a subsequent restart retained all five active (activation evidence, not new event certification). LocalDaemon native delivery was captured through the installed package on 0.152.1 and 0.153.4, darwin-arm64; minimum 0.152.1, recorded opt-in, current feature probe and exact thread/cwd/process/version/protocol checks are required. Ordinary launch preserves the receiver workspace without ACC arguments or daemon ownership. Embedded or unreachable sessions keep their inbox. Native `replyRoute` remains false. |
|
|
76
76
|
| Claude Code | 2.1.233 next-turn delivery waits for the next user prompt. From 2.1.282, captured on darwin-arm64 and applied on every platform whose inbox is a Unix socket, `delivery.livePush` is a live capability behind the native contract (experimental, off until opted in). ACC wakes the session through the inbox socket that Claude Code opens for every session, with one line of fixed ACC text and the message id. An idle session starts a turn. A busy session takes the wake between two tool calls. Each delivered wake fires `UserPromptSubmit`, so the next-turn hook shows the body and records the receipt `offered` via `next-turn`. The model answers with `acc reply`, so `delivery.replyRoute` stays false. A session in `bypassPermissions` mode holds each wake for approval unless `crossSessionInbound` is `accept`, and `refuse` drops wakes. Native Windows keeps next-turn delivery: its inbox is a named pipe that requires an auth line, and it is uncaptured. Linux is uncaptured. |
|
|
77
77
|
| Gemini CLI | Package-shipped next-turn certification starts at 0.57.0. Its TUI has no captured external wake or queue interface and `--acp` changes launch ownership, so native delivery is fallback-only; live push and reply routing remain false. |
|
package/docs/CLI.md
CHANGED
|
@@ -104,6 +104,17 @@ got. Two sessions of one participant show the same numbers, so read the workspac
|
|
|
104
104
|
`<n> offered, not retrieved` when that number is above zero. Offered is not read: a
|
|
105
105
|
transport took the bytes, and the model may or may not have looked.
|
|
106
106
|
|
|
107
|
+
A session is `stale` when no turn has sent a heartbeat for three heartbeat cadences. Each
|
|
108
|
+
session row says what a message to such a session meets. `processTracked` is true when ACC
|
|
109
|
+
knows the client process. A dead process makes the session `offline`, so a stale session with
|
|
110
|
+
a tracked process is idle. `liveDelivery` is true when the session has a live delivery
|
|
111
|
+
binding, and `liveLeaseCurrent` says whether the binding's lease is still valid. A stale
|
|
112
|
+
session wakes on send when the lease is valid, or when its adapter can verify the receiver
|
|
113
|
+
again: the router does that for a lapsed lease before it offers. The text line counts stale
|
|
114
|
+
sessions by that result:
|
|
115
|
+
`5 live (2 idle, wake on send; 1 idle until next turn; 1 idle, inbox only)`. `not answering`
|
|
116
|
+
is kept for a stale session whose process ACC does not know.
|
|
117
|
+
|
|
107
118
|
A participant with no open session is left out, unless messages still wait for it: queued,
|
|
108
119
|
or offered by a live transport and not yet shown again, so that its next turn would show
|
|
109
120
|
them. A message the next-turn hook already showed does not wait, since nothing will reach the
|
|
@@ -373,6 +384,11 @@ Your existing npm or Homebrew command and shell profiles remain unchanged.
|
|
|
373
384
|
An older consent that covered service start receives one expanded choice for the download.
|
|
374
385
|
An accepted or declined answer persists. To change a declined answer, use
|
|
375
386
|
`acc install --adapter codex --delivery actionable` (or `all` for that policy).
|
|
387
|
+
Installing the Antigravity adapter always adds one prefix rule for ACC's wrapper to
|
|
388
|
+
`~/.gemini/antigravity-cli/settings.json`, so ACC's commands run there without an approval
|
|
389
|
+
prompt; nothing asks about it and the delivery policy does not change it. Uninstall removes
|
|
390
|
+
exactly that rule. See
|
|
391
|
+
[Antigravity CLI command approval](CONFIGURATION.md#antigravity-cli-command-approval).
|
|
376
392
|
Explicit `--delivery actionable|all` also approves a required download on supported clients.
|
|
377
393
|
Dry runs, delivery off, doctor, automatic refresh, and message delivery do not download
|
|
378
394
|
Codex or start its service. Uninstall does not remove Codex or stop the shared vendor daemon.
|
package/docs/CONFIGURATION.md
CHANGED
|
@@ -131,8 +131,9 @@ The allowed values are `off`, `actionable`, and `all`; the default is `off`. Thi
|
|
|
131
131
|
does not belong in `acc.workspace.json`, where a pull request could opt someone else into
|
|
132
132
|
spending a turn. It also cannot create a capability. Every adapter reads live-delivery
|
|
133
133
|
consent from this installation record, and only from it. Exact-version evidence governs
|
|
134
|
-
ordinary hook features. Claude Code live delivery separately requires
|
|
135
|
-
|
|
134
|
+
ordinary hook features. Claude Code live delivery separately requires version 2.1.282 or
|
|
135
|
+
newer on macOS or Linux (on native Windows its inbox is a named pipe, so delivery stays
|
|
136
|
+
next-turn), and a current feature probe before installation applies the requested
|
|
136
137
|
policy. If those install-time checks fail, effective policy remains `off` and the installer
|
|
137
138
|
reports next-turn or inbox fallback. Each later session must also pass its own
|
|
138
139
|
generation-bound handshake. A failed session handshake clears or refuses that binding and
|
|
@@ -146,7 +147,7 @@ each wake for your approval unless its `crossSessionInbound` setting is `accept`
|
|
|
146
147
|
never overrides them. See
|
|
147
148
|
[held or dropped wakes](TROUBLESHOOTING.md#a-claude-code-session-holds-or-drops-acc-wakes).
|
|
148
149
|
|
|
149
|
-
Codex LocalDaemon delivery separately requires
|
|
150
|
+
Codex LocalDaemon delivery separately requires Codex 0.152.1 or newer, a
|
|
150
151
|
current feature probe, and exact thread, canonical cwd, process, version and protocol
|
|
151
152
|
checks. On Codex 0.154.0 or newer, explicit complete setup can download a missing matching
|
|
152
153
|
standalone package and prepare a definitely absent service. The setup choice names the
|
|
@@ -160,15 +161,47 @@ Unavailable or ineligible sessions retain durable inbox fallback. Use
|
|
|
160
161
|
### Codex outgoing permissions
|
|
161
162
|
|
|
162
163
|
Receiving a native message and sending from the agent's sandbox are separate operations.
|
|
163
|
-
On Codex 0.153.4 or newer
|
|
164
|
+
On Codex 0.153.4 or newer, live opt-in also configures outgoing access
|
|
164
165
|
for default workspace permissions. This happens even when the daemon is not yet available.
|
|
165
166
|
Installation, its preview, and the interactive consent question disclose this change.
|
|
166
167
|
|
|
167
168
|
ACC selects a permission profile named `acc-workspace`, extending `:workspace`. It grants
|
|
168
|
-
write access to the ACC state directory and allows only the
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
169
|
+
write access to the ACC state directory and allows only the Unix sockets ACC delivers to.
|
|
170
|
+
Each receiving adapter declares its own, and the profile lists all of them even when an
|
|
171
|
+
install names Codex alone:
|
|
172
|
+
|
|
173
|
+
| Receiver | Allowed path |
|
|
174
|
+
|---|---|
|
|
175
|
+
| Codex | the control socket, `<CODEX_HOME>/app-server-control/app-server-control.sock` |
|
|
176
|
+
| Antigravity CLI relay | the ACC channel directory, `/tmp/acc-ch-<uid>` on macOS |
|
|
177
|
+
| Claude Code inbox | `/tmp/cc-socks`, `/tmp/cc-socks-<uid>`, `$XDG_RUNTIME_DIR/cc-socks` or else `$CLAUDE_CODE_TMPDIR/cc-socks` when set, `/run/user/<uid>/cc-socks` on Linux, and the directory of every Claude Code inbox ACC has bound on this machine |
|
|
178
|
+
|
|
179
|
+
ACC writes each path with its existing parent resolved, so on macOS the entries read
|
|
180
|
+
`/private/tmp/...`. Codex resolves a granted path only if it exists when Codex builds the
|
|
181
|
+
sandbox policy, and the sandbox compares resolved paths: a `/tmp/cc-socks-<uid>` entry
|
|
182
|
+
written before that directory existed never matched. A socket that is a link, such as the
|
|
183
|
+
Codex control socket, keeps its own name.
|
|
184
|
+
|
|
185
|
+
A command in the Codex sandbox can therefore connect to any of your Claude Code sessions'
|
|
186
|
+
inbox sockets. Claude Code's own inbound settings still decide what a received frame may do,
|
|
187
|
+
and ACC checks Claude Code's session registry before each wake it sends.
|
|
188
|
+
|
|
189
|
+
The profile enables networking through `features.network_proxy = true`, with no external
|
|
190
|
+
domains allowed. The proxy and socket grants must stay together: enabling networking
|
|
191
|
+
without the proxy changes its scope.
|
|
192
|
+
|
|
193
|
+
Doctor reports outgoing delivery as configured only while the profile allows every socket
|
|
194
|
+
above. A profile that ACC 0.8.0 or 0.8.1 wrote lacks the Claude Code inbox directories;
|
|
195
|
+
doctor names the missing paths and `acc install --adapter codex`. That command and
|
|
196
|
+
`acc update` rewrite ACC's own profile under the recorded delivery policy, `off` included.
|
|
197
|
+
Start a new Codex session afterwards.
|
|
198
|
+
|
|
199
|
+
The environment variables above are read from the process that runs `acc install` or
|
|
200
|
+
`acc doctor`. A Claude Code session started with its own `CLAUDE_CODE_TMPDIR` or
|
|
201
|
+
`XDG_RUNTIME_DIR` binds its inbox elsewhere. ACC learns that directory when its hooks first
|
|
202
|
+
bind the session, from its own endpoint record. From then on doctor names the directory
|
|
203
|
+
until `acc install --adapter codex` or `acc update` adds it. Only a directory named as Claude
|
|
204
|
+
Code names its inboxes, `cc-socks` or `cc-socks-<uid>`, is taken from a record.
|
|
172
205
|
|
|
173
206
|
An existing legacy workspace-write configuration is migrated only when its sole writable
|
|
174
207
|
root is ACC's state directory. Custom permission/configuration profiles, additional roots,
|
|
@@ -184,6 +217,38 @@ generated permission component is unchanged.
|
|
|
184
217
|
If any component was edited or another setting depends on it, ACC preserves the entire
|
|
185
218
|
bundle and reports it for review. Plugin registration can still be removed independently.
|
|
186
219
|
|
|
220
|
+
### Antigravity CLI command approval
|
|
221
|
+
|
|
222
|
+
Antigravity CLI asks for approval before each shell command, ACC's included. A session that
|
|
223
|
+
live delivery wakes while you are away would therefore stop at the agent's first ACC command,
|
|
224
|
+
and the peer would get no answer until someone approved it. So when `acc install` installs
|
|
225
|
+
the Antigravity adapter, it always adds one rule to the client's own settings:
|
|
226
|
+
|
|
227
|
+
```text
|
|
228
|
+
~/.gemini/antigravity-cli/settings.json
|
|
229
|
+
permissions.allow: command(<home>/.gemini/config/acc/acc-cli.sh)
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
A one-word rule is a prefix: every command that starts with that path runs without asking.
|
|
233
|
+
The agent then runs every ACC command without asking you, including one a peer's message
|
|
234
|
+
prompts; every other command still asks. Install does not ask about the rule, and the
|
|
235
|
+
delivery policy does not change it: it is part of ACC's Antigravity integration, as its hooks
|
|
236
|
+
are.
|
|
237
|
+
|
|
238
|
+
ACC keeps every other key and rule in the file, leaves a rule you already had as yours, and
|
|
239
|
+
records what it added in its own data home. `acc uninstall` removes every copy of that rule (one
|
|
240
|
+
in the same words cannot be told from ACC's), and a
|
|
241
|
+
container or file ACC created only if nothing else is in it. A rule removed by hand comes back
|
|
242
|
+
at the next `acc install` or automatic refresh; uninstall is what keeps it out. A file that is
|
|
243
|
+
not valid JSON, or whose `permissions.allow` is not a list, is left as it is and reported. The
|
|
244
|
+
client reads the file when it starts, so restart `agy` after install.
|
|
245
|
+
|
|
246
|
+
The rule matches only a command whose first word is the path without quotes, so ACC's skill
|
|
247
|
+
for this client writes the path without quotes. When your home path contains a space or a
|
|
248
|
+
shell metacharacter, the path needs quotes, no rule can match it, and ACC adds none.
|
|
249
|
+
`acc doctor` reports the rule as present, absent, or unable to apply, and asks for
|
|
250
|
+
`acc install --adapter antigravity` when ACC's rule is missing.
|
|
251
|
+
|
|
187
252
|
## Override local paths and identity
|
|
188
253
|
|
|
189
254
|
Nothing in `acc.workspace.json` says where state is stored, and nothing there can — that is
|
package/docs/GETTING_STARTED.md
CHANGED
|
@@ -43,7 +43,7 @@ session after that review; changed hook definitions may require trust again.
|
|
|
43
43
|
|
|
44
44
|
For Codex live delivery, follow the outgoing-permission and local-service instructions
|
|
45
45
|
from install/doctor, then start a new session. Default workspace permissions can be
|
|
46
|
-
configured automatically on Codex 0.153.4 or newer
|
|
46
|
+
configured automatically on Codex 0.153.4 or newer. Custom settings are
|
|
47
47
|
preserved; see [outgoing permissions](CONFIGURATION.md#codex-outgoing-permissions).
|
|
48
48
|
With legacy sandbox settings, the named ACC state directory must also be in
|
|
49
49
|
`sandbox_workspace_write.writable_roots` in the config the installer identifies.
|
|
@@ -58,7 +58,7 @@ hooks wherever the client is at or after a captured version.
|
|
|
58
58
|
An interactive install asks one default-No question for all selected clients that need a
|
|
59
59
|
choice. Use `--delivery actionable|all` for explicit noninteractive consent. Use
|
|
60
60
|
`--delivery off` to disable incoming automatic requests. A dry run does not ask, write
|
|
61
|
-
configuration, download Codex, or start a service. On macOS
|
|
61
|
+
configuration, download Codex, or start a service. On macOS or Linux with Codex 0.154.0 or newer,
|
|
62
62
|
the choice includes downloading a missing standalone package from OpenAI. ACC selects the
|
|
63
63
|
matching version and keeps your existing npm or Homebrew command and shell profiles.
|
|
64
64
|
When supported Codex service preparation succeeds, it
|
|
@@ -150,7 +150,10 @@ infrastructure, recorded opt-in, and a verified session. Supported explicit setu
|
|
|
150
150
|
prepare a missing service. Start the client with your normal command. A loaded daemon thread can receive
|
|
151
151
|
messages after its terminal exits. Antigravity CLI 1.2.7 and later has one too: with delivery enabled,
|
|
152
152
|
ACC's context asks the agent to start a relay from its own shell, up to three times while
|
|
153
|
-
none is running, and you approve that command at the client's prompt.
|
|
153
|
+
none is running, and you approve that command at the client's prompt. Antigravity also asks
|
|
154
|
+
before each shell command, so install adds a rule that lets ACC's own commands run without
|
|
155
|
+
that prompt, and a woken session can answer while you are away; see
|
|
156
|
+
[Antigravity CLI command approval](CONFIGURATION.md#antigravity-cli-command-approval).
|
|
154
157
|
[Capabilities](CAPABILITIES.md) explains policy, versions and fallback.
|
|
155
158
|
|
|
156
159
|
Delivery evidence is deliberately narrow: `queued -> offered -> retrieved -> acknowledged`.
|
package/docs/HOW_IT_WORKS.md
CHANGED
|
@@ -123,7 +123,9 @@ All recipients have the same durable record, but adapters expose different accel
|
|
|
123
123
|
endpoint exists only in the agent's own shell, so ACC's context asks the agent once per
|
|
124
124
|
conversation to start a relay; the user approves that command. The relay keeps the endpoint
|
|
125
125
|
in memory, wakes an idle session with a fenced peer message, holds one for a busy session,
|
|
126
|
-
and ends with the client. It is experimental, off by default, and can spend tokens.
|
|
126
|
+
and ends with the client. It is experimental, off by default, and can spend tokens. The
|
|
127
|
+
woken agent's ACC commands run without the client's approval prompt because install adds
|
|
128
|
+
one allow rule for ACC's wrapper.
|
|
127
129
|
|
|
128
130
|
Grok, generic MCP, unsupported versions and uncaptured platforms use inbox polling.
|
|
129
131
|
[Capabilities](CAPABILITIES.md) lists evidence and fallback.
|
package/docs/SECURITY_MODEL.md
CHANGED
|
@@ -94,12 +94,22 @@ user's: a session in `bypassPermissions` mode holds each wake for approval unles
|
|
|
94
94
|
`crossSessionInbound` is `accept`, and `refuse` drops wakes.
|
|
95
95
|
|
|
96
96
|
On captured Codex/macOS configurations, live opt-in also grants outgoing access to ACC's
|
|
97
|
-
state and local Unix sockets through a deny-by-default network proxy.
|
|
97
|
+
state and local Unix sockets through a deny-by-default network proxy. The sockets are the
|
|
98
|
+
ones ACC delivers to, which include the directories where Claude Code binds each session's
|
|
99
|
+
inbox: a command in the Codex sandbox can connect to those sockets, and Claude Code's own
|
|
100
|
+
inbound settings decide what a received frame may do. Custom permission
|
|
98
101
|
policies remain user-owned. Selection, proxy and grants are restored together only while
|
|
99
102
|
unchanged; edited or newly referenced settings remain intact. See
|
|
100
103
|
[Codex outgoing permissions](CONFIGURATION.md#codex-outgoing-permissions). Configuration
|
|
101
104
|
readiness does not prove that an active session's overrides permit a live offer.
|
|
102
105
|
|
|
106
|
+
Antigravity CLI asks before each shell command. Installing its adapter adds one prefix rule
|
|
107
|
+
to that client's `permissions.allow`, for ACC's own wrapper path only. The agent then runs
|
|
108
|
+
every ACC command without a prompt, including one that a peer's message prompts. Every other
|
|
109
|
+
command still asks. ACC records the one rule it added and uninstall removes only that rule.
|
|
110
|
+
It never writes a settings file that it cannot parse. See
|
|
111
|
+
[Antigravity CLI command approval](CONFIGURATION.md#antigravity-cli-command-approval).
|
|
112
|
+
|
|
103
113
|
## Claims
|
|
104
114
|
|
|
105
115
|
CLI claims default to advisory. Guarded enforcement must be requested explicitly and
|
|
@@ -175,6 +185,7 @@ caller chooses to send. The sender remains responsible for that content.
|
|
|
175
185
|
| Symlink or traversal escapes a managed root | Per-segment containment, no-follow reads, closed config schema | Host filesystem compromise is out of scope |
|
|
176
186
|
| Claim denial of service | Leases, visible owner, explicit authority release | Deliberate abuse by a trusted local peer is social |
|
|
177
187
|
| Installer removes user configuration | Content-hashed ownership and byte comparison | User must remove modified leftovers manually |
|
|
188
|
+
| Peer message leads an Antigravity agent to run ACC commands unasked | Allow rule scoped to ACC's wrapper; every other command still asks; uninstall removes it | A peer can still prompt ACC actions, such as a reply or a claim, that nobody approves one by one |
|
|
178
189
|
| False delivery claim | Record-first order, transport-owned `offered`, recipient-owned retrieval/ack, mutation tests | Crash after offer before commit can cause duplicate display |
|
|
179
190
|
| Native endpoint leaks | Ephemeral opaque reference, user-only local endpoint, status redaction | Same-user local processes are outside the trust boundary |
|
|
180
191
|
| MCP client impersonates another session | Identity fixed by launch env, closed tool schemas | A compromised launch config already controls that client |
|
package/docs/TROUBLESHOOTING.md
CHANGED
|
@@ -138,8 +138,16 @@ client-owned hook and trust review.
|
|
|
138
138
|
If a reply stays queued with `transport_permission_denied`, the sender's permissions
|
|
139
139
|
blocked local transport. This is distinct from an unavailable recipient. The message was
|
|
140
140
|
recorded successfully; the error does not mean it was read or acknowledged.
|
|
141
|
-
On Codex 0.153.4 or newer
|
|
141
|
+
On Codex 0.153.4 or newer, rerun `acc install --adapter codex` with existing
|
|
142
142
|
live consent. Add `--delivery actionable` when new consent is required, then start a new session.
|
|
143
|
+
With ACC 0.8.0 or 0.8.1, every live offer from a Codex session to Claude Code failed this way:
|
|
144
|
+
the Codex profile did not allow Claude Code's inbox directories, and doctor still reported it
|
|
145
|
+
configured. Doctor now names the missing paths. `acc install --adapter codex` or `acc update`
|
|
146
|
+
rewrites the profile; start a new Codex session so it runs under the new one.
|
|
147
|
+
A Claude Code session started with its own `CLAUDE_CODE_TMPDIR` or `XDG_RUNTIME_DIR` binds its
|
|
148
|
+
inbox outside the directories your shell's environment implies. After ACC first binds that
|
|
149
|
+
session, doctor names its directory. Run `acc install --adapter codex` again, then start a new
|
|
150
|
+
Codex session.
|
|
143
151
|
Doctor's `outgoingDelivery` reports the installed permission configuration separately
|
|
144
152
|
from `nativeDelivery.runtime`: an active receiving channel does not establish outgoing
|
|
145
153
|
access. Custom policies and active-session overrides remain unverified; inspect the config
|
|
@@ -301,10 +309,11 @@ agy -p "/skills" --output-format json
|
|
|
301
309
|
|
|
302
310
|
An agent that receives a peer message in print mode (`agy -p`) cannot answer it on its own.
|
|
303
311
|
It forms the right `acc reply` command from the skill, and print mode denies every command
|
|
304
|
-
because it cannot ask for approval; the client says so on stderr
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
312
|
+
because it cannot ask for approval; the client says so on stderr and names
|
|
313
|
+
`permissions.allow` in its settings. The TUI asks instead. The one rule ACC's install adds
|
|
314
|
+
there is described in
|
|
315
|
+
[Antigravity CLI command approval](CONFIGURATION.md#antigravity-cli-command-approval); it was
|
|
316
|
+
captured in the TUI, and print mode with it has not been captured.
|
|
308
317
|
|
|
309
318
|
## Antigravity never wakes while idle
|
|
310
319
|
|
|
@@ -322,6 +331,24 @@ Live delivery needs four things, and `acc doctor` shows each:
|
|
|
322
331
|
active. A relay ends with its client; nothing is left running after the TUI exits or after
|
|
323
332
|
`acc uninstall`.
|
|
324
333
|
|
|
334
|
+
## Antigravity wakes and never answers
|
|
335
|
+
|
|
336
|
+
A woken session that stops at an approval prompt answers only once someone approves its
|
|
337
|
+
first ACC command. `acc doctor` prints an `Antigravity CLI inbound:` line with what it found in
|
|
338
|
+
`~/.gemini/antigravity-cli/settings.json`:
|
|
339
|
+
|
|
340
|
+
- **No rule.** Each ACC command waits for approval. ACC's install writes the rule, so it was
|
|
341
|
+
removed since or the install did not reach this file: run `acc install --adapter antigravity`,
|
|
342
|
+
then restart `agy`. Doctor lists this under what to run next.
|
|
343
|
+
- **The rule is present.** The client reads it at startup, so a session started before it was
|
|
344
|
+
added still asks; restart `agy`. If a prompt still appears, check the command the agent
|
|
345
|
+
ran: a path in quotes, or a command wrapped in `sh -c`, matches no rule.
|
|
346
|
+
- **The rule cannot apply.** The path to ACC's wrapper contains a space or a shell
|
|
347
|
+
metacharacter, so it needs quotes, and a quoted first word matches no rule. ACC adds no
|
|
348
|
+
rule and approvals stay manual.
|
|
349
|
+
- **The file cannot be read.** ACC leaves an invalid `settings.json` as it is. Repair it, then
|
|
350
|
+
run `acc install --adapter antigravity` again.
|
|
351
|
+
|
|
325
352
|
## Grok shows no injected message
|
|
326
353
|
|
|
327
354
|
Grok discards UserPromptSubmit context. On the observed 1.0.24 client, run public
|
package/docs/UPGRADING.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# Upgrading to 0.5.0
|
|
2
2
|
|
|
3
|
+
## From 0.8.x
|
|
4
|
+
|
|
5
|
+
Update as usual:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
acc update
|
|
9
|
+
acc version
|
|
10
|
+
acc doctor
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The update refreshes every installed integration with its recorded policy. Two of them change
|
|
14
|
+
a client's own settings:
|
|
15
|
+
|
|
16
|
+
- **Codex.** ACC's permission profile in `~/.codex/config.toml` also allows the Claude Code
|
|
17
|
+
inbox socket directories, so a Codex session can wake a Claude Code session live. Grants are
|
|
18
|
+
written in their resolved form, such as `/private/tmp/cc-socks` on macOS. A profile you
|
|
19
|
+
edited stays yours: doctor then names the missing grants and `acc install --adapter codex`.
|
|
20
|
+
Start a new Codex session after the update; a session already open keeps its old policy.
|
|
21
|
+
- **Antigravity CLI.** The install adds `command(<wrapper>)` to `permissions.allow` in
|
|
22
|
+
`~/.gemini/antigravity-cli/settings.json`, and the skill calls the wrapper without quotes, so
|
|
23
|
+
a woken session runs its ACC commands without an approval prompt. Restart `agy`: it reads
|
|
24
|
+
the file only at startup. `acc uninstall` removes every copy of that rule.
|
|
25
|
+
|
|
26
|
+
`acc doctor` and `acc status` describe an idle session by what a message sent to it meets
|
|
27
|
+
(`idle, wake on send`, `idle until next turn`, `idle, inbox only`), and each status row carries
|
|
28
|
+
`processTracked`, `liveDelivery` and `liveLeaseCurrent`. This release adds no store event type
|
|
29
|
+
or field, so a store it writes stays readable by 0.8.x.
|
|
30
|
+
|
|
3
31
|
## From 0.7.x
|
|
4
32
|
|
|
5
33
|
Claude Code live delivery wakes each session through the inbox socket that Claude Code opens
|
|
@@ -165,7 +193,7 @@ keeps holding activation across an uninstall until it exits.
|
|
|
165
193
|
|
|
166
194
|
## Confirmed client service maintenance
|
|
167
195
|
|
|
168
|
-
|
|
196
|
+
`acc update` can ask once to restart a verified Codex service that holds a
|
|
169
197
|
native binding blocking activation, or that is serving a version outside the captured
|
|
170
198
|
native-delivery contract. A serving version that satisfies that contract is left alone,
|
|
171
199
|
even when the installed CLI has moved to a newer build. The captured maintenance contract
|
|
@@ -41,6 +41,13 @@ work. An MCP connection can have a different participant from the hook session;
|
|
|
41
41
|
use inbox/reply only for the participant the message addresses. Do not borrow a
|
|
42
42
|
peer's ID, read runtime bindings, or improvise credentials.
|
|
43
43
|
|
|
44
|
+
### Run each command as written
|
|
45
|
+
|
|
46
|
+
Start every ACC command with `{{ACC}}` exactly as this skill writes it: add no
|
|
47
|
+
quotes around it and no `sh -c` wrapper. Antigravity CLI decides from a command's
|
|
48
|
+
first word whether it needs approval, and the rule that lets ACC commands run
|
|
49
|
+
without a prompt matches only that form.
|
|
50
|
+
|
|
44
51
|
## Start shared work once
|
|
45
52
|
|
|
46
53
|
After understanding the request, publish one concise intent:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineAdapter, projectContext, projectContextResult }
|
|
1
|
+
import { channelSocketDirectory, defineAdapter, projectContext, projectContextResult }
|
|
2
2
|
from "@agents-can-communicate/adapter-sdk";
|
|
3
3
|
import certification from "../certification.json" with { type: "json" };
|
|
4
4
|
|
|
@@ -82,6 +82,8 @@ export function createAntigravityAdapter() {
|
|
|
82
82
|
},
|
|
83
83
|
probeNativeDelivery, planNativeActivation, bindNativeSession, refreshNativeSession,
|
|
84
84
|
offerMessage,
|
|
85
|
+
// The relay binds in ACC's own channel directory; a sandboxed sender is allowed it.
|
|
86
|
+
inboundSockets: () => [channelSocketDirectory()],
|
|
85
87
|
deliveryFallback: { diagnostic:
|
|
86
88
|
`Antigravity CLI next-turn and live delivery are certified from ${ANTIGRAVITY_CLI_VERSION} `
|
|
87
89
|
+ "onward; live delivery also needs the agent to start ACC's relay once per conversation, "
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
import { blankJson, isShellWord, removeIfEmpty, writeForeignJson }
|
|
5
|
+
from "@agents-can-communicate/adapter-sdk";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The one allow rule ACC may add to Antigravity CLI's settings, with consent.
|
|
9
|
+
*
|
|
10
|
+
* Antigravity CLI asks before every shell command. On 1.2.12 a live push woke an
|
|
11
|
+
* idle session and its first ACC command waited at an approval prompt with
|
|
12
|
+
* nobody there, so the peer never got an answer (issue #214). A rule under
|
|
13
|
+
* `permissions.allow` removes the prompt. What 1.2.12 was captured doing:
|
|
14
|
+
*
|
|
15
|
+
* - The file is `~/.gemini/antigravity-cli/settings.json`, read once at startup.
|
|
16
|
+
* `~/.gemini/settings.json` belongs to Gemini CLI and is never touched here.
|
|
17
|
+
* - A one-word rule is a prefix: `command("<wrapper>")` let `<wrapper> help`
|
|
18
|
+
* run unasked.
|
|
19
|
+
* - A command whose first word is quoted matched no rule at all, quoted or not;
|
|
20
|
+
* quotes around an argument are fine. So the skill names the wrapper bare,
|
|
21
|
+
* and a wrapper path that only stays one word inside quotes cannot be allowed.
|
|
22
|
+
*
|
|
23
|
+
* ACC writes the bare form, `command(<wrapper>)`, on every install of this
|
|
24
|
+
* adapter: the user decided on 2026-09-27 that it is always on, with no
|
|
25
|
+
* question and no dependence on the delivery policy. The file is still the
|
|
26
|
+
* operator's: one that does not parse, or whose `permissions.allow` is not a
|
|
27
|
+
* list, is never rewritten. What ACC added is recorded in its own data home -
|
|
28
|
+
* the rule and the containers it had to create - and uninstall takes back
|
|
29
|
+
* exactly that, and always ends the claim, so the same words added later by
|
|
30
|
+
* the operator stay theirs.
|
|
31
|
+
*/
|
|
32
|
+
export const agySettingsPath = home => path.join(home, ".gemini", "antigravity-cli",
|
|
33
|
+
"settings.json");
|
|
34
|
+
export const cliWrapperPath = home => path.join(home, ".gemini", "config", "acc", "acc-cli.sh");
|
|
35
|
+
export const accAllowRule = wrapper => `command(${wrapper})`;
|
|
36
|
+
|
|
37
|
+
// Forms that already allow every command starting with the bare wrapper: the
|
|
38
|
+
// one ACC writes, and the quoted one-word form 1.2.12 was captured matching.
|
|
39
|
+
const allowingForms = wrapper => [accAllowRule(wrapper), `command("${wrapper}")`];
|
|
40
|
+
|
|
41
|
+
// Beside the `created-*` markers, for the same reason: the installer removes the
|
|
42
|
+
// shim directory before uninstall runs. `acc doctor` passes the state root.
|
|
43
|
+
const claimDir = ({ dataHome, stateRoot, home }) => typeof dataHome === "string" && dataHome !== ""
|
|
44
|
+
? path.join(dataHome, "acc", "adapter-antigravity")
|
|
45
|
+
: typeof stateRoot === "string" && stateRoot !== ""
|
|
46
|
+
? path.join(stateRoot, "adapter-antigravity")
|
|
47
|
+
: path.join(home, ".gemini", "config", "acc");
|
|
48
|
+
const claimPath = (context, file) => path.join(claimDir(context),
|
|
49
|
+
`allow-rule-${Buffer.from(file).toString("base64url")}`);
|
|
50
|
+
|
|
51
|
+
const isObject = value => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
52
|
+
|
|
53
|
+
async function readClaim(file) {
|
|
54
|
+
try {
|
|
55
|
+
const claim = JSON.parse(await readFile(file, "utf8"));
|
|
56
|
+
return typeof claim?.rule === "string" ? claim : null;
|
|
57
|
+
} catch {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** The settings as the client would read them, or why ACC must not edit them. */
|
|
63
|
+
async function readSettings(file) {
|
|
64
|
+
let text;
|
|
65
|
+
try {
|
|
66
|
+
text = await readFile(file, "utf8");
|
|
67
|
+
} catch (error) {
|
|
68
|
+
if (error.code === "ENOENT") return { state: "missing", value: {}, allow: [] };
|
|
69
|
+
return { state: "unreadable", reason: `could not be read (${error.code ?? error.message})` };
|
|
70
|
+
}
|
|
71
|
+
let value;
|
|
72
|
+
try {
|
|
73
|
+
value = JSON.parse(text);
|
|
74
|
+
} catch {
|
|
75
|
+
return { state: "unreadable", reason: "is not valid JSON" };
|
|
76
|
+
}
|
|
77
|
+
if (!isObject(value)) return { state: "unreadable", reason: "does not hold a JSON object" };
|
|
78
|
+
if (value.permissions !== undefined && !isObject(value.permissions)) {
|
|
79
|
+
return { state: "unreadable", reason: "has a permissions value that is not an object" };
|
|
80
|
+
}
|
|
81
|
+
const allow = value.permissions?.allow;
|
|
82
|
+
if (allow !== undefined && !Array.isArray(allow)) {
|
|
83
|
+
return { state: "unreadable", reason: "has a permissions.allow value that is not a list" };
|
|
84
|
+
}
|
|
85
|
+
return { state: "read", value, allow: allow ?? [] };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const RESTART = "Antigravity CLI reads it at startup, so a session started before it was "
|
|
89
|
+
+ "added still asks until agy restarts";
|
|
90
|
+
|
|
91
|
+
/** What the rule's state is on this machine, in words doctor can print. */
|
|
92
|
+
export async function inspectAllowRule(context) {
|
|
93
|
+
const file = agySettingsPath(context.home);
|
|
94
|
+
const wrapper = cliWrapperPath(context.home);
|
|
95
|
+
const rule = accAllowRule(wrapper);
|
|
96
|
+
const base = { file, wrapper, rule, owned: false };
|
|
97
|
+
if (!isShellWord(wrapper)) {
|
|
98
|
+
return { ...base, state: "unmatchable", diagnostic: "each ACC command waits for approval, "
|
|
99
|
+
+ "so a live wake stops at the agent's first ACC command until someone answers the "
|
|
100
|
+
+ `approval prompt. No allow rule can remove it here: the wrapper ${wrapper} stays one `
|
|
101
|
+
+ "shell word only inside quotes, and Antigravity CLI matches no rule against a command "
|
|
102
|
+
+ "whose first word is quoted. ACC adds the prefix rule to permissions.allow in "
|
|
103
|
+
+ `${file} when the wrapper path holds only letters, digits and . _ - /` };
|
|
104
|
+
}
|
|
105
|
+
const settings = await readSettings(file);
|
|
106
|
+
if (settings.state === "unreadable") {
|
|
107
|
+
return { ...base, state: "unreadable", diagnostic: `${file} ${settings.reason}, so ACC `
|
|
108
|
+
+ "leaves it as it is and cannot tell whether ACC commands wait for approval; a live "
|
|
109
|
+
+ "wake stops at the agent's first ACC command while they do. Repair the file, then run "
|
|
110
|
+
+ `acc install --adapter antigravity to add ${rule} to permissions.allow` };
|
|
111
|
+
}
|
|
112
|
+
const matched = settings.allow.find(entry => allowingForms(wrapper).includes(entry));
|
|
113
|
+
if (matched !== undefined) {
|
|
114
|
+
const claim = await readClaim(claimPath(context, file));
|
|
115
|
+
const owned = claim?.rule === matched;
|
|
116
|
+
return { ...base, state: "allowed", owned, diagnostic: "ACC commands run without an "
|
|
117
|
+
+ `approval prompt: permissions.allow in ${file} holds ${matched}`
|
|
118
|
+
+ `${owned ? ", added by ACC" : ""}. ${RESTART}` };
|
|
119
|
+
}
|
|
120
|
+
// Every install writes the rule, so its absence means one did not run here, or
|
|
121
|
+
// the rule was taken out since.
|
|
122
|
+
return { ...base, state: "prompts",
|
|
123
|
+
diagnostic: "each ACC command waits for approval, so a live wake stops at the agent's "
|
|
124
|
+
+ "first ACC command until someone answers the approval prompt. ACC's install adds "
|
|
125
|
+
+ `${rule} to permissions.allow in ${file}, and it is not there: run acc install `
|
|
126
|
+
+ "--adapter antigravity, then restart agy" };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async function addRule(context, found) {
|
|
130
|
+
const settings = await readSettings(found.file);
|
|
131
|
+
const claimFile = claimPath(context, found.file);
|
|
132
|
+
// Only what this write creates. A file or container that is already there is
|
|
133
|
+
// the operator's as far as ACC can tell: one ACC made earlier cannot be told
|
|
134
|
+
// from one they put in its place, and carrying the old flags over deleted
|
|
135
|
+
// their file at uninstall (review of #218). The cost is an empty container
|
|
136
|
+
// ACC once made staying after uninstall, never the operator's file going.
|
|
137
|
+
const created = {
|
|
138
|
+
file: settings.state === "missing",
|
|
139
|
+
permissions: settings.value.permissions === undefined,
|
|
140
|
+
allow: settings.value.permissions?.allow === undefined,
|
|
141
|
+
};
|
|
142
|
+
// The claim first: a crash between the two leaves a claim with no rule, which
|
|
143
|
+
// uninstall drops, rather than a rule nobody can tell is ACC's.
|
|
144
|
+
await mkdir(path.dirname(claimFile), { recursive: true });
|
|
145
|
+
await writeFile(claimFile, `${JSON.stringify({ file: found.file, rule: found.rule,
|
|
146
|
+
created })}\n`);
|
|
147
|
+
await writeForeignJson(found.file, { ...settings.value, permissions: {
|
|
148
|
+
...settings.value.permissions, allow: [...settings.allow, found.rule] } },
|
|
149
|
+
{ readFile, writeFile, mkdir });
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Take back the rule ACC recorded adding, and the containers it created if they
|
|
154
|
+
* are empty. Every copy of it goes: one in the same words cannot be told from
|
|
155
|
+
* ACC's, and the client itself has duplicated grants across reloads, so taking
|
|
156
|
+
* one back left ACC commands running unasked after uninstall (review of #218).
|
|
157
|
+
* Anything else in the file stays, and a rule the operator had before ACC came
|
|
158
|
+
* was never claimed.
|
|
159
|
+
*/
|
|
160
|
+
export async function withdrawAllowRule(context) {
|
|
161
|
+
const file = agySettingsPath(context.home);
|
|
162
|
+
const claimFile = claimPath(context, file);
|
|
163
|
+
const claim = await readClaim(claimFile);
|
|
164
|
+
if (claim === null) return { changes: [], diagnostics: [], needsAction: [] };
|
|
165
|
+
const settings = await readSettings(file);
|
|
166
|
+
if (settings.state === "unreadable") {
|
|
167
|
+
// Kept, so the next install or uninstall can finish once the file reads.
|
|
168
|
+
return { changes: [], diagnostics: [], needsAction: [`${file} ${settings.reason}; ACC `
|
|
169
|
+
+ `left it as it is and still has to remove its ${claim.rule} from permissions.allow`] };
|
|
170
|
+
}
|
|
171
|
+
if (!settings.allow.includes(claim.rule)) {
|
|
172
|
+
await rm(claimFile, { force: true });
|
|
173
|
+
return { changes: [], diagnostics: [], needsAction: [] };
|
|
174
|
+
}
|
|
175
|
+
const permissions = { ...settings.value.permissions,
|
|
176
|
+
allow: settings.allow.filter(rule => rule !== claim.rule) };
|
|
177
|
+
if (claim.created?.allow === true && permissions.allow.length === 0) delete permissions.allow;
|
|
178
|
+
const next = { ...settings.value, permissions };
|
|
179
|
+
if (claim.created?.permissions === true && Object.keys(permissions).length === 0) {
|
|
180
|
+
delete next.permissions;
|
|
181
|
+
}
|
|
182
|
+
await writeForeignJson(file, next, { readFile, writeFile, mkdir });
|
|
183
|
+
if (claim.created?.file === true) {
|
|
184
|
+
await removeIfEmpty(file, { readFile, rm, isEmpty: blankJson() });
|
|
185
|
+
}
|
|
186
|
+
await rm(claimFile, { force: true });
|
|
187
|
+
return { changes: [file], diagnostics: [`removed ACC's ${claim.rule} from ${file}`],
|
|
188
|
+
needsAction: [] };
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** Put ACC's rule in place, at every install. */
|
|
192
|
+
export async function ensureAllowRule(context) {
|
|
193
|
+
const found = await inspectAllowRule(context);
|
|
194
|
+
if (found.state === "unmatchable" || found.state === "unreadable") {
|
|
195
|
+
return { changes: [], diagnostics: [found.diagnostic], needsAction: [found.diagnostic] };
|
|
196
|
+
}
|
|
197
|
+
if (found.state === "allowed") {
|
|
198
|
+
return { changes: [], diagnostics: [found.diagnostic], needsAction: [] };
|
|
199
|
+
}
|
|
200
|
+
await addRule(context, found);
|
|
201
|
+
return { changes: [found.file], needsAction: [], diagnostics: [`added ${found.rule} to `
|
|
202
|
+
+ `permissions.allow in ${found.file}: ACC commands run without an approval prompt in `
|
|
203
|
+
+ "Antigravity sessions started from now on; restart agy for a session already open"] };
|
|
204
|
+
}
|