@ory/antigravity 0.10.0 → 0.11.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 +2 -2
- package/dist/cli/assets.d.ts +15 -1
- package/dist/cli/assets.js +102 -9
- package/dist/emit.d.ts +17 -0
- package/dist/emit.js +30 -0
- package/dist/hook.js +15 -4
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -48,7 +48,7 @@ npx -y -p @ory/antigravity ory-antigravity status
|
|
|
48
48
|
npx -y -p @ory/antigravity ory-antigravity uninstall
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
If the `agy` binary isn't on your `PATH`, `npx -y -p @ory/antigravity ory-antigravity-setup` writes the plugin bundle directly into your project's `.agents/` directory (`plugin.json`, `hooks.json`, `mcp_config.json`, `skills/`, `commands/`).
|
|
51
|
+
If the `agy` binary isn't on your `PATH`, `npx -y -p @ory/antigravity ory-antigravity-setup` writes the plugin bundle directly into your project's `.agents/` directory (`plugin.json`, `hooks.json`, `mcp_config.json`, `skills/`, `commands/`). Because `.agents/` is shared with your own configuration, the setup merges rather than overwrites: it only sets or replaces the Ory-owned entries in `hooks.json` and `mcp_config.json`, leaving your hook rules and MCP servers intact, and it never touches a `plugin.json` that isn't Ory's own. Uninstall is the mirror image — it removes only the Ory-owned entries and deletes a file only once nothing else is left in it.
|
|
52
52
|
|
|
53
53
|
</details>
|
|
54
54
|
|
|
@@ -223,7 +223,7 @@ npx -y -p @ory/antigravity ory-antigravity configure [--project-url <url>
|
|
|
223
223
|
npx -y -p @ory/antigravity ory-antigravity agent <status|unregister>
|
|
224
224
|
npx -y -p @ory/antigravity ory-antigravity permissions <status|bootstrap|observe|enforce>
|
|
225
225
|
npx -y -p @ory/antigravity ory-antigravity local <up|down|status|seed|logs|env|configure|reset>
|
|
226
|
-
npx -y -p @ory/antigravity ory-antigravity
|
|
226
|
+
npx -y -p @ory/antigravity ory-antigravity-setup [--project-dir <path>] # .agents fallback
|
|
227
227
|
npx -y -p @ory/antigravity ory-antigravity status
|
|
228
228
|
```
|
|
229
229
|
|
package/dist/cli/assets.d.ts
CHANGED
|
@@ -23,7 +23,21 @@ export declare const PLUGIN_NAME = "ory";
|
|
|
23
23
|
* Write the full Ory plugin bundle under `root`. Used both for the
|
|
24
24
|
* bundle handed to `agy plugin install` and for the manual `.agents`
|
|
25
25
|
* fallback.
|
|
26
|
+
*
|
|
27
|
+
* The manual fallback targets the workspace's shared `.agents/` directory,
|
|
28
|
+
* where users keep their own hook rules and MCP servers — so the JSON
|
|
29
|
+
* files are MERGED, never whole-file overwritten: only the Ory-owned key
|
|
30
|
+
* is set/replaced, everything else is preserved. (In the package-owned
|
|
31
|
+
* bundle dir the merge is a no-op over a fresh tree, so the same code
|
|
32
|
+
* path is used everywhere.)
|
|
26
33
|
*/
|
|
27
34
|
export declare function installAntigravityOryAssets(root: string): void;
|
|
28
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* Remove every Ory skill, command, and bundle entry written under `root`.
|
|
37
|
+
*
|
|
38
|
+
* Mirror of the merge-aware install: only Ory-owned keys are removed from
|
|
39
|
+
* `hooks.json` / `mcp_config.json`, and each file is deleted only when it
|
|
40
|
+
* becomes empty. `plugin.json` is deleted only when it is Ory's own
|
|
41
|
+
* manifest. Unparseable files are left untouched.
|
|
42
|
+
*/
|
|
29
43
|
export declare function uninstallAntigravityOryAssets(root: string): void;
|
package/dist/cli/assets.js
CHANGED
|
@@ -126,16 +126,47 @@ function renderMcpConfig(version) {
|
|
|
126
126
|
},
|
|
127
127
|
};
|
|
128
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* Read a JSON file as a plain object. Returns `undefined` when the file
|
|
131
|
+
* is missing, unparseable, or not a JSON object — callers treat all three
|
|
132
|
+
* as "nothing mergeable here".
|
|
133
|
+
*/
|
|
134
|
+
function readJsonObject(file) {
|
|
135
|
+
try {
|
|
136
|
+
const parsed = JSON.parse(fs.readFileSync(file, "utf-8"));
|
|
137
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
138
|
+
return parsed;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
/* missing or unparseable */
|
|
143
|
+
}
|
|
144
|
+
return undefined;
|
|
145
|
+
}
|
|
146
|
+
function writeJson(file, obj) {
|
|
147
|
+
fs.writeFileSync(file, JSON.stringify(obj, null, 2) + "\n");
|
|
148
|
+
}
|
|
149
|
+
/** True when a parsed plugin.json manifest is Ory's own. */
|
|
150
|
+
function isOryManifest(manifest) {
|
|
151
|
+
return manifest?.name === exports.PLUGIN_NAME;
|
|
152
|
+
}
|
|
129
153
|
/**
|
|
130
154
|
* Write the full Ory plugin bundle under `root`. Used both for the
|
|
131
155
|
* bundle handed to `agy plugin install` and for the manual `.agents`
|
|
132
156
|
* fallback.
|
|
157
|
+
*
|
|
158
|
+
* The manual fallback targets the workspace's shared `.agents/` directory,
|
|
159
|
+
* where users keep their own hook rules and MCP servers — so the JSON
|
|
160
|
+
* files are MERGED, never whole-file overwritten: only the Ory-owned key
|
|
161
|
+
* is set/replaced, everything else is preserved. (In the package-owned
|
|
162
|
+
* bundle dir the merge is a no-op over a fresh tree, so the same code
|
|
163
|
+
* path is used everywhere.)
|
|
133
164
|
*/
|
|
134
165
|
function installAntigravityOryAssets(root) {
|
|
135
166
|
const version = readPackageVersion();
|
|
136
167
|
fs.mkdirSync(root, { recursive: true });
|
|
137
168
|
const skillsDir = path.join(root, "skills");
|
|
138
|
-
|
|
169
|
+
(0, argus_1.removeSkillDirs)(skillsDir, argus_1.ORY_SKILL_NAMES);
|
|
139
170
|
(0, argus_1.writeSkillTree)(skillsDir, (0, argus_1.renderOrySkills)("antigravity", RENDER_OPTS));
|
|
140
171
|
const cmdDir = path.join(root, "commands", CMD_SUBDIR);
|
|
141
172
|
fs.rmSync(cmdDir, { recursive: true, force: true });
|
|
@@ -143,9 +174,31 @@ function installAntigravityOryAssets(root) {
|
|
|
143
174
|
for (const cmd of (0, argus_1.renderOryCommands)("antigravity", RENDER_OPTS)) {
|
|
144
175
|
fs.writeFileSync(path.join(cmdDir, `${cmd.slug}.toml`), (0, argus_1.commandToToml)(cmd));
|
|
145
176
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
177
|
+
// hooks.json is keyed by rule id — replace only the "ory" rule and keep
|
|
178
|
+
// any rules the user has defined alongside it.
|
|
179
|
+
const hooksPath = path.join(root, "hooks.json");
|
|
180
|
+
const hooks = readJsonObject(hooksPath) ?? {};
|
|
181
|
+
hooks[exports.PLUGIN_NAME] = renderHooks(version)[exports.PLUGIN_NAME];
|
|
182
|
+
writeJson(hooksPath, hooks);
|
|
183
|
+
// 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);
|
|
194
|
+
// plugin.json — only write over a manifest that is Ory's own (or absent).
|
|
195
|
+
const manifestPath = path.join(root, "plugin.json");
|
|
196
|
+
if (!fs.existsSync(manifestPath) || isOryManifest(readJsonObject(manifestPath))) {
|
|
197
|
+
writeJson(manifestPath, renderManifest(version));
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
console.warn(`Warning: ${manifestPath} exists and is not the Ory plugin manifest; leaving it untouched.`);
|
|
201
|
+
}
|
|
149
202
|
}
|
|
150
203
|
function safeRmEmpty(dir) {
|
|
151
204
|
try {
|
|
@@ -157,7 +210,14 @@ function safeRmEmpty(dir) {
|
|
|
157
210
|
/* leave the dir if removal fails */
|
|
158
211
|
}
|
|
159
212
|
}
|
|
160
|
-
/**
|
|
213
|
+
/**
|
|
214
|
+
* Remove every Ory skill, command, and bundle entry written under `root`.
|
|
215
|
+
*
|
|
216
|
+
* Mirror of the merge-aware install: only Ory-owned keys are removed from
|
|
217
|
+
* `hooks.json` / `mcp_config.json`, and each file is deleted only when it
|
|
218
|
+
* becomes empty. `plugin.json` is deleted only when it is Ory's own
|
|
219
|
+
* manifest. Unparseable files are left untouched.
|
|
220
|
+
*/
|
|
161
221
|
function uninstallAntigravityOryAssets(root) {
|
|
162
222
|
const skillsDir = path.join(root, "skills");
|
|
163
223
|
if (fs.existsSync(skillsDir)) {
|
|
@@ -174,9 +234,42 @@ function uninstallAntigravityOryAssets(root) {
|
|
|
174
234
|
safeRmEmpty(cmdDir);
|
|
175
235
|
safeRmEmpty(path.join(root, "commands"));
|
|
176
236
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
237
|
+
// hooks.json — drop only the Ory rule id.
|
|
238
|
+
const hooksPath = path.join(root, "hooks.json");
|
|
239
|
+
const hooks = readJsonObject(hooksPath);
|
|
240
|
+
if (hooks && exports.PLUGIN_NAME in hooks) {
|
|
241
|
+
delete hooks[exports.PLUGIN_NAME];
|
|
242
|
+
if (Object.keys(hooks).length === 0) {
|
|
243
|
+
fs.unlinkSync(hooksPath);
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
writeJson(hooksPath, hooks);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
// mcp_config.json — drop only the Ory server entry.
|
|
250
|
+
const mcpPath = path.join(root, "mcp_config.json");
|
|
251
|
+
const mcp = readJsonObject(mcpPath);
|
|
252
|
+
if (mcp) {
|
|
253
|
+
const servers = mcp.mcpServers;
|
|
254
|
+
if (servers &&
|
|
255
|
+
typeof servers === "object" &&
|
|
256
|
+
!Array.isArray(servers) &&
|
|
257
|
+
exports.PLUGIN_NAME in servers) {
|
|
258
|
+
delete servers[exports.PLUGIN_NAME];
|
|
259
|
+
if (Object.keys(servers).length === 0) {
|
|
260
|
+
delete mcp.mcpServers;
|
|
261
|
+
}
|
|
262
|
+
if (Object.keys(mcp).length === 0) {
|
|
263
|
+
fs.unlinkSync(mcpPath);
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
writeJson(mcpPath, mcp);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
// plugin.json — delete only when it is Ory's own manifest.
|
|
271
|
+
const manifestPath = path.join(root, "plugin.json");
|
|
272
|
+
if (fs.existsSync(manifestPath) && isOryManifest(readJsonObject(manifestPath))) {
|
|
273
|
+
fs.unlinkSync(manifestPath);
|
|
181
274
|
}
|
|
182
275
|
}
|
package/dist/emit.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Write-once stdout emitter for the Antigravity hook.
|
|
3
|
+
*
|
|
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
|
|
8
|
+
* carries two concatenated JSON documents and the harness blocks the
|
|
9
|
+
* tool. This factory guarantees exactly one write ever reaches stdout.
|
|
10
|
+
*/
|
|
11
|
+
export type EmitOnce<T> = (output: T) => boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Create an emitter that serializes `output` as JSON and writes it via
|
|
14
|
+
* `write` on the first call only. Subsequent calls are no-ops that
|
|
15
|
+
* return `false`.
|
|
16
|
+
*/
|
|
17
|
+
export declare function createEmitOnce<T>(write?: (chunk: string) => void): EmitOnce<T>;
|
package/dist/emit.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Write-once stdout emitter for the Antigravity hook.
|
|
4
|
+
*
|
|
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
|
|
9
|
+
* carries two concatenated JSON documents and the harness blocks the
|
|
10
|
+
* tool. This factory guarantees exactly one write ever reaches stdout.
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.createEmitOnce = createEmitOnce;
|
|
14
|
+
/**
|
|
15
|
+
* Create an emitter that serializes `output` as JSON and writes it via
|
|
16
|
+
* `write` on the first call only. Subsequent calls are no-ops that
|
|
17
|
+
* return `false`.
|
|
18
|
+
*/
|
|
19
|
+
function createEmitOnce(write = (chunk) => {
|
|
20
|
+
process.stdout.write(chunk);
|
|
21
|
+
}) {
|
|
22
|
+
let wrote = false;
|
|
23
|
+
return (output) => {
|
|
24
|
+
if (wrote)
|
|
25
|
+
return false;
|
|
26
|
+
wrote = true;
|
|
27
|
+
write(JSON.stringify(output));
|
|
28
|
+
return true;
|
|
29
|
+
};
|
|
30
|
+
}
|
package/dist/hook.js
CHANGED
|
@@ -18,9 +18,18 @@
|
|
|
18
18
|
*/
|
|
19
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
20
|
const argus_1 = require("@ory/argus");
|
|
21
|
+
const emit_js_1 = require("./emit.js");
|
|
21
22
|
const handlers_js_1 = require("./handlers.js");
|
|
22
23
|
/** The fail-open response: explicitly allow, so a crash never blocks. */
|
|
23
24
|
const FAIL_OPEN = { allow_tool: true };
|
|
25
|
+
/**
|
|
26
|
+
* Single write-once gate shared by every exit path (normal, parse
|
|
27
|
+
* failure, and the top-level catch). Because Antigravity fails closed on
|
|
28
|
+
* 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.
|
|
31
|
+
*/
|
|
32
|
+
const emit = (0, emit_js_1.createEmitOnce)();
|
|
24
33
|
/**
|
|
25
34
|
* Read all of stdin as a string. Uses event listeners (not `for await`)
|
|
26
35
|
* with an idle timer so we don't hang if the parent never sends EOF.
|
|
@@ -60,7 +69,7 @@ async function main() {
|
|
|
60
69
|
catch {
|
|
61
70
|
client.logger.error("hook.stdin.parse_failed", { raw: raw.slice(0, 200) });
|
|
62
71
|
// Can't tell the event; allow to avoid wedging a PreToolUse call.
|
|
63
|
-
|
|
72
|
+
emit(FAIL_OPEN);
|
|
64
73
|
await client.tracer.shutdown();
|
|
65
74
|
process.exit(0);
|
|
66
75
|
}
|
|
@@ -75,13 +84,15 @@ async function main() {
|
|
|
75
84
|
});
|
|
76
85
|
output = FAIL_OPEN;
|
|
77
86
|
}
|
|
78
|
-
|
|
87
|
+
emit(output);
|
|
79
88
|
await client.tracer.shutdown();
|
|
80
89
|
process.exit(0);
|
|
81
90
|
}
|
|
82
91
|
main().catch((err) => {
|
|
83
|
-
// Last-resort guard: allow rather than block, then exit cleanly.
|
|
92
|
+
// Last-resort guard: allow rather than block, then exit cleanly. The
|
|
93
|
+
// write-once emitter makes this a no-op when the decision was already
|
|
94
|
+
// written before the rejection (e.g. a failing tracer shutdown).
|
|
84
95
|
process.stderr.write(`[ory-agent] fatal: ${err}\n`);
|
|
85
|
-
|
|
96
|
+
emit(FAIL_OPEN);
|
|
86
97
|
process.exit(0);
|
|
87
98
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ory/antigravity",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.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",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"!dist/**/*.tsbuildinfo"
|
|
73
73
|
],
|
|
74
74
|
"dependencies": {
|
|
75
|
-
"@ory/argus": "0.
|
|
75
|
+
"@ory/argus": "0.11.1"
|
|
76
76
|
},
|
|
77
77
|
"devDependencies": {
|
|
78
78
|
"typescript": "^6.0.2",
|