* feat(cli): native hooks adapter for Antigravity CLI (agy)
Antigravity ships two products with unrelated configuration: the IDE,
already wired by `connect antigravity`, and the `agy` CLI, which reads
its customizations out of ~/.gemini/ and until now was not wired at all.
This adds `connect antigravity-cli` for the latter — MCP via
~/.gemini/config/mcp_config.json, plus optional native auto-capture hooks
behind --with-hooks.
Unlike Droid (#1130), the Codex merge engine could not be reused. The
Antigravity hooks contract differs in three ways:
* hooks.json is a map of *named* hook bundles at the root, not the
`{ hooks: { <Event>: [...] } }` envelope, so antigravity-hooks.ts
implements a merge that owns top-level keys instead of per-event
entries. User-authored bundles are preserved; a re-install replaces
only the bundle whose commands point under the bundled plugin dir.
* only five events exist (PreToolUse, PostToolUse, PreInvocation,
PostInvocation, Stop) — no SessionStart/SessionEnd/UserPromptSubmit,
so the session lifecycle is synthesized from the first PreInvocation
and from Stop. PostInvocation is left unwired to avoid double-capture.
* the stdin payload is camelCase and nested (`toolCall.args` with
PascalCase keys, `conversationId`, `workspacePaths`), and stdout must
be a JSON object — `pre-tool-use.mjs` writes raw prose when context
injection is on.
plugin/scripts/antigravity-bridge.mjs bridges all three: it normalizes the
payload onto the shape the bundled hooks already accept, maps Cascade tool
names (view_file, replace_file_content, …) onto the read/edit/write/grep
vocabulary the capture heuristics use, pipes to the right script, discards
child stdout and always answers `{}` so Antigravity's own permission
decisions are never overridden.
Event names, tool names and arg keys were verified against the shipped
agy binary rather than docs alone (docs disagree on the global hooks
path); the customization dir is ~/.gemini/config/, matching where agy
already keeps mcp_config.json and plugins/.
Signed-off-by: Bertho Joris <bertho_joris@yahoo.co.id>
* fix(cli): keep $-bearing plugin paths literal when resolving hook commands
resolveBundle() expanded ${CLAUDE_PLUGIN_ROOT} via
String.prototype.replace with a string argument, so a plugin root
containing `$$`, `$&`, "$`" or `$'` was read as a replacement pattern
and rewritten:
C:/plug$&in -> C:/plug${CLAUDE_PLUGIN_ROOT}in/scripts/...
C:/plug$$in -> C:/plug$in/scripts/...
`$1` and `$<name>` are unaffected — the regex has no capture groups.
Switching to a replacer function keeps the path verbatim. The failure
mode this closes is silent: the hook installs with a broken command and
auto-capture simply never fires.
Regression test builds the manifest against a temp plugin root named
`plug$&$$in` and asserts the resolved command contains it literally.
Reported by CodeRabbit on #1146.
Signed-off-by: Bertho Joris <bertho_joris@yahoo.co.id>
* fix(antigravity): emit an explicit allow decision from the PreToolUse hook
Antigravity documents `decision` as a required field of PreToolUse hook
output, and agy treats a response that omits it as a denial: the bare `{}`
the bridge used to write made the agent refuse every matched tool call
(reported against agy 1.0.5 in cmux#5358) instead of passively capturing
it. `responseFor` now answers PreToolUse with `{"decision":"allow"}` and
leaves every other event on `{}`, so no event that carries no permission
decision starts overriding the user's own settings.
The response is written from the `finally` block, so a failed capture or an
unparseable payload still produces the contract rather than empty stdout,
which PreToolUse would read the same way as `{}`.
Tests cover both the pure contract and the built bundled script running
end to end with no server listening. Also extends the ARG_KEY_MAP test to
every mapped key and pins that an explicit canonical key wins over a
PascalCase alias.
* fix(antigravity): match agy's real hooks.json schema, verified against 1.0.15
Three defects found by probing a live agy 1.0.15 with an instrumented hook,
each of which stopped the adapter from capturing anything at all.
Lifecycle events take a flat handler list, not the tool-event wrapper. agy
parses `PreToolUse`/`PostToolUse` as `[{matcher, hooks: [...]}]` but
`PreInvocation`/`PostInvocation`/`Stop` as a bare `[{type, command}]`, since
there is no tool name to match on. Wrapping a lifecycle event makes agy read
the wrapper itself as a handler and reject the *whole file* with
`invalid hook "agentmemory": command hook must specify 'command'` — so the
mis-shaped Stop entry disabled every hook in the bundle, and would have
disabled hooks other tools had written to the same file.
`command` is not run through a shell and quotes are not stripped, so the
quoted path resolved to a module name that literally began with a double
quote: `Cannot find module 'C:\Users\…\.gemini\config\"C:\…\bridge.mjs"'`.
Commands are now bare. That also means a path containing spaces cannot be
expressed at all — quoted and unquoted both fail — so the installer refuses
with an explanation instead of writing hooks that can only fail at tool time.
The merge engine reads both shapes when deciding which bundles agentmemory
owns, so a re-install over the old wrapped layout still replaces it rather
than leaving a second copy behind.
Tests pin both event shapes, the absence of quotes, the space check, and
normalization of a payload captured verbatim from the live run — which also
confirms `conversationId`, PascalCase `toolCall.args`, and that agy sends no
`cwd` key at all.
* refactor(antigravity): cut comment volume to match the sibling adapters
The bundled script carried 24 comment lines where every other script in
plugin/scripts has three. The bundler strips `//` comments but preserves
JSDoc blocks, so the fix is to document the bridge's exported helpers with
line comments: the explanations stay in source and the generated artifact
comes out as clean as its siblings.
The connect adapter and merge engine restated the same facts in a file
header and again in a per-function block. Kept one statement of each,
dropped the repetition, and left the verified agy behaviour in place since
that is the part not derivable from the code.
---------
Signed-off-by: Bertho Joris <bertho_joris@yahoo.co.id>
* feat(cli): add native hooks adapter for Droid (Factory.ai)
Droid ships a first-party hooks system (~/.factory/hooks.json) using
the same manifest shape as Codex/Claude Code. `agentmemory connect
droid --with-hooks` now merges the bundled hooks.droid.json into it,
covering SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, and
SessionEnd via the existing buildMergedHooks merge/re-install logic.
Also fixes a Windows test-isolation bug in connect-new-agents.test.ts
where os.homedir() reads USERPROFILE (not HOME), which was silently
letting adapter tests write into the real user home directory.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* docs: changelog entry + regenerate agentmemory-agents skill reference for Droid hooks
CHANGELOG [Unreleased] entry for the new --with-hooks path, and
npm run skills:gen to sync the auto-generated agents table (pulled
from src/cli/connect/index.ts protocolNote) so it reflects Droid's
updated hooks capability. tools/rest/config/hooks reference docs
showed as stale too but diffed empty (pre-existing line-ending-only
drift on this checkout) so left untouched.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* fix(cli): surface skipped hook results in dry-run branch, tighten Droid hook tests
- json-mcp-adapter: capture and warn on skipped hook results in the
dry-run branch (consistent with already-wired and post-install branches)
- droid-connect-hooks test: assert exact five-event set instead of
presence-only plus selective absence checks
- droid-connect-hooks test: use deep equality (toEqual) for idempotency
check instead of per-event length comparison
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
* fix(cli): use Droid Create tool in PreToolUse matcher
Droid has no Write tool — file creation is Create — so the Claude-era
matcher blocked enrichment on new files. Align the manifest and test.
Co-authored-by: Cursor <cursoragent@cursor.com>
* docs: drop changelog entry and trim Droid README row
Per review: remove the Unreleased CHANGELOG addition, and keep the
Droid agents-table row short with a brief --with-hooks mention.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
* feat: add Copilot CLI plugin asset slice
- plugin/.plugin/plugin.json: Copilot manifest with name/version/skills/mcpServers/hooks refs
- plugin/.mcp.copilot.json: MCP server config with type:local, npx, env passthrough, tools:[*]
- plugin/hooks/hooks.copilot.json: Copilot hooks (version:1) with 11 supported events and PreToolUse matcher
- test/copilot-plugin.test.ts: 11 tests covering manifest, MCP config, and hooks validation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add Copilot CLI connect support
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add GitHub Copilot CLI support
Adds Copilot CLI support through a root plugin manifest, Copilot-specific MCP and hook configuration, and a connect adapter for MCP-only setup.
Includes Windows-safe Copilot MCP command generation, COPILOT_HOME handling, Copilot hook payload normalization, generated hook scripts, and targeted tests for plugin shape, hook execution, and connect behavior.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Harden Copilot hook handling
Addresses upstream AI review suggestions by aligning the Copilot preToolUse matcher with the hook allowlist, narrowing hook payload fields at runtime, normalizing subagent fallbacks, and tightening hook config validation.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add Copilot to first-run onboarding
Includes GitHub Copilot CLI in the first-run agent picker and adds a regression test so the Copilot setup path remains discoverable.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Default onboarding to Copilot inside Copilot CLI
Detect Copilot CLI environment markers during first-run setup so pressing Enter wires the current agent instead of the historical Claude Code default.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Support framed stdio MCP transport
Accept Content-Length framed JSON-RPC messages in addition to the existing newline-delimited transport so Copilot CLI can initialize the standalone MCP server.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Narrow Copilot pre-tool session ids
Ensures pre-tool-use only forwards string session IDs and falls back to unknown for invalid Copilot payload values, with regression coverage for the generated plugin script.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Ross Story <rostory@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Rohit Ghumare <ghumare64@gmail.com>
* feat(plugin): ship Codex plugin manifest + marketplace (#codex-plugins)
OpenAI Codex shipped a plugin platform
(developers.openai.com/codex/plugins) with the same shape as Anthropic
Claude Code plugins: .codex-plugin/plugin.json manifest, optional
.mcp.json, hooks/hooks.json, and a skills/ directory.
Verified against openai/codex source
(codex-rs/hooks/src/engine/discovery.rs): Codex's hook engine
explicitly injects CLAUDE_PLUGIN_ROOT into hook subprocesses for
OOTB compat with existing Claude Code plugins. The wire-format
input schemas
(codex-rs/hooks/schema/generated/session-start.command.input.schema.json
and siblings) use the same field names as Claude Code
(session_id, cwd, hook_event_name, source, transcript_path, model,
permission_mode).
Net result: our existing plugin/ directory already works as a Codex
plugin with two small additions:
1. plugin/.codex-plugin/plugin.json — Codex manifest pointing at the
shared ./.mcp.json, ./skills/, and a Codex-specific ./hooks/
hooks.codex.json. Name (kebab-case), version, description match
the Claude Code manifest.
2. plugin/hooks/hooks.codex.json — Codex-compatible hook subset.
Drops SubagentStart, SubagentStop, SessionEnd, Notification,
TaskCompleted, PostToolUseFailure (Claude-Code-only). Keeps
SessionStart, UserPromptSubmit, PreToolUse, PostToolUse,
PreCompact, Stop. Adds Codex-specific `statusMessage` decorations
on the two hooks the user sees most (SessionStart + UserPromptSubmit).
The script commands themselves still reference ${CLAUDE_PLUGIN_ROOT}
because Codex's engine injects it.
3. .codex-plugin/marketplace.json at repo root — git-subdir source
pointing at ./plugin so `codex plugin marketplace add rohitg00/
agentmemory` works the same way `claude plugin marketplace add`
does. Mirrors the existing .claude-plugin/marketplace.json shape
but in Codex's marketplace schema (name + interface.displayName
+ plugins[].source.{source, url, path, ref} + plugins[].policy).
README updates:
- Codex CLI tile in the Works-with-every-agent grid now reads
"6 hooks + MCP + skills" instead of "MCP server" to surface the
upgraded surface.
- "Other agents" install table now distinguishes "Codex CLI (MCP
only)" (existing codex mcp add path) from "Codex CLI (full
plugin)" (new marketplace install).
- New Codex section in the "paste this prompt" block with the
two-command install (server + marketplace add + plugin install),
the list of registered surfaces, and the env-var-injection note
citing the Codex source line.
6 new tests in test/codex-plugin.test.ts cover:
1. .codex-plugin/plugin.json present with kebab-case name and
required references.
2. Manifest version matches main package.json (so future bumps
don't drift the Codex side).
3. Every path referenced in the manifest resolves to a real file or
directory on disk.
4. hooks.codex.json contains only events Codex supports — any
future addition has to be added to a Codex allowlist or the
test fails loudly.
5. Every ${CLAUDE_PLUGIN_ROOT}/scripts/* command references an
existing script file (catches typos before users hit them).
6. .codex-plugin/marketplace.json declares git-subdir source with
path: "./plugin" pointing at this repo.
874 / 874 tests pass.
* fix(plugin/codex): align manifest description + assert PreCompact hook
Two reviewer findings addressed:
1. plugin/.codex-plugin/plugin.json's description claimed "12 hooks"
but Codex only registers 6 (the Codex hook input schemas don't
define SubagentStart, SubagentStop, SessionEnd, Notification,
TaskCompleted, PostToolUseFailure). Updated the description to
"6 hooks, 51 MCP tools, 4 skills, real-time viewer." so the
marketplace listing matches the registered surface.
2. test/codex-plugin.test.ts asserted five lifecycle events
(SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, Stop)
but omitted PreCompact, leaving a regression hole: dropping
PreCompact from hooks.codex.json would still pass the test
because the allowlist loop only blocks UNKNOWN events. Added
expect(events).toContain("PreCompact") so the suite enforces
the full six-hook contract.
Skipped (with reason):
3. marketplace.json source.ref currently "main" — reviewer asked
for a fixed tag/SHA. Skipping because pinning to a tag forces
updating marketplace.json on every release; "main" matches our
convention where releases tag from main HEAD and pre-release
work is on feature branches. Users wanting an immutable cut
can pass --ref vX.Y.Z to `codex plugin marketplace add` per
Codex docs.
Validation: 6/6 codex tests pass; 874/874 full suite unchanged.
New hooks (7):
- PreToolUse: inject file history before edits (Edit/Write/Read/Glob/Grep)
- PostToolUseFailure: capture error patterns for learning
- PreCompact: preserve memory context through compaction
- SubagentStart/SubagentStop: track multi-agent workflows
- Notification: capture permission prompts (tool preferences)
- TaskCompleted: track team task completions
New functions (4):
- mem::file-context: file-centric memory index for PreToolUse
- mem::consolidate: merge observations into long-term memories via LLM
- mem::patterns + mem::generate-rules: detect co-change patterns and recurring errors
- mem::remember + mem::forget: explicit save/delete for long-term memory
MCP server (2 endpoints):
- GET /agentmemory/mcp/tools: list 5 MCP tools (recall, save, file_history, patterns, sessions)
- POST /agentmemory/mcp/call: dispatch tool calls to iii functions
Skills (4):
- /recall [query]: search past observations
- /remember [insight]: save to long-term memory
- /session-history: show past session timeline
- /forget [target]: delete specific memory data
New API endpoints (7):
- POST /agentmemory/file-context
- POST /agentmemory/remember
- POST /agentmemory/forget
- POST /agentmemory/consolidate
- POST /agentmemory/patterns
- POST /agentmemory/generate-rules
- GET/POST /agentmemory/mcp/*
Updated: types (7 new HookTypes, 3 new ObservationTypes), version 0.2.0