@cybedefend/vibedefend 1.7.0 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -13
- package/dist/clients/antigravity.js +342 -0
- package/dist/clients/antigravity.js.map +1 -0
- package/dist/clients/registry.js +2 -0
- package/dist/clients/registry.js.map +1 -1
- package/dist/clients/windsurf.js +20 -8
- package/dist/clients/windsurf.js.map +1 -1
- package/dist/hook-runner.js +930 -227
- package/dist/hooks/install.js +1 -1
- package/dist/hooks/install.js.map +1 -1
- package/dist/hooks/runtime/antigravity-session.js +400 -0
- package/dist/hooks/runtime/antigravity-session.js.map +1 -0
- package/dist/hooks/runtime/emit.js +206 -0
- package/dist/hooks/runtime/emit.js.map +1 -1
- package/dist/hooks/runtime/exit-deadlock-guard.js +46 -0
- package/dist/hooks/runtime/exit-deadlock-guard.js.map +1 -0
- package/dist/hooks/runtime/fetch-rules.js +39 -3
- package/dist/hooks/runtime/fetch-rules.js.map +1 -1
- package/dist/hooks/runtime/pre-invocation.js +45 -0
- package/dist/hooks/runtime/pre-invocation.js.map +1 -0
- package/dist/hooks/runtime/runner-args.js +12 -0
- package/dist/hooks/runtime/runner-args.js.map +1 -0
- package/dist/hooks/runtime/session-activation.js +10 -4
- package/dist/hooks/runtime/session-activation.js.map +1 -1
- package/dist/hooks/runtime/session-review.js +42 -0
- package/dist/hooks/runtime/session-review.js.map +1 -1
- package/dist/hooks/runtime/session-start.js +21 -1
- package/dist/hooks/runtime/session-start.js.map +1 -1
- package/dist/hooks/runtime/sniff.js +345 -71
- package/dist/hooks/runtime/sniff.js.map +1 -1
- package/dist/hooks/runtime/work-dir.js +3 -0
- package/dist/hooks/runtime/work-dir.js.map +1 -1
- package/dist/hooks/shim.js +102 -5
- package/dist/hooks/shim.js.map +1 -1
- package/dist/install.js +17 -3
- package/dist/install.js.map +1 -1
- package/dist/json-file.js +6 -3
- package/dist/json-file.js.map +1 -1
- package/dist/shim.js +53 -3
- package/dist/utils.js +9 -0
- package/dist/utils.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -59,29 +59,35 @@ npm install -g @cybedefend/vibedefend && vibedefend install
|
|
|
59
59
|
|
|
60
60
|
VibeDefend auto-detects and wires whichever of these you have installed.
|
|
61
61
|
|
|
62
|
-
| Capability | Claude Code | Cursor | OpenAI Codex | Windsurf | VS Code Copilot |
|
|
63
|
-
|
|
64
|
-
| **MCP server install** | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
65
|
-
| **Business + Security Rules** *(injected pre-write)* | ✅ edit + shell⁴ | ✅ | ✅ edit + shell⁴ | ⚠️ writes only | ✅ |
|
|
66
|
-
| **Action Guards** *(hard block on deny)* | ✅ all tools | ✅ all tools | ✅ all tools | ⚠️ writes + MCP fallback¹ | ❌ not yet wired |
|
|
67
|
-
| **Session Start** *(loads doctrine + proposals inbox)* | ✅ | ✅ | ✅ | ⚠️ proxied² | ✅ |
|
|
68
|
-
| **Session Review** *(end-of-session gap analysis + pre-commit diff scan)* | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
69
|
-
| **PreCompact** *(long-session gap analysis)* | ✅ | ✅ | ❌ no event | ❌ no event | ✅ |
|
|
70
|
-
| **Doctrine backstop** *(per-prompt reminder)* | ✅ | ❌ | ✱ via MCP³ | ❌ | ❌ |
|
|
71
|
-
| **Min version** | latest | ≥ 1.7 | latest | latest | ≥ 1.110 |
|
|
62
|
+
| Capability | Claude Code | Cursor | OpenAI Codex | Windsurf | VS Code Copilot | Google Antigravity |
|
|
63
|
+
|---|:---:|:---:|:---:|:---:|:---:|:---:|
|
|
64
|
+
| **MCP server install** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
65
|
+
| **Business + Security Rules** *(injected pre-write)* | ✅ edit + shell⁴ | ✅ | ✅ edit + shell⁴ | ⚠️ writes only | ✅ | ⚠️ edit + shell⁴, after the edit⁵ |
|
|
66
|
+
| **Action Guards** *(hard block on deny)* | ✅ all tools | ✅ all tools | ✅ all tools | ⚠️ writes, reads, shell + MCP fallback¹ | ❌ not yet wired | ✅ all tools⁶ |
|
|
67
|
+
| **Session Start** *(loads doctrine + proposals inbox)* | ✅ | ✅ | ✅ | ⚠️ proxied² | ✅ | ✅ |
|
|
68
|
+
| **Session Review** *(end-of-session gap analysis + pre-commit diff scan)* | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
69
|
+
| **PreCompact** *(long-session gap analysis)* | ✅ | ✅ | ❌ no event | ❌ no event | ✅ | ❌ no event |
|
|
70
|
+
| **Doctrine backstop** *(per-prompt reminder)* | ✅ | ❌ | ✱ via MCP³ | ❌ | ❌ | ❌ |
|
|
71
|
+
| **Min version** | latest | ≥ 1.7 | latest | latest | ≥ 1.110 | ≥ 2.0 (app / IDE) |
|
|
72
72
|
|
|
73
73
|
**Legend** — ✅ supported · ⚠️ supported with caveats · ❌ not exposed by the agent · ✱ alternate mechanism
|
|
74
74
|
|
|
75
|
-
¹ Windsurf
|
|
75
|
+
¹ Windsurf hard-blocks file writes (`pre_write_code`), file reads (`pre_read_code`) and shell commands (`pre_run_command`): the hook exits 2 and Cascade shows the agent the reason. A warning lets the action through unseen by the agent, since Cascade only shows it a hook's output on a block. Cascade has no hook for web fetches, and MCP tool calls are not gated: for those the installer drops a snippet into `.windsurfrules` instructing the agent to call `cybe_guards_check` via MCP before sensitive actions — soft enforcement that relies on the model following its rules file.
|
|
76
76
|
|
|
77
77
|
² Windsurf has no native SessionStart event. We wire `pre_user_prompt`, which fires on every turn. The hook is idempotent and cheap (one GET to the proposals endpoint, returns "0 pending" once the inbox is empty), so the per-turn cost is negligible.
|
|
78
78
|
|
|
79
79
|
³ Codex follows the doctrine via the MCP server's `Server.instructions` field on each session, removing the need for a per-prompt reminder hook.
|
|
80
80
|
|
|
81
|
-
⁴ On Claude Code and
|
|
81
|
+
⁴ On Claude Code, Codex and Antigravity (its `run_command` tool) the rules hook also fires on shell commands that write files (`>` / `>>` redirections, heredocs, `tee`, `sed -i`, `perl -pi`, `cp` / `mv`, `dd of=`, `bash -c '…'`), so an agent that edits through the shell gets the same rules as one using the edit tool. Read-only commands fetch nothing. Inline interpreters (`python -c`, `node -e`) and `git apply` / `patch` are not inspected. Cursor, Windsurf and VS Code Copilot: edit tools only.
|
|
82
|
+
|
|
83
|
+
⁵ Antigravity has no channel to inject context into the model from its PreToolUse hook, so rules fetched before a write are held and delivered at the agent's next model call (its PreInvocation event) instead — one step later than on every other client, but before the agent acts on what it just read.
|
|
84
|
+
|
|
85
|
+
⁶ `agy --dangerously-skip-permissions` runs no hook at all, on any event. On Windows, a home path with a space in it is not supported — Antigravity has no way to quote the hook command it runs, so the installer detects this and refuses to wire a dead command rather than silently blocking every tool call. Antigravity's MCP servers are **not** wrapped by the VibeDefend MCP proxy (like Codex today): the CybeDefend server is registered directly against the region's URL.
|
|
82
86
|
|
|
83
87
|
**Codex setup gotcha:** Codex 0.131+ requires you to approve each hook via the `/hooks` panel inside Codex *before* they fire. After running `vibedefend install`, open Codex, run `/hooks`, and trust the `cybedefend` entries — until you do that the panel will show `Installed N / Active 0`.
|
|
84
88
|
|
|
89
|
+
**Antigravity sign-in:** Antigravity does not open the CybeDefend sign-in on its own, and `agy` has no login command the installer could run for you (as it runs `codex mcp login` for Codex). Until you sign in once, the `cybedefend` server answers *Unauthorized*. In the Antigravity app, open **Customizations → Installed → MCP Servers** and click **Authenticate** next to `cybedefend`. In the `agy` CLI, run `/mcp`, pick `cybedefend`, then **Authenticate**. The app, the IDE and the CLI each keep their own sign-in. The installer prints these steps under *Next steps*.
|
|
90
|
+
|
|
85
91
|
**Pre-commit diff scan (on by default):** when Session Review fires, the agent
|
|
86
92
|
is also asked to run a quick **diff scan** (SAST / IaC / secrets) on the files
|
|
87
93
|
it changed this session, via the `cybe_scan_diff` MCP tool — a best-effort
|
|
@@ -276,7 +282,10 @@ deletes `~/.cybedefend/`, keeping only your own `~/.cybedefend/regions.json`.
|
|
|
276
282
|
Repositories keep their committed `.cybedefend/config.json`. A Windsurf
|
|
277
283
|
`.windsurfrules` block is removed from the current directory only: in any other
|
|
278
284
|
repo you wired for Windsurf, delete it by hand. Codex's `[features] hooks = true`
|
|
279
|
-
flag stays set, since other hooks may rely on it.
|
|
285
|
+
flag stays set, since other hooks may rely on it. Antigravity's `hooks.json` and
|
|
286
|
+
`mcp_config.json` are user-global (shared by the app, the IDE extension and
|
|
287
|
+
`agy`, never per-project), so uninstall drops our `cybedefend-*` groups and MCP
|
|
288
|
+
server from there once, for every project — there is no per-repo cleanup to do.
|
|
280
289
|
|
|
281
290
|
## Sibling: `cybedefend-cli`
|
|
282
291
|
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Antigravity adapter.
|
|
3
|
+
*
|
|
4
|
+
* Antigravity shares one hooks file between the app, the IDE extension and
|
|
5
|
+
* `agy` — global, never per-project: `~/.gemini/config/hooks.json` (Windows:
|
|
6
|
+
* `%USERPROFILE%\.gemini\config\hooks.json`). Its top-level keys are hook
|
|
7
|
+
* GROUP names, not event names (contrast Cursor/Codex/Windsurf, which key by
|
|
8
|
+
* event). Each group nests its handlers under the events it fires on:
|
|
9
|
+
*
|
|
10
|
+
* PreToolUse (and other tool events):
|
|
11
|
+
* { "<group>": { "PreToolUse": [{ "matcher": "<regex>", "hooks": [
|
|
12
|
+
* { "type": "command", "command": "…", "timeout": 30 } ] }] } }
|
|
13
|
+
* Every other event (SessionStart, PreInvocation, Stop, …) lists the
|
|
14
|
+
* handler directly, with no matcher/hooks nesting:
|
|
15
|
+
* { "<group>": { "SessionStart": [
|
|
16
|
+
* { "type": "command", "command": "…", "timeout": 30 } ] } }
|
|
17
|
+
* A group may also carry a sibling `"enabled"` boolean, which the user can
|
|
18
|
+
* flip in the Antigravity UI; `writeSettings` preserves it across a
|
|
19
|
+
* reinstall (see `writeSettings` below).
|
|
20
|
+
*
|
|
21
|
+
* We write 5 groups, one per moment, all prefixed `cybedefend-`:
|
|
22
|
+
* - cybedefend-session-start SessionStart → session-start
|
|
23
|
+
* - cybedefend-rules PreToolUse → fetch-rules (matcher "*", self-filtered)
|
|
24
|
+
* - cybedefend-rules-delivery PreInvocation → pre-invocation (injects stashed rules)
|
|
25
|
+
* - cybedefend-guards PreToolUse → guard-check (matcher "*", every tool)
|
|
26
|
+
* - cybedefend-session-review Stop → session-review (only when enabled)
|
|
27
|
+
*
|
|
28
|
+
* A top-level key is OURS when its name starts with `cybedefend-` AND its
|
|
29
|
+
* JSON references our managed hook dir (`textReferencesHookRunner`). That
|
|
30
|
+
* is a stronger bar than the prefix alone — a user's own `cybedefend-mine`
|
|
31
|
+
* group, wired to a command of their own, is never touched. `writeSettings`
|
|
32
|
+
* drops our groups wholesale and rewrites them fresh (so a re-install can
|
|
33
|
+
* never duplicate a handler inside a group — there's nothing to dedupe,
|
|
34
|
+
* each key is written exactly once, and an old group of ours under a
|
|
35
|
+
* command shape a previous version wrote is replaced, never kept alongside
|
|
36
|
+
* the new one), and `uninstall` only drops them.
|
|
37
|
+
*
|
|
38
|
+
* Hook commands: Antigravity runs a POSIX hook through `sh -c "<command>"`
|
|
39
|
+
* and a Windows one through `cmd /C "<command>"` — never execve directly —
|
|
40
|
+
* so:
|
|
41
|
+
* - POSIX: `node <runner> <sub> --client antigravity || echo '<fallback>'`.
|
|
42
|
+
* A missing `node`/runner (or any runner crash) then answers the same
|
|
43
|
+
* fallback a healthy run would print on its own early-exit path, instead
|
|
44
|
+
* of blocking every tool call fail-closed forever.
|
|
45
|
+
* - Windows: `node <runner> <sub> --client antigravity`, no quoting and no
|
|
46
|
+
* `|| echo '<fallback>'`. `agy` escapes embedded quotes, and the
|
|
47
|
+
* fallback JSON (`{"decision":"allow"}`) is itself quote-bearing, so
|
|
48
|
+
* there is no way to nest it inside the already-quoted `cmd /C "…"`
|
|
49
|
+
* invocation without `agy` mangling it on the way in. The runner path
|
|
50
|
+
* can't be quoted either, so a path containing whitespace can't be
|
|
51
|
+
* spawned at all — `detect()`, AND `writeSettings()` itself (belt and
|
|
52
|
+
* suspenders: a manually-ticked client that `detect()` never got to
|
|
53
|
+
* veto, or `vibedefend doctor` re-wiring from `detect().installed`
|
|
54
|
+
* alone), both check this (`antigravityWindowsBlock`) and refuse to
|
|
55
|
+
* wire a command that would never run.
|
|
56
|
+
*
|
|
57
|
+
* The fallback is `{"decision":"allow"}` for the two PreToolUse subcommands
|
|
58
|
+
* (fetch-rules, guard-check) — a dead runner must fail OPEN there, exactly
|
|
59
|
+
* like every other client's hook does when it can't execute — and `{}` for
|
|
60
|
+
* every other subcommand, which Antigravity expects verbatim on success.
|
|
61
|
+
*/
|
|
62
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
63
|
+
import { readJson, writeJson } from '../json-file.js';
|
|
64
|
+
import { home, log, stripBom } from '../utils.js';
|
|
65
|
+
import { HOOK_RUNNER_PATH, toPosixPath, quoteCommandPath, textReferencesHookRunner } from '../hooks/install.js';
|
|
66
|
+
import { PRE_TOOL_USE_SUBCOMMANDS } from '../hooks/runtime/emit.js';
|
|
67
|
+
import { mcpStatus, readJsonServerEntry } from './mcp-url.js';
|
|
68
|
+
import { deleteKeys, editJsonFile } from './unwire.js';
|
|
69
|
+
import { configDirExists, probeBinaryVersion } from './detect.js';
|
|
70
|
+
const ANTIGRAVITY_HOOKS = home('.gemini', 'config', 'hooks.json');
|
|
71
|
+
const ANTIGRAVITY_MCP = home('.gemini', 'config', 'mcp_config.json');
|
|
72
|
+
/**
|
|
73
|
+
* The `command` field of an Antigravity hook handler, targeting `sub` on
|
|
74
|
+
* `--client antigravity`. `--client` and `antigravity` are two separate
|
|
75
|
+
* argv tokens — the runner's arg parser skips anything before the
|
|
76
|
+
* subcommand and ignores a combined `--client=antigravity`.
|
|
77
|
+
*/
|
|
78
|
+
export function antigravityHookCommand(sub, opts = {}) {
|
|
79
|
+
const platform = opts.platform ?? process.platform;
|
|
80
|
+
// Forward-slash first (Windows-shell safe), as `hookCommand` does.
|
|
81
|
+
const runnerPath = toPosixPath(opts.runnerPath ?? HOOK_RUNNER_PATH);
|
|
82
|
+
if (platform === 'win32') {
|
|
83
|
+
// No quoting (a quoted path can't be spawned) and no `|| echo` fallback:
|
|
84
|
+
// the fallback JSON is quote-bearing and `agy` escapes embedded quotes,
|
|
85
|
+
// so nesting it inside the already-quoted `cmd /C "…"` invocation would
|
|
86
|
+
// be mangled rather than run.
|
|
87
|
+
return `node ${runnerPath} ${sub} --client antigravity`;
|
|
88
|
+
}
|
|
89
|
+
const fallback = PRE_TOOL_USE_SUBCOMMANDS.has(sub) ? '{"decision":"allow"}' : '{}';
|
|
90
|
+
return `node ${quoteCommandPath(runnerPath)} ${sub} --client antigravity || echo '${fallback}'`;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* `null` unless Antigravity on Windows cannot spawn `runnerPath` at all — a
|
|
94
|
+
* whitespace path with no safe quoting mechanism available. Used by both
|
|
95
|
+
* `detect()` and `writeSettings()` (to report/refuse instead of wiring a
|
|
96
|
+
* dead command) and by tests.
|
|
97
|
+
*/
|
|
98
|
+
export function antigravityWindowsBlock(platform, runnerPath) {
|
|
99
|
+
if (platform !== 'win32')
|
|
100
|
+
return null;
|
|
101
|
+
if (!/\s/.test(runnerPath))
|
|
102
|
+
return null;
|
|
103
|
+
return `Antigravity on Windows cannot run a hook whose path contains a space: ${runnerPath}`;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* The 5 (or 4, with session review off) `cybedefend-*` hook groups, keyed by
|
|
107
|
+
* group name — ready to be merged as whole top-level keys into `hooks.json`.
|
|
108
|
+
*/
|
|
109
|
+
export function buildAntigravityHookGroups(opts) {
|
|
110
|
+
const cmd = (sub) => antigravityHookCommand(sub, { platform: opts.platform, runnerPath: opts.runnerPath });
|
|
111
|
+
const groups = {
|
|
112
|
+
'cybedefend-session-start': {
|
|
113
|
+
SessionStart: [{ type: 'command', command: cmd('session-start'), timeout: 30 }],
|
|
114
|
+
},
|
|
115
|
+
'cybedefend-rules': {
|
|
116
|
+
PreToolUse: [
|
|
117
|
+
{
|
|
118
|
+
// Every tool (Ruling R14): Antigravity's tool names change with the
|
|
119
|
+
// model (`write_to_file` or `write_file`, `replace_file_content` or
|
|
120
|
+
// `edit_file`, …), and a matcher that missed one silently dropped
|
|
121
|
+
// the rules for every write. fetch-rules keeps only the write and
|
|
122
|
+
// shell tools itself and answers `allow` at once on any other.
|
|
123
|
+
matcher: '*',
|
|
124
|
+
hooks: [{ type: 'command', command: cmd('fetch-rules'), timeout: 30 }],
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
},
|
|
128
|
+
'cybedefend-rules-delivery': {
|
|
129
|
+
PreInvocation: [{ type: 'command', command: cmd('pre-invocation'), timeout: 10 }],
|
|
130
|
+
},
|
|
131
|
+
'cybedefend-guards': {
|
|
132
|
+
PreToolUse: [
|
|
133
|
+
{
|
|
134
|
+
matcher: '*',
|
|
135
|
+
hooks: [{ type: 'command', command: cmd('guard-check'), timeout: 30 }],
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
if (opts.enableSessionReview) {
|
|
141
|
+
groups['cybedefend-session-review'] = {
|
|
142
|
+
Stop: [{ type: 'command', command: cmd('session-review'), timeout: 30 }],
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
return groups;
|
|
146
|
+
}
|
|
147
|
+
/** Top-level keys of `file` that are ours: prefix `cybedefend-` AND the JSON references our managed hook dir. */
|
|
148
|
+
function ourGroupKeys(file) {
|
|
149
|
+
return Object.keys(file).filter((key) => key.startsWith('cybedefend-') && textReferencesHookRunner(JSON.stringify(file[key])));
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Delete every top-level key of `file` that is ours (prefix `cybedefend-`
|
|
153
|
+
* AND its JSON references our managed hook dir). A user's own
|
|
154
|
+
* `cybedefend-*` group that doesn't mention our runner is left alone — the
|
|
155
|
+
* prefix alone is not a strong enough signal to delete someone else's
|
|
156
|
+
* config. Returns whether anything was removed.
|
|
157
|
+
*/
|
|
158
|
+
function dropOurGroups(file) {
|
|
159
|
+
const keys = ourGroupKeys(file);
|
|
160
|
+
for (const key of keys)
|
|
161
|
+
delete file[key];
|
|
162
|
+
return keys.length > 0;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* The names of our groups the user has switched off (`"enabled": false`,
|
|
166
|
+
* Antigravity's own per-group toggle) before they get dropped and rewritten
|
|
167
|
+
* — so `writeSettings` can carry that flag over onto the fresh replacement
|
|
168
|
+
* instead of silently re-enabling a group the user turned off.
|
|
169
|
+
*/
|
|
170
|
+
function disabledOurGroups(file) {
|
|
171
|
+
const disabled = new Set();
|
|
172
|
+
for (const key of ourGroupKeys(file)) {
|
|
173
|
+
const group = file[key];
|
|
174
|
+
if (group && typeof group === 'object' && group.enabled === false) {
|
|
175
|
+
disabled.add(key);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return disabled;
|
|
179
|
+
}
|
|
180
|
+
function detect() {
|
|
181
|
+
const version = probeBinaryVersion('agy') ?? undefined;
|
|
182
|
+
const hasConfigDir = configDirExists(home('.gemini', 'antigravity')) ||
|
|
183
|
+
configDirExists(home('.gemini', 'antigravity-ide')) ||
|
|
184
|
+
configDirExists(home('.gemini', 'antigravity-cli'));
|
|
185
|
+
const hasApp = process.platform === 'darwin' && existsSync('/Applications/Antigravity.app');
|
|
186
|
+
const installed = version !== undefined || hasConfigDir || hasApp;
|
|
187
|
+
// Computed regardless of `installed`: a Windows home with a whitespace
|
|
188
|
+
// path is the more actionable reason to surface, and `writeSettings` is
|
|
189
|
+
// reachable even from a "not installed" detection (a client manually
|
|
190
|
+
// ticked in the install picker, or `vibedefend doctor` re-wiring from
|
|
191
|
+
// `detect().installed` alone without re-checking `supportsHooks`).
|
|
192
|
+
const windowsBlock = antigravityWindowsBlock(process.platform, HOOK_RUNNER_PATH);
|
|
193
|
+
if (!installed) {
|
|
194
|
+
return {
|
|
195
|
+
installed: false,
|
|
196
|
+
supportsHooks: false,
|
|
197
|
+
reason: windowsBlock ??
|
|
198
|
+
'`agy` CLI not on PATH, no ~/.gemini/antigravity(-ide|-cli)/ directory, ' +
|
|
199
|
+
'and no /Applications/Antigravity.app.',
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
// No version gate — hooks shipped with Antigravity's first release.
|
|
203
|
+
if (windowsBlock) {
|
|
204
|
+
return { installed: true, version, supportsHooks: false, reason: windowsBlock };
|
|
205
|
+
}
|
|
206
|
+
return { installed: true, version, supportsHooks: true };
|
|
207
|
+
}
|
|
208
|
+
function supports(event) {
|
|
209
|
+
// Antigravity has no PreCompact and no UserPromptSubmit event. Action
|
|
210
|
+
// Guards (guard-check) and rules delivery (pre-invocation) are wired
|
|
211
|
+
// unconditionally below — they aren't part of the LifecycleEvent surface
|
|
212
|
+
// `supports()` is asked about.
|
|
213
|
+
return event === 'fetch-rules' || event === 'session-start' || event === 'stop';
|
|
214
|
+
}
|
|
215
|
+
function writeSettings(opts) {
|
|
216
|
+
// Belt and suspenders: `detect()` is what normally keeps this adapter out
|
|
217
|
+
// of the picker on an unspawnable Windows path, but `writeSettings` can
|
|
218
|
+
// still be reached directly (a client ticked by hand before `detect()`
|
|
219
|
+
// ran, or a re-wire driven only by `detect().installed`). Never wire a
|
|
220
|
+
// command that would block every Antigravity tool call for want of a
|
|
221
|
+
// runnable hook — and clean up anything an earlier, unguarded install
|
|
222
|
+
// left behind.
|
|
223
|
+
const windowsBlock = antigravityWindowsBlock(process.platform, HOOK_RUNNER_PATH);
|
|
224
|
+
if (windowsBlock) {
|
|
225
|
+
log.warn(windowsBlock);
|
|
226
|
+
editJsonFile(ANTIGRAVITY_HOOKS, dropOurGroups);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
const file = readJson(ANTIGRAVITY_HOOKS, {});
|
|
230
|
+
const disabled = disabledOurGroups(file);
|
|
231
|
+
dropOurGroups(file);
|
|
232
|
+
const groups = buildAntigravityHookGroups({ enableSessionReview: opts.enableSessionReview });
|
|
233
|
+
for (const key of disabled) {
|
|
234
|
+
const group = groups[key];
|
|
235
|
+
if (group && typeof group === 'object') {
|
|
236
|
+
group.enabled = false;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
Object.assign(file, groups);
|
|
240
|
+
writeJson(ANTIGRAVITY_HOOKS, file);
|
|
241
|
+
log.ok(`Antigravity hooks wired into ${ANTIGRAVITY_HOOKS}`);
|
|
242
|
+
log.hint('`agy --dangerously-skip-permissions` runs no hook at all.');
|
|
243
|
+
log.hint('Rules reach the agent at its next model call (PreInvocation), not immediately after the edit that triggered them.');
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Register the CybeDefend MCP server in `~/.gemini/config/mcp_config.json`.
|
|
247
|
+
* This is NOT wrapped by the VibeDefend MCP proxy (like Codex today) — the
|
|
248
|
+
* entry points straight at the region's URL.
|
|
249
|
+
*/
|
|
250
|
+
function registerMcp(opts) {
|
|
251
|
+
log.step(`Registering MCP "${opts.region.mcpName}" in Antigravity`);
|
|
252
|
+
log.hint(`URL: ${opts.region.mcpUrl}`);
|
|
253
|
+
const file = readJson(ANTIGRAVITY_MCP, {});
|
|
254
|
+
file.mcpServers ??= {};
|
|
255
|
+
file.mcpServers[opts.region.mcpName] = { serverUrl: opts.region.mcpUrl };
|
|
256
|
+
writeJson(ANTIGRAVITY_MCP, file);
|
|
257
|
+
log.ok(`MCP "${opts.region.mcpName}" registered in ${ANTIGRAVITY_MCP}`);
|
|
258
|
+
log.hint(`Sign in to it once: ${signInHowTo(opts.region)}`);
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Antigravity opens no sign-in on its own: until the user authenticates,
|
|
263
|
+
* the server shows "Unauthorized" next to an Authenticate button (observed
|
|
264
|
+
* on Antigravity 2.28.2). `agy` has no login command the installer could
|
|
265
|
+
* run, unlike `codex mcp login`. The app, the IDE and the CLI each keep
|
|
266
|
+
* their own sign-in.
|
|
267
|
+
*/
|
|
268
|
+
function signInHowTo(region) {
|
|
269
|
+
return (`in Antigravity, open Customizations → Installed → MCP Servers and click Authenticate next to "${region.mcpName}"; ` +
|
|
270
|
+
`in the agy CLI, run /mcp, pick "${region.mcpName}", then Authenticate. Each of them keeps its own sign-in.`);
|
|
271
|
+
}
|
|
272
|
+
function mcpSignInStep(region) {
|
|
273
|
+
return `Google Antigravity: ${signInHowTo(region)}`;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Pure introspection — never throws, as Windsurf's does. `hooksWired` from a
|
|
277
|
+
* raw-text marker check on `hooks.json`, `mcpRegistered` from the
|
|
278
|
+
* `serverUrl` of our entry in `mcp_config.json` — it must point at this
|
|
279
|
+
* region, not just exist. Both reads strip a leading BOM first, since
|
|
280
|
+
* either file may carry one.
|
|
281
|
+
*/
|
|
282
|
+
function inspect(region) {
|
|
283
|
+
let hooksWired = false;
|
|
284
|
+
try {
|
|
285
|
+
if (existsSync(ANTIGRAVITY_HOOKS)) {
|
|
286
|
+
hooksWired = textReferencesHookRunner(stripBom(readFileSync(ANTIGRAVITY_HOOKS, 'utf8')));
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
catch {
|
|
290
|
+
/* missing/unreadable → false */
|
|
291
|
+
}
|
|
292
|
+
const entry = readJsonServerEntry(() => stripBom(readFileSync(ANTIGRAVITY_MCP, 'utf8')), 'mcpServers', region.mcpName);
|
|
293
|
+
return { hooksWired, ...mcpStatus(entry?.serverUrl, region) };
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Drop our `cybedefend-*` groups from `hooks.json` (whole top-level keys —
|
|
297
|
+
* see `dropOurGroups`) and our servers from `mcp_config.json`. Every other
|
|
298
|
+
* key / server is left untouched.
|
|
299
|
+
*
|
|
300
|
+
* The two files are independent, so both steps always run even when one
|
|
301
|
+
* throws (a malformed `hooks.json` must not leave our MCP server behind) —
|
|
302
|
+
* only once both have been attempted does this re-throw the FIRST error, if
|
|
303
|
+
* any.
|
|
304
|
+
*/
|
|
305
|
+
function uninstall(opts) {
|
|
306
|
+
let hooksRemoved = false;
|
|
307
|
+
let hooksError;
|
|
308
|
+
try {
|
|
309
|
+
hooksRemoved = editJsonFile(ANTIGRAVITY_HOOKS, dropOurGroups);
|
|
310
|
+
}
|
|
311
|
+
catch (err) {
|
|
312
|
+
hooksError = err;
|
|
313
|
+
}
|
|
314
|
+
let mcpRemoved = [];
|
|
315
|
+
let mcpError;
|
|
316
|
+
try {
|
|
317
|
+
editJsonFile(ANTIGRAVITY_MCP, (file) => {
|
|
318
|
+
mcpRemoved = deleteKeys(file.mcpServers, opts.mcpNames);
|
|
319
|
+
return mcpRemoved.length > 0;
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
catch (err) {
|
|
323
|
+
mcpError = err;
|
|
324
|
+
}
|
|
325
|
+
if (hooksError)
|
|
326
|
+
throw hooksError;
|
|
327
|
+
if (mcpError)
|
|
328
|
+
throw mcpError;
|
|
329
|
+
return { hookFiles: hooksRemoved ? [ANTIGRAVITY_HOOKS] : [], mcpRemoved };
|
|
330
|
+
}
|
|
331
|
+
export const antigravityAdapter = {
|
|
332
|
+
id: 'antigravity',
|
|
333
|
+
label: 'Google Antigravity',
|
|
334
|
+
detect,
|
|
335
|
+
supports,
|
|
336
|
+
writeSettings,
|
|
337
|
+
registerMcp,
|
|
338
|
+
mcpSignInStep,
|
|
339
|
+
inspect,
|
|
340
|
+
uninstall,
|
|
341
|
+
};
|
|
342
|
+
//# sourceMappingURL=antigravity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"antigravity.js","sourceRoot":"","sources":["../../src/clients/antigravity.ts"],"names":[],"mappings":"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"}
|
package/dist/clients/registry.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* order. Claude Code first because it has the most mature hook surface
|
|
7
7
|
* and is the assumed default; the others follow alphabetically.
|
|
8
8
|
*/
|
|
9
|
+
import { antigravityAdapter } from './antigravity.js';
|
|
9
10
|
import { claudeCodeAdapter } from './claude-code.js';
|
|
10
11
|
import { codexAdapter } from './codex.js';
|
|
11
12
|
import { cursorAdapter } from './cursor.js';
|
|
@@ -17,6 +18,7 @@ export const ALL_ADAPTERS = [
|
|
|
17
18
|
vscodeAdapter,
|
|
18
19
|
windsurfAdapter,
|
|
19
20
|
codexAdapter,
|
|
21
|
+
antigravityAdapter,
|
|
20
22
|
];
|
|
21
23
|
/** Look up an adapter by ID. Throws if not found (programming error). */
|
|
22
24
|
export function adapterFor(id) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/clients/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAIhD,MAAM,CAAC,MAAM,YAAY,GAA6B;IACpD,iBAAiB;IACjB,aAAa;IACb,aAAa;IACb,eAAe;IACf,YAAY;
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/clients/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAIhD,MAAM,CAAC,MAAM,YAAY,GAA6B;IACpD,iBAAiB;IACjB,aAAa;IACb,aAAa;IACb,eAAe;IACf,YAAY;IACZ,kBAAkB;CACV,CAAC;AAEX,yEAAyE;AACzE,MAAM,UAAU,UAAU,CAAC,EAAY;IACrC,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IACtD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,wCAAwC,EAAE,IAAI,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,SAAS;IAIvB,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACpC,OAAO;QACP,SAAS,EAAE,OAAO,CAAC,MAAM,EAAE;KAC5B,CAAC,CAAC,CAAC;AACN,CAAC"}
|
package/dist/clients/windsurf.js
CHANGED
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
* │ Our event │ Windsurf event │
|
|
11
11
|
* ├──────────────────┼─────────────────────────────────────────────┤
|
|
12
12
|
* │ fetch-rules │ pre_write_code │
|
|
13
|
+
* │ guard-check │ pre_write_code, pre_read_code, │
|
|
14
|
+
* │ │ pre_run_command │
|
|
13
15
|
* │ session-start │ pre_user_prompt (no SessionStart in Cascade)│
|
|
14
16
|
* │ stop │ post_cascade_response │
|
|
15
17
|
* │ pre-compact │ (not supported — Cascade has no equivalent) │
|
|
@@ -68,18 +70,27 @@ function dropOurs(entries) {
|
|
|
68
70
|
function writeSettings(opts) {
|
|
69
71
|
const file = readJson(WINDSURF_HOOKS, {});
|
|
70
72
|
file.pre_write_code ??= [];
|
|
73
|
+
file.pre_read_code ??= [];
|
|
74
|
+
file.pre_run_command ??= [];
|
|
71
75
|
file.pre_user_prompt ??= [];
|
|
72
76
|
file.post_cascade_response ??= [];
|
|
73
77
|
file.pre_write_code = dropOurs(file.pre_write_code);
|
|
78
|
+
file.pre_read_code = dropOurs(file.pre_read_code);
|
|
79
|
+
file.pre_run_command = dropOurs(file.pre_run_command);
|
|
74
80
|
file.pre_user_prompt = dropOurs(file.pre_user_prompt);
|
|
75
81
|
file.post_cascade_response = dropOurs(file.post_cascade_response);
|
|
76
82
|
file.pre_write_code.push({ command: hookCommand('fetch-rules') });
|
|
77
83
|
file.pre_user_prompt.push({ command: hookCommand('session-start') });
|
|
78
|
-
// Action Guards:
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
//
|
|
84
|
+
// Action Guards: Cascade has no single PreToolUse, it has one pre-hook per
|
|
85
|
+
// kind of action. guard-check runs on the three that carry a target to
|
|
86
|
+
// gate — a write (`tool_info.file_path`), a read (`tool_info.file_path`)
|
|
87
|
+
// and a shell command (`tool_info.command_line`) — and blocks with exit 2,
|
|
88
|
+
// the agent reading the reason on stderr. Not wired on pre_user_prompt
|
|
89
|
+
// (a prompt has no target) nor pre_mcp_tool_use (tools with arbitrary
|
|
90
|
+
// arguments; the .windsurfrules snippet below covers them).
|
|
82
91
|
file.pre_write_code.push({ command: hookCommand('guard-check') });
|
|
92
|
+
file.pre_read_code.push({ command: hookCommand('guard-check') });
|
|
93
|
+
file.pre_run_command.push({ command: hookCommand('guard-check') });
|
|
83
94
|
if (opts.enableSessionReview) {
|
|
84
95
|
file.post_cascade_response.push({
|
|
85
96
|
command: hookCommand('session-review'),
|
|
@@ -89,10 +100,11 @@ function writeSettings(opts) {
|
|
|
89
100
|
log.ok(`Windsurf hooks wired into ${WINDSURF_HOOKS}`);
|
|
90
101
|
log.hint('Note: Cascade has no PreCompact event, so long-session gap analysis only fires at end-of-response (post_cascade_response).');
|
|
91
102
|
// Inject the soft-enforcement snippet into .windsurfrules in the project
|
|
92
|
-
// directory (process.cwd() at install time = repo root).
|
|
93
|
-
//
|
|
94
|
-
//
|
|
95
|
-
// model to call cybe_guards_check before ANY sensitive
|
|
103
|
+
// directory (process.cwd() at install time = repo root). The hooks above
|
|
104
|
+
// gate writes, reads and shell commands; Cascade has no hook for web
|
|
105
|
+
// fetches, and MCP tool calls are not gated, so the snippet closes that gap
|
|
106
|
+
// by instructing the model to call cybe_guards_check before ANY sensitive
|
|
107
|
+
// action via MCP.
|
|
96
108
|
const windsurfRulesPath = join(process.cwd(), '.windsurfrules');
|
|
97
109
|
appendGuardSnippetIdempotent(windsurfRulesPath, WINDSURF_GUARDS_SNIPPET, '<see .cybedefend/config.json>');
|
|
98
110
|
log.ok(`.windsurfrules updated at ${windsurfRulesPath}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"windsurf.js","sourceRoot":"","sources":["../../src/clients/windsurf.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"windsurf.js","sourceRoot":"","sources":["../../src/clients/windsurf.ts"],"names":[],"mappings":"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"}
|