super-dsh 0.1.9 → 0.1.10-e

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.
Files changed (178) hide show
  1. package/README.md +25 -3
  2. package/agent-agy/cordis.patch.yml +7 -4
  3. package/agent-agy/dist/agent.d.ts +12 -11
  4. package/agent-agy/dist/agy-auth-gateway.d.ts +124 -0
  5. package/agent-agy/dist/agy-auth-gateway.js +233 -0
  6. package/agent-agy/dist/agy-auth.d.ts +153 -0
  7. package/agent-agy/dist/agy-auth.js +179 -0
  8. package/agent-agy/dist/agy-cli-client.d.ts +39 -9
  9. package/agent-agy/dist/agy-cli-client.js +82 -18
  10. package/agent-agy/dist/agy-store.d.ts +8 -0
  11. package/agent-agy/dist/index.d.ts +46 -16
  12. package/agent-agy/dist/index.js +82 -56
  13. package/agent-agy/dist/models.d.ts +70 -0
  14. package/agent-agy/dist/models.js +102 -3
  15. package/agent-agy/package.json +7 -5
  16. package/agent-agy-sdk/cordis.patch.yml +58 -0
  17. package/agent-agy-sdk/dist/adapter.d.ts +15 -0
  18. package/agent-agy-sdk/dist/adapter.js +42 -0
  19. package/agent-agy-sdk/dist/agent-preset-agy.d.ts +27 -0
  20. package/agent-agy-sdk/dist/agent-preset-agy.js +32 -0
  21. package/agent-agy-sdk/dist/agent.d.ts +138 -0
  22. package/agent-agy-sdk/dist/agent.js +494 -0
  23. package/{agent-agy → agent-agy-sdk}/dist/agy-client.d.ts +26 -6
  24. package/{agent-agy → agent-agy-sdk}/dist/agy-client.js +43 -25
  25. package/agent-agy-sdk/dist/agy-sessions.d.ts +25 -0
  26. package/agent-agy-sdk/dist/agy-sessions.js +107 -0
  27. package/agent-agy-sdk/dist/agy-store.d.ts +39 -0
  28. package/agent-agy-sdk/dist/agy-store.js +83 -0
  29. package/agent-agy-sdk/dist/inbox.d.ts +26 -0
  30. package/agent-agy-sdk/dist/inbox.js +53 -0
  31. package/agent-agy-sdk/dist/index.d.ts +93 -0
  32. package/agent-agy-sdk/dist/index.js +476 -0
  33. package/agent-agy-sdk/dist/models.d.ts +41 -0
  34. package/agent-agy-sdk/dist/models.js +74 -0
  35. package/agent-agy-sdk/dist/sdk-venv.d.ts +76 -0
  36. package/agent-agy-sdk/dist/sdk-venv.js +173 -0
  37. package/agent-agy-sdk/dist/world-plugin.d.ts +10 -0
  38. package/agent-agy-sdk/dist/world-plugin.js +82 -0
  39. package/agent-agy-sdk/package.json +64 -0
  40. package/agent-claude/dist/adapter.js +106 -31
  41. package/agent-claude/dist/agent.js +154 -17
  42. package/agent-claude/dist/claude-client.js +84 -43
  43. package/agent-claude/dist/claude-launch.js +101 -0
  44. package/agent-claude/dist/claude-native-config.js +169 -0
  45. package/agent-claude/dist/claude-provider-gateway.js +340 -0
  46. package/agent-claude/dist/claude-providers.js +391 -0
  47. package/agent-claude/dist/claude-route.js +152 -0
  48. package/agent-claude/dist/index.js +214 -37
  49. package/agent-claude/dist/models.js +14 -0
  50. package/agent-claude/dist/sdk-runtime.js +320 -0
  51. package/agent-claude/package.json +6 -4
  52. package/agent-codex/README.md +141 -36
  53. package/agent-codex/cordis.patch.yml +14 -10
  54. package/agent-codex/dist/adapter.js +64 -28
  55. package/agent-codex/dist/agent.js +255 -81
  56. package/agent-codex/dist/app-server-approvals.js +165 -0
  57. package/agent-codex/dist/app-server-client.js +723 -0
  58. package/agent-codex/dist/app-server-events.js +432 -0
  59. package/agent-codex/dist/app-server-protocol.js +95 -0
  60. package/agent-codex/dist/app-server-wire.js +299 -0
  61. package/agent-codex/dist/codex-launch.js +78 -0
  62. package/agent-codex/dist/codex-native-config.js +392 -0
  63. package/agent-codex/dist/codex-provider-gateway.js +402 -0
  64. package/agent-codex/dist/codex-providers.js +376 -0
  65. package/agent-codex/dist/codex-route.js +86 -0
  66. package/agent-codex/dist/index.js +256 -115
  67. package/agent-codex/dist/permission.js +75 -1
  68. package/agent-codex/package.json +1 -2
  69. package/agent-codex-sdk/README.md +79 -0
  70. package/agent-codex-sdk/cordis.patch.yml +81 -0
  71. package/agent-codex-sdk/dist/adapter.js +91 -0
  72. package/agent-codex-sdk/dist/agent-preset-codex.js +32 -0
  73. package/agent-codex-sdk/dist/agent.js +1085 -0
  74. package/agent-codex-sdk/dist/codex-native-config.js +392 -0
  75. package/agent-codex-sdk/dist/codex-provider-gateway.js +402 -0
  76. package/agent-codex-sdk/dist/codex-providers.js +376 -0
  77. package/agent-codex-sdk/dist/codex-route.js +86 -0
  78. package/{agent-codex/dist/codex-client.js → agent-codex-sdk/dist/codex-sdk-client.js} +253 -32
  79. package/agent-codex-sdk/dist/codex-sdk-launch.js +92 -0
  80. package/agent-codex-sdk/dist/codex-store.js +180 -0
  81. package/agent-codex-sdk/dist/inbox.js +53 -0
  82. package/agent-codex-sdk/dist/index.js +739 -0
  83. package/agent-codex-sdk/dist/permission.js +71 -0
  84. package/agent-codex-sdk/dist/sdk-runtime.js +307 -0
  85. package/agent-codex-sdk/dist/session-map.js +167 -0
  86. package/agent-codex-sdk/dist/world-plugin.js +93 -0
  87. package/agent-codex-sdk/package.json +79 -0
  88. package/agent-codex-sdk/scripts/fetch-sdk-runtime.mjs +57 -0
  89. package/agent-omp/README.md +72 -55
  90. package/agent-omp/dist/agent.js +36 -11
  91. package/agent-omp/dist/index.js +92 -52
  92. package/agent-omp/dist/lazy-rpc.js +11 -4
  93. package/agent-omp/dist/omp-cli.js +114 -97
  94. package/agent-omp/dist/omp-store.js +12 -4
  95. package/agent-omp/dist/permission.js +70 -5
  96. package/agent-omp/dist/rpc-client.js +409 -0
  97. package/agent-omp/dist/world-plugin.js +36 -3
  98. package/agent-omp/package.json +2 -6
  99. package/agent-omp-sdk/README.md +103 -0
  100. package/agent-omp-sdk/cordis.patch.yml +108 -0
  101. package/agent-omp-sdk/dist/adapter.d.ts +21 -0
  102. package/agent-omp-sdk/dist/adapter.js +36 -0
  103. package/agent-omp-sdk/dist/agent-preset-omp.d.ts +31 -0
  104. package/agent-omp-sdk/dist/agent-preset-omp.js +32 -0
  105. package/agent-omp-sdk/dist/agent.d.ts +64 -0
  106. package/agent-omp-sdk/dist/agent.js +1178 -0
  107. package/agent-omp-sdk/dist/discovery.d.ts +57 -0
  108. package/agent-omp-sdk/dist/discovery.js +116 -0
  109. package/agent-omp-sdk/dist/inbox.d.ts +28 -0
  110. package/agent-omp-sdk/dist/inbox.js +53 -0
  111. package/agent-omp-sdk/dist/index.d.ts +60 -0
  112. package/agent-omp-sdk/dist/index.js +632 -0
  113. package/agent-omp-sdk/dist/knobs.d.ts +34 -0
  114. package/agent-omp-sdk/dist/knobs.js +50 -0
  115. package/agent-omp-sdk/dist/lazy-rpc.d.ts +98 -0
  116. package/agent-omp-sdk/dist/lazy-rpc.js +178 -0
  117. package/agent-omp-sdk/dist/mobile/zoom-guard.d.ts +187 -0
  118. package/agent-omp-sdk/dist/mobile/zoom-guard.js +294 -0
  119. package/agent-omp-sdk/dist/mobile-boot.d.ts +49 -0
  120. package/agent-omp-sdk/dist/mobile-boot.js +38 -0
  121. package/agent-omp-sdk/dist/models.d.ts +39 -0
  122. package/agent-omp-sdk/dist/models.js +299 -0
  123. package/agent-omp-sdk/dist/omp-cli.d.ts +67 -0
  124. package/agent-omp-sdk/dist/omp-cli.js +164 -0
  125. package/agent-omp-sdk/dist/omp-disk-discovery.d.ts +27 -0
  126. package/agent-omp-sdk/dist/omp-disk-discovery.js +178 -0
  127. package/agent-omp-sdk/dist/omp-executable.d.ts +2 -0
  128. package/agent-omp-sdk/dist/omp-executable.js +30 -0
  129. package/agent-omp-sdk/dist/omp-store.d.ts +134 -0
  130. package/agent-omp-sdk/dist/omp-store.js +526 -0
  131. package/agent-omp-sdk/dist/pairing.d.ts +7 -0
  132. package/agent-omp-sdk/dist/pairing.js +45 -0
  133. package/agent-omp-sdk/dist/permission.d.ts +138 -0
  134. package/agent-omp-sdk/dist/permission.js +161 -0
  135. package/agent-omp-sdk/dist/protocol.d.ts +189 -0
  136. package/agent-omp-sdk/dist/rpc-types.d.ts +77 -0
  137. package/agent-omp-sdk/dist/rpc-types.js +1 -0
  138. package/agent-omp-sdk/dist/sdk-client.d.ts +160 -0
  139. package/{agent-omp → agent-omp-sdk}/dist/sdk-client.js +108 -56
  140. package/agent-omp-sdk/dist/sdk-runtime.d.ts +211 -0
  141. package/agent-omp-sdk/dist/sdk-runtime.js +418 -0
  142. package/agent-omp-sdk/dist/sidecar-client.d.ts +87 -0
  143. package/agent-omp-sdk/dist/sidecar-client.js +197 -0
  144. package/agent-omp-sdk/dist/store/adapter.d.ts +17 -0
  145. package/agent-omp-sdk/dist/store/adapter.js +47 -0
  146. package/agent-omp-sdk/dist/store/db.d.ts +70 -0
  147. package/agent-omp-sdk/dist/store/db.js +210 -0
  148. package/agent-omp-sdk/dist/store/index.d.ts +23 -0
  149. package/agent-omp-sdk/dist/store/index.js +59 -0
  150. package/agent-omp-sdk/dist/store/reconcile.d.ts +15 -0
  151. package/agent-omp-sdk/dist/store/reconcile.js +51 -0
  152. package/agent-omp-sdk/dist/store/schema.d.ts +8 -0
  153. package/agent-omp-sdk/dist/store/schema.js +40 -0
  154. package/agent-omp-sdk/dist/transport.d.ts +49 -0
  155. package/agent-omp-sdk/dist/transport.js +35 -0
  156. package/agent-omp-sdk/dist/world-home.d.ts +4 -0
  157. package/agent-omp-sdk/dist/world-home.js +23 -0
  158. package/agent-omp-sdk/dist/world-plugin.d.ts +10 -0
  159. package/agent-omp-sdk/dist/world-plugin.js +137 -0
  160. package/agent-omp-sdk/package.json +87 -0
  161. package/client/index.js +1204 -93
  162. package/cordis.patch.yml +64 -0
  163. package/package.json +17 -8
  164. package/superd-hub/dist/client/agent-settings.d.ts +210 -0
  165. package/superd-hub/dist/client/agent-settings.js +300 -0
  166. package/superd-hub/dist/client/roster.js +6 -0
  167. package/superd-hub/dist/client/runtime-settings-api.d.ts +76 -0
  168. package/superd-hub/dist/client/runtime-settings-api.js +137 -0
  169. package/superd-hub/dist/client/switch.d.ts +165 -0
  170. package/superd-hub/dist/client/switch.js +295 -0
  171. package/superd-hub/lib/client/index.js +1204 -93
  172. package/agent-codex/dist/models.js +0 -152
  173. package/agent-omp/dist/sidecar-client.js +0 -195
  174. /package/{agent-agy → agent-agy-sdk}/bridge/agy_bridge.py +0 -0
  175. /package/{agent-agy → agent-agy-sdk}/bridge/gemini_openai_server.mjs +0 -0
  176. /package/{agent-codex/dist/codex-events.js → agent-codex-sdk/dist/codex-sdk-events.js} +0 -0
  177. /package/{agent-omp → agent-omp-sdk}/dist/protocol.js +0 -0
  178. /package/{agent-omp → agent-omp-sdk}/sidecar/main.ts +0 -0
