anyray-connect 0.2.0 → 0.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.
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Seat-state detection — does this machine already have a subscription sign-in
3
+ * for each provider family? This is what makes the one-command flow autonomous:
4
+ * `authMode: 'auto'` reads it and rides the dev's own seat when present, falling
5
+ * back to the org key when not. No human input, no flags.
6
+ *
7
+ * Best-effort and SILENT: every probe is wrapped so a missing file, a denied
8
+ * keychain, or a slow `security` call resolves to "not signed in" rather than
9
+ * throwing — a detection miss just means we fall back to the org key, which
10
+ * always works. We read only whether a credential EXISTS, never its value: a
11
+ * keychain *metadata* lookup (no `-w`) doesn't prompt and doesn't expose the
12
+ * secret, and credential files are probed with `fileExists`, not read. The seat
13
+ * token itself stays in the tool; connect never holds it.
14
+ *
15
+ * Signals (macOS-first, since that's where coding tools mostly run):
16
+ * - Anthropic (Claude Code): `CLAUDE_CODE_OAUTH_TOKEN` env, `~/.claude/.oauth_token`,
17
+ * `~/.claude/.credentials.json` (Linux), or the macOS Keychain item
18
+ * `Claude Code-credentials`.
19
+ * - OpenAI (Codex): `~/.codex/auth.json` carrying a ChatGPT `tokens.access_token`
20
+ * (an API-key-only `auth.json` is NOT a subscription seat).
21
+ */
22
+ import { homedir, platform } from 'node:os';
23
+ import { join } from 'node:path';
24
+ import { execFile } from 'node:child_process';
25
+ import { readFile } from 'node:fs/promises';
26
+ import { fileExists } from './jsonFile.js';
27
+ const KEYCHAIN_TIMEOUT_MS = 3000;
28
+ const CLAUDE_KEYCHAIN_SERVICE = 'Claude Code-credentials';
29
+ /** True if a Keychain generic-password item exists for `service`. Metadata-only
30
+ * lookup (no `-w`) so macOS does NOT prompt and the secret is never read. */
31
+ const keychainHasItem = (service) => new Promise((resolve) => {
32
+ try {
33
+ const child = execFile('security', ['find-generic-password', '-s', service], { timeout: KEYCHAIN_TIMEOUT_MS }, (err) => resolve(!err));
34
+ child.on('error', () => resolve(false));
35
+ }
36
+ catch {
37
+ resolve(false);
38
+ }
39
+ });
40
+ /** Detect an Anthropic subscription seat (Claude Code). */
41
+ export const detectAnthropicSeat = async () => {
42
+ if (process.env.CLAUDE_CODE_OAUTH_TOKEN?.trim())
43
+ return true;
44
+ const claudeDir = join(homedir(), '.claude');
45
+ if (await fileExists(join(claudeDir, '.oauth_token')))
46
+ return true;
47
+ if (await fileExists(join(claudeDir, '.credentials.json')))
48
+ return true;
49
+ if (platform() === 'darwin' && (await keychainHasItem(CLAUDE_KEYCHAIN_SERVICE))) {
50
+ return true;
51
+ }
52
+ return false;
53
+ };
54
+ /** Detect a ChatGPT subscription seat (Codex) — a `tokens.access_token` in
55
+ * `~/.codex/auth.json`. An API-key-only file is a keyed login, not a seat. */
56
+ export const detectOpenAiSeat = async () => {
57
+ const authPath = join(process.env.CODEX_HOME?.trim() || join(homedir(), '.codex'), 'auth.json');
58
+ if (!(await fileExists(authPath)))
59
+ return false;
60
+ try {
61
+ const parsed = JSON.parse(await readFile(authPath, 'utf-8'));
62
+ return typeof parsed.tokens?.access_token === 'string' &&
63
+ parsed.tokens.access_token.trim() !== ''
64
+ ? true
65
+ : false;
66
+ }
67
+ catch {
68
+ return false;
69
+ }
70
+ };
71
+ /** Detect seat sign-in for every provider family in parallel. Never throws. */
72
+ export const detectSeatState = async () => {
73
+ const [anthropic, openai] = await Promise.all([
74
+ detectAnthropicSeat(),
75
+ detectOpenAiSeat(),
76
+ ]);
77
+ return { anthropic, openai };
78
+ };
79
+ //# sourceMappingURL=seatState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seatState.js","sourceRoot":"","sources":["../../src/util/seatState.ts"],"names":[],"mappings":"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"}
@@ -74,6 +74,10 @@ export const resolveSetupLink = async (link, opts = {}) => {
74
74
  if (!gatewayUrl) {
75
75
  throw new Error('this setup link has no gateway configured yet — ask your admin to add a gateway in the Anyray console, then re-run.');
76
76
  }
77
- return { gatewayUrl, org: optionalString(body.org) };
77
+ return {
78
+ gatewayUrl,
79
+ org: optionalString(body.org),
80
+ seatMode: body.seatMode === true,
81
+ };
78
82
  };
79
83
  //# sourceMappingURL=setupLink.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"setupLink.js","sourceRoot":"","sources":["../../src/util/setupLink.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"setupLink.js","sourceRoot":"","sources":["../../src/util/setupLink.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Local, deterministic trimming of oversized tool outputs.
3
+ *
4
+ * This is the cache-SAFE half of Anyray's optimization: it runs inside Claude
5
+ * Code (a `PostToolUse` hook) and caps a bulky tool result the moment it's
6
+ * produced — BEFORE it enters the conversation and gets a `cache_control`
7
+ * prefix. Trimming here keeps the cached prefix coherent (the trimmed text is
8
+ * what gets cached and re-sent every later turn), unlike a gateway rewrite that
9
+ * mutates already-cached content and busts Anthropic's prefix cache.
10
+ *
11
+ * The trim is lossy-but-bounded by design: we keep the head (orientation) and
12
+ * the tail (the result/conclusion — where the signal usually is for logs, shell
13
+ * output, and search dumps) and elide the middle behind a CONTENT-FREE marker.
14
+ * No network, no model call, no stash — a `connect` hook can't reach the
15
+ * gateway's `/v1/retrieve`, so this trades reversibility for cache-safety and
16
+ * zero data exposure. Char-based (a ~4 chars/token heuristic) to stay
17
+ * dependency-free and fast on the hot path.
18
+ *
19
+ * PRIVACY: nothing here logs or transmits the content; the marker carries only
20
+ * counts. The trimmed text is handed straight back to Claude Code.
21
+ */
22
+ /** ~4 chars per token — the standard rough heuristic; good enough for a metric. */
23
+ const CHARS_PER_TOKEN = 4;
24
+ export const DEFAULT_TRIM = {
25
+ maxChars: 12_000,
26
+ headChars: 6_000,
27
+ tailChars: 4_000,
28
+ };
29
+ const passthrough = (text) => ({
30
+ text,
31
+ trimmed: false,
32
+ originalChars: text.length,
33
+ trimmedChars: text.length,
34
+ estTokensSaved: 0,
35
+ });
36
+ /**
37
+ * Trim a single string. Keeps `headChars` + a content-free marker + `tailChars`
38
+ * when the input exceeds `maxChars`; otherwise returns it untouched. Clamps the
39
+ * head/tail budget so the result is always strictly shorter than the original.
40
+ */
41
+ export const trimText = (input, opts = {}) => {
42
+ if (typeof input !== 'string')
43
+ return passthrough(String(input ?? ''));
44
+ const maxChars = Math.max(1, opts.maxChars ?? DEFAULT_TRIM.maxChars);
45
+ if (input.length <= maxChars)
46
+ return passthrough(input);
47
+ let headChars = Math.max(0, opts.headChars ?? DEFAULT_TRIM.headChars);
48
+ let tailChars = Math.max(0, opts.tailChars ?? DEFAULT_TRIM.tailChars);
49
+ // Never keep so much that we fail to shrink: cap the kept budget under maxChars
50
+ // (leave room for the marker), preferring to shave the head first.
51
+ const keepBudget = maxChars - 1;
52
+ if (headChars + tailChars > keepBudget) {
53
+ tailChars = Math.min(tailChars, keepBudget);
54
+ headChars = Math.max(0, keepBudget - tailChars);
55
+ }
56
+ const head = input.slice(0, headChars);
57
+ const tail = tailChars > 0 ? input.slice(input.length - tailChars) : '';
58
+ const elided = input.length - head.length - tail.length;
59
+ const estTokensSaved = Math.round(elided / CHARS_PER_TOKEN);
60
+ const marker = `\n\n…[anyray-hook trimmed ${elided} chars (~${estTokensSaved} tokens) — full output elided locally, cache-safe]…\n\n`;
61
+ const text = head + marker + tail;
62
+ // Degenerate guard: if the marker made it longer (tiny maxChars), don't trim.
63
+ if (text.length >= input.length)
64
+ return passthrough(input);
65
+ return {
66
+ text,
67
+ trimmed: true,
68
+ originalChars: input.length,
69
+ trimmedChars: text.length,
70
+ estTokensSaved,
71
+ };
72
+ };
73
+ /** Keys whose string value is treated as the trimmable body of a tool output. */
74
+ const BODY_KEYS = ['stdout', 'content', 'output', 'text', 'result'];
75
+ /**
76
+ * Locate the trimmable text inside a tool output whose shape varies by tool
77
+ * (Bash `{stdout,stderr,exit_code}`, Read `{content}`, a bare string for some
78
+ * tools/MCP, …). Returns the body string plus a `rebuild` that puts a
79
+ * (possibly optimized) string back in the SAME field, preserving the structure
80
+ * Claude Code expects. Defensive about field names: first known body key, else
81
+ * the longest string-valued field. Returns null when there's nothing to trim.
82
+ */
83
+ export const extractToolOutputBody = (output) => {
84
+ if (typeof output === 'string') {
85
+ return { body: output, rebuild: (s) => s };
86
+ }
87
+ if (!output || typeof output !== 'object' || Array.isArray(output)) {
88
+ return null;
89
+ }
90
+ const obj = output;
91
+ let key = BODY_KEYS.find((k) => typeof obj[k] === 'string');
92
+ if (!key) {
93
+ let bestLen = -1;
94
+ for (const [k, v] of Object.entries(obj)) {
95
+ if (typeof v === 'string' && v.length > bestLen) {
96
+ key = k;
97
+ bestLen = v.length;
98
+ }
99
+ }
100
+ }
101
+ if (!key)
102
+ return null;
103
+ const field = key;
104
+ return { body: obj[field], rebuild: (s) => ({ ...obj, [field]: s }) };
105
+ };
106
+ /**
107
+ * Trim the body of a tool output locally (the fail-open fallback when the
108
+ * gateway/optimizer is unreachable — the smart strategies run server-side, see
109
+ * commands/hook.ts). Returns the rebuilt value plus the trim metrics.
110
+ */
111
+ export const trimToolOutput = (output, opts = {}) => {
112
+ const found = extractToolOutputBody(output);
113
+ if (!found)
114
+ return { value: output, result: passthrough('') };
115
+ const result = trimText(found.body, opts);
116
+ if (!result.trimmed)
117
+ return { value: output, result };
118
+ return { value: found.rebuild(result.text), result };
119
+ };
120
+ //# sourceMappingURL=trimOutput.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trimOutput.js","sourceRoot":"","sources":["../../src/util/trimOutput.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Post-apply smoke test — confirm the connection actually works, with the same
3
+ * shape of request the configured tool will send, and turn any failure into one
4
+ * specific next step instead of a cryptic 4xx on the dev's first real request.
5
+ *
6
+ * Two paths, because the two modes authenticate differently:
7
+ * - org key (placeholder): the gateway key is the bearer; we probe the
8
+ * OpenAI-compatible `/v1/chat/completions`. A 2xx means the gateway accepted
9
+ * the key and routed upstream end-to-end.
10
+ * - seat (subscription): the seat OAuth token lives in the *tool*, not connect,
11
+ * so we DON'T need (or want) the secret. We send a sentinel bearer with the
12
+ * pass-through headers to `/v1/messages` and read where it lands: if the
13
+ * gateway forwards it to Anthropic (which rejects the sentinel as an invalid
14
+ * bearer), pass-through is wired and the dev's real seat will work; if it
15
+ * comes back a Bedrock/org-provider error, pass-through ISN'T honored. This
16
+ * verifies the part connect owns — the gateway routing — without a keychain
17
+ * prompt and without ever false-alarming on a stale token (the tool itself
18
+ * tells the dev to re-`/login` if their seat lapsed).
19
+ *
20
+ * PRIVACY: probe bodies are fixed synthetic "ping"s — no user content; the
21
+ * sentinel is a literal non-secret string. Responses are read only to classify
22
+ * status + error type, never logged as content.
23
+ */
24
+ import { effectiveSubscription, metadataHeaderValue } from '../types.js';
25
+ const VERIFY_TIMEOUT_MS = 12_000;
26
+ /** A deliberately-invalid bearer for the seat-wiring probe. Not a secret; its
27
+ * only job is to be rejected by whatever upstream the gateway forwards it to,
28
+ * so we can tell Anthropic-passthrough from org-provider routing. */
29
+ const WIRING_SENTINEL = 'anyray-wiring-probe-not-a-real-token';
30
+ /** Smallest valid OpenAI-style body; `anyray-default` lets gateway routing pick
31
+ * the real model/provider. `max_tokens: 1` keeps the probe a fraction of a cent. */
32
+ const PLACEHOLDER_PROBE_BODY = {
33
+ model: 'anyray-default',
34
+ messages: [{ role: 'user', content: 'ping' }],
35
+ max_tokens: 1,
36
+ };
37
+ /** Smallest valid Anthropic-style body for the seat-wiring probe. */
38
+ const WIRING_PROBE_BODY = {
39
+ model: 'claude-3-5-haiku-20241022',
40
+ max_tokens: 1,
41
+ messages: [{ role: 'user', content: 'ping' }],
42
+ };
43
+ /** A short, content-free snippet of an error body for the status line. */
44
+ const snippet = (bodyText) => {
45
+ const oneLine = bodyText.replace(/\s+/g, ' ').trim();
46
+ return oneLine.length > 160 ? `${oneLine.slice(0, 157)}…` : oneLine;
47
+ };
48
+ /** True when the body looks like the org's Bedrock path answered instead of the
49
+ * intended provider — the tell that pass-through didn't happen. */
50
+ const looksLikeOrgProvider = (bodyText) => {
51
+ const lower = bodyText.toLowerCase();
52
+ return lower.includes('bedrock') || lower.includes('unsupported model');
53
+ };
54
+ /** Classify the org-key probe (OpenAI-compatible completion). */
55
+ export const classifyPlaceholder = (status, bodyText) => {
56
+ if (status >= 200 && status < 300) {
57
+ return {
58
+ kind: 'ok',
59
+ detail: 'gateway served a completion with the org key — traffic flows.',
60
+ remedy: [],
61
+ };
62
+ }
63
+ if (status === 401 || status === 403) {
64
+ if (looksLikeOrgProvider(bodyText)) {
65
+ return {
66
+ kind: 'routed-elsewhere',
67
+ detail: `gateway routed to the org provider and it rejected the request: ${snippet(bodyText)}`,
68
+ remedy: [
69
+ 'The org provider rejected the request — check the gateway’s provider',
70
+ 'key/config (e.g. the model is enabled for that account).',
71
+ ],
72
+ };
73
+ }
74
+ return {
75
+ kind: 'key-rejected',
76
+ detail: `gateway rejected the key (HTTP ${status}).`,
77
+ remedy: [
78
+ 'The key was refused — the setup link may be expired; ask your admin for a fresh one.',
79
+ ],
80
+ };
81
+ }
82
+ return {
83
+ kind: 'unknown',
84
+ detail: `gateway responded HTTP ${status}: ${snippet(bodyText)}`,
85
+ remedy: [],
86
+ };
87
+ };
88
+ /** Classify the seat-wiring probe (sentinel bearer through the gateway). */
89
+ export const classifySeatWiring = (status, bodyText) => {
90
+ if (looksLikeOrgProvider(bodyText)) {
91
+ return {
92
+ kind: 'routed-elsewhere',
93
+ detail: 'gateway sent the request to the org provider, not your subscription.',
94
+ remedy: [
95
+ 'Pass-through isn’t being honored for this gateway — your seat token would',
96
+ 'not be used. Check the gateway is current (subscription pass-through support).',
97
+ ],
98
+ };
99
+ }
100
+ const lower = bodyText.toLowerCase();
101
+ // The sentinel reaching Anthropic and being rejected as a bad bearer is the
102
+ // SUCCESS signal: it proves the gateway forwards seat auth to Anthropic, so
103
+ // the dev's real (valid) seat token will be honored.
104
+ if (status === 401 ||
105
+ lower.includes('authentication_error') ||
106
+ lower.includes('invalid bearer') ||
107
+ lower.includes('"provider":"anthropic"')) {
108
+ return {
109
+ kind: 'ok',
110
+ detail: 'gateway passes your sign-in through to Anthropic — your Claude seat will be used.',
111
+ remedy: [],
112
+ };
113
+ }
114
+ if (status >= 200 && status < 300) {
115
+ return {
116
+ kind: 'ok',
117
+ detail: 'gateway pass-through reached the provider — your seat will be used.',
118
+ remedy: [],
119
+ };
120
+ }
121
+ return {
122
+ kind: 'unknown',
123
+ detail: `seat-wiring probe got HTTP ${status}: ${snippet(bodyText)}`,
124
+ remedy: [],
125
+ };
126
+ };
127
+ const probe = async (url, headers, body, timeoutMs) => {
128
+ const controller = new AbortController();
129
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
130
+ try {
131
+ const res = await fetch(url, {
132
+ method: 'POST',
133
+ headers: { 'content-type': 'application/json', ...headers },
134
+ body: JSON.stringify(body),
135
+ signal: controller.signal,
136
+ });
137
+ return { status: res.status, bodyText: await res.text() };
138
+ }
139
+ finally {
140
+ clearTimeout(timer);
141
+ }
142
+ };
143
+ const unreachable = (timeoutMs, error) => {
144
+ const reason = error instanceof Error && error.name === 'AbortError'
145
+ ? `no response within ${timeoutMs}ms`
146
+ : error instanceof Error
147
+ ? error.message
148
+ : String(error);
149
+ return {
150
+ kind: 'unreachable',
151
+ detail: `could not reach the gateway to verify (${reason}).`,
152
+ remedy: [
153
+ 'Your config was still written — re-run the curl below once the gateway is reachable.',
154
+ ],
155
+ };
156
+ };
157
+ /**
158
+ * Probe the gateway with the auth the Anthropic-family tool will use and return
159
+ * a classified verdict. Never throws — a transport failure becomes `unreachable`
160
+ * (the config was still written; the dev can re-test by hand). Anthropic is the
161
+ * representative family: its org path and its seat-passthrough path are exactly
162
+ * what this smoke test distinguishes.
163
+ */
164
+ export const verifyConnection = async (target, opts = {}) => {
165
+ const timeoutMs = opts.timeoutMs ?? VERIFY_TIMEOUT_MS;
166
+ const meta = metadataHeaderValue(target.metadata);
167
+ try {
168
+ if (effectiveSubscription(target, 'anthropic')) {
169
+ const headers = {
170
+ Authorization: `Bearer ${WIRING_SENTINEL}`,
171
+ 'anthropic-version': '2023-06-01',
172
+ 'anthropic-beta': 'oauth-2025-04-20',
173
+ 'x-anyray-auth-mode': 'passthrough',
174
+ 'x-anyray-provider': 'anthropic',
175
+ };
176
+ if (meta)
177
+ headers['x-anyray-metadata'] = meta;
178
+ const { status, bodyText } = await probe(`${target.anthropicBaseUrl}/v1/messages`, headers, WIRING_PROBE_BODY, timeoutMs);
179
+ return classifySeatWiring(status, bodyText);
180
+ }
181
+ const key = target.clientKey ?? target.placeholderKey;
182
+ const headers = { Authorization: `Bearer ${key}` };
183
+ if (meta)
184
+ headers['x-anyray-metadata'] = meta;
185
+ const { status, bodyText } = await probe(`${target.openaiBaseUrl}/chat/completions`, headers, PLACEHOLDER_PROBE_BODY, timeoutMs);
186
+ return classifyPlaceholder(status, bodyText);
187
+ }
188
+ catch (error) {
189
+ return unreachable(timeoutMs, error);
190
+ }
191
+ };
192
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/util/verify.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anyray-connect",
3
- "version": "0.2.0",
3
+ "version": "0.5.0",
4
4
  "description": "Anyray connect — points local coding tools (Claude Code, Cursor, Windsurf, SDKs) at the Anyray gateway by writing their base URL + a placeholder key. The gateway stays the brain; this is just the on-ramp.",
5
5
  "type": "module",
6
6
  "bin": {