dsh-agy-link 0.4.67 → 0.4.74

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.
@@ -21,6 +21,19 @@ Deliberate v1 boundaries and upstream-behavior notes.
21
21
  persists a rotated access token and restores the primary. Only identity
22
22
  SWITCHES serialize — a switcher registers its claim BEFORE queueing, and
23
23
  new same-identity joins are refused while a different identity waits.
24
+ - **The slot is held only until agy has READ it (v0.4.68).** Measured on agy
25
+ 1.4.3 with a live 14-minute run: print mode resolves its credential once at
26
+ startup (`printmode.go:403 "not authenticated, trying silent auth"` →
27
+ `:405 "silent auth succeeded"` at +3.2s) and performs zero further
28
+ token/auth work for the rest of the run. The adapter therefore arms
29
+ `armSlotHandoff` before the spawn and releases the lease on the child's
30
+ FIRST output line (45s ceiling for a slow startup) instead of holding the
31
+ machine-wide slot for the whole run. Different accounts now overlap: the
32
+ 2026-10-22 design parked two sessions for 15 minutes behind another
33
+ project's 14-minute run; the exclusive window is now a few seconds.
34
+ Residual exposure (unchanged in kind, now diagnosable): a mid-run 401 that
35
+ forces a re-auth would read whatever identity is installed at that moment —
36
+ the hand-off logs when it fires so that case is visible instead of silent.
24
37
  - `SlotUnavailableError` aborts a run instead of letting it silently spend
25
38
  the wrong account when the primary cannot be verified.
