@ory/antigravity 0.14.0 → 1.0.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 CHANGED
@@ -2,9 +2,12 @@
2
2
 
3
3
  Security and developer experience for [Google Antigravity](https://antigravity.google), powered by [Ory](https://ory.com).
4
4
 
5
- **Security.** Antigravity runs real actions on your machine — editing files, running shell commands, calling APIs. The plugin gives every session a verifiable identity (you sign in once; Antigravity and any sub-agents it spawns each get their own), checks every tool call against permissions you control, and records each decision as an audit trace you can ship to your observability stack. It starts in watch mode so nothing is blocked on day one, and if Ory is ever unreachable it steps aside rather than locking you out.
5
+ Antigravity runs real actions on your machine — editing files, running shell commands, calling APIs. This plugin gives those actions an identity, a permission check, and an audit trail.
6
6
 
7
- **Developer experience.** A single command installs the plugin and walks you through connecting — choose Ory Network, a local Docker stack, or audit-only, and it wires up the project, sign-in client, login, and permissions for you. It also helps you build Ory into your own app: ask in plain language to scaffold login, registration, and recovery pages, run a local Ory, or manage identities and permissions through the bundled MCP server.
7
+ One command installs two independent halves:
8
+
9
+ - **Developer experience** — the Ory skill catalog, `/ory:` slash commands, the local Ory dev stack, an MCP server, and activity logging. No account, no keys, nothing to configure: it works the moment it's installed.
10
+ - **Ory Agent Security** — browser sign-in, brokered permission checks before tool calls, and the delegation trail. Opt-in connection details from the [Ory Console](https://console.ory.sh) switch it on, and it takes nothing away from the half above. See [Connect to Ory Agent Security](#connect-to-ory-agent-security).
8
11
 
9
12
  > **Antigravity is the successor to Gemini CLI.** If you used the Ory Gemini CLI extension, this is its counterpart for the `agy` CLI and the Antigravity IDE. Your existing skills and commands carry over.
10
13
 
@@ -17,29 +20,19 @@ Security and developer experience for [Google Antigravity](https://antigravity.g
17
20
 
18
21
  ## Get started
19
22
 
20
- Run one command. It installs the plugin (registering it with Antigravity via `agy plugin install`) and walks you through connecting:
23
+ Run one command It installs the plugin, registering it with Antigravity via `agy plugin install`:
21
24
 
22
25
  ```bash
23
26
  npx -y -p @ory/antigravity ory-agy install
24
27
  ```
25
28
 
26
- It opens a guided setup **in your browser** where you pick how to connect — the default takes just a click:
27
-
28
- - **Ory Network** *(default)* — sign in, or create a free account, in your browser. The project, keys, permissions, and login are all set up for you. Nothing to configure by hand.
29
- - **Local** — run a complete Ory on your laptop with Docker. No account, no signup, no keys. Great for trying it out.
30
- - **Audit-only** — skip Ory entirely and just log what the agent does.
31
-
32
- > No browser available (CI, SSH, headless)? The same walkthrough runs right in your terminal instead — or force it with `--no-web`.
33
-
34
- That's it. Confirm everything landed with:
29
+ Confirm everything landed with:
35
30
 
36
31
  ```bash
37
32
  npx -y -p @ory/antigravity ory-agy status
38
33
  ```
39
34
 
40
- `status` is your one-stop check: what's configured, who's signed in, which tools are covered by permissions, plugin + skill registration, and recent activity. Anything not set up yet shows as `(unset)`.
41
-
42
- Re-run install with `--reconfigure` to change your connection later, or `--no-configure` to skip the wizard and configure by hand.
35
+ `status` is your one-stop check: what's configured, who's signed in, which tools are covered by permissions, plugin + skill registration, and recent activity. Until you connect Agent Security, the identity and permission rows say so and name what's missing.
43
36
 
44
37
  <details>
45
38
  <summary>No <code>agy</code> binary? Install into <code>.agents/</code> directly</summary>
@@ -53,13 +46,47 @@ npx -y -p @ory/antigravity ory-agy uninstall
53
46
 
54
47
  </details>
55
48
 
49
+ ## Skills and commands
50
+
51
+ Installing the plugin drops the full Ory playbook catalog into Antigravity. **Skills** are model-invoked — just say what you want in plain language and the matching one takes over.
52
+
53
+ | Skill | What it does for you |
54
+ |---|---|
55
+ | `ory-auth-setup` | Adds a complete auth system to your app — login, registration, recovery, verification, settings — on [Ory Elements](https://github.com/ory/elements) |
56
+ | `ory-login-flow` | Builds just the pages, wired to Ory's self-service flows |
57
+ | `ory-social-login` | "Sign in with…" for Google, GitHub, Apple, Microsoft, Discord, Slack, GitLab, Facebook |
58
+ | `ory-local-dev` | Develops and tests login/permission flows against a local Ory — no project, no account, offline |
59
+ | `ory-permissions-onboarding` | Walks a fresh install from observe mode to enforced per-tool permissions without getting blocked |
60
+ | `ory-build-agent` | Drops `@ory/argus` into an agent *you* own — Claude Agent SDK, OpenAI Agents, Mastra, Vercel AI, LangGraph/PydanticAI |
61
+ | `ory-build-integration` | Wires Ory into your app: Action webhooks, JWT validation at a gateway, live event streams |
62
+ | `ory-contribute-integration` | Authors and submits an integration to the public `ory/integrates` registry |
63
+ | `ory-e2b-sandbox` | Scaffolds an E2B sandbox template that boots with this plugin preinstalled |
64
+ | `ory-temporal-worker` | Scaffolds a Temporal TypeScript worker where every Activity is authenticated, authorized, and audited |
65
+
66
+ **Slash commands** run the local stack directly:
67
+
68
+ | Command | What it does |
69
+ |---|---|
70
+ | `/ory:local-up` | Starts a local Ory (Identities, OAuth2, Permissions) in Docker and seeds a test user — it prints the email + password to sign in with |
71
+ | `/ory:local-down` | Stops it, keeping your data volumes |
72
+ | `/ory:temporal-up` | Starts a local Temporal dev server for the `ory-temporal-worker` scaffold |
73
+
74
+ The local stack runs entirely on your laptop: Ory APIs at `http://localhost:4000`, a login UI on `:4455` (not `:3000`, to dodge Next.js port clashes), and the Ory Console on `:4100`.
75
+
76
+ A built-in **Ory MCP server** rounds it out — Antigravity can manage identities, projects, and permissions straight from chat.
77
+
78
+ So: ask Antigravity *"add Ory login to this app"* and it scaffolds the pages, starts a local Ory, and wires them together.
79
+
56
80
  ## What you get
57
81
 
58
- Once connected, every tool the agent runs is governed by Ory three things happen automatically:
82
+ Out of the box, every tool the agent runs produces a privacy-safe structured activity event in the unified local log.
83
+
84
+ Once you connect to Ory Agent Security, two more things happen automatically:
59
85
 
60
- - **Who's driving.** You sign in once in your browser (a secure sign-in flow, no tokens to copy around); the agent process gets its own identity, which it registers itself automatically on first run. The "who acted on whose behalf" trail stays queryable later.
61
- - **What it's allowed to do.** Before a tool runs, Ory checks whether it's permitted. It starts in **watch mode** — nothing is blocked, you just *see* what would be — so it never gets in your way on day one.
62
- - **A record of everything.** Every decision (allowed, denied, skipped) is logged as a trace you can send to Jaeger, Honeycomb, Grafana, or just a file.
86
+ - **Who's driving.** You sign in once in your browser (a secure sign-in flow, no tokens to copy around); each agent session gets its own identity, which it registers automatically on first use. The "who acted on whose behalf" trail stays queryable later.
87
+ - **What it's allowed to do.** Before a tool runs, Ory checks whether it's permitted. It starts in **observe mode** — nothing is blocked, you just *see* what would be — so it never gets in your way on day one.
88
+
89
+ If Ory is ever unreachable, the plugin gets out of the way and lets the agent keep working — so it can't lock you out.
63
90
 
64
91
  The plugin hooks into these Antigravity lifecycle events: `SessionStart` (check who's signed in), `PreToolUse` (authorize the tool), `PostToolUse` (record it), `Notification`, and `SessionEnd`.
65
92
 
@@ -67,92 +94,63 @@ The plugin hooks into these Antigravity lifecycle events: `SessionStart` (check
67
94
 
68
95
  ### See what's happening
69
96
 
70
- Everything the plugin does is observable out of the box — no configuration required:
97
+ Everything the plugin does is observable out of the box:
71
98
 
72
- - **Status at a glance.** `npx -y -p @ory/antigravity ory-agy status` shows what's configured, who's signed in, how many built-in tools your permissions cover, and the most recent tool-call activity.
73
- - **Live dashboard.** `npx -y -p @ory/antigravity ory-agy dashboard` opens the same picture in your browser — configuration, identities, permission coverage, Ory service health, and the latest tool-call activity, all refreshing live. From there you can flip **enforcement** on or off, toggle **user login**, and use **Change stack** to reconnect to a different Ory — no CLI required.
74
- - **Live traces.** Every tool call is recorded as an OpenTelemetry-style span. Watch them stream as the agent works:
99
+ - **Activity log.** Privacy-safe activity is always appended to `~/.config/ory-agent-plugins/antigravity/ory-agent-debug.log`. View events, decisions, and errors live with:
75
100
 
76
101
  ```bash
77
102
  npx -y -p @ory/antigravity ory-agy watch
78
103
  ```
79
104
 
80
- Spans are also written to `~/.config/ory-agent-plugins/antigravity/ory-agent-trace.ndjson` (NDJSON, one span per line) — tail that file, or point `OTEL_EXPORTER_OTLP_ENDPOINT` at a collector to ship them straight to Jaeger, Honeycomb, or Grafana.
81
- - **Debug log.** For a verbose play-by-play, set `ORY_AGENT_DEBUG=true`; structured logs land in `~/.config/ory-agent-plugins/antigravity/ory-agent-debug.log`.
105
+ Set `ORY_AGENT_LOG_FILE` to override the path; set it empty to disable file persistence.
106
+ - **Live debug.** Launch Antigravity with `ORY_AGENT_DEBUG=true` to add verbose local diagnostics, including raw shell commands, to the watched log and stderr. Secrets are recursively redacted; pass `watch --json` for NDJSON.
82
107
 
83
108
  ### Ready to enforce?
84
109
 
85
- When the watch-mode logs look right, turn on blocking with one command (setup already granted you the built-in tools):
110
+ Once connected, the deny posture lives on the Ory project: when the observe-mode activity looks right, an admin promotes it to **enforce** in the **Ory Console** (Agent Security). Every session reads that posture live, so nothing has to be reinstalled.
86
111
 
87
112
  ```bash
88
- npx -y -p @ory/antigravity ory-agy permissions enforce
113
+ npx -y -p @ory/antigravity ory-agy permissions # what the project grants, and the live mode
89
114
  ```
90
115
 
91
- Now a denied tool is actually blocked and Antigravity shows why (the `deny_reason`). Go back to watch mode anytime with `permissions observe`. Prefer clicking? The dashboard has the same **Enforce** switch — flip it on, or back to watch mode, without touching the CLI. Use `permissions status` to see what's covered and `permissions bootstrap` to (re-)grant the built-in tools (`run_command`, `view_file`, `write_to_file`, …) — or add permissions for MCP-server tools by hand, or via the Ory MCP server right from inside Antigravity.
92
-
93
- ## Also: add login to your own app
94
-
95
- Beyond securing the agent, the plugin helps you build Ory into whatever you're working on. Ask Antigravity *"add Ory login to this app"* (or invoke the `ory-auth-setup` skill) and it scaffolds the login, registration, recovery, and settings pages (using [Ory Elements](https://github.com/ory/elements)) wired to a local Ory — no signup or keys needed. Start that local Ory with `/ory:local-up` (it prints a test email + password to sign in with) and tear it down with `/ory:local-down`.
96
-
97
- Bundled **skills** (just ask in plain language) cover more: `ory-auth-setup`, `ory-login-flow`, `ory-social-login` (Google, GitHub, Apple…), `ory-permissions-onboarding`, and playbooks for wiring Ory into your own agents, E2B sandboxes, or Temporal workers. A built-in **Ory MCP server** lets the agent manage identities, projects, and permissions straight from chat.
98
-
99
- The local Ory runs entirely on your laptop:
100
-
101
- ```
102
- /ory:local-up # start a local Ory instance in Docker
103
- /ory:local-down # tear it all down
104
- /ory:temporal-up # start a local Temporal dev server (for ory-temporal-worker)
105
- ```
116
+ Then a denied tool is actually blocked and Antigravity shows why (the `deny_reason`).
106
117
 
107
- `local-up` brings up the Ory APIs (Identities, OAuth2, Permissions) at `http://localhost:4000`, a login UI on `:4455` (not `:3000`, to dodge Next.js port clashes), and Jaeger (the trace viewer) on `:16686`. A test user is seeded and its credentials printed — learn Ory hands-on, prototype flows, and test end-to-end, all offline.
118
+ ## Connect to Ory Agent Security
108
119
 
109
- ## Configure by hand (CI / advanced)
120
+ Copy the connection details from the [Ory Console](https://console.ory.sh) under **Agent Security**:
110
121
 
111
- The guided setup covers most people. For scripted or CI setups, or to point at an existing Ory Network project, configure directly. Settings are saved to `~/.config/ory-agent-plugins/config.json` and shared across all your Ory agent plugins; environment variables win when both are set.
122
+ | Value | Flag | Environment variable |
123
+ |---|---|---|
124
+ | Project URL | `--project-url` | `ORY_PROJECT_URL` |
125
+ | Agent Security URL | `--agent-security-url` | `ORY_AGENT_SECURITY_URL` |
126
+ | Sign-in client id override (default `ory-agent-security-login`) | `--oauth2-client-id` | `ORY_OAUTH2_CLIENT_ID` |
112
127
 
113
128
  ```bash
114
129
  npx -y -p @ory/antigravity ory-agy configure \
115
130
  --project-url https://<slug>.projects.oryapis.com \
116
- --oauth2-client-id <login client id>
131
+ --agent-security-url https://agents.console.ory.com
117
132
  ```
118
133
 
119
- The agent's own identity registers itself automatically on first run nothing to create. The `--oauth2-client-id` is the one piece browser sign-in needs; the guided setup makes it for you, or see below to do it by hand. For logging-only with no checks, use `--audit-only`. The interactive user login runs every session (always on, non-blocking) and only needs `ORY_OAUTH2_CLIENT_ID` to complete the browser flow. The matching env vars are `ORY_PROJECT_URL`, `ORY_OAUTH2_CLIENT_ID`, and `ORY_AGENT_API_KEY`.
134
+ `install` accepts the same flags, so you can register the plugin **and** connect in one shot (`install --project-url <URL> --agent-security-url <URL>`). The login client defaults to `ory-agent-security-login`; custom deployments can override it with `--oauth2-client-id`. Existing configurations fall back to the project URL when the Agent Security URL is unset. To turn sign-in and checks back off later, use `configure --disconnect`.
120
135
 
121
- <details>
122
- <summary>Create the sign-in client by hand</summary>
136
+ **Ory Network or OEL.** Either works. For an Ory Network project the URL is `https://<slug>.projects.oryapis.com`; for a self-hosted **Ory Enterprise License** deployment, point `--project-url` at that deployment's base URL and use the sign-in client id from its Agent Security configuration. Everything downstream — sign-in, checks, delegation — is identical.
123
137
 
124
- The guided setup normally does this. To do it yourself, create a **public** OAuth2 client (no secret) listing all four loopback URLs the plugin tries each in turn so sign-in survives a busy port:
138
+ **There is nothing else for you to create.** The sign-in client, the permission model, the per-tool grants and blocks, and the observe/enforce posture are all provisioned in the Console by someone with project access. At runtime the plugin only *reads* permissions it has no write path into your project, which is why installing it needs no workspace privilege. Each Antigravity session registers its own identity automatically on first use.
125
139
 
126
- ```bash
127
- ory create oauth2-client --project <project-id> \
128
- --name "Ory Agent Security · user login (PKCE)" \
129
- --grant-type authorization_code,refresh_token \
130
- --response-type code \
131
- --scope openid,offline_access \
132
- --token-endpoint-auth-method none \
133
- --redirect-uri http://127.0.0.1:47823/callback \
134
- --redirect-uri http://127.0.0.1:47824/callback \
135
- --redirect-uri http://127.0.0.1:47825/callback \
136
- --redirect-uri http://127.0.0.1:47826/callback
137
- ```
138
-
139
- Pass the resulting id to `configure --oauth2-client-id`. Running headless with a session token already? Set `ORY_USER_SESSION_TOKEN` and skip the browser step entirely.
140
-
141
- </details>
140
+ Sign-in runs at the start of every session and never blocks — a declined, skipped, or timed-out login simply leaves that session without a user identity.
142
141
 
143
- With nothing configured, the plugin still loads and runs in **pass-through mode**: skills, commands, and logging work, but no checks run and nothing is blocked. Perfectly fine if you only want the app-building features.
142
+ Settings are saved to `~/.config/ory-agent-plugins/config.json` and shared across all your Ory agent plugins; environment variables win when both are set. Running headless with an OAuth2 access token already? Set `ORY_USER_OAUTH2_TOKEN` and the browser step is skipped entirely.
144
143
 
145
144
  ## Commands
146
145
 
147
146
  ```
148
- ory-agy install | uninstall Install/remove; --reconfigure re-runs setup, --no-web forces the terminal wizard, --no-configure skips it
149
- ory-agy status Show configuration, identities, permission coverage, recent activity
150
- ory-agy dashboard Open the live browser dashboard (status + service health + Change stack)
151
- ory-agy watch Tail the live trace stream (OTel spans)
152
- ory-agy permissions <cmd> status | bootstrap | observe (watch) | enforce (block)
153
- ory-agy configure <flags> Point at a project by hand (--project-url, --oauth2-client-id, --audit-only)
154
- ory-agy agent <status|unregister> Manage the agent's own auto-created identity
155
- ory-agy local <up|down|status|…> Run / manage a local Ory in Docker
147
+ ory-agy install | uninstall Install (add --project-url to also connect Agent Security) / remove
148
+ ory-agy status Show configuration, identities, permission coverage, recent activity
149
+ ory-agy permissions <cmd> status (read-only; grants + posture live in the Ory Console)
150
+ ory-agy configure <flags> Connect a project (--project-url) or --disconnect
151
+ ory-agy agent <status|unregister> Manage the agent's own auto-created identity
152
+ ory-agy local <up|down|status|…> Run / manage a local Ory in Docker
153
+ ory-agy version Print plugin, core, and Node versions (--json for machine-readable)
156
154
  ory-agy-setup Install into .agents/ directly (no agy binary)
157
155
  ```
158
156
 
@@ -161,10 +159,9 @@ All prefixed with `npx -y -p @ory/antigravity`.
161
159
  ## Troubleshooting
162
160
 
163
161
  - **`/ory:local-up` fails** — make sure Docker is running and ports `4000`, `4455`, and `16686` are free.
164
- - **Browser sign-in loops** — reset with `ory-agy agent unregister` and try again.
165
- - **Install ran but never asked how to connect** — you're almost certainly on a stale `npx` cache. `npx -p @ory/antigravity` (no version pin) reuses a previously-downloaded copy instead of re-resolving to the latest, so an older CLI whose install predates the setup wizard can run while you believe you're on the current release. The install banner prints the running version; confirm it with `npx -y -p @ory/antigravity ory-agy version`. To force the current release, clear the cache and reinstall: `rm -rf ~/.npm/_npx` then `npx -y -p @ory/antigravity ory-agy install`. Pinning an exact version (`@ory/antigravity@<version>`) also bypasses the cached copy.
166
- - **A tool was unexpectedly blocked** — because Antigravity blocks by default, first confirm the hook is answering: set `ORY_AGENT_DEBUG=true` and check the logs for hook errors. Then verify the user has `use` on the tool with `permissions status`.
167
- - **Want to see what's happening** — `npx -y -p @ory/antigravity ory-agy status` for a snapshot, `npx -y -p @ory/antigravity ory-agy watch` for the live trace stream, or set `ORY_AGENT_DEBUG=true` for a verbose log. Traces and logs live under `~/.config/ory-agent-plugins/antigravity/` (see [See what's happening](#see-whats-happening)).
162
+ - **Browser sign-in loops** (after connecting) — reset with `ory-agy agent unregister` and try again.
163
+ - **Running an older CLI than expected** — `npx -p @ory/antigravity` (no version pin) reuses a previously-downloaded copy instead of re-resolving to the latest. The install banner prints the running version; confirm it with `npx -y -p @ory/antigravity ory-agy version`. To force the current release, clear the cache and reinstall: `rm -rf ~/.npm/_npx` then `npx -y -p @ory/antigravity ory-agy install`. Pinning an exact version (`@ory/antigravity@<version>`) also bypasses the cached copy.
164
+ - **A tool was unexpectedly blocked** — because Antigravity blocks by default, first confirm the hook is answering: set `ORY_AGENT_DEBUG=true` and check the logs for hook errors. Then verify the user has `use` on the tool with `permissions`.
168
165
 
169
166
  ## Learn more
170
167
 
@@ -17,8 +17,19 @@
17
17
  * hooks.json shape (verified): top-level rule id → event name → array of
18
18
  * `{ matcher, hooks: [{ type, command, timeout }] }`.
19
19
  */
20
+ import { type PreparedRuntime } from "@ory/argus";
20
21
  /** Plugin / rule / MCP-server id. */
21
22
  export declare const PLUGIN_NAME = "ory";
23
+ /**
24
+ * Resolve this install's runtime and write its shims. Both entry points (the
25
+ * `agy plugin install` path in `main.ts` and the manual `.agents` fallback in
26
+ * `setup.ts`) go through here so they wire the same runtime.
27
+ *
28
+ * Antigravity **fails closed**: a hook that crashes or answers with malformed
29
+ * output blocks the tool. So the shim's runtime-missing path has to emit an
30
+ * explicit allow, matching what the hook itself returns on every error path.
31
+ */
32
+ export declare function wireAntigravityRuntime(args: readonly string[]): PreparedRuntime;
22
33
  /**
23
34
  * Write the full Ory plugin bundle under `root`. Used both for the
24
35
  * bundle handed to `agy plugin install` and for the manual `.agents`
@@ -31,7 +42,7 @@ export declare const PLUGIN_NAME = "ory";
31
42
  * bundle dir the merge is a no-op over a fresh tree, so the same code
32
43
  * path is used everywhere.)
33
44
  */
34
- export declare function installAntigravityOryAssets(root: string): void;
45
+ export declare function installAntigravityOryAssets(root: string, runtime: PreparedRuntime): void;
35
46
  /**
36
47
  * Remove every Ory skill, command, and bundle entry written under `root`.
37
48
  *
@@ -53,17 +53,35 @@ var __importStar = (this && this.__importStar) || (function () {
53
53
  })();
54
54
  Object.defineProperty(exports, "__esModule", { value: true });
55
55
  exports.PLUGIN_NAME = void 0;
56
+ exports.wireAntigravityRuntime = wireAntigravityRuntime;
56
57
  exports.installAntigravityOryAssets = installAntigravityOryAssets;
57
58
  exports.uninstallAntigravityOryAssets = uninstallAntigravityOryAssets;
58
59
  const fs = __importStar(require("node:fs"));
59
60
  const path = __importStar(require("node:path"));
60
61
  const argus_1 = require("@ory/argus");
61
62
  const PACKAGE_NAME = "@ory/antigravity";
62
- const HOOK_BIN_NAME = "ory-agy-hook";
63
- const MCP_PACKAGE_NAME = "@ory/mcp-server";
64
- const MCP_BIN_NAME = "ory-mcp-server";
65
63
  /** Plugin / rule / MCP-server id. */
66
64
  exports.PLUGIN_NAME = "ory";
65
+ const PACKAGE_ROOT = path.resolve(__dirname, "..", "..");
66
+ /**
67
+ * Resolve this install's runtime and write its shims. Both entry points (the
68
+ * `agy plugin install` path in `main.ts` and the manual `.agents` fallback in
69
+ * `setup.ts`) go through here so they wire the same runtime.
70
+ *
71
+ * Antigravity **fails closed**: a hook that crashes or answers with malformed
72
+ * output blocks the tool. So the shim's runtime-missing path has to emit an
73
+ * explicit allow, matching what the hook itself returns on every error path.
74
+ */
75
+ function wireAntigravityRuntime(args) {
76
+ return (0, argus_1.wireRuntime)({
77
+ harness: "antigravity",
78
+ packageName: PACKAGE_NAME,
79
+ packageRoot: PACKAGE_ROOT,
80
+ installCommand: "npx -y -p @ory/antigravity ory-agy install",
81
+ args,
82
+ fallbackStdout: JSON.stringify({ allow_tool: true }),
83
+ });
84
+ }
67
85
  const RENDER_OPTS = {
68
86
  binName: "ory-agy",
69
87
  packageName: PACKAGE_NAME,
@@ -82,23 +100,28 @@ function readPackageVersion() {
82
100
  return parsed.version;
83
101
  }
84
102
  /**
85
- * Render hooks.json. The hook command is a self-contained
86
- * `npx -y -p @ory/antigravity@<version> ory-agy-hook` so the
87
- * binary need not be on PATH after install. `matcher: ".*"` matches every
88
- * tool name on the tool events.
103
+ * Render hooks.json. The command points at the runtime shim resolved at
104
+ * install time, so no package resolution happens per tool call.
105
+ * `matcher: ".*"` matches every tool name on the tool events.
89
106
  */
90
- function renderHooks(version) {
91
- const command = (0, argus_1.pinHookToLocalRegistry)(`npx -y -p ${PACKAGE_NAME}@${version} ${HOOK_BIN_NAME}`);
107
+ function renderHooks(command) {
92
108
  const entry = (matcher, timeout) => [
93
109
  { matcher, hooks: [{ type: "command", command, timeout }] },
94
110
  ];
111
+ // Antigravity's hook timeout is in SECONDS and it *validates* the value —
112
+ // "timeout must be between 5 and 120 seconds". The previous 10000/5000 were
113
+ // both far outside that range, so the values were never what they looked
114
+ // like. Core clamps to the 120s ceiling and asserts the session-start window
115
+ // still outlasts the login (#220).
116
+ const sessionStartSec = (0, argus_1.sessionStartHookTimeout)("antigravity", "seconds");
117
+ const toolSec = (0, argus_1.toolHookTimeout)("antigravity", "seconds");
95
118
  return {
96
119
  [exports.PLUGIN_NAME]: {
97
- SessionStart: entry(".*", 10000),
98
- SessionEnd: entry(".*", 5000),
99
- PreToolUse: entry(".*", 5000),
100
- PostToolUse: entry(".*", 5000),
101
- Notification: entry(".*", 5000),
120
+ SessionStart: entry(".*", sessionStartSec),
121
+ SessionEnd: entry(".*", toolSec),
122
+ PreToolUse: entry(".*", toolSec),
123
+ PostToolUse: entry(".*", toolSec),
124
+ Notification: entry(".*", toolSec),
102
125
  },
103
126
  };
104
127
  }
@@ -107,24 +130,16 @@ function renderManifest(version) {
107
130
  return {
108
131
  name: exports.PLUGIN_NAME,
109
132
  version,
110
- description: "Ory authentication, authorization, and distributed tracing for Google Antigravity",
133
+ description: "Ory authentication, authorization, and activity auditing for Google Antigravity",
111
134
  };
112
135
  }
113
136
  /**
114
137
  * Render mcp_config.json. Antigravity uses the standard `mcpServers` map;
115
- * stdio servers use `command` + `args` (remote servers would use
116
- * `serverUrl`). The Ory MCP server is resolved via npx for the same
117
- * reason as the hook command.
138
+ * stdio servers use `command` + `args` (remote servers would use `serverUrl`).
139
+ * The server is started from the resolved runtime via its shim.
118
140
  */
119
- function renderMcpConfig(version) {
120
- return {
121
- mcpServers: {
122
- [exports.PLUGIN_NAME]: {
123
- command: "npx",
124
- args: ["-y", "-p", `${MCP_PACKAGE_NAME}@${version}`, MCP_BIN_NAME],
125
- },
126
- },
127
- };
141
+ function renderMcpConfig(server) {
142
+ return { mcpServers: { [exports.PLUGIN_NAME]: server } };
128
143
  }
129
144
  /**
130
145
  * Read a JSON file as a plain object. Returns `undefined` when the file
@@ -162,7 +177,7 @@ function isOryManifest(manifest) {
162
177
  * bundle dir the merge is a no-op over a fresh tree, so the same code
163
178
  * path is used everywhere.)
164
179
  */
165
- function installAntigravityOryAssets(root) {
180
+ function installAntigravityOryAssets(root, runtime) {
166
181
  const version = readPackageVersion();
167
182
  fs.mkdirSync(root, { recursive: true });
168
183
  const skillsDir = path.join(root, "skills");
@@ -178,19 +193,23 @@ function installAntigravityOryAssets(root) {
178
193
  // any rules the user has defined alongside it.
179
194
  const hooksPath = path.join(root, "hooks.json");
180
195
  const hooks = readJsonObject(hooksPath) ?? {};
181
- hooks[exports.PLUGIN_NAME] = renderHooks(version)[exports.PLUGIN_NAME];
196
+ hooks[exports.PLUGIN_NAME] = renderHooks((0, argus_1.requireHookCommand)(runtime))[exports.PLUGIN_NAME];
182
197
  writeJson(hooksPath, hooks);
183
198
  // mcp_config.json — replace only the Ory server entry under `mcpServers`,
184
- // preserving other servers and any unrelated top-level keys.
185
- const mcpPath = path.join(root, "mcp_config.json");
186
- const mcp = readJsonObject(mcpPath) ?? {};
187
- const existingServers = mcp.mcpServers;
188
- const servers = existingServers && typeof existingServers === "object" && !Array.isArray(existingServers)
189
- ? existingServers
190
- : {};
191
- servers[exports.PLUGIN_NAME] = renderMcpConfig(version).mcpServers[exports.PLUGIN_NAME];
192
- mcp.mcpServers = servers;
193
- writeJson(mcpPath, mcp);
199
+ // preserving other servers and any unrelated top-level keys. Skipped when
200
+ // the runtime ships no MCP server: better no registration than one that
201
+ // cannot start.
202
+ if (runtime.mcpServer) {
203
+ const mcpPath = path.join(root, "mcp_config.json");
204
+ const mcp = readJsonObject(mcpPath) ?? {};
205
+ const existingServers = mcp.mcpServers;
206
+ const servers = existingServers && typeof existingServers === "object" && !Array.isArray(existingServers)
207
+ ? existingServers
208
+ : {};
209
+ servers[exports.PLUGIN_NAME] = renderMcpConfig(runtime.mcpServer).mcpServers[exports.PLUGIN_NAME];
210
+ mcp.mcpServers = servers;
211
+ writeJson(mcpPath, mcp);
212
+ }
194
213
  // plugin.json — only write over a manifest that is Ory's own (or absent).
195
214
  const manifestPath = path.join(root, "plugin.json");
196
215
  if (!fs.existsSync(manifestPath) || isOryManifest(readJsonObject(manifestPath))) {
package/dist/cli/main.js CHANGED
@@ -61,8 +61,18 @@ function agyAvailable() {
61
61
  }
62
62
  function main() {
63
63
  const [command, ...args] = process.argv.slice(2);
64
+ // `--help` after a matched subcommand: print usage, do nothing else.
65
+ // Without this the switch below ignores the flag and `install --help`
66
+ // performs a real install (#221).
67
+ if ((0, argus_1.shouldPrintHelp)(command, args))
68
+ return help();
64
69
  switch (command) {
65
70
  case "install":
71
+ if (args.includes("--print")) {
72
+ process.argv = ["node", "setup.js", ...args];
73
+ require("./setup.js");
74
+ break;
75
+ }
66
76
  (0, argus_1.beginDeferNextSteps)();
67
77
  install(args);
68
78
  (0, argus_1.runPostInstall)("ory-agy", "antigravity", args).then(() => process.exit(0), (err) => {
@@ -72,7 +82,10 @@ function main() {
72
82
  break;
73
83
  case "uninstall":
74
84
  uninstall(args);
75
- (0, argus_1.clearCredentialsForUninstall)().then(() => process.exit(0), (err) => {
85
+ (0, argus_1.clearCredentialsForUninstall)({
86
+ harness: "antigravity",
87
+ purge: args.includes("--purge"),
88
+ }).then(() => process.exit(0), (err) => {
76
89
  console.error(err.message ?? err);
77
90
  process.exit(1);
78
91
  });
@@ -81,7 +94,7 @@ function main() {
81
94
  (0, argus_1.runConfigureCommand)("ory-agy", args);
82
95
  break;
83
96
  case "agent":
84
- (0, argus_1.runAgentCommand)("ory-agy", args).then((code) => process.exit(code), (err) => {
97
+ (0, argus_1.runAgentCommand)("ory-agy", "antigravity", args).then((code) => process.exit(code), (err) => {
85
98
  console.error(err.message ?? err);
86
99
  process.exit(1);
87
100
  });
@@ -101,17 +114,11 @@ function main() {
101
114
  process.exit(1);
102
115
  });
103
116
  break;
104
- case "local":
105
- (0, argus_1.runLocalCommand)("ory-agy", args).catch((err) => {
106
- console.error(err.message ?? err);
107
- process.exit(1);
108
- });
109
- break;
110
117
  case "watch":
111
- (0, argus_1.runWatchCommand)("antigravity", args);
118
+ (0, argus_1.runWatchCommand)("ory-agy", "antigravity", args).then((code) => process.exit(code), (err) => { console.error(err.message ?? err); process.exit(1); });
112
119
  break;
113
- case "dashboard":
114
- (0, argus_1.runDashboardCommand)("ory-agy", "antigravity", args).then((code) => process.exit(code), (err) => {
120
+ case "local":
121
+ (0, argus_1.runLocalCommand)("ory-agy", args).catch((err) => {
115
122
  console.error(err.message ?? err);
116
123
  process.exit(1);
117
124
  });
@@ -134,10 +141,19 @@ function main() {
134
141
  }
135
142
  }
136
143
  function install(args) {
144
+ // Resolve the runtime first: the bundle's hooks.json / mcp_config.json point
145
+ // at the shims it writes.
146
+ const runtime = (0, assets_js_1.wireAntigravityRuntime)(args);
147
+ console.log(runtime.target.kind === "linked"
148
+ ? `Runtime: linked to ${runtime.target.packageDir} (dev)`
149
+ : `Runtime: ${runtime.target.packageName}@${runtime.target.version} in ${runtime.target.storeDir}`);
150
+ for (const pruned of runtime.prunedStores) {
151
+ console.log(` Removed stale runtime: ${pruned}`);
152
+ }
137
153
  // Materialize the bundle (plugin.json + hooks.json + mcp_config.json +
138
154
  // skills + commands) before handing it to `agy plugin install`.
139
155
  console.log("Materializing the Ory plugin bundle...");
140
- (0, assets_js_1.installAntigravityOryAssets)(BUNDLE_DIR);
156
+ (0, assets_js_1.installAntigravityOryAssets)(BUNDLE_DIR, runtime);
141
157
  if (agyAvailable()) {
142
158
  console.log("Installing Ory plugin into Antigravity...");
143
159
  const result = (0, node_child_process_1.spawnSync)(AGY, ["plugin", "install", BUNDLE_DIR], {
@@ -208,11 +224,11 @@ Commands:
208
224
  uninstall Remove the Ory plugin from Antigravity
209
225
  configure Set or view Ory project URL and credentials
210
226
  agent <cmd> Manage the agent's OAuth2 (DCR) identity (status, unregister)
211
- permissions <cmd> Manage permission mode and tool permissions (status, bootstrap, observe, enforce)
227
+ permissions Show the live permission mode and per-tool coverage
212
228
  setup [--project-dir] Write the plugin bundle into .agents directly (fallback)
213
229
  status Show plugin status and configuration
214
- dashboard Open the Ory Agent dashboard (system health + configuration)
215
- watch [trace-file] Tail the trace stream (OTel spans) live
230
+ watch [--json] [--lines <count>]
231
+ Follow the live activity/debug log
216
232
  version Show version and the ory-agent-plugins build commit
217
233
  local <cmd> Manage local Ory dev environment (up, down, status, seed, ...)
218
234
 
package/dist/cli/setup.js CHANGED
@@ -74,9 +74,13 @@ function main() {
74
74
  }
75
75
  (0, assets_js_1.uninstallAntigravityOryAssets)(agentsDir);
76
76
  console.log(`Removed Ory plugin bundle from ${agentsDir}`);
77
+ (0, argus_1.removeRuntimeWiring)("antigravity");
78
+ for (const pruned of (0, argus_1.pruneRuntimeStores)()) {
79
+ console.log(` Removed runtime: ${pruned}`);
80
+ }
77
81
  return;
78
82
  }
79
- (0, assets_js_1.installAntigravityOryAssets)(agentsDir);
83
+ (0, assets_js_1.installAntigravityOryAssets)(agentsDir, (0, assets_js_1.wireAntigravityRuntime)(process.argv.slice(2)));
80
84
  console.log(`Ory plugin bundle installed to ${agentsDir}`);
81
85
  (0, argus_1.printNextSteps)("Google Antigravity", "npx -y -p @ory/antigravity ory-agy-setup --uninstall", { binName: "ory-agy", harness: "antigravity" });
82
86
  }
@@ -85,7 +89,10 @@ main();
85
89
  // stored Ory credentials. When required by the plugin's main CLI, that
86
90
  // command owns the purge, so the `require.main` guard prevents a double run.
87
91
  if (require.main === module && process.argv.includes("--uninstall")) {
88
- (0, argus_1.clearCredentialsForUninstall)().then(() => process.exit(0), (err) => {
92
+ (0, argus_1.clearCredentialsForUninstall)({
93
+ harness: "antigravity",
94
+ purge: process.argv.includes("--purge"),
95
+ }).then(() => process.exit(0), (err) => {
89
96
  console.error(err.message ?? err);
90
97
  process.exit(1);
91
98
  });
package/dist/emit.d.ts CHANGED
@@ -2,9 +2,7 @@
2
2
  * Write-once stdout emitter for the Antigravity hook.
3
3
  *
4
4
  * Antigravity parses the hook's stdout as a single JSON document and
5
- * FAILS CLOSED on malformed output. If two code paths both write (e.g.
6
- * the main path writes the decision and then `tracer.shutdown()` rejects,
7
- * landing in the top-level catch which writes FAIL_OPEN again), stdout
5
+ * FAILS CLOSED on malformed output. If two code paths both write, stdout
8
6
  * carries two concatenated JSON documents and the harness blocks the
9
7
  * tool. This factory guarantees exactly one write ever reaches stdout.
10
8
  */
package/dist/emit.js CHANGED
@@ -3,9 +3,7 @@
3
3
  * Write-once stdout emitter for the Antigravity hook.
4
4
  *
5
5
  * Antigravity parses the hook's stdout as a single JSON document and
6
- * FAILS CLOSED on malformed output. If two code paths both write (e.g.
7
- * the main path writes the decision and then `tracer.shutdown()` rejects,
8
- * landing in the top-level catch which writes FAIL_OPEN again), stdout
6
+ * FAILS CLOSED on malformed output. If two code paths both write, stdout
9
7
  * carries two concatenated JSON documents and the harness blocks the
10
8
  * tool. This factory guarantees exactly one write ever reaches stdout.
11
9
  */
package/dist/handlers.js CHANGED
@@ -19,11 +19,7 @@ async function handleHookEvent(input, client, deps = {}) {
19
19
  sessionId: input.session_id,
20
20
  toolName: input.tool_name,
21
21
  });
22
- client.tracer.setContext({
23
- traceId: (0, argus_1.deriveTraceId)(input.session_id),
24
- sessionId: input.session_id,
25
- });
26
- try {
22
+ return (0, argus_1.withHookContext)(client, { sessionId: input.session_id }, async () => {
27
23
  switch (event) {
28
24
  case "SessionStart":
29
25
  return await handleSessionStart(input, client, deps);
@@ -38,15 +34,12 @@ async function handleHookEvent(input, client, deps = {}) {
38
34
  return handleSessionEnd(input, client);
39
35
  default:
40
36
  client.logger.debug("hook.passthrough", { event });
41
- client.tracer.record("hook.passthrough", "skipped", {
37
+ client.logger.activity("hook.passthrough", "skipped", {
42
38
  attributes: { event },
43
39
  });
44
40
  return ALLOW;
45
41
  }
46
- }
47
- finally {
48
- client.tracer.clearContext();
49
- }
42
+ });
50
43
  }
51
44
  // ─── SessionStart ───────────────────────────────────────────────────
52
45
  async function handleSessionStart(input, client, deps) {
@@ -55,25 +48,13 @@ async function handleSessionStart(input, client, deps) {
55
48
  model: input.model,
56
49
  source: input.source,
57
50
  });
58
- client.tracer.record("session.start", "ok", {
59
- attributes: { model: input.model, source: input.source },
60
- });
61
- // User login (interactive PKCE / token refresh). Runs every session and
62
- // never blocks — it refreshes tokens, prompts if needed, and emits the
63
- // audit span, but the session always proceeds. Enforcement happens at
64
- // tool-call time and is governed solely by permissionMode.
65
- const userGate = deps.userLogin ?? argus_1.ensureUserAuthenticated;
66
- await userGate(client, {
51
+ await (0, argus_1.sessionStart)(client, {
67
52
  binName: "ory-agy",
68
53
  harness: HARNESS,
54
+ userLogin: deps.userLogin,
55
+ agentGate: deps.agentGate,
56
+ activityAttributes: { model: input.model, source: input.source },
69
57
  });
70
- // Resolve the agent identity regardless of how user auth went — never
71
- // blocks; attaches the agent's bearer token to outgoing Ory calls.
72
- const agentGate = deps.agentGate ?? argus_1.ensureAgentIdentity;
73
- await agentGate(client, { projectUrl: (0, argus_1.resolveConfig)().projectUrl, harness: HARNESS });
74
- // Record the user→agent delegation (audit-trail only; fail-open).
75
- // Written at most once per install.
76
- await (0, argus_1.writeUserDelegatesAgent)(client);
77
58
  return {};
78
59
  }
79
60
  // ─── PreToolUse ─────────────────────────────────────────────────────
@@ -84,61 +65,19 @@ async function handlePreToolUse(input, client) {
84
65
  toolName,
85
66
  toolInput: input.tool_input,
86
67
  });
87
- const inputSummary = (0, argus_1.summarizeToolInput)(toolName, input.tool_input);
88
- // Audit-only mode: log the invocation, skip the permission check, allow.
89
- if ((0, argus_1.resolveConfig)().auditOnly) {
90
- client.tracer.record("tool.invoke", "ok", {
91
- attributes: { toolName, ...inputSummary },
92
- });
93
- return ALLOW;
94
- }
95
- const subject = (0, argus_1.resolveUserSubject)(client, `session:${input.session_id}`);
96
- const subjectId = (0, argus_1.subjectLabel)(subject);
97
- const namespace = resolveNamespace();
98
- try {
99
- const outcome = await (0, argus_1.gateToolCall)(client, {
100
- harness: HARNESS,
101
- toolName,
102
- check: { namespace, object: toolName, relation: "use", ...subject },
103
- spanAttributes: { toolName },
104
- });
105
- // Interactive tools surface UI to the user; gateToolCall already
106
- // recorded the user.interaction span. Let the harness prompt.
107
- if (outcome.kind === "interactive") {
108
- return ALLOW;
109
- }
110
- if (outcome.kind === "fail_open") {
111
- return failOpen(outcome.error, toolName, client);
112
- }
113
- const attrs = { toolName, ...inputSummary };
114
- const decisionAttrs = outcome.spanAttributes;
115
- if (outcome.kind === "allow") {
116
- client.tracer.record("tool.invoke", "ok", {
117
- attributes: { ...attrs, ...decisionAttrs, allowed: true },
118
- });
119
- return ALLOW;
120
- }
121
- if (outcome.kind === "observe") {
122
- client.tracer.record("tool.block", "denied", {
123
- attributes: { ...attrs, ...decisionAttrs, allowed: false, ...(0, argus_1.alertAttributes)(false) },
124
- });
125
- client.tracer.record("tool.invoke", "ok", {
126
- attributes: { ...attrs, ...decisionAttrs, allowed: false, observed: true },
127
- });
128
- return ALLOW;
129
- }
130
- // deny → block the tool (enforce mode).
131
- client.tracer.record("tool.block", "denied", {
132
- attributes: { ...attrs, ...decisionAttrs, allowed: false, ...(0, argus_1.alertAttributes)(true) },
133
- });
68
+ const result = await (0, argus_1.gate)(client, {
69
+ harness: HARNESS,
70
+ toolName,
71
+ toolArgs: input.tool_input,
72
+ subjectFallback: `session:${input.session_id}`,
73
+ });
74
+ if (result.blocked) {
134
75
  return {
135
76
  allow_tool: false,
136
- deny_reason: (0, argus_1.formatDenialMessage)({ tool: toolName, subjectId, namespace }),
77
+ deny_reason: result.denialMessage,
137
78
  };
138
79
  }
139
- catch (err) {
140
- return failOpen(err, toolName, client);
141
- }
80
+ return ALLOW;
142
81
  }
143
82
  // ─── PostToolUse ────────────────────────────────────────────────────
144
83
  async function handlePostToolUse(input, client) {
@@ -149,36 +88,31 @@ async function handlePostToolUse(input, client) {
149
88
  });
150
89
  const failed = input.tool_error !== undefined && input.tool_error !== null;
151
90
  if (failed) {
152
- client.tracer.record("tool.fail", "error", {
153
- attributes: {
154
- toolName,
155
- toolError: typeof input.tool_error === "string"
156
- ? input.tool_error.slice(0, 500)
157
- : "[object]",
158
- ...(0, argus_1.summarizeToolInput)(toolName, input.tool_input),
159
- },
91
+ client.logger.debug("lifecycle.post_tool_use.error", { error: input.tool_error });
92
+ (0, argus_1.fail)(client, {
93
+ toolName,
94
+ input: input.tool_input,
95
+ error: input.tool_error,
160
96
  });
161
97
  return {};
162
98
  }
163
- client.tracer.record("tool.complete", "ok", {
164
- attributes: {
165
- toolName,
166
- ...(0, argus_1.summarizeToolInput)(toolName, input.tool_input),
167
- ...(0, argus_1.summarizeToolOutput)(toolName, input.tool_response),
168
- },
99
+ (0, argus_1.complete)(client, {
100
+ toolName,
101
+ input: input.tool_input,
102
+ output: input.tool_response,
169
103
  });
170
104
  return {};
171
105
  }
172
106
  // PreInvocation / PostInvocation bracket each agent turn (not user
173
107
  // prompts). We don't model them specially — they fall through to the
174
- // default `hook.passthrough` audit span in handleHookEvent.
108
+ // default `hook.passthrough` activity event in handleHookEvent.
175
109
  // ─── Notification ───────────────────────────────────────────────────
176
110
  function handleNotification(input, client) {
177
111
  client.logger.info("lifecycle.notification", {
178
112
  sessionId: input.session_id,
179
113
  messageLen: input.message?.length,
180
114
  });
181
- client.tracer.record("user.interaction", "ok", {
115
+ client.logger.activity("user.interaction", "ok", {
182
116
  attributes: { harness: HARNESS, kind: "notification" },
183
117
  });
184
118
  return {};
@@ -189,39 +123,8 @@ function handleSessionEnd(input, client) {
189
123
  sessionId: input.session_id,
190
124
  reason: input.reason,
191
125
  });
192
- client.tracer.record("session.end", "ok", {
126
+ client.logger.activity("session.end", "ok", {
193
127
  attributes: { reason: input.reason },
194
128
  });
195
129
  return {};
196
130
  }
197
- // ─── Helpers ────────────────────────────────────────────────────────
198
- function resolveNamespace() {
199
- return process.env.ORY_PERMISSION_NAMESPACE ?? "AgentTools";
200
- }
201
- /**
202
- * Fail-open on a permission-check error: log and allow the tool. Critical
203
- * on Antigravity — returning anything other than `allow_tool: true` here
204
- * would block the user on a transient Ory/network blip.
205
- */
206
- function failOpen(oryErr, toolName, client) {
207
- if (oryErr.code === "network_error") {
208
- client.logger.warn("permission.network_error", {
209
- toolName,
210
- message: "Ory unreachable, failing open",
211
- });
212
- }
213
- else if (oryErr.code === "rate_limited") {
214
- client.logger.warn("permission.rate_limited", {
215
- toolName,
216
- message: "Ory rate limited, failing open",
217
- });
218
- }
219
- else {
220
- client.logger.error("permission.check.error", {
221
- toolName,
222
- code: oryErr.code,
223
- message: oryErr.message,
224
- });
225
- }
226
- return ALLOW;
227
- }
package/dist/hook.js CHANGED
@@ -22,12 +22,21 @@ const emit_js_1 = require("./emit.js");
22
22
  const handlers_js_1 = require("./handlers.js");
23
23
  /** The fail-open response: explicitly allow, so a crash never blocks. */
24
24
  const FAIL_OPEN = { allow_tool: true };
25
+ const EVENT_FLUSH_TIMEOUT_MS = 750;
26
+ let client;
27
+ async function flushEvents() {
28
+ try {
29
+ await client?.flushEvents(EVENT_FLUSH_TIMEOUT_MS);
30
+ }
31
+ catch {
32
+ // The hook decision must not depend on activity delivery.
33
+ }
34
+ }
25
35
  /**
26
36
  * Single write-once gate shared by every exit path (normal, parse
27
37
  * failure, and the top-level catch). Because Antigravity fails closed on
28
38
  * malformed stdout, a double write (two concatenated JSON documents)
29
- * would BLOCK the tool — e.g. when the main path writes its decision and
30
- * `tracer.shutdown()` then rejects into the top-level catch.
39
+ * would BLOCK the tool.
31
40
  */
32
41
  const emit = (0, emit_js_1.createEmitOnce)();
33
42
  /**
@@ -60,7 +69,7 @@ function readStdin() {
60
69
  });
61
70
  }
62
71
  async function main() {
63
- const client = argus_1.OryAgentClient.fromEnv("antigravity");
72
+ client = argus_1.OryAgentClient.fromEnv("antigravity");
64
73
  const raw = await readStdin();
65
74
  let input;
66
75
  try {
@@ -70,7 +79,6 @@ async function main() {
70
79
  client.logger.error("hook.stdin.parse_failed", { raw: raw.slice(0, 200) });
71
80
  // Can't tell the event; allow to avoid wedging a PreToolUse call.
72
81
  emit(FAIL_OPEN);
73
- await client.tracer.shutdown();
74
82
  process.exit(0);
75
83
  }
76
84
  let output;
@@ -85,14 +93,15 @@ async function main() {
85
93
  output = FAIL_OPEN;
86
94
  }
87
95
  emit(output);
88
- await client.tracer.shutdown();
96
+ await flushEvents();
89
97
  process.exit(0);
90
98
  }
91
- main().catch((err) => {
99
+ main().catch(async (err) => {
92
100
  // Last-resort guard: allow rather than block, then exit cleanly. The
93
101
  // write-once emitter makes this a no-op when the decision was already
94
- // written before the rejection (e.g. a failing tracer shutdown).
102
+ // written before the rejection.
95
103
  process.stderr.write(`[ory-agent] fatal: ${err}\n`);
96
104
  emit(FAIL_OPEN);
105
+ await flushEvents();
97
106
  process.exit(0);
98
107
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ory/antigravity",
3
- "version": "0.14.0",
3
+ "version": "1.0.1",
4
4
  "description": "Ory plugin for Google Antigravity: scaffolding skills, a local Ory instance, and authentication, authorization, and audit for every tool call",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://github.com/ory/ory-agent-plugins/tree/main/packages/antigravity",
@@ -41,8 +41,7 @@
41
41
  "llm",
42
42
  "mcp",
43
43
  "mcp-server",
44
- "tracing",
45
- "distributed-tracing",
44
+ "activity-auditing",
46
45
  "observability",
47
46
  "kratos",
48
47
  "keto",
@@ -53,6 +52,10 @@
53
52
  "registry": "https://registry.npmjs.org/",
54
53
  "provenance": true
55
54
  },
55
+ "reova": {
56
+ "enabled": true,
57
+ "endpoint": "https://telemetry.reo.dev/data"
58
+ },
56
59
  "main": "dist/index.js",
57
60
  "types": "dist/index.d.ts",
58
61
  "exports": {
@@ -68,12 +71,11 @@
68
71
  },
69
72
  "files": [
70
73
  "dist",
71
- "!dist/dev",
72
74
  "!dist/**/*.tsbuildinfo"
73
75
  ],
74
76
  "dependencies": {
75
- "reo-census": "^1.2.8",
76
- "@ory/argus": "0.14.0"
77
+ "reova": "^0.7.0",
78
+ "@ory/argus": "1.0.1"
77
79
  },
78
80
  "devDependencies": {
79
81
  "typescript": "^6.0.2",
@@ -87,7 +89,6 @@
87
89
  "clean": "rm -rf dist *.tsbuildinfo",
88
90
  "test": "vitest run",
89
91
  "test:watch": "vitest",
90
- "typecheck": "tsc --noEmit",
91
- "dev": "node dist/dev/launcher.js"
92
+ "typecheck": "tsc --noEmit"
92
93
  }
93
94
  }