@@ -1,15 +1,16 @@
1
1
  /**
2
- * agent-agy provider — Google Antigravity (Gemini) provider plugin for DeepSeek
3
- * Harness (Super D, consumer-first line, 2026-09-18).
2
+ * agent-agy provider — Google Antigravity provider plugin for DeepSeek Harness
3
+ * (Super D, consumer-first line, 2026-09-18).
4
4
  *
5
- * An `AgentFactory` that drives an `AgyBridgeClient` (the Python google-
6
- * antigravity SDK bridge child — localharness materializes inside it on the
7
- * FIRST prompt, so create/resume spawn nothing). Auth is consumer-first:
8
- * a Gemini API key persisted in the adapter's world-home state, or ADC via the
9
- * environment (the SDK picks it up; we never touch the agy CLI — dev-rules §16a).
5
+ * An `AgentFactory` that drives an `AgyCliClient` — the user's OWN Antigravity
6
+ * CLI in headless stream-json mode. 2026-10-02 ruling 「拥抱用户自己的使用环境」:
7
+ * the adapter shares the user's real `~/.gemini` (native settings.json), their
8
+ * ADC (`~/.config/gcloud`), and their keyring, instead of isolating a HOME the
9
+ * CLI never had. The SDK/bridge transport lives in its own opt-in package,
10
+ * `@pgmi-builds/agent-agy-sdk`.
10
11
  *
11
12
  * Session identity ("mapping only"): the DSH session id is the authority,
12
- * supplied by the harness. The SDK conversation id materializes after the
13
+ * supplied by the harness. The CLI conversation id materializes after the
13
14
  * first turn, so the pairing is persisted in `<worldHome>/dsh-sessions.json`
14
15
  * (agy-sessions.ts). Resume resolves that record and fails CLOSED
15
16
  * (CONVERSATION_NOT_FOUND) when no conversation is recorded. The DSH session
@@ -21,14 +22,15 @@ import { join } from "node:path";
21
22
  import { Service } from "@deepseek-ai/cordis";
22
23
  import { installModelSelection } from "@deepseek-ai/dsh-agent";
23
24
  import { SessionLogOffset, SessionPreparation, interruptedTurnClosers, } from "@deepseek-ai/dsh-session";
24
- import { AgyBridgeClient } from "./agy-client.js";
25
25
  import { AgyCliClient } from "./agy-cli-client.js";
26
+ import { hasSigninCredential, resolveAuthMode } from "./agy-auth.js";
27
+ import { AgyAuthGateway } from "./agy-auth-gateway.js";
26
28
  import { registerAntigravityPreset } from "./agent-preset-agy.js";
27
- import { readAdapterState, writeAdapterState, readNativeDefaultModel, hasAdcEvidence, readGcloudProject } from "./agy-store.js";
29
+ import { readAdapterState, writeAdapterState, readNativeDefaultModel, hasAdcEvidence } from "./agy-store.js";
28
30
  import { AgyLlmAdapter, AGY_PROVIDER_ID } from "./adapter.js";
29
31
  import { AgyAgent } from "./agent.js";
30
32
  import { sessionRecord, upsertSession } from "./agy-sessions.js";
31
- import { AGY_MODEL_CATALOG, CLI_DEFAULT_MODEL, parseModelId, toModelSlug } from "./models.js";
33
+ import { AGY_MODEL_CATALOG, CLI_DEFAULT_MODEL, parseModelId, resolveEffort, toModelSlug } from "./models.js";
32
34
  /** Realpath of a recorded cwd, accepted only when it names an existing directory. */
