@claudexor/harness-agy 3.5.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Anton Razzhigaev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,13 @@
1
+ # @claudexor/harness-agy
2
+
3
+ Adapter for Google's Antigravity CLI (`agy`): translates
4
+ `agy -p --output-format stream-json` into typed `HarnessEvent`s.
5
+
6
+ Accounts are NAMED credential profiles only (there is no engine-default agy
7
+ credential): each profile is a Claudexor-owned HOME whose vendor config root
8
+ (`$HOME/.gemini/...`) holds a file-based OAuth token. See
9
+ `src/profile.ts` for the mechanism and its constraints (never create a
10
+ keychain inside a profile HOME).
11
+
12
+ Fixtures under `fixtures/` pin the recorded 1.1.13 stream shapes; see
13
+ `fixtures/manifest.yaml` for provenance and stream-semantics expectations.
@@ -0,0 +1,12 @@
1
+ import type { HarnessAdapter } from "@claudexor/core";
2
+ export { AGY_BIN, agyProfileRunEnv, agyTokenFilePresent, canonicalAgyProfileHome, } from "./profile.js";
3
+ /**
4
+ * The vendor's two quota GROUPS map onto disjoint halves of the same
5
+ * inventory: "Gemini Models" and "Claude and GPT models" (PLAN §1.2 F8). The
6
+ * split is DERIVED from the one model list so a slug the vendor adds cannot
7
+ * land in neither half and silently escape window scoping (INV-138).
8
+ */
9
+ export declare const AGY_GEMINI_MODELS: ("claude-opus-4-6-thinking" | "claude-sonnet-4-6" | "gemini-3.1-pro-high" | "gemini-3.1-pro-low" | "gemini-3.5-flash-high" | "gemini-3.5-flash-low" | "gemini-3.5-flash-medium" | "gemini-3.6-flash-high" | "gemini-3.6-flash-low" | "gemini-3.6-flash-medium" | "gemini-3.7-flash-high" | "gemini-3.7-flash-low" | "gemini-3.7-flash-medium" | "gpt-oss-120b-medium")[];
10
+ export declare const AGY_THIRD_PARTY_MODELS: ("claude-opus-4-6-thinking" | "claude-sonnet-4-6" | "gemini-3.1-pro-high" | "gemini-3.1-pro-low" | "gemini-3.5-flash-high" | "gemini-3.5-flash-low" | "gemini-3.5-flash-medium" | "gemini-3.6-flash-high" | "gemini-3.6-flash-low" | "gemini-3.6-flash-medium" | "gemini-3.7-flash-high" | "gemini-3.7-flash-low" | "gemini-3.7-flash-medium" | "gpt-oss-120b-medium")[];
11
+ export declare function createAgyAdapter(): HarnessAdapter;
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAc,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAclE,OAAO,EACL,OAAO,EACP,gBAAgB,EAChB,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,cAAc,CAAC;AA2DtB;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,0WAA0D,CAAC;AACzF,eAAO,MAAM,sBAAsB,0WAA2D,CAAC;AAe/F,wBAAgB,gBAAgB,IAAI,cAAc,CA4LjD"}
package/dist/index.js ADDED
@@ -0,0 +1,316 @@
1
+ import { ConformanceReport as ConformanceReportSchema, HarnessManifest as HarnessManifestSchema, } from "@claudexor/schema";
2
+ import { HarnessUnavailableError, promptWithInstructions, runCapture, runCliHarness, } from "@claudexor/core";
3
+ import { CLAUDEXOR_VERSION, nowIso, redactSecrets } from "@claudexor/util";
4
+ import { parseAgyEvent } from "./parse.js";
5
+ import { AGY_BIN, probeAgyCredentialProfile, resolveAgyProfileRoute } from "./profile.js";
6
+ import { AGY_VENDOR_CLI_VERSION } from "./vendor-cli-version.js";
7
+ // The package publishes only what other packages consume. The profile probe,
8
+ // the route resolver and the stream parser are reached through the adapter
9
+ // this file returns, so re-exporting them would be a dead public surface.
10
+ export { AGY_BIN, agyProfileRunEnv, agyTokenFilePresent, canonicalAgyProfileHome, } from "./profile.js";
11
+ /**
12
+ * Access mapping, each leg LIVE-PROVEN on agy 1.1.13 (PLAN §1.2 F11, §1.2d):
13
+ * plan mode answered read-only prompts and withheld a requested write;
14
+ * accept-edits wrote into the workspace; --dangerously-skip-permissions wrote
15
+ * and ran commands. Owner decision Л-7 admits full access explicitly.
16
+ */
17
+ function accessArgs(access) {
18
+ switch (access) {
19
+ case "readonly":
20
+ return ["--mode", "plan"];
21
+ case "workspace_write":
22
+ return ["--mode", "accept-edits"];
23
+ case "full":
24
+ case "external_sandbox_full":
25
+ return ["--dangerously-skip-permissions"];
26
+ case "inherit_native":
27
+ return [];
28
+ }
29
+ }
30
+ async function detectVersion() {
31
+ try {
32
+ const r = await runCapture(AGY_BIN(), ["--version"], { timeoutMs: 10_000 });
33
+ return r.stdout.trim() || `${AGY_BIN()} (version unknown)`;
34
+ }
35
+ catch {
36
+ return null;
37
+ }
38
+ }
39
+ /**
40
+ * Manifest model truth (INV-104): the vendor's own list, captured live from
41
+ * `agy models` on the pinned version (evidence: PLAN §1.2 F9 and the sprint
42
+ * evidence dir; the vendor emits TSV, not JSON, in 1.1.13). Slugs
43
+ * carry the reasoning effort (`-high`/`-medium`/`-low`) exactly like Cursor's
44
+ * inventory, so the effort ladder is deliberately empty and an effort hint is
45
+ * disclosed as ignored rather than mapped (Л-21). No live `models()`:
46
+ * `agy models --output-format json` is rejected by 1.1.13 (upstream #777) and
47
+ * the unauthenticated plain listing fails — an empty live list would refuse
48
+ * every explicit model (PLAN §2.6).
49
+ */
50
+ const AGY_KNOWN_MODELS = [
51
+ "gemini-3.7-flash-high",
52
+ "gemini-3.7-flash-medium",
53
+ "gemini-3.7-flash-low",
54
+ "gemini-3.6-flash-high",
55
+ "gemini-3.6-flash-medium",
56
+ "gemini-3.6-flash-low",
57
+ "gemini-3.5-flash-high",
58
+ "gemini-3.5-flash-medium",
59
+ "gemini-3.5-flash-low",
60
+ "gemini-3.1-pro-high",
61
+ "gemini-3.1-pro-low",
62
+ "claude-sonnet-4-6",
63
+ "claude-opus-4-6-thinking",
64
+ "gpt-oss-120b-medium",
65
+ ];
66
+ /**
67
+ * The vendor's two quota GROUPS map onto disjoint halves of the same
68
+ * inventory: "Gemini Models" and "Claude and GPT models" (PLAN §1.2 F8). The
69
+ * split is DERIVED from the one model list so a slug the vendor adds cannot
70
+ * land in neither half and silently escape window scoping (INV-138).
71
+ */
72
+ export const AGY_GEMINI_MODELS = AGY_KNOWN_MODELS.filter((m) => m.startsWith("gemini-"));
73
+ export const AGY_THIRD_PARTY_MODELS = AGY_KNOWN_MODELS.filter((m) => !m.startsWith("gemini-"));
74
+ const AGY_ENABLED_INTENTS = [
75
+ "explain",
76
+ "plan",
77
+ "spec",
78
+ "implement",
79
+ "repair",
80
+ "create_from_scratch",
81
+ "review",
82
+ "verify",
83
+ "synthesize",
84
+ "audit",
85
+ ];
86
+ export function createAgyAdapter() {
87
+ return {
88
+ id: "agy",
89
+ async discover() {
90
+ const version = await detectVersion();
91
+ if (version === null) {
92
+ throw new HarnessUnavailableError("agy not found on PATH (install Antigravity CLI or set CLAUDEXOR_AGY_BIN)");
93
+ }
94
+ return HarnessManifestSchema.parse({
95
+ id: "agy",
96
+ display_name: "Antigravity",
97
+ kind: "local_cli",
98
+ version,
99
+ adapter_version: CLAUDEXOR_VERSION,
100
+ provider_family: "google",
101
+ capabilities: {
102
+ plan: true,
103
+ implement: true,
104
+ create_from_scratch: true,
105
+ review: true,
106
+ verify: true,
107
+ synthesize: true,
108
+ read_files: true,
109
+ // No MCP flag path exists (config is file-only), so no browser
110
+ // injector is wired — honest false (INV-066).
111
+ browser_tool: false,
112
+ // Built-in web tools with no enforceable off switch (cursor parity).
113
+ web_policy: "uncontrolled",
114
+ // D-16 default recommendation (В-10): the fenced-block tier costs
115
+ // zero extra vendor turns; the schema-constrained tier is proven to
116
+ // force a SECOND turn per run (PLAN §1.2e) and stays off until the
117
+ // owner opts in.
118
+ work_report_transport: "validated",
119
+ // Effort rides the model slug (`-high`), not a flag (Л-21).
120
+ effort_levels: [],
121
+ known_models: [...AGY_KNOWN_MODELS],
122
+ known_models_verified_against: AGY_VENDOR_CLI_VERSION,
123
+ },
124
+ capability_profile: {
125
+ auth: {
126
+ supported_sources: ["native_session"],
127
+ preferred_source: "native_session",
128
+ credential_transports: [
129
+ // The profile HOME relocates the vendor's whole config root and
130
+ // its file-based OAuth token (Л-15/Л-16): config_file, HOME.
131
+ { source: "native_session", kind: "config_file", relocatable_by: ["HOME"] },
132
+ ],
133
+ },
134
+ // readonly = vendor plan mode: write tools are withheld
135
+ // (permission-denied), reads and answers flow (live-proven F11).
136
+ access_control: { readonly_mechanism: "permission_deny" },
137
+ isolation: { supported_containment: ["env_or_file_injection"] },
138
+ // No proven attachment path yet — honest empty set (INV-064/065).
139
+ attachment_inputs: [],
140
+ },
141
+ auth_modes: ["local_session"],
142
+ access_profiles_supported: [
143
+ "readonly",
144
+ "workspace_write",
145
+ "full",
146
+ "external_sandbox_full",
147
+ "inherit_native",
148
+ ],
149
+ });
150
+ },
151
+ async doctor(spec) {
152
+ const version = await detectVersion();
153
+ const installedSemver = version === null ? null : (/\d+\.\d+\.\d+/.exec(version)?.[0] ?? null);
154
+ const versionDrift = version !== null && installedSemver !== AGY_VENDOR_CLI_VERSION
155
+ ? `installed agy "${version}" differs from the verified ${AGY_VENDOR_CLI_VERSION}; the file-token profile mechanism is re-proven per version (R-2')`
156
+ : null;
157
+ // Л-24: the account isolation mechanism — one Claudexor-owned HOME per
158
+ // identity, with the vendor keeping its token in a file inside it — was
159
+ // proven on macOS across three live Google accounts. The same HOME lever
160
+ // exists on every platform the vendor supports, but nobody has run it
161
+ // there, so the platform says so instead of implying a proof it lacks.
162
+ const platformProof = process.platform === "darwin"
163
+ ? null
164
+ : `named-account isolation is unverified on ${process.platform}: the mechanism is the same profile HOME proven on macOS, but no live multi-account run has been recorded here`;
165
+ const requestedSource = spec.authSource;
166
+ if (requestedSource !== undefined && requestedSource !== "native_session") {
167
+ return ConformanceReportSchema.parse({
168
+ harness_id: "agy",
169
+ status: "unavailable",
170
+ checks: [
171
+ version === null
172
+ ? { id: "installed", status: "fail", detail: "agy not found" }
173
+ : { id: "installed", status: "pass", detail: redactSecrets(version) },
174
+ {
175
+ id: "auth_source",
176
+ status: "fail",
177
+ detail: `agy does not support ${requestedSource}`,
178
+ },
179
+ ],
180
+ enabled_intents: [],
181
+ disabled_intents: AGY_ENABLED_INTENTS,
182
+ reasons: [`agy does not support auth source ${requestedSource}`],
183
+ auth_sources: [
184
+ {
185
+ source: requestedSource,
186
+ availability: "unavailable",
187
+ verification: "not_run",
188
+ detail: `agy does not support ${requestedSource}`,
189
+ },
190
+ ],
191
+ });
192
+ }
193
+ if (version === null) {
194
+ return ConformanceReportSchema.parse({
195
+ harness_id: "agy",
196
+ status: "unavailable",
197
+ checks: [{ id: "installed", status: "fail", detail: "agy not found" }],
198
+ enabled_intents: [],
199
+ disabled_intents: AGY_ENABLED_INTENTS,
200
+ reasons: ["agy not found (install Antigravity CLI or set CLAUDEXOR_AGY_BIN)"],
201
+ auth_sources: [
202
+ {
203
+ source: "native_session",
204
+ availability: "unknown",
205
+ verification: "not_run",
206
+ detail: "agy binary not installed",
207
+ },
208
+ ],
209
+ });
210
+ }
211
+ // Owner decision Л-4: agy has NO engine-default credential store — every
212
+ // account is a named profile. The harness-level doctor therefore reports
213
+ // the default subject honestly unavailable with the remedy; PINNED
214
+ // routing is admitted by the per-profile probe (INV-135 round-15 #1),
215
+ // exactly like a logged-out cursor default with valid named profiles.
216
+ return ConformanceReportSchema.parse({
217
+ harness_id: "agy",
218
+ status: "unavailable",
219
+ checks: [
220
+ { id: "installed", status: "pass", detail: redactSecrets(version) },
221
+ {
222
+ id: "default_credential",
223
+ status: "fail",
224
+ detail: "agy has no engine-default credential by design; accounts are named profiles",
225
+ },
226
+ ...(versionDrift
227
+ ? [{ id: "version_pin", status: "fail", detail: versionDrift }]
228
+ : [{ id: "version_pin", status: "pass", detail: AGY_VENDOR_CLI_VERSION }]),
229
+ ...(platformProof
230
+ ? [{ id: "platform_isolation", status: "warn", detail: platformProof }]
231
+ : []),
232
+ ],
233
+ enabled_intents: [],
234
+ disabled_intents: AGY_ENABLED_INTENTS,
235
+ reasons: [
236
+ "agy routes only through named accounts: add one (`claudexor profiles add agy <id>` + `claudexor profiles login agy <id>`) and pin it (--profile)",
237
+ ...(versionDrift ? [versionDrift] : []),
238
+ ...(platformProof ? [platformProof] : []),
239
+ ],
240
+ auth_sources: [
241
+ {
242
+ source: "native_session",
243
+ availability: "unavailable",
244
+ verification: "not_run",
245
+ detail: "no default store by design (accounts are named profiles)",
246
+ },
247
+ ],
248
+ });
249
+ },
250
+ run(spec) {
251
+ return runAgy(spec);
252
+ },
253
+ review(spec) {
254
+ return runAgy(spec);
255
+ },
256
+ // INV-135: pinned routing is admitted by THIS probe (there is no default
257
+ // store for the harness doctor to credit).
258
+ async probeCredentialProfile(profile, abortSignal) {
259
+ // The signal must reach the live probe: dropping it left an aborted
260
+ // doctor sweep waiting out the probe's own 30s timeout.
261
+ return probeAgyCredentialProfile(profile, undefined, abortSignal);
262
+ },
263
+ };
264
+ }
265
+ async function* runAgy(spec) {
266
+ const profile = spec.credential_profile;
267
+ // Л-4: no engine-default credential — an unpinned agy run has nothing to
268
+ // route. Typed stream refusal (error then completed), the one refusal
269
+ // mechanism every adapter's profile gate uses.
270
+ if (!profile) {
271
+ yield {
272
+ type: "error",
273
+ session_id: spec.session_id,
274
+ ts: nowIso(),
275
+ error: "agy has no engine-default credential; pin a named account (--profile, or `claudexor profiles add agy <id>`)",
276
+ };
277
+ yield { type: "completed", session_id: spec.session_id, ts: nowIso() };
278
+ return;
279
+ }
280
+ const route = resolveAgyProfileRoute(profile, spec.env);
281
+ if ("refusal" in route) {
282
+ yield { type: "error", session_id: spec.session_id, ts: nowIso(), error: route.refusal };
283
+ yield { type: "completed", session_id: spec.session_id, ts: nowIso() };
284
+ return;
285
+ }
286
+ const args = ["-p", promptWithInstructions(spec), "--output-format", "stream-json"];
287
+ // Л-18: without --add-dir agy resolves relative paths against its own app
288
+ // data dir instead of the workspace (live-proven §1.2d).
289
+ args.push("--add-dir", spec.cwd);
290
+ args.push(...accessArgs(spec.access));
291
+ if (spec.model_hint)
292
+ args.push("--model", spec.model_hint);
293
+ // INV-137: the vendor conversation id is the resumable native session.
294
+ if (spec.resume_session_id)
295
+ args.push("--conversation", spec.resume_session_id);
296
+ yield* runCliHarness({
297
+ bin: AGY_BIN(),
298
+ args,
299
+ spec,
300
+ env: route.env,
301
+ label: "agy",
302
+ redact: redactSecrets,
303
+ parseEvent: (obj, sessionId) => {
304
+ const out = parseAgyEvent(obj, sessionId);
305
+ if (out) {
306
+ for (const ev of out) {
307
+ ev.credential_route = "vendor_native";
308
+ ev.credential_source = "native_session";
309
+ ev.credential_profile_id = profile.profile_id;
310
+ }
311
+ }
312
+ return out;
313
+ },
314
+ });
315
+ }
316
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { HarnessEvent } from "@claudexor/schema";
2
+ type Json = any;
3
+ /**
4
+ * Map an Antigravity CLI (`agy -p --output-format stream-json`) ND-JSON event
5
+ * to normalized events. Field shapes are pinned by RECORDED fixtures captured
6
+ * on agy 1.1.13 (fixtures/manifest.yaml): `init` / `step_update` / `result`,
7
+ * with `step_update.step_type` an OPEN vocabulary
8
+ * (user_input | agent_response | tool | checkpoint | finish | unknown | …).
9
+ * Unknown step types are recognized no-ops (empty array, never a drop);
10
+ * unknown TOP-LEVEL events return `null` so the run loop counts them.
11
+ */
12
+ export declare function parseAgyEvent(obj: Json, sessionId: string): HarnessEvent[] | null;
13
+ export {};
14
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAqB,MAAM,mBAAmB,CAAC;AAGzE,KAAK,IAAI,GAAG,GAAG,CAAC;AAEhB;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,GAAG,YAAY,EAAE,GAAG,IAAI,CAqJjF"}
package/dist/parse.js ADDED
@@ -0,0 +1,240 @@
1
+ import { nowIso, redactSecrets } from "@claudexor/util";
2
+ /**
3
+ * Map an Antigravity CLI (`agy -p --output-format stream-json`) ND-JSON event
4
+ * to normalized events. Field shapes are pinned by RECORDED fixtures captured
5
+ * on agy 1.1.13 (fixtures/manifest.yaml): `init` / `step_update` / `result`,
6
+ * with `step_update.step_type` an OPEN vocabulary
7
+ * (user_input | agent_response | tool | checkpoint | finish | unknown | …).
8
+ * Unknown step types are recognized no-ops (empty array, never a drop);
9
+ * unknown TOP-LEVEL events return `null` so the run loop counts them.
10
+ */
11
+ export function parseAgyEvent(obj, sessionId) {
12
+ const ts = nowIso();
13
+ // A non-string `event` must not be COERCED: an object whose `toString` is
14
+ // not callable throws, and the run loop would report a mid-stream parse
15
+ // failure as "the harness failed to start" and drop the rest of the run.
16
+ const event = typeof obj?.event === "string" ? obj.event : "";
17
+ if (event === "init") {
18
+ const nativeId = stringOrUndef(obj.conversation_id);
19
+ const model = stringOrUndef(obj.init?.model);
20
+ return [
21
+ {
22
+ type: "started",
23
+ session_id: sessionId,
24
+ ts,
25
+ ...(model ? { observed_model: model } : {}),
26
+ // The vendor conversation id IS the resumable native session
27
+ // (`agy --conversation <id>`); surface it for INV-137 lane resume.
28
+ ...(nativeId ? { payload: { native_session_id: nativeId } } : {}),
29
+ },
30
+ ];
31
+ }
32
+ if (event === "step_update") {
33
+ const step = obj.step_update ?? {};
34
+ const stepType = typeof step.step_type === "string" ? step.step_type : "";
35
+ const events = [];
36
+ if (stepType === "tool") {
37
+ const info = step.tool_info ?? {};
38
+ const name = typeof info.name === "string" && info.name
39
+ ? info.name
40
+ : typeof step.tool_name === "string" && step.tool_name
41
+ ? step.tool_name
42
+ : "tool";
43
+ const target = boundedTarget(primaryToolTarget(info.parameters));
44
+ const tool = { name, kind: toolKindFor(name), target };
45
+ const state = typeof step.state === "string" ? step.state : "";
46
+ if (state === "ACTIVE") {
47
+ // ACTIVE/DONE arrive as a pair per call (fixture-pinned): ACTIVE is
48
+ // the call, DONE the result.
49
+ events.push({ type: "tool_call", session_id: sessionId, ts, text: name, tool });
50
+ }
51
+ else if (state === "DONE") {
52
+ const errorDetail = summarize(info.error);
53
+ if (errorDetail) {
54
+ events.push({
55
+ type: "tool_result",
56
+ session_id: sessionId,
57
+ ts,
58
+ text: `tool_result: error: ${errorDetail}`,
59
+ tool: { ...tool, status: "error", error_summary: errorDetail },
60
+ });
61
+ }
62
+ else {
63
+ const output = summarize(info.output);
64
+ events.push({
65
+ type: "tool_result",
66
+ session_id: sessionId,
67
+ ts,
68
+ text: "tool_result",
69
+ tool: { ...tool, status: "ok", content_summary: output || undefined },
70
+ });
71
+ if (isWriteTool(name)) {
72
+ events.push({
73
+ type: "file_change",
74
+ session_id: sessionId,
75
+ ts,
76
+ tool: { name, kind: "file" },
77
+ payload: { path: boundedTarget(primaryToolTarget(info.parameters)), tool: name },
78
+ });
79
+ }
80
+ }
81
+ }
82
+ // Any OTHER state (PENDING/CANCELLED/ERROR/absent, or a future value) is
83
+ // a recognized lifecycle no-op: claiming success for it would fabricate
84
+ // a completed tool call — and, for a write-named tool, a file change
85
+ // that never happened (Ф0 review #1).
86
+ }
87
+ else if (typeof step.text_delta === "string" && step.text_delta) {
88
+ // agent_response chunks: completed narration segments (not display
89
+ // deltas — no payload.delta). The typed final comes from `result`.
90
+ events.push({ type: "message", session_id: sessionId, ts, text: step.text_delta });
91
+ }
92
+ // user_input / checkpoint / finish / unknown / future types: recognized
93
+ // lifecycle no-ops. Step usage is deliberately NOT emitted: the recorded
94
+ // fixtures prove the per-step usages sum EXACTLY to the terminal
95
+ // aggregate, so emitting both counted every token twice (sol review).
96
+ // The one authoritative usage event rides `result`.
97
+ return events;
98
+ }
99
+ if (event === "result") {
100
+ const r = obj.result ?? {};
101
+ const status = typeof r.status === "string" ? r.status : "";
102
+ const events = [];
103
+ const usage = stepUsage(r.usage);
104
+ if (status === "SUCCESS") {
105
+ // Л-20: with a schema envelope the parsed object rides
106
+ // `structured_output` while `response` concatenates prose AND the JSON;
107
+ // serialize the parsed object as the typed final (codex model) instead
108
+ // of parsing mixed text. Without a schema the final is `response`.
109
+ // Only an OBJECT envelope is a structured final: `false`/`0`/`""` are
110
+ // not envelopes and must fall through to the prose response (review #7).
111
+ const structured = r.structured_output !== null && typeof r.structured_output === "object"
112
+ ? r.structured_output
113
+ : null;
114
+ const finalText = structured !== null
115
+ ? JSON.stringify(structured)
116
+ : typeof r.response === "string"
117
+ ? r.response
118
+ : "";
119
+ if (finalText.trim()) {
120
+ events.push({
121
+ type: "message",
122
+ session_id: sessionId,
123
+ ts,
124
+ text: finalText,
125
+ final: true,
126
+ payload: {
127
+ final_source: structured !== null ? "structured_output" : "result",
128
+ },
129
+ });
130
+ }
131
+ else {
132
+ // Vendor soft-deny class (upstream #794): SUCCESS with an empty
133
+ // response means a permission-denied turn that did nothing. Honest
134
+ // typed error, never a silent empty success.
135
+ events.push({
136
+ type: "error",
137
+ session_id: sessionId,
138
+ ts,
139
+ error: "agy reported SUCCESS with an empty response (no output produced; commonly a vendor soft-deny of a required tool permission)",
140
+ });
141
+ }
142
+ }
143
+ else {
144
+ events.push({
145
+ type: "error",
146
+ session_id: sessionId,
147
+ ts,
148
+ error: summarize(r.error) || `agy terminal status ${status || "unknown"}`,
149
+ });
150
+ }
151
+ if (usage)
152
+ events.push({ type: "usage", session_id: sessionId, ts, usage });
153
+ return events;
154
+ }
155
+ return null;
156
+ }
157
+ /** Tools that MUTATE the workspace. The regex catches the vendor's naming
158
+ * convention; the allowlist covers proven writers whose names do not match
159
+ * (`generate_image` writes an image file — Ф0 review #5). `sed_file` is
160
+ * deliberately absent: whether it mutates on 1.1.13 is unverified, and
161
+ * claiming a file change we cannot prove is the same defect class as #1. */
162
+ const WRITE_TOOL_NAMES = new Set(["generate_image"]);
163
+ const WRITE_TOOLS_RE = /write|edit|replace|apply|patch/i;
164
+ function isWriteTool(name) {
165
+ return WRITE_TOOL_NAMES.has(name) || WRITE_TOOLS_RE.test(name);
166
+ }
167
+ function toolKindFor(name) {
168
+ const n = name.toLowerCase();
169
+ if (n.includes("command") || n.includes("shell") || n.includes("bash"))
170
+ return "command";
171
+ if (n.includes("search") || n.includes("grep") || n.includes("glob") || n.includes("list_dir"))
172
+ return "search";
173
+ if (n.includes("browser") || n.includes("url") || n.includes("web"))
174
+ return "web";
175
+ if (isWriteTool(n) || n.includes("read") || n.includes("file") || n.includes("view"))
176
+ return "file";
177
+ if (n.includes("mcp"))
178
+ return "mcp";
179
+ return "other";
180
+ }
181
+ /** The one human-meaningful target among agy's PascalCase tool parameters. */
182
+ function primaryToolTarget(parameters) {
183
+ if (!parameters || typeof parameters !== "object")
184
+ return undefined;
185
+ const p = parameters;
186
+ for (const key of [
187
+ "TargetFile",
188
+ "AbsolutePath",
189
+ "DirectoryPath",
190
+ "CommandLine",
191
+ "Query",
192
+ "Url",
193
+ ]) {
194
+ const v = p[key];
195
+ if (typeof v === "string" && v)
196
+ return v;
197
+ }
198
+ return undefined;
199
+ }
200
+ /**
201
+ * agy usage: {input_tokens, output_tokens, thinking_tokens, cache_read_tokens,
202
+ * total_tokens}. `thinking_tokens` has no schema home and is deliberately
203
+ * DROPPED (disclosed absence), never folded into output (PLAN R-9).
204
+ */
205
+ function stepUsage(raw) {
206
+ if (!raw || typeof raw !== "object")
207
+ return null;
208
+ const u = raw;
209
+ const usage = {};
210
+ if (typeof u.input_tokens === "number")
211
+ usage.input_tokens = u.input_tokens;
212
+ if (typeof u.output_tokens === "number")
213
+ usage.output_tokens = u.output_tokens;
214
+ if (typeof u.cache_read_tokens === "number")
215
+ usage.cached_input_tokens = u.cache_read_tokens;
216
+ return Object.keys(usage).length ? usage : null;
217
+ }
218
+ function summarize(value) {
219
+ if (typeof value === "string")
220
+ return value.trim() ? redactSecrets(value).trim().replace(/\s+/g, " ").slice(0, 1000) : "";
221
+ // A non-string detail (the vendor sometimes nests an object) must not be
222
+ // silently dropped into a generic message (Ф0 review #7).
223
+ if (value === null || value === undefined)
224
+ return "";
225
+ try {
226
+ return redactSecrets(JSON.stringify(value)).trim().slice(0, 1000);
227
+ }
228
+ catch {
229
+ return "";
230
+ }
231
+ }
232
+ function boundedTarget(value) {
233
+ if (typeof value !== "string" || !value.trim())
234
+ return undefined;
235
+ return redactSecrets(value).slice(0, 500);
236
+ }
237
+ function stringOrUndef(v) {
238
+ return typeof v === "string" && v ? v : undefined;
239
+ }
240
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ import type { CredentialProfile, CredentialProfileStatus } from "@claudexor/schema";
2
+ type EnvMap = Record<string, string | null | undefined>;
3
+ export declare const AGY_BIN: () => string;
4
+ /** Canonical, Claudexor-owned HOME for one named Antigravity identity. */
5
+ export declare function canonicalAgyProfileHome(locator: string): string;
6
+ /**
7
+ * The vendor's file-based OAuth token inside a profile HOME. agy lands on
8
+ * file storage because its keyring lookup FAILS in a scoped HOME (macOS: no
9
+ * login keychain in `$HOME/Library/Keychains` → `falling back to file`); the
10
+ * profile mechanism therefore REQUIRES that no keychain ever be created
11
+ * inside the profile HOME. Live-proven on three separate Google accounts
12
+ * (PLAN §1.2a-1.2c); re-proven per AGY_VENDOR_CLI_VERSION bump because the
13
+ * fallback is a vendor error path, not a documented mode (R-2').
14
+ */
15
+ export declare function agyTokenPath(profileHome: string): string;
16
+ /** The token must be a regular FILE: a directory at that path is a malformed
17
+ * profile, not a login, and must refuse rather than route (Ф0 review #11). */
18
+ export declare function agyTokenFilePresent(profileHome: string): boolean;
19
+ /**
20
+ * Exact strict-profile env: the profile HOME selects the vendor's whole
21
+ * config root (`$HOME/.gemini/...`) — agy has no config-dir env var, HOME is
22
+ * the single lever. `USERPROFILE` mirrors HOME for the win32 resolver, the
23
+ * auto-updater is pinned off so the closed vendor binary cannot replace
24
+ * itself mid-run, and the provider scrub drops every API-key route
25
+ * (`GEMINI_API_KEY` included) so a native subscription run can never silently
26
+ * turn metered (INV-061).
27
+ *
28
+ * Unlike Cursor — whose mutable state is separately relocatable via
29
+ * `CURSOR_CONFIG_DIR`, so a run keeps state in its LANE home and reads auth
30
+ * from the profile — agy has exactly one lever. Overriding HOME therefore
31
+ * moves the vendor's conversations/brain/cache into the profile HOME too, and
32
+ * the per-lane home is unused for agy runs. Deliberate, not an oversight: a
33
+ * lane-scoped `.gemini` would be a dead directory the vendor never reads.
34
+ * What holds today is per-lane RESUME: a lane replays its own vendor
35
+ * conversation by id (`--conversation`, INV-137). Nothing scopes those
36
+ * conversations to a lane yet — the vendor's project mechanism
37
+ * (`--new-project`/`--project`, Л-19) is not wired here — so one profile HOME
38
+ * accumulates every thread's vendor state, and conversations are NOT scoped per
39
+ * chat thread.
40
+ */
41
+ export declare function agyProfileRunEnv(profileHome: string, specEnv?: EnvMap): EnvMap;
42
+ export type AgyResolvedProfileRoute = {
43
+ home: string;
44
+ env: EnvMap;
45
+ } | {
46
+ refusal: string;
47
+ };
48
+ /**
49
+ * INV-135 strict profile routing: an agy profile is exactly its
50
+ * `config_dir_login` HOME with a present vendor token file, or a typed
51
+ * refusal. There is NO engine-default agy credential (owner decision Л-4),
52
+ * so no fallback ladder exists to fall into.
53
+ */
54
+ export declare function resolveAgyProfileRoute(profile: Pick<CredentialProfile, "profile_id" | "credential_kind" | "isolation_locator">, specEnv?: EnvMap): AgyResolvedProfileRoute;
55
+ export interface AgyProfileProbeDeps {
56
+ /** Injectable live probe (tests): print-mode `/model` under the profile env. */
57
+ runModelProbe: (env: EnvMap, abortSignal?: AbortSignal) => Promise<AgyModelProbe>;
58
+ }
59
+ export type AgyModelProbe = {
60
+ kind: "authenticated";
61
+ modelId: string | null;
62
+ } | {
63
+ kind: "unauthenticated";
64
+ detail: string;
65
+ } | {
66
+ kind: "probe_failed";
67
+ detail: string;
68
+ };
69
+ /**
70
+ * Quota-free liveness probe: `agy -p "/model" --output-format json` answers
71
+ * from the CLI without spending a turn (vendor 1.1.11+ print-mode
72
+ * slash-commands). SUCCESS proves the profile's token authenticates in the
73
+ * exact env its runs will spawn with (INV-067); an auth error is an honest
74
+ * logged-out/revoked verdict, and a spawn/parse failure stays `unknown`.
75
+ */
76
+ export declare function defaultAgyModelProbe(env: EnvMap, abortSignal?: AbortSignal): Promise<AgyModelProbe>;
77
+ /**
78
+ * Doctor projection for one agy profile (INV-135): the SAME route resolution
79
+ * the run uses, then the quota-free live probe. A valid profile must admit
80
+ * the route even though agy has no default store at all — the orchestrator
81
+ * consults THIS probe for pinned routing.
82
+ */
83
+ export declare function probeAgyCredentialProfile(profile: CredentialProfile, deps?: AgyProfileProbeDeps, abortSignal?: AbortSignal): Promise<CredentialProfileStatus>;
84
+ export {};
85
+ //# sourceMappingURL=profile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile.d.ts","sourceRoot":"","sources":["../src/profile.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAIpF,KAAK,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;AAExD,eAAO,MAAM,OAAO,cAA+C,CAAC;AAEpE,0EAA0E;AAC1E,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;8EAC8E;AAC9E,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAMhE;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,GAAE,MAAW,GAAG,MAAM,CASlF;AAED,MAAM,MAAM,uBAAuB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1F;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,IAAI,CAAC,iBAAiB,EAAE,YAAY,GAAG,iBAAiB,GAAG,mBAAmB,CAAC,EACxF,OAAO,GAAE,MAAW,GACnB,uBAAuB,CAezB;AAED,MAAM,WAAW,mBAAmB;IAClC,gFAAgF;IAChF,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;CACnF;AAED,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7C;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,GAAG,EAAE,MAAM,EACX,WAAW,CAAC,EAAE,WAAW,GACxB,OAAO,CAAC,aAAa,CAAC,CAwBxB;AAED;;;;;GAKG;AACH,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,iBAAiB,EAC1B,IAAI,GAAE,mBAA6D,EACnE,WAAW,CAAC,EAAE,WAAW,GACxB,OAAO,CAAC,uBAAuB,CAAC,CAgClC"}
@@ -0,0 +1,160 @@
1
+ import { statSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { canonicalIsolationLocator, providerScrubEnv, runCapture } from "@claudexor/core";
4
+ import { CredentialProfileStatus as CredentialProfileStatusSchema } from "@claudexor/schema";
5
+ import { nowIso, redactSecrets } from "@claudexor/util";
6
+ export const AGY_BIN = () => process.env.CLAUDEXOR_AGY_BIN || "agy";
7
+ /** Canonical, Claudexor-owned HOME for one named Antigravity identity. */
8
+ export function canonicalAgyProfileHome(locator) {
9
+ return canonicalIsolationLocator(locator, "credential profile Antigravity HOME");
10
+ }
11
+ /**
12
+ * The vendor's file-based OAuth token inside a profile HOME. agy lands on
13
+ * file storage because its keyring lookup FAILS in a scoped HOME (macOS: no
14
+ * login keychain in `$HOME/Library/Keychains` → `falling back to file`); the
15
+ * profile mechanism therefore REQUIRES that no keychain ever be created
16
+ * inside the profile HOME. Live-proven on three separate Google accounts
17
+ * (PLAN §1.2a-1.2c); re-proven per AGY_VENDOR_CLI_VERSION bump because the
18
+ * fallback is a vendor error path, not a documented mode (R-2').
19
+ */
20
+ export function agyTokenPath(profileHome) {
21
+ return join(profileHome, ".gemini", "antigravity-cli", "antigravity-oauth-token");
22
+ }
23
+ /** The token must be a regular FILE: a directory at that path is a malformed
24
+ * profile, not a login, and must refuse rather than route (Ф0 review #11). */
25
+ export function agyTokenFilePresent(profileHome) {
26
+ try {
27
+ return statSync(agyTokenPath(profileHome)).isFile();
28
+ }
29
+ catch {
30
+ return false;
31
+ }
32
+ }
33
+ /**
34
+ * Exact strict-profile env: the profile HOME selects the vendor's whole
35
+ * config root (`$HOME/.gemini/...`) — agy has no config-dir env var, HOME is
36
+ * the single lever. `USERPROFILE` mirrors HOME for the win32 resolver, the
37
+ * auto-updater is pinned off so the closed vendor binary cannot replace
38
+ * itself mid-run, and the provider scrub drops every API-key route
39
+ * (`GEMINI_API_KEY` included) so a native subscription run can never silently
40
+ * turn metered (INV-061).
41
+ *
42
+ * Unlike Cursor — whose mutable state is separately relocatable via
43
+ * `CURSOR_CONFIG_DIR`, so a run keeps state in its LANE home and reads auth
44
+ * from the profile — agy has exactly one lever. Overriding HOME therefore
45
+ * moves the vendor's conversations/brain/cache into the profile HOME too, and
46
+ * the per-lane home is unused for agy runs. Deliberate, not an oversight: a
47
+ * lane-scoped `.gemini` would be a dead directory the vendor never reads.
48
+ * What holds today is per-lane RESUME: a lane replays its own vendor
49
+ * conversation by id (`--conversation`, INV-137). Nothing scopes those
50
+ * conversations to a lane yet — the vendor's project mechanism
51
+ * (`--new-project`/`--project`, Л-19) is not wired here — so one profile HOME
52
+ * accumulates every thread's vendor state, and conversations are NOT scoped per
53
+ * chat thread.
54
+ */
55
+ export function agyProfileRunEnv(profileHome, specEnv = {}) {
56
+ const home = canonicalAgyProfileHome(profileHome);
57
+ return {
58
+ ...specEnv,
59
+ ...providerScrubEnv(),
60
+ HOME: home,
61
+ USERPROFILE: home,
62
+ AGY_CLI_DISABLE_AUTO_UPDATE: "true",
63
+ };
64
+ }
65
+ /**
66
+ * INV-135 strict profile routing: an agy profile is exactly its
67
+ * `config_dir_login` HOME with a present vendor token file, or a typed
68
+ * refusal. There is NO engine-default agy credential (owner decision Л-4),
69
+ * so no fallback ladder exists to fall into.
70
+ */
71
+ export function resolveAgyProfileRoute(profile, specEnv = {}) {
72
+ if (profile.credential_kind !== "config_dir_login")
73
+ return {
74
+ refusal: `credential profile "${profile.profile_id}": agy supports only the config_dir_login transport (a named profile HOME)`,
75
+ };
76
+ try {
77
+ const home = canonicalAgyProfileHome(profile.isolation_locator ?? "");
78
+ if (!agyTokenFilePresent(home))
79
+ return {
80
+ refusal: `credential profile "${profile.profile_id}" has no Antigravity login in its profile HOME (run \`claudexor profiles login agy ${profile.profile_id}\` first)`,
81
+ };
82
+ return { home, env: agyProfileRunEnv(home, specEnv) };
83
+ }
84
+ catch (err) {
85
+ return { refusal: err instanceof Error ? err.message : String(err) };
86
+ }
87
+ }
88
+ /**
89
+ * Quota-free liveness probe: `agy -p "/model" --output-format json` answers
90
+ * from the CLI without spending a turn (vendor 1.1.11+ print-mode
91
+ * slash-commands). SUCCESS proves the profile's token authenticates in the
92
+ * exact env its runs will spawn with (INV-067); an auth error is an honest
93
+ * logged-out/revoked verdict, and a spawn/parse failure stays `unknown`.
94
+ */
95
+ export async function defaultAgyModelProbe(env, abortSignal) {
96
+ try {
97
+ const r = await runCapture(AGY_BIN(), ["-p", "/model", "--output-format", "json"], {
98
+ timeoutMs: 30_000,
99
+ env,
100
+ abortSignal,
101
+ cancelSignal: "SIGTERM",
102
+ });
103
+ const parsed = JSON.parse(r.stdout.trim() || "{}");
104
+ if (parsed?.status === "SUCCESS")
105
+ return {
106
+ kind: "authenticated",
107
+ modelId: typeof parsed?.command?.data?.id === "string" ? parsed.command.data.id : null,
108
+ };
109
+ return {
110
+ kind: "unauthenticated",
111
+ detail: redactSecrets(String(parsed?.error ?? "authentication required")).slice(0, 300),
112
+ };
113
+ }
114
+ catch (err) {
115
+ return {
116
+ kind: "probe_failed",
117
+ detail: redactSecrets(err instanceof Error ? err.message : String(err)).slice(0, 300),
118
+ };
119
+ }
120
+ }
121
+ /**
122
+ * Doctor projection for one agy profile (INV-135): the SAME route resolution
123
+ * the run uses, then the quota-free live probe. A valid profile must admit
124
+ * the route even though agy has no default store at all — the orchestrator
125
+ * consults THIS probe for pinned routing.
126
+ */
127
+ export async function probeAgyCredentialProfile(profile, deps = { runModelProbe: defaultAgyModelProbe }, abortSignal) {
128
+ const base = { profile_id: profile.profile_id, harness_id: "agy" };
129
+ const route = resolveAgyProfileRoute(profile);
130
+ if ("refusal" in route)
131
+ return CredentialProfileStatusSchema.parse({
132
+ ...base,
133
+ availability: "unavailable",
134
+ verification: "not_run",
135
+ detail: route.refusal,
136
+ });
137
+ const probe = await deps.runModelProbe(route.env, abortSignal);
138
+ if (probe.kind === "authenticated")
139
+ return CredentialProfileStatusSchema.parse({
140
+ ...base,
141
+ availability: "available",
142
+ verification: "passed",
143
+ detail: `Antigravity login verified in the profile HOME${probe.modelId ? ` (model ${probe.modelId})` : ""}`,
144
+ last_verified_at: nowIso(),
145
+ });
146
+ if (probe.kind === "unauthenticated")
147
+ return CredentialProfileStatusSchema.parse({
148
+ ...base,
149
+ availability: "unavailable",
150
+ verification: "failed",
151
+ detail: `Antigravity token present but not accepted: ${probe.detail}`,
152
+ });
153
+ return CredentialProfileStatusSchema.parse({
154
+ ...base,
155
+ availability: "unknown",
156
+ verification: "not_run",
157
+ detail: probe.detail,
158
+ });
159
+ }
160
+ //# sourceMappingURL=profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile.js","sourceRoot":"","sources":["../src/profile.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { PinnedVendorCliVersion } from "@claudexor/util";
2
+ /**
3
+ * The Antigravity CLI (`agy`) version this adapter's recorded fixtures,
4
+ * manifest `known_models` list, and file-token-fallback proof were captured
5
+ * against. Unlike the claude/codex constants this is NOT an npm install pin —
6
+ * agy ships as a closed Google binary with no npm artifact (the installer
7
+ * uses the vendor's official script, cursor-style, `human_observed`). It IS
8
+ * the verification stamp: `known_models_verified_against` reads it, fixture
9
+ * provenance records it, and the doctor discloses drift when the installed
10
+ * binary self-updates past it. The profile file-token fallback (the whole
11
+ * multi-account mechanism) is re-proven per bump of this constant — it is a
12
+ * vendor ERROR path, not a documented mode (PLAN Л-15/R-2').
13
+ */
14
+ export declare const AGY_VENDOR_CLI_VERSION: PinnedVendorCliVersion;
15
+ //# sourceMappingURL=vendor-cli-version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vendor-cli-version.d.ts","sourceRoot":"","sources":["../src/vendor-cli-version.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAE9D;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,sBAAsB,EAAE,sBAAiC,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * The Antigravity CLI (`agy`) version this adapter's recorded fixtures,
3
+ * manifest `known_models` list, and file-token-fallback proof were captured
4
+ * against. Unlike the claude/codex constants this is NOT an npm install pin —
5
+ * agy ships as a closed Google binary with no npm artifact (the installer
6
+ * uses the vendor's official script, cursor-style, `human_observed`). It IS
7
+ * the verification stamp: `known_models_verified_against` reads it, fixture
8
+ * provenance records it, and the doctor discloses drift when the installed
9
+ * binary self-updates past it. The profile file-token fallback (the whole
10
+ * multi-account mechanism) is re-proven per bump of this constant — it is a
11
+ * vendor ERROR path, not a documented mode (PLAN Л-15/R-2').
12
+ */
13
+ export const AGY_VENDOR_CLI_VERSION = "1.1.13";
14
+ //# sourceMappingURL=vendor-cli-version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vendor-cli-version.js","sourceRoot":"","sources":["../src/vendor-cli-version.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAA2B,QAAQ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@claudexor/harness-agy",
3
+ "version": "3.5.0",
4
+ "license": "MIT",
5
+ "description": "Google Antigravity CLI adapter (agy -p --output-format stream-json).",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "default": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "dependencies": {
19
+ "@claudexor/util": "3.5.0",
20
+ "@claudexor/schema": "3.5.0",
21
+ "@claudexor/core": "3.5.0"
22
+ },
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/razzant/claudexor.git",
26
+ "directory": "packages/harness-agy"
27
+ },
28
+ "homepage": "https://github.com/razzant/claudexor#readme",
29
+ "bugs": {
30
+ "url": "https://github.com/razzant/claudexor/issues"
31
+ },
32
+ "engines": {
33
+ "node": ">=20.19"
34
+ },
35
+ "publishConfig": {
36
+ "access": "public"
37
+ },
38
+ "devDependencies": {
39
+ "yaml": "^2.6.1"
40
+ },
41
+ "scripts": {
42
+ "build": "tsc",
43
+ "typecheck": "tsc --noEmit"
44
+ }
45
+ }