26
39
  - Remaining boundary: the mutex is **per process**, so two DSH hosts (web +
@@ -34,15 +47,37 @@ injection (each account's HOME carries its own credential, no global slot, no
34
47
  mutex, identical on macOS/Linux/Windows). It is NOT available in the current
35
48
  agy build — measured, not assumed:
36
49
 
37
- - **The per-HOME token file is a BACKUP, not the source.** A fresh isolated
38
- HOME containing a deliberately bogus
50
+ - **The per-HOME token file is a FALLBACK, not the source (re-measured
51
+ 2026-10-23).** With an entry in the keyring the file is ignored: a fresh
52
+ isolated HOME containing a deliberately bogus
39
53
  `.gemini/antigravity-cli/antigravity-oauth-token` still authenticated from the
40
54
  machine keyring and completed a prompt (exit 0, `OK`), and the bogus file was
41
- left untouched. With the keyring present, writing per-account token files
42
- does not isolate identities. (`fileTokenStorage` exists but is only a
43
- fallback when keyring save/load times out or is unavailable.)
55
+ left untouched.
56
+ - **But with the keyring entry ABSENT, agy DOES read the per-HOME file.**
57
+ Probe: delete `gemini:antigravity`, isolate a HOME whose token file holds
58
+ `ya29.BOGUS_FROM_HOME_FILE`, run a prompt → `Eligibility check failed:
59
+ UNAUTHENTICATED (code 401)`. The bogus file was the only credential in play,
60
+ so the load path really did come from the file.
61
+ - That is *not* enough for a lock-free design, because the keyring is
62
+ keyring-first on the SAVE side too (`Failed to save token to keyring,
63
+ falling back to file` — the file is only written when the keyring write
64
+ fails). Any successful run therefore repopulates the single global entry,
65
+ and the next spawn on a different account would inherit it. (Inferred from
66
+ the binary's strings; not yet reproduced with a live token save.)
67
+ - Net: per-account credential isolation is read-path only. The machine-wide
68
+ entry still needs an owner, so identity SWITCHES stay serialized — but only
69
+ until the child has read the credential (see above), not for the whole run.
44
70
  - **No credential CLI flag**: `agy --help` exposes no `--api-key` /
45
71
  `--credential*` / `--token*` option.
72
+ - **`JETSKI_OAUTH_TOKEN` exists in the binary but is IGNORED (re-measured
73
+ 2026-10-22).** `agy.exe` contains the string pair
74
+ `JETSKI_OAUTH_TOKEN` + `Using OAuth token from environment variable`, so it
75
+ looked like the per-process injection route. Probing it directly: a brand-new
76
+ isolated HOME with `JETSKI_OAUTH_TOKEN=bogus-token-should-fail` still
77
+ completed a prompt (`exit 0`, `PROBE_OK`) — the variable is not consulted on
78
+ this build (1.4.3), and with no per-HOME token file either, the credential
79
+ could only have come from the machine keyring. The string belongs to another
80
+ auth product in the same binary.
46
81
  - **Documented env routes are different auth products**: `AGY_ADC_AUTH`
47
82
  (Application Default Credentials / Agent Platform), and
48
83
  `GEMINI_API_KEY` + `"modelProvider": "gemini"` in `settings.json` (the Gemini
@@ -72,9 +107,32 @@ reference-counted slot is the strongest isolation the plugin can provide.
72
107
  - **DSH tools to agy (reverse MCP bridge)** - available since v0.2 behind the
73
108
  `mcpBridge` config flag (experimental): the plugin runs a loopback-only,
74
109
  token-guarded HTTP endpoint and registers a zero-dependency stdio MCP
75
- server (`dsh-tools`) in the workspace `.mcp.json` (merged in, restored on
76
- disable). `run_code` and `agy_ask` are never bridged; `mcpToolAllowlist`
77
- restricts the set further.
110
+ server in the MCP registry (`~/.gemini/config/mcp_config.json` by default,
111
+ where `agy` 1.4+ actually reads it, merged in and restored on disable).
112
+ Bridged calls carry caller identity via `DSH_MCP_SESSION` so identity-enforcing
113
+ tools (such as `agent_teams`) function correctly. `run_code` and `agy_ask`
114
+ are never bridged; `mcpToolAllowlist` restricts the set further.
115
+ Every bridged call is audit-logged as `mcp call <tool> [<outcome>] <ms>` with
116
+ the caller class and the failure text (never the arguments), so a failed run
117
+ is visible in journald instead of only in transcripts.
118
+ - **DSH `send_message` from an agy child** - DSH's sub-agent runtime appends a
119
+ footer telling the child to report with `send_message({ agent_id: <parent> })`.
120
+ In an agy run that name resolves to agy's **own** `send_message`, which does
121
+ not know DSH agent ids and fails with `recipient "..." not found`. The DSH
122
+ tool itself is bridgeable - add `send_message` to `mcpToolAllowlist` and call
123
+ it explicitly on the `dsh-tools-<port>` MCP server (agy dispatches MCP calls
124
+ by server + tool name, so there is no collision with the native tool). The
125
+ footer still names the native one, so an agy member should report through
126
+ `agent_teams_send_message` (or an explicit instruction) instead. Root cause is
127
+ upstream in `@deepseek-ai/dsh-subagent`, which assumes a DSH-native child.
128
+ - **Weekly quota auto-warmup is opt-in (v0.4.74+)** - `autoWarmup` defaults to
129
+ `false` because the feature deliberately bypasses the CLI-first quota path and
130
+ sends minimal `loadCodeAssist` + `generateContent` probes straight to Google's
131
+ internal endpoints. When enabled it scans every 5 minutes, only targets rows
132
+ whose `weeklyFraction` is explicitly >= 99.9%, records a 30-minute failure
133
+ backoff, skips accounts in cooldown / auth quarantine, and never guesses a
134
+ missing `cloudaicompanionProject` (no shared fallback project id). The manual
135
+ "Warmup" buttons still work while auto mode is off.
78
136
  - **Full tool args / diff cards (v0.4.28+)** - the bridge reads agy's
79
137
  conversation SQLite DB via the `sqlite3` CLI to recover arguments that
80
138
  `filterToolParameters` strips from stream-json. When `sqlite3` is missing
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-agy-link",
3
- "version": "0.4.67",
3
+ "version": "0.4.74",
4
4
  "description": "Google Antigravity (agy CLI) models for DeepSeek Harness — stream Gemini/Claude/GPT-OSS subscriptions into DSH with thinking, tool activity, token usage and in-GUI Google OAuth login.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -97,6 +97,7 @@
97
97
  "build": "tsdown",
98
98
  "check": "tsc --noEmit",
99
99
  "test": "node --experimental-transform-types --test --test-concurrency=1 \"test/**/*.test.ts\"",
100
+ "test:fast": "node scripts/fast-test.mjs",
100
101
  "prepare": "npm run build",
101
102
  "prepack": "npm run build"
102
103
  },