33
35
  /** Extract the session-selected model id (string form) from agent options. */
34
36
  function agentOptionsModel(agentOptions) {
@@ -98,6 +100,26 @@ export class AgyProvider extends Service {
98
100
  registerAntigravityPreset(ctx);
99
101
  this.registerModelCatalog();
100
102
  this.registerDefaultModel();
103
+ // The Hub settings panel's data plane (P3): an adapter-owned Typert Remote
104
+ // (`agyAuth/get` | `agyAuth/set`) on this world's context. The hub's
105
+ // carrier forwards `envelope.method` verbatim, so the panel reaches it
106
+ // through the existing `/hub/api?agent=agy` family — no new hub route, and
107
+ // no config knowledge leaks out of the adapter (dev-rules §12). Cordis
108
+ // keeps the instance alive as this context's `agyAuth` service.
109
+ new AgyAuthGateway(ctx, this.home, () => this.opts.realHome ?? process.env.HOME ?? "", () => this.authAvailability());
110
+ }
111
+ /** Which auth forms are present on this machine right now (probe, not choice). */
112
+ authAvailability() {
113
+ return {
114
+ apiKey: this.resolveApiKey() !== undefined,
115
+ // The CLI's OWN Google sign-in (Agent Platform) — measured 2026-10-02 as
116
+ // the plane headless actually uses, and the one that WORKS on this
117
+ // machine. Hardcoding it to `false` (the old "OAuth is a placeholder"
118
+ // note) forced the ladder onto ADC, whose project has cloudcode-pa
119
+ // disabled, so no turn could start.
120
+ oauth: hasSigninCredential(this.opts.realHome ?? process.env.HOME ?? ""),
121
+ adc: hasAdcEvidence(process.env, process.env.HOME ?? ""),
122
+ };
101
123
  }
102
124
  /** The world's DSH home: boot-provided dshHomePath first, env last. */
103
125
  resolveHome() {
@@ -153,7 +175,7 @@ export class AgyProvider extends Service {
153
175
  }
154
176
  /** Static route: provider `agy` + the resolved default (or the explicit ask).
155
177
  * The selected model id (`slug` or `slug@level`) rides in `options.model`
156
- * so clientOptions can forward slug+thinkingLevel to the bridge start frame. */
178
+ * so cliOptions can forward slug+thinkingLevel to the CLI child. */
157
179
  sessionAgentOptions(requested) {
158
180
  const requestedModel = typeof requested?.model === "string" ? requested.model : undefined;
159
181
  const explicit = requestedModel !== undefined && parseModelId(requestedModel) !== undefined
@@ -333,18 +355,29 @@ export class AgyProvider extends Service {
333
355
  }
334
356
  }
335
357
  /**
336
- * Live transport routing (2026-09-18 user ruling): gemini-api-key > oauth >
337
- * adc. Key present → CLI stream (richest surface). ADC-only → SDK bridge.
338
- * Neither → CLI as well (auth fails at first prompt; the §17 onboarding
339
- * branch answers locally before any spawn).
358
+ * Live transport: CLI-ONLY (2026-10-02 user ruling).
359
+ *
360
+ * The SDK/bridge route moved to its own package
361
+ * (`@pgmi-builds/agent-agy-sdk`, delivered disabled by default): the product
362
+ * case is that the user ALREADY runs Antigravity, so the CLI reuses that
363
+ * environment for free while the SDK is an opt-in extra. Auth-form selection
364
+ * still rides the agy-auth ladder.
340
365
  */
341
366
  createLiveClient(cwd, modelId, reasoningEffort) {
342
- const apiKey = this.resolveApiKey();
343
- if (apiKey === undefined && hasAdcEvidence(process.env, process.env.HOME ?? "")) {
344
- return new AgyBridgeClient(this.clientOptions(cwd, modelId, reasoningEffort));
345
- }
346
367
  return new AgyCliClient(this.cliOptions(cwd, modelId, reasoningEffort));
347
368
  }
369
+ /**
370
+ * The auth form this machine should use: an explicitly selected, actually
371
+ * available form wins; otherwise the ladder Gemini API key → OAuth → ADC
372
+ * (user ruling 2026-10-02). OAuth is a placeholder this round — no eligible
373
+ * account exists to characterise which native fields a real sign-in stores —
374
+ * so nothing reports it present and it can never win. Falls back to `apiKey`
375
+ * so an unconfigured machine still reaches the §17 onboarding path.
376
+ */
377
+ effectiveAuthMode() {
378
+ const selected = readAdapterState(this.home).authMode;
379
+ return resolveAuthMode(this.authAvailability(), selected) ?? "apiKey";
380
+ }
348
381
  /**
349
382
  * The effective permission preset this provider was mounted with. The
350
383
  * cordis.patch.yml default is danger-full-access; a patch-level override
@@ -365,11 +398,31 @@ export class AgyProvider extends Service {
365
398
  const parsed = parseModelId(modelId ?? this.resolveDefaultModelId());
366
399
  const slug = parsed?.slug ?? CLI_DEFAULT_MODEL.slug;
367
400
  // Effort precedence: explicit session reasoningEffort (WebUI Effort
368
- // selector → AgentOptions) > legacy @level id suffix > CLI cheap default.
369
- const level = reasoningEffort ?? parsed?.thinkingLevel ?? CLI_DEFAULT_MODEL.thinkingLevel;
401
+ // selector → AgentOptions.reasoningEffort) > legacy `slug@level` id suffix >
402
+ // THIS model's own declared default.
403
+ //
404
+ // The last arm used to read CLI_DEFAULT_MODEL.thinkingLevel, which is the
405
+ // 3.6-flash cheap-pair constant ("low") — so every model inherited it and
406
+ // the CLI got `--effort low` while the UI showed the model's own default
407
+ // (observed 2026-10-02: 3.7 Flash + UI "medium" → `--effort "low"`).
408
+ // defaultEffortFor() is the per-model answer and existed unused.
409
+ const level = resolveEffort(slug, reasoningEffort, parsed?.thinkingLevel);
410
+ // The ID ENCODING IS PLANE-DEPENDENT (measured 2026-10-02):
411
+ // OAuth / Agent Platform — `agy models` lists ONLY effort-suffixed ids
412
+ // (`gemini-3.7-flash-medium`) and the bare id is not a model at all:
413
+ // `--model gemini-3.7-flash --effort medium` → "--effort is not
414
+ // supported for model …". The suffixed id starts a turn, and a
415
+ // redundant `--effort` alongside it is tolerated.
416
+ // apiKey — the bare slug PLUS `--effort` (dev3); the suffixed id is not a
417
+ // model on that plane.
418
+ // The UI catalog therefore stays four base models with an effort slot (no
419
+ // list explosion) and the transport folds the level into the id when the
420
+ // active plane wants it that way.
421
+ const mode = this.effectiveAuthMode();
422
+ const model = mode === "oauth" && level !== undefined ? `${slug}-${level}` : slug;
370
423
  return {
371
424
  apiKey: () => this.resolveApiKey(),
372
- model: slug,
425
+ model,
373
426
  ...(level === undefined ? {} : { effort: level }),
374
427
  cwd,
375
428
  proxy: this.opts.proxy ?? process.env.AGY_PROXY,
@@ -379,39 +432,12 @@ export class AgyProvider extends Service {
379
432
  // tighter presets keep the CLI's request-review (soft-deny, honest).
380
433
  skipPermissions: (this.opts.skipPermissions ?? (this.currentPermissionPreset() === "danger-full-access")),
381
434
  agyBin: this.opts.agyBin,
382
- nativeCliHome: this.opts.nativeHome,
383
- home: this.opts.cliHome ?? process.env.AGY_CLI_HOME,
384
- spawnAttempts: this.opts.spawnAttempts,
385
- };
386
- }
387
- /** Bridge child options: world cwd + overrides; the api key rides the start config. */
388
- clientOptions(cwd, modelId, reasoningEffort) {
389
- // Auth plane (§16a): API key when present; otherwise the SDK's Vertex
390
- // endpoint over ADC — which needs an explicit project, read from the
391
- // gcloud CLI default. Without either, sessions gate into §17 onboarding.
392
- const apiKey = this.resolveApiKey();
393
- let project = this.opts.project;
394
- let location = this.opts.location;
395
- if (apiKey === undefined && project === undefined && hasAdcEvidence(process.env, process.env.HOME ?? "")) {
396
- project = readGcloudProject(process.env.HOME ?? "");
397
- location = location ?? "global";
398
- }
399
- // Session-selected model id wins over the provider default (previously a
400
- // split-brain: the session showed one model, the bridge started another).
401
- // `slug@level` decodes into model + thinking_level for the start frame.
402
- const parsed = parseModelId(modelId ?? this.resolveDefaultModelId());
403
- return {
404
- apiKey,
405
- project,
406
- location,
407
- model: parsed?.slug ?? this.resolveDefaultModelId(),
408
- // TUI parity: the native default ships (Medium); without an explicit
409
- // level the bridge sends none and thinking blocks rarely stream.
410
- thinkingLevel: parsed?.thinkingLevel ?? "medium",
411
- approvalMode: this.opts.approvalMode ?? "allow",
412
- workspaces: [cwd],
413
- bridgePath: this.opts.bridgePath,
414
- pythonBin: this.opts.pythonBin,
435
+ authMode: mode,
436
+ // The USER's real home — hard-coded relative to the current user, as the
437
+ // 2026-10-02 ruling requires: the CLI, `~/.config/gcloud` (ADC), the
438
+ // keyring, and the native settings we maintain all resolve against it, so
439
+ // the adapter and the user's own TUI share one configuration.
440
+ realHome: this.opts.realHome ?? process.env.HOME ?? "",
415
441
  spawnAttempts: this.opts.spawnAttempts,
416
442
  };
417
443
  }
@@ -16,6 +16,41 @@ export interface AgyCatalogModel {
16
16
  efforts?: readonly string[];
17
17
  defaultEffort?: string;
18
18
  }
19
+ /**
20
+ * The effort vocabulary is Antigravity's, not DSH's — the WebUI's Effort slot is
21
+ * only a SLOT; the values offered through it are borrowed from the runtime
22
+ * (2026-10-02 user ruling). `agy --help` advertises `low|medium|high|max`, so
23
+ * `max` belongs in the list: the previous three-value vocabulary was DSH's own
24
+ * and silently hid a level the CLI accepts.
25
+ *
26
+ * Capability stays per-model: a model without `efforts` gets NO effort flag at
27
+ * all (see resolveEffort), and per-model acceptance of `max` still needs a
28
+ * working auth plane to confirm — no live plane could be probed on 2026-10-02
29
+ * (ADC serves no catalog; the account plane is eligibility-gated headless).
30
+ */
31
+ /**
32
+ * The catalog as the CLI ACTUALLY serves it (probed 2026-10-02 on dev3 against
33
+ * the live key plane; the CLI answers `available: <levels>` when `--effort` is
34
+ * omitted, which is the authoritative per-model vocabulary):
35
+ *
36
+ * gemini-3.1-pro low, high (NO medium — a global list cannot say this)
37
+ * gemini-3.7-flash low, medium, high
38
+ * gemini-3.6-flash low, medium, high
39
+ * gemini-3.8-flash low, medium, high
40
+ * gemini-2.5-pro / 2.5-flash / 3.5-flash → `not recognized as a known model`
41
+ *
42
+ * `efforts` therefore exists to describe a model's real vocabulary, NOT to be
43
+ * transmitted as a default (see resolveEffort: undecided sends nothing).
44
+ * `defaultEffort` is the Effort slot's display default only.
45
+ *
46
+ * MODEL LIST SOURCE: the CLI itself enumerates via
47
+ * `POST https://cloudcode-pa.googleapis.com/v1internal:fetchAvailableModels`
48
+ * (+ `v1internal:listModelConfigs`), which needs an eligible account AND a
49
+ * quota project with Cloud Code PA enabled. Neither transport could reach it on
50
+ * this machine (ADC: API disabled / no bind permission on the project; account:
51
+ * headless eligibility gate), so this table stays a static capture per
52
+ * dev-rules §16a — with a probe path recorded for whoever has a working plane.
53
+ */
19
54
  export declare const AGY_MODEL_CATALOG: readonly AgyCatalogModel[];
20
55
  /** Selectable model ids (plain slugs). */
21
56
  export declare function modelIds(): string[];
@@ -33,6 +68,41 @@ export declare const CLI_DEFAULT_MODEL: {
33
68
  slug: string;
34
69
  thinkingLevel: string;
35
70
  };
71
+ /**
72
+ * The `--effort` value to send for one model.
73
+ *
74
+ * `--effort` is REQUIRED, not optional: omitting it makes the CLI refuse to
75
+ * start (`--model X requires --effort (available: low, high)` — verified
76
+ * 2026-10-02 against 3.8-flash, 3.7-flash and 3.1-pro). So this always returns a
77
+ * level for a known model; the only `undefined` case is a slug with no declared
78
+ * vocabulary, where we forward exactly what was asked for.
79
+ *
80
+ * The per-model step is what matters: the original defect read
81
+ * CLI_DEFAULT_MODEL's level wholesale (a 3.6-flash constant), so every model
82
+ * got `--effort low` whatever the UI showed, and 3.1-pro — which serves only
83
+ * low|high — could never start.
84
+ *
85
+ * Precedence: an explicit session choice (the WebUI Effort selector arrives as
86
+ * `AgentOptions.reasoningEffort`) > a legacy `slug@level` id suffix > THIS
87
+ * model's own declared default.
88
+ *
89
+ * The third arm is the one that matters: it used to read
90
+ * {@link CLI_DEFAULT_MODEL}'s thinking level wholesale — a constant belonging
91
+ * to the 3.6-flash cheap pair — so every model was sent `--effort low` no
92
+ * matter what the UI showed (observed 2026-10-02: 3.7 Flash + UI "medium" →
93
+ * the CLI received `--effort "low"` and refused it). A slug that declares no
94
+ * effort support yields `undefined`: sending a flag the model rejects is worse
95
+ * than sending none.
96
+ *
97
+ * `slug` is the model actually being launched; an unrecognised slug (the
98
+ * caller already fell back to the CLI default pair) inherits that pair's level.
99
+ *
100
+ * @param slug - the model id being launched (a catalog slug).
101
+ * @param explicit - the session's reasoning-effort choice, when it made one.
102
+ * @param legacyLevel - effort decoded from a `slug@level` id, when present.
103
+ * @returns the effort to pass, or `undefined` to pass no `--effort`.
104
+ */
105
+ export declare function resolveEffort(slug: string, explicit?: string | undefined, legacyLevel?: string | undefined): string | undefined;
36
106
  /**
37
107
  * Normalize a model reference to an SDK-facing slug. The native TUI settings
38
108
  * store display names ("Gemini 3.7 Flash (Medium)"); slugs pass through;
@@ -9,12 +9,46 @@
9
9
  * AgentOptions.reasoningEffort), NOT extra catalog entries (user ruling
10
10
  * 2026-09-18).
11
11
  */
12
+ /**
13
+ * The effort vocabulary is Antigravity's, not DSH's — the WebUI's Effort slot is
14
+ * only a SLOT; the values offered through it are borrowed from the runtime
15
+ * (2026-10-02 user ruling). `agy --help` advertises `low|medium|high|max`, so
16
+ * `max` belongs in the list: the previous three-value vocabulary was DSH's own
17
+ * and silently hid a level the CLI accepts.
18
+ *
19
+ * Capability stays per-model: a model without `efforts` gets NO effort flag at
20
+ * all (see resolveEffort), and per-model acceptance of `max` still needs a
21
+ * working auth plane to confirm — no live plane could be probed on 2026-10-02
22
+ * (ADC serves no catalog; the account plane is eligibility-gated headless).
23
+ */
24
+ /**
25
+ * The catalog as the CLI ACTUALLY serves it (probed 2026-10-02 on dev3 against
26
+ * the live key plane; the CLI answers `available: <levels>` when `--effort` is
27
+ * omitted, which is the authoritative per-model vocabulary):
28
+ *
29
+ * gemini-3.1-pro low, high (NO medium — a global list cannot say this)
30
+ * gemini-3.7-flash low, medium, high
31
+ * gemini-3.6-flash low, medium, high
32
+ * gemini-3.8-flash low, medium, high
33
+ * gemini-2.5-pro / 2.5-flash / 3.5-flash → `not recognized as a known model`
34
+ *
35
+ * `efforts` therefore exists to describe a model's real vocabulary, NOT to be
36
+ * transmitted as a default (see resolveEffort: undecided sends nothing).
37
+ * `defaultEffort` is the Effort slot's display default only.
38
+ *
39
+ * MODEL LIST SOURCE: the CLI itself enumerates via
40
+ * `POST https://cloudcode-pa.googleapis.com/v1internal:fetchAvailableModels`
41
+ * (+ `v1internal:listModelConfigs`), which needs an eligible account AND a
42
+ * quota project with Cloud Code PA enabled. Neither transport could reach it on
43
+ * this machine (ADC: API disabled / no bind permission on the project; account:
44
+ * headless eligibility gate), so this table stays a static capture per
45
+ * dev-rules §16a — with a probe path recorded for whoever has a working plane.
46
+ */
12
47
  export const AGY_MODEL_CATALOG = [
48
+ { slug: "gemini-3.8-flash", label: "Gemini 3.8 Flash", efforts: ["low", "medium", "high"], defaultEffort: "medium" },
13
49
  { slug: "gemini-3.7-flash", label: "Gemini 3.7 Flash", efforts: ["low", "medium", "high"], defaultEffort: "medium" },
14
50
  { slug: "gemini-3.6-flash", label: "Gemini 3.6 Flash", efforts: ["low", "medium", "high"], defaultEffort: "low" },
15
- { slug: "gemini-3.5-flash", label: "Gemini 3.5 Flash", efforts: ["low", "medium", "high"], defaultEffort: "medium" },
16
- { slug: "gemini-2.5-pro", label: "Gemini 2.5 Pro" },
17
- { slug: "gemini-2.5-flash", label: "Gemini 2.5 Flash" },
51
+ { slug: "gemini-3.1-pro", label: "Gemini 3.1 Pro", efforts: ["low", "high"], defaultEffort: "low" },
18
52
  ];
19
53
  /** Selectable model ids (plain slugs). */
20
54
  export function modelIds() {
@@ -51,6 +85,71 @@ export const CLI_DEFAULT_MODEL = {
51
85
  slug: "gemini-3.6-flash",
52
86
  thinkingLevel: "low",
53
87
  };
88
+ /**
89
+ * The `--effort` value to send for one model.
90
+ *
91
+ * `--effort` is REQUIRED, not optional: omitting it makes the CLI refuse to
92
+ * start (`--model X requires --effort (available: low, high)` — verified
93
+ * 2026-10-02 against 3.8-flash, 3.7-flash and 3.1-pro). So this always returns a
94
+ * level for a known model; the only `undefined` case is a slug with no declared
95
+ * vocabulary, where we forward exactly what was asked for.
96
+ *
97
+ * The per-model step is what matters: the original defect read
98
+ * CLI_DEFAULT_MODEL's level wholesale (a 3.6-flash constant), so every model
99
+ * got `--effort low` whatever the UI showed, and 3.1-pro — which serves only
100
+ * low|high — could never start.
101
+ *
102
+ * Precedence: an explicit session choice (the WebUI Effort selector arrives as
103
+ * `AgentOptions.reasoningEffort`) > a legacy `slug@level` id suffix > THIS
104
+ * model's own declared default.
105
+ *
106
+ * The third arm is the one that matters: it used to read
107
+ * {@link CLI_DEFAULT_MODEL}'s thinking level wholesale — a constant belonging
108
+ * to the 3.6-flash cheap pair — so every model was sent `--effort low` no
109
+ * matter what the UI showed (observed 2026-10-02: 3.7 Flash + UI "medium" →
110
+ * the CLI received `--effort "low"` and refused it). A slug that declares no
111
+ * effort support yields `undefined`: sending a flag the model rejects is worse
112
+ * than sending none.
113
+ *
114
+ * `slug` is the model actually being launched; an unrecognised slug (the
115
+ * caller already fell back to the CLI default pair) inherits that pair's level.
116
+ *
117
+ * @param slug - the model id being launched (a catalog slug).
118
+ * @param explicit - the session's reasoning-effort choice, when it made one.
119
+ * @param legacyLevel - effort decoded from a `slug@level` id, when present.
120
+ * @returns the effort to pass, or `undefined` to pass no `--effort`.
121
+ */
122
+ export function resolveEffort(slug, explicit, legacyLevel) {
123
+ const entry = AGY_MODEL_CATALOG.find((m) => m.slug === slug);
124
+ const allowed = entry?.efforts;
125
+ const wanted = firstNonEmpty(explicit, legacyLevel);
126
+ // No declared vocabulary (a slug we do not know): forward exactly what was
127
+ // asked for and no more. We cannot validate against a set we do not have.
128
+ if (allowed === undefined)
129
+ return wanted;
130
+ if (wanted !== undefined && allowed.includes(wanted))
131
+ return wanted;
132
+ // Either nothing was chosen or the chosen level is not one THIS model serves
133
+ // (a stale session, a model swap). Either way we must still send a level:
134
+ // the CLI refuses to start without one —
135
+ // `--model X requires --effort (available: low, high)`
136
+ // verified 2026-10-02 against 3.8-flash, 3.7-flash and 3.1-pro. So fall back
137
+ // to the model's own default, then to its cheapest available level, instead
138
+ // of transmitting nothing (fatal) or another model's constant (the original
139
+ // defect: every model got 3.6-flash's "low", and 3.1-pro has no medium).
140
+ const fallback = entry?.defaultEffort;
141
+ if (fallback !== undefined && allowed.includes(fallback))
142
+ return fallback;
143
+ return allowed[0];
144
+ }
145
+ /** First non-empty string, or undefined. An empty value is an absent choice. */
146
+ function firstNonEmpty(...values) {
147
+ for (const value of values) {
148
+ if (value !== undefined && value !== "")
149
+ return value;
150
+ }
151
+ return undefined;
152
+ }
54
153
  /**
55
154
  * Normalize a model reference to an SDK-facing slug. The native TUI settings
56
155
  * store display names ("Gemini 3.7 Flash (Medium)"); slugs pass through;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pgmi-builds/agent-agy",
3
3
  "version": "0.1.0",
4
- "description": "Google Antigravity (Gemini) provider for DeepSeek Harness (dsh) — drives the google-antigravity Python SDK through a JSONL stdio bridge (bridge/agy_bridge.py, localharness embedded). Consumer-first auth: Gemini API key stored adapter-side; ADC picked up transparently by the SDK. The agy CLI is never invoked.",
4
+ "description": "Google Antigravity provider for DeepSeek Harness (dsh) — drives the user's own Antigravity CLI headless (`agy --input-format stream-json`). 2026-10-02 ruling 「拥抱用户自己的使用环境」: the adapter shares the real ~/.gemini settings.json, ADC and keyring instead of isolating a HOME. Auth ladder: Gemini API key → OAuth (placeholder) → ADC. The heavy Python SDK transport lives in the opt-in sibling @pgmi-builds/agent-agy-sdk.",
5
5
  "type": "module",
6
6
  "exports": {
7
7
  ".": "./dist/index.js",
@@ -9,7 +9,6 @@
9
9
  },
10
10
  "files": [
11
11
  "dist",
12
- "bridge",
13
12
  "cordis.patch.yml"
14
13
  ],
15
14
  "dsh": {
@@ -19,8 +18,7 @@
19
18
  },
20
19
  "scripts": {
21
20
  "build": "tsc -p tsconfig.json",
22
- "test": "node --test test/*.test.mjs",
23
- "setup-venv": "bash scripts/setup-venv.sh"
21
+ "test": "node --test test/*.test.mjs"
24
22
  },
25
23
  "dependencies": {
26
24
  "zod": "3.25.76"
@@ -31,7 +29,8 @@
31
29
  "@deepseek-ai/dsh-llm": ">=0.1.5-0 <0.3.0-0",
32
30
  "@deepseek-ai/dsh-scope": ">=0.1.5-0 <0.3.0-0",
33
31
  "@deepseek-ai/dsh-session": ">=0.1.5-0 <0.3.0-0",
34
- "@deepseek-ai/dsh-session-persistence": ">=0.1.5-0 <0.3.0-0"
32
+ "@deepseek-ai/dsh-session-persistence": ">=0.1.5-0 <0.3.0-0",
33
+ "@deepseek-ai/dsh-typert-protocol": ">=0.1.5-0 <0.3.0-0"
35
34
  },
36
35
  "peerDependenciesMeta": {
37
36
  "@deepseek-ai/cordis": {
@@ -51,6 +50,9 @@
51
50
  },
52
51
  "@deepseek-ai/dsh-session-persistence": {
53
52
  "optional": true
53
+ },
54
+ "@deepseek-ai/dsh-typert-protocol": {
55
+ "optional": true
54
56
  }
55
57
  },
56
58
  "devDependencies": {
@@ -0,0 +1,58 @@
1
+ # @pgmi-builds/agent-agy-sdk bundle patch (opt-in SDK line, pi/hermes form).
2
+ # The `dsh.bundle.patch` layer of the adapter package: mounts the agy-sdk
3
+ # provider and disables the native components it replaces. Port/webserver
4
+ # posture is NOT here (worldMountPatches owns it); the profile patch pins home.
5
+ #
6
+ # Auth (dev-rules §16a): Gemini API key in adapter world-home state (or
7
+ # GEMINI_API_KEY env), else ADC — the SDK consumes either transparently. The
8
+ # agy CLI is never invoked (that is @pgmi-builds/agent-agy).
9
+ #
10
+ # This whole bundle sits behind a `disabled: true` row in the super-dsh
11
+ # composite: the SDK half is opt-in (2026-10-02 user ruling) because the CLI
12
+ # half reuses the user's existing Antigravity environment for free.
13
+
14
+
15
+ - insert:
16
+ - id: agy-sdk-provider
17
+ name: '@pgmi-builds/agent-agy-sdk'
18
+
19
+ # The SDK bridge owns the live transcript; disable the built-in loop so it
20
+ # does not double-run alongside the bridge session.
21
+ - id: agent-loop
22
+ disabled: true
23
+
24
+ # The agy provider registers the single `agy` route on ctx.llm; leaving the
25
+ # native deepseek row mounted would advertise foreign models in this world.
26
+ - id: llm-deepseek
27
+ disabled: true
28
+
29
+ # Single-preset roster like pi: launch-only permission mapping (headless bridge
30
+ # has no per-action approval channel). Full 3-preset restatement per §4.1.
31
+ # 0.1.7: the host AgentPresetRegistry row (renamed `agent-presets` ->
32
+ # `agent-preset-registry`) stays MOUNTED — the adapter registers its one
33
+ # fixed preset into it (src/agent-preset-agy.ts); pin only the default.
34
+ - id: agent-preset-registry
35
+ config:
36
+ default: agy
37
+ - id: permission
38
+ config:
39
+ presets:
40
+ read-only:
41
+ sandbox: read-only
42
+ approval: ask
43
+ workspace-write:
44
+ sandbox: workspace-write
45
+ approval: ask
46
+ danger-full-access:
47
+ sandbox: danger-full-access
48
+ approval: never
49
+ defaultPreset: danger-full-access
50
+
51
+ # Directory picker: pin both faces of `browse`, unmount the auto row (§4.1).
52
+ - insert:
53
+ - id: directory-picker-browse
54
+ name: '@deepseek-ai/dsh-host-directory-picker-browse'
55
+ - id: directory-picker-browse-surface
56
+ name: '@deepseek-ai/dsh-client-ui-directory-picker-browse'
57
+ - id: directory-picker
58
+ disabled: true
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Antigravity-backed `LlmAdapter` registered on `ctx.llm` by the Agy provider.
3
+ * Catalog is STATIC (models.ts): the SDK has no model-list API and the CLI
4
+ * catalog path is auth-gated (dev-rules §16a), so every surface is synchronous.
5
+ * `stream` is never dispatched — the Antigravity agent owns generation through
6
+ * its bridge child (`AgyAgent`); it throws rather than fabricating a wire route.
7
+ */
8
+ import { LlmAdapter, type GenerateOptions, type LlmModelInfo, type LlmProviderInfo, type LlmResolvedModelInfo, type StreamChunk } from "@deepseek-ai/dsh-llm";
9
+ export declare const AGY_PROVIDER_ID = "agy";
10
+ export declare class AgyLlmAdapter extends LlmAdapter {
11
+ providerInfo(provider: string): LlmProviderInfo;
12
+ listModels(provider: string): Promise<readonly LlmModelInfo[]>;
13
+ resolveModel(provider: string, model: string): Promise<LlmResolvedModelInfo>;
14
+ stream(_options: GenerateOptions): AsyncIterable<StreamChunk>;
15
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Antigravity-backed `LlmAdapter` registered on `ctx.llm` by the Agy provider.
3
+ * Catalog is STATIC (models.ts): the SDK has no model-list API and the CLI
4
+ * catalog path is auth-gated (dev-rules §16a), so every surface is synchronous.
5
+ * `stream` is never dispatched — the Antigravity agent owns generation through
6
+ * its bridge child (`AgyAgent`); it throws rather than fabricating a wire route.
7
+ */
8
+ import { LlmAdapter, LlmError, ReasoningEffortId, } from "@deepseek-ai/dsh-llm";
9
+ import { AGY_MODEL_CATALOG } from "./models.js";
10
+ export const AGY_PROVIDER_ID = "agy";
11
+ export class AgyLlmAdapter extends LlmAdapter {
12
+ providerInfo(provider) {
13
+ return { id: provider, name: provider === AGY_PROVIDER_ID ? "Google" : provider };
14
+ }
15
+ async listModels(provider) {
16
+ return AGY_MODEL_CATALOG.map((model) => ({
17
+ provider,
18
+ id: model.slug,
19
+ name: model.label,
20
+ }));
21
+ }
22
+ async resolveModel(provider, model) {
23
+ const found = AGY_MODEL_CATALOG.find((candidate) => candidate.slug === model);
24
+ if (found === undefined) {
25
+ throw new LlmError(`Agy provider "${provider}" does not serve model "${model}"`, "MODEL_NOT_FOUND");
26
+ }
27
+ return {
28
+ provider,
29
+ id: found.slug,
30
+ name: found.label,
31
+ ...(found.efforts === undefined ? {} : {
32
+ reasoning: {
33
+ efforts: found.efforts.map((level) => ({ id: ReasoningEffortId(level), name: level })),
34
+ ...(found.defaultEffort === undefined ? {} : { defaultEffort: ReasoningEffortId(found.defaultEffort) }),
35
+ },
36
+ }),
37
+ };
38
+ }
39
+ stream(_options) {
40
+ throw new LlmError("the Agy adapter does not stream: Antigravity owns generation through its bridge agent", "UNSUPPORTED_STREAM");
41
+ }
42
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Antigravity preset registration — the profile's one fixed Agent preset.
3
+ *
4
+ * 0.1.7 alignment (upstream split `dsh-agent-presets` into `dsh-agent-preset`
5
+ * + `dsh-agent-preset-registry` and moved roster, selection, document RPC and
6
+ * the `agentPreset` session projection into the host `AgentPresetRegistry`,
7
+ * mounted by the dsh-web-app bundle's `agent-preset-registry` row): the
8
+ * adapter no longer implements the `agentPresets` service — the 0.1.6
9
+ * SingleAgyPresetRoster and its own projection fold are retired. It only REGISTERS the
10
+ * single fixed preset into the host registry.
11
+ *
12
+ * Antigravity is single-mode: the foreign agent drives its own tools, so no
13
+ * Dash-side preset composition exists to choose from. The preset's
14
+ * composition deliberately mounts nothing.
15
+ */
16
+ import type { Context } from "@deepseek-ai/cordis";
17
+ import type { PresetDefinition } from "@deepseek-ai/dsh-agent-preset-registry";
18
+ export declare const AGY_PRESET_ID = "agy";
19
+ /** The single fixed Antigravity preset: mounting it composes nothing. */
20
+ export declare const AGY_PRESET: PresetDefinition;
21
+ /**
22
+ * Register the fixed preset into the host `AgentPresetRegistry` once the
23
+ * service is up. Registration failure keeps the roster row visible as
24
+ * `broken` inside the registry (upstream owns that lifecycle) — the adapter
25
+ * only owns the disposer.
26
+ */
27
+ export declare function registerAntigravityPreset(ctx: Context): void;
@@ -0,0 +1,32 @@
1
+ export const AGY_PRESET_ID = "agy";
2
+ /** The single fixed Antigravity preset: mounting it composes nothing. */
3
+ export const AGY_PRESET = Object.freeze({
4
+ id: AGY_PRESET_ID,
5
+ name: "Antigravity",
6
+ description: "Google Antigravity (Gemini) via the agent-agy adapter",
7
+ plugins: Object.freeze([]),
8
+ });
9
+ /**
10
+ * Register the fixed preset into the host `AgentPresetRegistry` once the
11
+ * service is up. Registration failure keeps the roster row visible as
12
+ * `broken` inside the registry (upstream owns that lifecycle) — the adapter
13
+ * only owns the disposer.
14
+ */
15
+ export function registerAntigravityPreset(ctx) {
16
+ ctx.inject(["agentPresets"], (scoped) => {
17
+ let dispose;
18
+ let settled = false;
19
+ void scoped.agentPresets.register(AGY_PRESET).then((unregister) => {
20
+ if (settled) {
21
+ void unregister();
22
+ }
23
+ else {
24
+ dispose = unregister;
25
+ }
26
+ });
27
+ ctx.effect(() => async () => {
28
+ settled = true;
29
+ await dispose?.();
30
+ }, "agyAdapter.preset");
31
+ });
32
+ }