anyray-connect 0.3.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +88 -7
- package/dist/cli.js.map +1 -1
- package/dist/commands/hook.js +233 -0
- package/dist/commands/hook.js.map +1 -0
- package/dist/target.js +11 -1
- package/dist/target.js.map +1 -1
- package/dist/tools/claudeCode.js +103 -3
- package/dist/tools/claudeCode.js.map +1 -1
- package/dist/tools/codex.js +3 -3
- package/dist/tools/codex.js.map +1 -1
- package/dist/tools/shellEnv.js +40 -8
- package/dist/tools/shellEnv.js.map +1 -1
- package/dist/types.js +13 -0
- package/dist/types.js.map +1 -1
- package/dist/util/seatState.js +79 -0
- package/dist/util/seatState.js.map +1 -0
- package/dist/util/trimOutput.js +120 -0
- package/dist/util/trimOutput.js.map +1 -0
- package/dist/util/verify.js +192 -0
- package/dist/util/verify.js.map +1 -0
- package/package.json +1 -1
package/dist/tools/claudeCode.js
CHANGED
|
@@ -25,16 +25,96 @@
|
|
|
25
25
|
*
|
|
26
26
|
* We only own these keys — any other settings/env the user has are preserved.
|
|
27
27
|
*/
|
|
28
|
-
import { homedir } from 'node:os';
|
|
28
|
+
import { homedir, tmpdir } from 'node:os';
|
|
29
29
|
import { join } from 'node:path';
|
|
30
30
|
import { readJson, writeJson, fileExists } from '../util/jsonFile.js';
|
|
31
|
-
import { metadataHeaderValue } from '../types.js';
|
|
31
|
+
import { effectiveSubscription, metadataHeaderValue } from '../types.js';
|
|
32
32
|
const settingsPath = () => join(homedir(), '.claude', 'settings.json');
|
|
33
33
|
const OWNED_KEYS = [
|
|
34
34
|
'ANTHROPIC_BASE_URL',
|
|
35
35
|
'ANTHROPIC_AUTH_TOKEN',
|
|
36
36
|
'ANTHROPIC_CUSTOM_HEADERS',
|
|
37
37
|
];
|
|
38
|
+
/** Unique flag that identifies the Anyray PostToolUse hook command (so re-apply
|
|
39
|
+
* and revert can find/replace exactly our entry, never the user's own hooks). */
|
|
40
|
+
const HOOK_FLAG = '__anyray-hook';
|
|
41
|
+
/**
|
|
42
|
+
* The command Claude Code runs for the PostToolUse hook: re-invoke this very
|
|
43
|
+
* `anyray-connect` in hidden hook mode. The standalone (Bun-compiled) binary —
|
|
44
|
+
* the zero-install distribution — IS `process.execPath`, so we invoke it
|
|
45
|
+
* directly; under Node/npx (`node dist/index.js`) we re-invoke the entry script
|
|
46
|
+
* under node. Quoted for paths with spaces.
|
|
47
|
+
*/
|
|
48
|
+
const hookCommand = () => {
|
|
49
|
+
const quote = (s) => (/\s/.test(s) ? JSON.stringify(s) : s);
|
|
50
|
+
const exe = process.execPath;
|
|
51
|
+
const runsUnderNode = /[\\/](node|node\.exe)$/i.test(exe);
|
|
52
|
+
const script = process.argv[1];
|
|
53
|
+
const base = runsUnderNode && script ? `${quote(exe)} ${quote(script)}` : quote(exe);
|
|
54
|
+
return `${base} ${HOOK_FLAG}`;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* The executable the installed hook command will re-invoke: the compiled binary
|
|
58
|
+
* itself, or (under node) the entry script. This is the path that must survive
|
|
59
|
+
* for the hook to keep working.
|
|
60
|
+
*/
|
|
61
|
+
const hookBinaryPath = () => {
|
|
62
|
+
const exe = process.execPath;
|
|
63
|
+
const runsUnderNode = /[\\/](node|node\.exe)$/i.test(exe);
|
|
64
|
+
return runsUnderNode && process.argv[1] ? process.argv[1] : exe;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* The hook command embeds an absolute path that Claude Code runs on every tool
|
|
68
|
+
* call — so it must point at a DURABLE binary. The zero-install `connect.sh`
|
|
69
|
+
* historically ran the binary from a `mktemp` dir; once the OS reaps `/tmp`, a
|
|
70
|
+
* hook pointing there silently breaks. If we're running from temp space, skip
|
|
71
|
+
* the hook (and say so) rather than write a command that will rot. `connect.sh`
|
|
72
|
+
* now installs the binary under `~/.anyray/bin`, so the normal path is durable.
|
|
73
|
+
*/
|
|
74
|
+
/** True when a path lives in OS temp space (where a hook command would rot). */
|
|
75
|
+
export const isEphemeralBinaryPath = (p) => {
|
|
76
|
+
const roots = [tmpdir(), '/tmp', '/var/folders', '/private/var/folders'];
|
|
77
|
+
return roots.some((r) => !!r && (p === r || p.startsWith(r.endsWith('/') ? r : `${r}/`)));
|
|
78
|
+
};
|
|
79
|
+
const hookBinaryIsDurable = () => !isEphemeralBinaryPath(hookBinaryPath());
|
|
80
|
+
const entryIsOurs = (entry) => {
|
|
81
|
+
const e = entry;
|
|
82
|
+
return (Array.isArray(e?.hooks) &&
|
|
83
|
+
e.hooks.some((h) => typeof h?.command === 'string' && h.command.includes(HOOK_FLAG)));
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Install (idempotently) our PostToolUse hook into the settings object. Omitting
|
|
87
|
+
* `matcher` matches every tool; a size gate in the hook itself means small
|
|
88
|
+
* outputs pass through untouched. Drops any prior Anyray entry first so a
|
|
89
|
+
* re-apply (or a changed binary path) replaces rather than duplicates it.
|
|
90
|
+
*/
|
|
91
|
+
const installHook = (settings) => {
|
|
92
|
+
const hooks = settings.hooks ?? {};
|
|
93
|
+
const list = Array.isArray(hooks.PostToolUse)
|
|
94
|
+
? hooks.PostToolUse
|
|
95
|
+
: [];
|
|
96
|
+
const cleaned = list.filter((e) => !entryIsOurs(e));
|
|
97
|
+
cleaned.push({ hooks: [{ type: 'command', command: hookCommand() }] });
|
|
98
|
+
hooks.PostToolUse = cleaned;
|
|
99
|
+
settings.hooks = hooks;
|
|
100
|
+
};
|
|
101
|
+
/** Remove our PostToolUse hook, pruning empty containers. Returns true if found. */
|
|
102
|
+
const removeHook = (settings) => {
|
|
103
|
+
const hooks = settings.hooks;
|
|
104
|
+
if (!hooks || !Array.isArray(hooks.PostToolUse))
|
|
105
|
+
return false;
|
|
106
|
+
const list = hooks.PostToolUse;
|
|
107
|
+
const cleaned = list.filter((e) => !entryIsOurs(e));
|
|
108
|
+
if (cleaned.length === list.length)
|
|
109
|
+
return false;
|
|
110
|
+
if (cleaned.length === 0)
|
|
111
|
+
delete hooks.PostToolUse;
|
|
112
|
+
else
|
|
113
|
+
hooks.PostToolUse = cleaned;
|
|
114
|
+
if (Object.keys(hooks).length === 0)
|
|
115
|
+
delete settings.hooks;
|
|
116
|
+
return true;
|
|
117
|
+
};
|
|
38
118
|
const customHeaders = (meta, subscription, clientKey) => {
|
|
39
119
|
// No provider pin in placeholder mode: the gateway's routing config owns
|
|
40
120
|
// that decision (see the module comment).
|
|
@@ -68,7 +148,9 @@ export const claudeCode = {
|
|
|
68
148
|
},
|
|
69
149
|
async apply(target, opts) {
|
|
70
150
|
const path = settingsPath();
|
|
71
|
-
|
|
151
|
+
// Anthropic family: subscription when forced, or (in auto mode) when a
|
|
152
|
+
// Claude seat was detected on this machine; else the org key.
|
|
153
|
+
const subscription = effectiveSubscription(target, 'anthropic');
|
|
72
154
|
const meta = metadataHeaderValue(target.metadata);
|
|
73
155
|
const headers = customHeaders(meta, subscription, target.clientKey);
|
|
74
156
|
const env = {
|
|
@@ -113,6 +195,19 @@ export const claudeCode = {
|
|
|
113
195
|
}
|
|
114
196
|
delete settings.env.ANTHROPIC_AUTH_TOKEN;
|
|
115
197
|
}
|
|
198
|
+
// Install the cache-safe PostToolUse hook: it trims oversized tool outputs
|
|
199
|
+
// (before they enter the cached prefix) and reports content-free savings.
|
|
200
|
+
// Applies in both auth modes — trimming helps subscription seats (usage
|
|
201
|
+
// caps/overage) and org-key billing alike. Skipped if we're running from a
|
|
202
|
+
// temp path, where the hook command would rot once the OS reaps it.
|
|
203
|
+
if (hookBinaryIsDurable()) {
|
|
204
|
+
installHook(settings);
|
|
205
|
+
messages.push('Installed a PostToolUse hook: trims oversized tool outputs (cache-safe) and reports content-free savings.');
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
removeHook(settings); // drop any stale hook a prior temp run may have left
|
|
209
|
+
messages.push(`Skipped the PostToolUse hook — anyray-connect is running from a temporary path (${hookBinaryPath()}). Re-run via the installer (it persists the binary under ~/.anyray/bin) or a global install to enable cache-safe tool-output trimming.`);
|
|
210
|
+
}
|
|
116
211
|
await writeJson(path, settings);
|
|
117
212
|
return { status: 'configured', messages, changedFiles: [path] };
|
|
118
213
|
},
|
|
@@ -146,14 +241,19 @@ export const claudeCode = {
|
|
|
146
241
|
}
|
|
147
242
|
const settings = await readJson(path);
|
|
148
243
|
const env = settings.env;
|
|
244
|
+
const hookRemoved = removeHook(settings);
|
|
149
245
|
if (env) {
|
|
150
246
|
for (const key of OWNED_KEYS)
|
|
151
247
|
delete env[key];
|
|
152
248
|
if (Object.keys(env).length === 0)
|
|
153
249
|
delete settings.env;
|
|
250
|
+
}
|
|
251
|
+
if (env || hookRemoved) {
|
|
154
252
|
await writeJson(path, settings);
|
|
155
253
|
}
|
|
156
254
|
const messages = [`removed Anyray keys from ${path}`];
|
|
255
|
+
if (hookRemoved)
|
|
256
|
+
messages.push('Removed the Anyray PostToolUse hook.');
|
|
157
257
|
// Revert only deletes our keys; if apply overwrote a pre-existing value
|
|
158
258
|
// (e.g. you already set ANTHROPIC_BASE_URL), point at the backup.
|
|
159
259
|
if (await fileExists(`${path}.anyray-bak`)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claudeCode.js","sourceRoot":"","sources":["../../src/tools/claudeCode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"claudeCode.js","sourceRoot":"","sources":["../../src/tools/claudeCode.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/codex.js
CHANGED
|
@@ -40,7 +40,7 @@ import { join } from 'node:path';
|
|
|
40
40
|
import { writeFile, rm } from 'node:fs/promises';
|
|
41
41
|
import { fileExists } from '../util/jsonFile.js';
|
|
42
42
|
import { removeProfileBlock } from '../util/profile.js';
|
|
43
|
-
import { metadataHeaderValue } from '../types.js';
|
|
43
|
+
import { effectiveSubscription, metadataHeaderValue } from '../types.js';
|
|
44
44
|
/** Model Codex sends when ANYRAY_CODEX_MODEL is unset; the gateway's default
|
|
45
45
|
* routing decides the real model/provider, so this is just a required token. */
|
|
46
46
|
const DEFAULT_MODEL = 'anyray-default';
|
|
@@ -92,7 +92,7 @@ const resolveModel = (subscription) => {
|
|
|
92
92
|
/** Full contents of the standalone profile file (flat top-level keys). */
|
|
93
93
|
const profileFile = (target) => {
|
|
94
94
|
const meta = codexMetadata(target);
|
|
95
|
-
const subscription = target
|
|
95
|
+
const subscription = effectiveSubscription(target, 'openai');
|
|
96
96
|
// Subscription traffic is ChatGPT-backend-only — the provider pin is not
|
|
97
97
|
// the operator's call there, so ANYRAY_CODEX_PROVIDER applies only to
|
|
98
98
|
// placeholder mode.
|
|
@@ -152,7 +152,7 @@ export const codex = {
|
|
|
152
152
|
async apply(target, opts) {
|
|
153
153
|
const path = profilePath();
|
|
154
154
|
const meta = codexMetadata(target);
|
|
155
|
-
const subscription = target
|
|
155
|
+
const subscription = effectiveSubscription(target, 'openai');
|
|
156
156
|
const model = resolveModel(subscription);
|
|
157
157
|
const messages = [
|
|
158
158
|
`${path} ← standalone Codex profile (model_provider = anyray)`,
|
package/dist/tools/codex.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/tools/codex.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAQxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/tools/codex.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/shellEnv.js
CHANGED
|
@@ -7,20 +7,34 @@
|
|
|
7
7
|
* headers, so per-request `x-anyray-metadata` attribution isn't set here —
|
|
8
8
|
* attribution for these falls back to the gateway's defaults. Tools that DO
|
|
9
9
|
* support headers (Claude Code) have their own adapter.
|
|
10
|
+
*
|
|
11
|
+
* SEATS — export keys PER FAMILY: a placeholder `OPENAI_API_KEY` /
|
|
12
|
+
* `ANTHROPIC_AUTH_TOKEN` exported here is not just useless against a seat, it is
|
|
13
|
+
* actively harmful — the seat-based tools (Claude Code, Codex) read these
|
|
14
|
+
* process-env vars with HIGHER precedence than their own config, so the
|
|
15
|
+
* placeholder silently overrides the seat sign-in and forces the request off the
|
|
16
|
+
* subscription onto the org's default provider. So we export a family's key only
|
|
17
|
+
* when that family is NOT on a seat (resolved via `effectiveSubscription`). Base
|
|
18
|
+
* URLs are always safe (they only redirect to the gateway; a seat tool still
|
|
19
|
+
* supplies its own token). Raw SDK/script callers on a seat must bring their own
|
|
20
|
+
* credential for that family.
|
|
10
21
|
*/
|
|
11
22
|
import { detectProfilePath, removeProfileBlock, upsertProfileBlock } from '../util/profile.js';
|
|
12
23
|
import { fileExists } from '../util/jsonFile.js';
|
|
13
24
|
import { maskKey } from '../util/redeem.js';
|
|
25
|
+
import { effectiveSubscription } from '../types.js';
|
|
14
26
|
// Single-quote the values: shells treat single-quoted strings literally, so a
|
|
15
27
|
// `$`, backtick, or double-quote in a URL/key can't trigger expansion or break
|
|
16
28
|
// out of the assignment. (Single quotes themselves can't appear in these.)
|
|
17
29
|
// The exported key is the dev's personal gateway key (from an invite) when
|
|
18
|
-
// present, else the shared placeholder.
|
|
19
|
-
|
|
30
|
+
// present, else the shared placeholder. A family on a seat exports its base URL
|
|
31
|
+
// only and NO key (see the module comment — a placeholder token here hijacks
|
|
32
|
+
// that tool's own sign-in).
|
|
33
|
+
const envLines = (target, key, openaiSeat, anthropicSeat) => [
|
|
20
34
|
`export OPENAI_BASE_URL='${target.openaiBaseUrl}'`,
|
|
21
|
-
`export OPENAI_API_KEY='${key}'
|
|
35
|
+
...(openaiSeat ? [] : [`export OPENAI_API_KEY='${key}'`]),
|
|
22
36
|
`export ANTHROPIC_BASE_URL='${target.anthropicBaseUrl}'`,
|
|
23
|
-
`export ANTHROPIC_AUTH_TOKEN='${key}'
|
|
37
|
+
...(anthropicSeat ? [] : [`export ANTHROPIC_AUTH_TOKEN='${key}'`]),
|
|
24
38
|
];
|
|
25
39
|
export const shellEnv = {
|
|
26
40
|
id: 'shell-env',
|
|
@@ -35,19 +49,37 @@ export const shellEnv = {
|
|
|
35
49
|
},
|
|
36
50
|
async apply(target, opts) {
|
|
37
51
|
const path = detectProfilePath();
|
|
52
|
+
// Per family: a detected/forced seat means the tool owns its own auth, so we
|
|
53
|
+
// must NOT export that family's key (it would override the seat sign-in).
|
|
54
|
+
const openaiSeat = effectiveSubscription(target, 'openai');
|
|
55
|
+
const anthropicSeat = effectiveSubscription(target, 'anthropic');
|
|
56
|
+
const anySeat = openaiSeat || anthropicSeat;
|
|
38
57
|
const key = target.clientKey ?? target.placeholderKey;
|
|
39
|
-
const lines = envLines(target, key);
|
|
58
|
+
const lines = envLines(target, key, openaiSeat, anthropicSeat);
|
|
40
59
|
// Console output masks a personal key (the file gets the real one) — a
|
|
41
60
|
// terminal/scrollback should never show the full credential.
|
|
42
61
|
const shownLines = target.clientKey
|
|
43
|
-
? envLines(target, maskKey(target.clientKey))
|
|
62
|
+
? envLines(target, maskKey(target.clientKey), openaiSeat, anthropicSeat)
|
|
44
63
|
: lines;
|
|
64
|
+
const seatLabel = openaiSeat && anthropicSeat
|
|
65
|
+
? 'either family'
|
|
66
|
+
: openaiSeat
|
|
67
|
+
? 'OpenAI'
|
|
68
|
+
: 'Anthropic';
|
|
45
69
|
const messages = [
|
|
46
70
|
`${path} ← managed Anyray block`,
|
|
47
71
|
...shownLines.map((l) => ` ${l}`),
|
|
48
72
|
`Run \`source ${path}\` or open a new terminal to apply.`,
|
|
49
|
-
|
|
50
|
-
|
|
73
|
+
...(anySeat
|
|
74
|
+
? [
|
|
75
|
+
`No auth token exported for ${seatLabel} — your seat-based tool keeps`,
|
|
76
|
+
'its own sign-in (a placeholder here would override it). Raw SDK/script',
|
|
77
|
+
'calls on a seat need your own key.',
|
|
78
|
+
]
|
|
79
|
+
: [
|
|
80
|
+
'Note: standard SDK env vars carry no per-user header, so attribution',
|
|
81
|
+
'for these falls back to the gateway default.',
|
|
82
|
+
]),
|
|
51
83
|
];
|
|
52
84
|
if (opts.dryRun)
|
|
53
85
|
return { status: 'configured', messages };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shellEnv.js","sourceRoot":"","sources":["../../src/tools/shellEnv.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"shellEnv.js","sourceRoot":"","sources":["../../src/tools/shellEnv.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
CHANGED
|
@@ -12,6 +12,19 @@
|
|
|
12
12
|
* grouping only (user/team/intent/session), matching the gateway's
|
|
13
13
|
* `x-anyray-metadata` contract.
|
|
14
14
|
*/
|
|
15
|
+
/**
|
|
16
|
+
* Resolve whether a given provider family should use subscription pass-through
|
|
17
|
+
* for this target. The single place that interprets `authMode` so adapters
|
|
18
|
+
* don't each re-derive it: forced modes win; `auto` defers to the detected
|
|
19
|
+
* `seat` state (absent → org key, the safe fallback).
|
|
20
|
+
*/
|
|
21
|
+
export const effectiveSubscription = (target, family) => {
|
|
22
|
+
if (target.authMode === 'subscription')
|
|
23
|
+
return true;
|
|
24
|
+
if (target.authMode === 'placeholder')
|
|
25
|
+
return false;
|
|
26
|
+
return target.seat?.[family] ?? false;
|
|
27
|
+
};
|
|
15
28
|
/** Build the `x-anyray-metadata` header value, or undefined when empty. */
|
|
16
29
|
export const metadataHeaderValue = (metadata) => {
|
|
17
30
|
const entries = Object.entries(metadata).filter(([, v]) => v);
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAqFH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,MAAqB,EACrB,MAAuB,EACd,EAAE;IACX,IAAI,MAAM,CAAC,QAAQ,KAAK,cAAc;QAAE,OAAO,IAAI,CAAC;IACpD,IAAI,MAAM,CAAC,QAAQ,KAAK,aAAa;QAAE,OAAO,KAAK,CAAC;IACpD,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC;AACxC,CAAC,CAAC;AAoDF,2EAA2E;AAC3E,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,QAA6B,EACT,EAAE;IACtB,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IAC9D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC3C,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC;AACrD,CAAC,CAAC"}
|
|
@@ -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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"}
|
|
@@ -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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"}
|