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.
@@ -28,13 +28,69 @@
28
28
  import { homedir } 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
+ const entryIsOurs = (entry) => {
57
+ const e = entry;
58
+ return (Array.isArray(e?.hooks) &&
59
+ e.hooks.some((h) => typeof h?.command === 'string' && h.command.includes(HOOK_FLAG)));
60
+ };
61
+ /**
62
+ * Install (idempotently) our PostToolUse hook into the settings object. Omitting
63
+ * `matcher` matches every tool; a size gate in the hook itself means small
64
+ * outputs pass through untouched. Drops any prior Anyray entry first so a
65
+ * re-apply (or a changed binary path) replaces rather than duplicates it.
66
+ */
67
+ const installHook = (settings) => {
68
+ const hooks = settings.hooks ?? {};
69
+ const list = Array.isArray(hooks.PostToolUse)
70
+ ? hooks.PostToolUse
71
+ : [];
72
+ const cleaned = list.filter((e) => !entryIsOurs(e));
73
+ cleaned.push({ hooks: [{ type: 'command', command: hookCommand() }] });
74
+ hooks.PostToolUse = cleaned;
75
+ settings.hooks = hooks;
76
+ };
77
+ /** Remove our PostToolUse hook, pruning empty containers. Returns true if found. */
78
+ const removeHook = (settings) => {
79
+ const hooks = settings.hooks;
80
+ if (!hooks || !Array.isArray(hooks.PostToolUse))
81
+ return false;
82
+ const list = hooks.PostToolUse;
83
+ const cleaned = list.filter((e) => !entryIsOurs(e));
84
+ if (cleaned.length === list.length)
85
+ return false;
86
+ if (cleaned.length === 0)
87
+ delete hooks.PostToolUse;
88
+ else
89
+ hooks.PostToolUse = cleaned;
90
+ if (Object.keys(hooks).length === 0)
91
+ delete settings.hooks;
92
+ return true;
93
+ };
38
94
  const customHeaders = (meta, subscription, clientKey) => {
39
95
  // No provider pin in placeholder mode: the gateway's routing config owns
40
96
  // that decision (see the module comment).
@@ -68,7 +124,9 @@ export const claudeCode = {
68
124
  },
69
125
  async apply(target, opts) {
70
126
  const path = settingsPath();
71
- const subscription = target.authMode === 'subscription';
127
+ // Anthropic family: subscription when forced, or (in auto mode) when a
128
+ // Claude seat was detected on this machine; else the org key.
129
+ const subscription = effectiveSubscription(target, 'anthropic');
72
130
  const meta = metadataHeaderValue(target.metadata);
73
131
  const headers = customHeaders(meta, subscription, target.clientKey);
74
132
  const env = {
@@ -113,9 +171,32 @@ export const claudeCode = {
113
171
  }
114
172
  delete settings.env.ANTHROPIC_AUTH_TOKEN;
115
173
  }
174
+ // Install the cache-safe PostToolUse hook: it trims oversized tool outputs
175
+ // locally (before they enter the cached prefix) and beacons content-free
176
+ // savings to the gateway. Applies in both auth modes — trimming helps
177
+ // subscription seats (usage caps/overage) and org-key billing alike.
178
+ installHook(settings);
179
+ messages.push('Installed a PostToolUse hook: trims oversized tool outputs locally (cache-safe) and reports content-free savings.');
116
180
  await writeJson(path, settings);
117
181
  return { status: 'configured', messages, changedFiles: [path] };
118
182
  },
183
+ skillsDir() {
184
+ return join(homedir(), '.claude', 'skills');
185
+ },
186
+ async pointsAt(origin) {
187
+ const path = settingsPath();
188
+ if (!(await fileExists(path)))
189
+ return false;
190
+ try {
191
+ const settings = await readJson(path);
192
+ const env = settings.env;
193
+ const base = env?.ANTHROPIC_BASE_URL;
194
+ return typeof base === 'string' && base.replace(/\/+$/, '') === origin;
195
+ }
196
+ catch {
197
+ return false;
198
+ }
199
+ },
119
200
  async revert(opts) {
120
201
  const path = settingsPath();
121
202
  if (!(await fileExists(path))) {
@@ -129,14 +210,19 @@ export const claudeCode = {
129
210
  }
130
211
  const settings = await readJson(path);
131
212
  const env = settings.env;
213
+ const hookRemoved = removeHook(settings);
132
214
  if (env) {
133
215
  for (const key of OWNED_KEYS)
134
216
  delete env[key];
135
217
  if (Object.keys(env).length === 0)
136
218
  delete settings.env;
219
+ }
220
+ if (env || hookRemoved) {
137
221
  await writeJson(path, settings);
138
222
  }
139
223
  const messages = [`removed Anyray keys from ${path}`];
224
+ if (hookRemoved)
225
+ messages.push('Removed the Anyray PostToolUse hook.');
140
226
  // Revert only deletes our keys; if apply overwrote a pre-existing value
141
227
  // (e.g. you already set ANTHROPIC_BASE_URL), point at the backup.
142
228
  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;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAQtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAElD,MAAM,YAAY,GAAG,GAAW,EAAE,CAChC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;AAE9C,MAAM,UAAU,GAAG;IACjB,oBAAoB;IACpB,sBAAsB;IACtB,0BAA0B;CAClB,CAAC;AAEX,MAAM,aAAa,GAAG,CACpB,IAAwB,EACxB,YAAqB,EACrB,SAA6B,EACrB,EAAE;IACV,yEAAyE;IACzE,0CAA0C;IAC1C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,YAAY,EAAE,CAAC;QACjB,mEAAmE;QACnE,wEAAwE;QACxE,0DAA0D;QAC1D,KAAK,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;QAC3C,KAAK,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;QAC9C,uEAAuE;QACvE,4DAA4D;QAC5D,IAAI,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,qBAAqB,SAAS,EAAE,CAAC,CAAC;IAC9D,CAAC;IACD,IAAI,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,sBAAsB,IAAI,EAAE,CAAC,CAAC;IACnD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAgB;IACrC,EAAE,EAAE,aAAa;IACjB,KAAK,EAAE,aAAa;IACpB,SAAS,EAAE,IAAI;IAEf,KAAK,CAAC,MAAM;QACV,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;QACxC,MAAM,SAAS,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;QACzC,OAAO;YACL,SAAS;YACT,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,wBAAwB;SAC9D,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,KAAK,CACT,MAAqB,EACrB,IAAkB;QAElB,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;QAC5B,MAAM,YAAY,GAAG,MAAM,CAAC,QAAQ,KAAK,cAAc,CAAC;QACxD,MAAM,IAAI,GAAG,mBAAmB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAClD,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;QACpE,MAAM,GAAG,GAA2B;YAClC,kBAAkB,EAAE,MAAM,CAAC,gBAAgB;YAC3C,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,wBAAwB,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzD,qEAAqE;YACrE,gEAAgE;YAChE,sEAAsE;YACtE,qEAAqE;YACrE,mEAAmE;YACnE,GAAG,CAAC,YAAY;gBACd,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,EAAE,oBAAoB,EAAE,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,cAAc,EAAE,CAAC;SACzE,CAAC;QAEF,MAAM,QAAQ,GAAG;YACf,GAAG,IAAI,+BAA+B,MAAM,CAAC,gBAAgB,EAAE;YAC/D,YAAY;gBACV,CAAC,CAAC,qHACE,MAAM,CAAC,SAAS;oBACd,CAAC,CAAC,oDAAoD;oBACtD,CAAC,CAAC,EACN,EAAE;gBACJ,CAAC,CAAC,MAAM,CAAC,SAAS;oBAChB,CAAC,CAAC,oEAAoE;oBACtE,CAAC,CAAC,gEAAgE;YACtE,gBAAgB,IAAI,IAAI,QAAQ,EAAE;YAClC,oEAAoE;SACrE,CAAC;QACF,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC;QAE3D,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC;QACtC,MAAM,WAAW,GACd,QAAQ,CAAC,GAA0C,IAAI,EAAE,CAAC;QAC7D,QAAQ,CAAC,GAAG,GAAG,EAAE,GAAG,WAAW,EAAE,GAAG,GAAG,EAAE,CAAC;QAC1C,yEAAyE;QACzE,2EAA2E;QAC3E,iBAAiB;QACjB,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAQ,QAAQ,CAAC,GAA8B,CAAC,wBAAwB,CAAC;QAC3E,CAAC;QACD,IAAI,YAAY,EAAE,CAAC;YACjB,wEAAwE;YACxE,IAAI,WAAW,CAAC,oBAAoB,EAAE,CAAC;gBACrC,QAAQ,CAAC,IAAI,CACX,iFAAiF,CAClF,CAAC;YACJ,CAAC;YACD,OAAQ,QAAQ,CAAC,GAA8B,CAAC,oBAAoB,CAAC;QACvE,CAAC;QACD,MAAM,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAEhC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;IAClE,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAkB;QAC7B,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;QAC5B,IAAI,CAAC,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;YAC9B,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,mBAAmB,CAAC,EAAE,CAAC;QAClE,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,OAAO;gBACL,MAAM,EAAE,UAAU;gBAClB,QAAQ,EAAE,CAAC,iCAAiC,IAAI,EAAE,CAAC;aACpD,CAAC;QACJ,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC;QACtC,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAyC,CAAC;QAC/D,IAAI,GAAG,EAAE,CAAC;YACR,KAAK,MAAM,GAAG,IAAI,UAAU;gBAAE,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC;YAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,QAAQ,CAAC,GAAG,CAAC;YACvD,MAAM,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAClC,CAAC;QACD,MAAM,QAAQ,GAAG,CAAC,4BAA4B,IAAI,EAAE,CAAC,CAAC;QACtD,wEAAwE;QACxE,kEAAkE;QAClE,IAAI,MAAM,UAAU,CAAC,GAAG,IAAI,aAAa,CAAC,EAAE,CAAC;YAC3C,QAAQ,CAAC,IAAI,CAAC,wBAAwB,IAAI,0CAA0C,CAAC,CAAC;QACxF,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;IAChE,CAAC;CACF,CAAC"}
1
+ {"version":3,"file":"claudeCode.js","sourceRoot":"","sources":["../../src/tools/claudeCode.ts"],"names":[],"mappings":"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"}
@@ -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.authMode === 'subscription';
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.authMode === 'subscription';
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)`,
@@ -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;AAElD;iFACiF;AACjF,MAAM,aAAa,GAAG,gBAAgB,CAAC;AAEvC;;uBAEuB;AACvB,MAAM,cAAc,GAAG,OAAO,CAAC;AAC/B,MAAM,oBAAoB,GAAG,WAAW,CAAC;AAEzC;iEACiE;AACjE,MAAM,qBAAqB,GAAG,uCAAuC,CAAC;AAEtE;;;+EAG+E;AAC/E,MAAM,4BAA4B,GAChC,iHAAiH,CAAC;AAEpH,4EAA4E;AAC5E,MAAM,SAAS,GAAG,GAAW,EAAE,CAC7B,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;AAE9D;gFACgF;AAChF,MAAM,cAAc,GAAG,GAAW,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,aAAa,CAAC,CAAC;AACtE,MAAM,WAAW,GAAG,GAAW,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,oBAAoB,CAAC,CAAC;AAE1E;;;;;GAKG;AACH,MAAM,aAAa,GAAG,CAAC,MAAqB,EAAsB,EAAE,CAClE,mBAAmB,CAAC;IAClB,GAAG,MAAM,CAAC,QAAQ;IAClB,MAAM,EACJ,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,IAAI,EAAE;QACvC,MAAM,CAAC,QAAQ,CAAC,MAAM;QACtB,cAAc;IAChB,WAAW,EACT,OAAO,CAAC,GAAG,CAAC,yBAAyB,EAAE,IAAI,EAAE;QAC7C,MAAM,CAAC,QAAQ,CAAC,WAAW;QAC3B,oBAAoB;CACvB,CAAC,CAAC;AAEL,+DAA+D;AAC/D,MAAM,UAAU,GAAG,CAAC,KAAa,EAAU,EAAE,CAC3C,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC;AAE3D;;4DAE4D;AAC5D,MAAM,YAAY,GAAG,CAAC,YAAqB,EAAsB,EAAE;IACjE,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,IAAI,EAAE,CAAC;IACxD,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC9B,OAAO,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC;AAClD,CAAC,CAAC;AAEF,0EAA0E;AAC1E,MAAM,WAAW,GAAG,CAAC,MAAqB,EAAU,EAAE;IACpD,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACnC,MAAM,YAAY,GAAG,MAAM,CAAC,QAAQ,KAAK,cAAc,CAAC;IACxD,yEAAyE;IACzE,sEAAsE;IACtE,oBAAoB;IACpB,MAAM,QAAQ,GAAG,YAAY;QAC3B,CAAC,CAAC,QAAQ;QACV,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE,IAAI,EAAE,CAAC;IAC9C,MAAM,KAAK,GAAG,YAAY,CAAC,YAAY,CAAC,CAAC;IAEzC,0EAA0E;IAC1E,2EAA2E;IAC3E,wEAAwE;IACxE,MAAM,OAAO,GAAa,YAAY;QACpC,CAAC,CAAC;YACE,uEAAuE;YACvE,qEAAqE;YACrE,sCAAsC;YACtC,4BAA4B,UAAU,CAAC,qBAAqB,CAAC,EAAE;YAC/D,gCAAgC,UAAU,CAAC,4BAA4B,CAAC,EAAE;YAC1E,GAAG,CAAC,MAAM,CAAC,SAAS;gBAClB,CAAC,CAAC,CAAC,wBAAwB,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC1D,CAAC,CAAC,EAAE,CAAC;SACR;QACH,CAAC,CAAC;YACE,qBAAqB,UAAU,CAC7B,UAAU,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,cAAc,EAAE,CACtD,EAAE;SACJ,CAAC;IACN,IAAI,IAAI;QAAE,OAAO,CAAC,IAAI,CAAC,yBAAyB,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACpE,IAAI,QAAQ;QAAE,OAAO,CAAC,IAAI,CAAC,yBAAyB,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAE5E,MAAM,KAAK,GAAG;QACZ,wEAAwE;QACxE,oEAAoE;QACpE,qCAAqC;QACrC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAClD,2BAA2B;QAC3B,EAAE;QACF,0BAA0B;QAC1B,yBAAyB;QACzB,cAAc,UAAU,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE;QAChD,wBAAwB;QACxB,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,6BAA6B,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACxD,oBAAoB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;KAC3C,CAAC;IACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AACjC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,KAAK,GAAgB;IAChC,EAAE,EAAE,OAAO;IACX,KAAK,EAAE,WAAW;IAClB,SAAS,EAAE,IAAI;IAEf,KAAK,CAAC,MAAM;QACV,MAAM,IAAI,GAAG,SAAS,EAAE,CAAC;QACzB,MAAM,SAAS,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;QACzC,OAAO;YACL,SAAS;YACT,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,YAAY;SAC3D,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,MAAqB,EAAE,IAAkB;QACnD,MAAM,IAAI,GAAG,WAAW,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;QACnC,MAAM,YAAY,GAAG,MAAM,CAAC,QAAQ,KAAK,cAAc,CAAC;QACxD,MAAM,KAAK,GAAG,YAAY,CAAC,YAAY,CAAC,CAAC;QAEzC,MAAM,QAAQ,GAAG;YACf,GAAG,IAAI,uDAAuD;YAC9D,aAAa,MAAM,CAAC,aAAa,oCAAoC;YACrE,YAAY;gBACV,CAAC,CAAC,+LAA+L;gBACjM,CAAC,CAAC,UAAU,KAAK,GACb,OAAO,CAAC,GAAG,CAAC,kBAAkB;oBAC5B,CAAC,CAAC,EAAE;oBACJ,CAAC,CAAC,iEACN,EAAE;YACN,GAAG,CAAC,YAAY,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB;gBACjD,CAAC,CAAC;oBACE,6FAA6F;iBAC9F;gBACH,CAAC,CAAC,EAAE,CAAC;YACP,gBAAgB,IAAI,IAAI,sBAAsB,EAAE;YAChD,6DAA6D;YAC7D,qDAAqD;SACtD,CAAC;QACF,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC;QAE3D,sEAAsE;QACtE,yEAAyE;QACzE,4EAA4E;QAC5E,MAAM,SAAS,CAAC,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;QAC3C,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,cAAc,EAAE,CAAC,CAAC;QAC5D,IAAI,QAAQ,EAAE,CAAC;YACb,QAAQ,CAAC,IAAI,CACX,6DAA6D,cAAc,EAAE,GAAG,CACjF,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;IAClE,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAkB;QAC7B,MAAM,IAAI,GAAG,WAAW,EAAE,CAAC;QAC3B,MAAM,UAAU,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;QAC1C,6EAA6E;QAC7E,MAAM,IAAI,GAAG,cAAc,EAAE,CAAC;QAC9B,MAAM,SAAS,GAAG,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;YACxC,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE;gBAChB,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;oBAChB,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;oBACtD,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,CAC7C,0BAA0B,CAC3B,CAAC;gBACJ,CAAC;gBACD,OAAO,kBAAkB,CAAC,IAAI,CAAC,CAAC;YAClC,CAAC,CAAC,EAAE;YACN,CAAC,CAAC,KAAK,CAAC;QAEV,IAAI,CAAC,UAAU,IAAI,CAAC,SAAS,EAAE,CAAC;YAC9B,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,mBAAmB,CAAC,EAAE,CAAC;QAClE,CAAC;QAED,MAAM,OAAO,GAAa,EAAE,CAAC;QAC7B,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,IAAI,UAAU,EAAE,CAAC;YACf,IAAI,CAAC,IAAI,CAAC,MAAM;gBAAE,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAClD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACnB,QAAQ,CAAC,IAAI,CACX,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,gBAAgB,IAAI,EAAE,CAAC,CAAC,CAAC,WAAW,IAAI,EAAE,CACzD,CAAC;QACJ,CAAC;QACD,IAAI,SAAS,EAAE,CAAC;YACd,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACnB,QAAQ,CAAC,IAAI,CACX,IAAI,CAAC,MAAM;gBACT,CAAC,CAAC,6CAA6C,IAAI,EAAE;gBACrD,CAAC,CAAC,wCAAwC,IAAI,EAAE,CACnD,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC;IACjE,CAAC;CACF,CAAC"}
1
+ {"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/tools/codex.ts"],"names":[],"mappings":"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"}
@@ -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
- const envLines = (target, key) => [
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
- 'Note: standard SDK env vars carry no per-user header, so attribution',
50
- 'for these falls back to the gateway default.',
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":"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"}
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;AAoGH,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"}
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"}
@@ -1,11 +1,35 @@
1
- import { writeFile, readFile, chmod } from 'node:fs/promises';
1
+ import { writeFile, readFile, chmod, stat } from 'node:fs/promises';
2
2
  import { homedir } from 'node:os';
3
3
  import { join } from 'node:path';
4
- const profilePath = () => join(homedir(), '.anyray');
5
- /** Read ~/.anyray; returns {} on missing or corrupt file. */
4
+ // Resolved per-call (not cached) so a changed $HOME is always honored.
5
+ const stateDir = () => join(homedir(), '.anyray');
6
+ /**
7
+ * Where the connect profile lives.
8
+ *
9
+ * Historically this is the file `~/.anyray`. But a locally-run Anyray gateway
10
+ * uses `~/.anyray/` as its DATA DIRECTORY (audit logs etc.), so on a machine
11
+ * that also runs the gateway, `~/.anyray` is a directory and writing it as a
12
+ * file fails with EISDIR. Resolve the collision: when `~/.anyray` is a
13
+ * directory, store the profile as a file inside it; otherwise use the simple
14
+ * `~/.anyray` file. The two states are mutually exclusive (a path is a file or
15
+ * a directory, never both), so no migration is needed.
16
+ */
17
+ const profilePath = async () => {
18
+ const dir = stateDir();
19
+ try {
20
+ if ((await stat(dir)).isDirectory()) {
21
+ return join(dir, 'connect.json');
22
+ }
23
+ }
24
+ catch {
25
+ /* missing → use the simple ~/.anyray file path */
26
+ }
27
+ return dir;
28
+ };
29
+ /** Read the connect profile; returns {} on missing or corrupt file. */
6
30
  export const loadProfile = async () => {
7
31
  try {
8
- const raw = await readFile(profilePath(), 'utf-8');
32
+ const raw = await readFile(await profilePath(), 'utf-8');
9
33
  const parsed = JSON.parse(raw);
10
34
  if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed))
11
35
  return {};
@@ -15,13 +39,14 @@ export const loadProfile = async () => {
15
39
  return {};
16
40
  }
17
41
  };
18
- /** Write ~/.anyray (mode 600) — replaced, not merged, so cleared values stay cleared. */
42
+ /** Write the connect profile (mode 600) — replaced, not merged, so cleared values stay cleared. */
19
43
  export const saveProfile = async (profile) => {
20
44
  const clean = Object.fromEntries(Object.entries(profile).filter(([, v]) => v !== undefined));
21
- await writeFile(profilePath(), `${JSON.stringify(clean, null, 2)}\n`, {
45
+ const path = await profilePath();
46
+ await writeFile(path, `${JSON.stringify(clean, null, 2)}\n`, {
22
47
  mode: 0o600,
23
48
  });
24
49
  // mode only applies on creation — tighten a pre-existing file too.
25
- await chmod(profilePath(), 0o600);
50
+ await chmod(path, 0o600);
26
51
  };
27
52
  //# sourceMappingURL=persist.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"persist.js","sourceRoot":"","sources":["../../src/util/persist.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAQjC,MAAM,WAAW,GAAG,GAAW,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;AAE7D,6DAA6D;AAC7D,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,IAA4B,EAAE;IAC5D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE,EAAE,OAAO,CAAC,CAAC;QACnD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;YAAE,OAAO,EAAE,CAAC;QACtF,OAAO,MAAuB,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC,CAAC;AAEF,yFAAyF;AACzF,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,EAAE,OAAsB,EAAiB,EAAE;IACzE,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAC9B,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAC1C,CAAC;IACnB,MAAM,SAAS,CAAC,WAAW,EAAE,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;QACpE,IAAI,EAAE,KAAK;KACZ,CAAC,CAAC;IACH,mEAAmE;IACnE,MAAM,KAAK,CAAC,WAAW,EAAE,EAAE,KAAK,CAAC,CAAC;AACpC,CAAC,CAAC"}
1
+ {"version":3,"file":"persist.js","sourceRoot":"","sources":["../../src/util/persist.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AA0BjC,uEAAuE;AACvE,MAAM,QAAQ,GAAG,GAAW,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;AAE1D;;;;;;;;;;GAUG;AACH,MAAM,WAAW,GAAG,KAAK,IAAqB,EAAE;IAC9C,MAAM,GAAG,GAAG,QAAQ,EAAE,CAAC;IACvB,IAAI,CAAC;QACH,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;YACpC,OAAO,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,kDAAkD;IACpD,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC,CAAC;AAEF,uEAAuE;AACvE,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,IAA4B,EAAE;IAC5D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,MAAM,WAAW,EAAE,EAAE,OAAO,CAAC,CAAC;QACzD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;YAAE,OAAO,EAAE,CAAC;QACtF,OAAO,MAAuB,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC,CAAC;AAEF,mGAAmG;AACnG,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,EAAE,OAAsB,EAAiB,EAAE;IACzE,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAC9B,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAC1C,CAAC;IACnB,MAAM,IAAI,GAAG,MAAM,WAAW,EAAE,CAAC;IACjC,MAAM,SAAS,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;QAC3D,IAAI,EAAE,KAAK;KACZ,CAAC,CAAC;IACH,mEAAmE;IACnE,MAAM,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAC3B,CAAC,CAAC"}
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Team skills/policy sync (client side).
3
+ *
4
+ * `anyray-connect sync` pulls the org's shared skills/instructions from the
5
+ * gateway and writes them as `SKILL.md` files into each supported coding tool's
6
+ * skills directory (e.g. Claude Code `~/.claude/skills/<id>/SKILL.md`). This is
7
+ * content-free TEAM POLICY text (instructions the org wants its tools to
8
+ * follow) — it is NOT user prompt/response content, so writing it to disk is
9
+ * fine and does not touch the privacy invariant.
10
+ *
11
+ * Contract (gateway-side): `GET <gatewayUrl>/connect/policy` with header
12
+ * `x-anyray-api-key: <personal key or placeholder>` → 200
13
+ * { "skills": [ { "id", "name", "version", "body" } ], "updatedAt": "ISO" }
14
+ *
15
+ * On a non-200 or a network error we fail gracefully with a clear message
16
+ * (never crash). The last-synced version per skill is tracked in ~/.anyray so
17
+ * re-runs only rewrite files whose `version` changed.
18
+ */
19
+ import { mkdir, writeFile } from 'node:fs/promises';
20
+ import { join } from 'node:path';
21
+ const POLICY_TIMEOUT_MS = 10_000;
22
+ const optionalString = (value) => typeof value === 'string' && value.trim() ? value.trim() : undefined;
23
+ /**
24
+ * A skill `id` becomes a directory name (`<skillsDir>/<id>/SKILL.md`). The
25
+ * gateway only validates it as non-empty, so a malicious or mistyped id like
26
+ * `../../evil` would escape the skills dir and write SKILL.md anywhere. Restrict
27
+ * it to a single safe path segment: a leading alphanumeric, then alphanumerics,
28
+ * `.`, `_`, `-` — which excludes `/`, `\`, `..`, and absolute paths.
29
+ */
30
+ const isSafeSkillId = (id) => /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(id) && id !== '.' && id !== '..';
31
+ /**
32
+ * Fetch the team policy from the gateway. Throws an Error with a clear,
33
+ * content-free message on non-200 or network failure — callers catch it and
34
+ * print it (no crash).
35
+ */
36
+ export const fetchTeamPolicy = async (gatewayUrl, apiKey, opts = {}) => {
37
+ const timeoutMs = opts.timeoutMs ?? POLICY_TIMEOUT_MS;
38
+ const url = `${gatewayUrl}/connect/policy`;
39
+ const controller = new AbortController();
40
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
41
+ let res;
42
+ try {
43
+ res = await fetch(url, {
44
+ method: 'GET',
45
+ headers: { 'x-anyray-api-key': apiKey },
46
+ signal: controller.signal,
47
+ });
48
+ }
49
+ catch (error) {
50
+ const reason = error instanceof Error && error.name === 'AbortError'
51
+ ? `no response within ${timeoutMs}ms`
52
+ : error instanceof Error
53
+ ? error.message
54
+ : String(error);
55
+ throw new Error(`could not reach the gateway at ${url}: ${reason}`);
56
+ }
57
+ finally {
58
+ clearTimeout(timer);
59
+ }
60
+ if (!res.ok) {
61
+ throw new Error(`team policy fetch failed: the gateway responded ${res.status} at ${url}`);
62
+ }
63
+ let body;
64
+ try {
65
+ body = (await res.json());
66
+ }
67
+ catch {
68
+ throw new Error('team policy fetch failed: the gateway returned a malformed response');
69
+ }
70
+ const rawSkills = Array.isArray(body.skills) ? body.skills : [];
71
+ const skills = [];
72
+ for (const raw of rawSkills) {
73
+ const entry = raw;
74
+ const id = optionalString(entry?.id);
75
+ const version = optionalString(entry?.version);
76
+ // Skip entries that can't be keyed/diffed; an id+version are required for
77
+ // the SKILL.md path and the version diff. Reject ids that aren't a safe path
78
+ // segment — they'd let a hostile policy write outside the skills dir.
79
+ if (!id || !version || !isSafeSkillId(id))
80
+ continue;
81
+ skills.push({
82
+ id,
83
+ name: optionalString(entry?.name) ?? id,
84
+ version,
85
+ body: typeof entry?.body === 'string' ? entry.body : '',
86
+ });
87
+ }
88
+ return { skills, updatedAt: optionalString(body.updatedAt) };
89
+ };
90
+ /**
91
+ * Diff the fetched policy against the previously synced versions and write
92
+ * `SKILL.md` for every skill whose version changed into each provided skills
93
+ * dir. Returns a content-free summary plus the new version baseline to persist.
94
+ *
95
+ * Pure I/O over the inputs — fetching and persistence are the caller's job, so
96
+ * this stays unit-testable with a real temp dir and no network.
97
+ */
98
+ export const syncPolicyToDirs = async (policy, skillsDirs, previousVersions) => {
99
+ const results = [];
100
+ const versions = {};
101
+ let changed = 0;
102
+ let unchanged = 0;
103
+ for (const skill of policy.skills) {
104
+ // Defense-in-depth: never turn an unsafe id into a write path, even if a
105
+ // caller passed skills that didn't go through fetchTeamPolicy's filter.
106
+ if (!isSafeSkillId(skill.id))
107
+ continue;
108
+ versions[skill.id] = skill.version;
109
+ const isUpToDate = previousVersions[skill.id] === skill.version;
110
+ if (isUpToDate) {
111
+ unchanged += 1;
112
+ results.push({
113
+ id: skill.id,
114
+ name: skill.name,
115
+ version: skill.version,
116
+ written: false,
117
+ files: [],
118
+ });
119
+ continue;
120
+ }
121
+ const files = [];
122
+ for (const dir of skillsDirs) {
123
+ const skillDir = join(dir, skill.id);
124
+ const file = join(skillDir, 'SKILL.md');
125
+ await mkdir(skillDir, { recursive: true });
126
+ // Skill bodies are team policy text (content-free); persisting them is
127
+ // intended. A trailing newline keeps the files diff-friendly.
128
+ await writeFile(file, ensureTrailingNewline(skill.body), 'utf-8');
129
+ files.push(file);
130
+ }
131
+ changed += 1;
132
+ results.push({
133
+ id: skill.id,
134
+ name: skill.name,
135
+ version: skill.version,
136
+ written: true,
137
+ files,
138
+ });
139
+ }
140
+ return { results, changed, unchanged, versions, updatedAt: policy.updatedAt };
141
+ };
142
+ const ensureTrailingNewline = (body) => body.endsWith('\n') ? body : `${body}\n`;
143
+ //# sourceMappingURL=policySync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policySync.js","sourceRoot":"","sources":["../../src/util/policySync.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Personal savings readout — the tangible number that ends onboarding.
3
+ *
4
+ * Contract (gateway-side): `GET <origin>/connect/savings` with header
5
+ * `x-anyray-api-key: <personal key or placeholder>` → 200
6
+ * { "tokensSaved": number, "savingsUsd": number,
7
+ * "requestCount": number, "windowDays": number }
8
+ *
9
+ * Best-effort: an older gateway returns 404 (or the network fails); callers
10
+ * silently skip the savings line — it must NEVER break the apply flow. Brand-new
11
+ * users see all-zero numbers, which we render as an encouraging "start sending
12
+ * traffic" line rather than "$0.00".
13
+ *
14
+ * PRIVACY: the endpoint returns content-free aggregates only (token counts, a
15
+ * dollar figure, a request count). Nothing here touches prompt/response content.
16
+ */
17
+ const SAVINGS_TIMEOUT_MS = 5000;
18
+ const finiteNumber = (value) => typeof value === 'number' && Number.isFinite(value) ? value : 0;
19
+ /**
20
+ * Fetch the dev's content-free savings, or `undefined` on any error / non-200
21
+ * (older gateway, network hiccup). Never throws — onboarding must not break.
22
+ */
23
+ export const fetchSavings = async (origin, apiKey, opts = {}) => {
24
+ const timeoutMs = opts.timeoutMs ?? SAVINGS_TIMEOUT_MS;
25
+ const url = `${origin}/connect/savings`;
26
+ const controller = new AbortController();
27
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
28
+ try {
29
+ const res = await fetch(url, {
30
+ method: 'GET',
31
+ headers: { 'x-anyray-api-key': apiKey },
32
+ signal: controller.signal,
33
+ });
34
+ if (!res.ok)
35
+ return undefined;
36
+ const body = (await res.json());
37
+ return {
38
+ tokensSaved: finiteNumber(body.tokensSaved),
39
+ savingsUsd: finiteNumber(body.savingsUsd),
40
+ requestCount: finiteNumber(body.requestCount),
41
+ windowDays: finiteNumber(body.windowDays),
42
+ };
43
+ }
44
+ catch {
45
+ return undefined;
46
+ }
47
+ finally {
48
+ clearTimeout(timer);
49
+ }
50
+ };
51
+ /** Round to whole tokens and group with thousands separators. */
52
+ const formatTokens = (tokens) => Math.round(tokens).toLocaleString('en-US');
53
+ /** Two-decimal USD, e.g. `$12.30`. */
54
+ const formatUsd = (usd) => `$${usd.toLocaleString('en-US', {
55
+ minimumFractionDigits: 2,
56
+ maximumFractionDigits: 2,
57
+ })}`;
58
+ /**
59
+ * Render the savings line for onboarding/status. Returns the encouraging
60
+ * zero-state line when there's no traffic yet (no requests / nothing saved).
61
+ */
62
+ export const formatSavingsLine = (savings) => {
63
+ const noTraffic = savings.requestCount <= 0 ||
64
+ (savings.tokensSaved <= 0 && savings.savingsUsd <= 0);
65
+ if (noTraffic) {
66
+ return 'No savings yet — start sending traffic through Anyray to see them add up.';
67
+ }
68
+ const window = savings.windowDays > 0 ? ` (last ${Math.round(savings.windowDays)}d)` : '';
69
+ return `You've saved ~${formatUsd(savings.savingsUsd)} / ~${formatTokens(savings.tokensSaved)} tokens via Anyray so far${window}.`;
70
+ };
71
+ //# sourceMappingURL=savings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"savings.js","sourceRoot":"","sources":["../../src/util/savings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAkBhC,MAAM,YAAY,GAAG,CAAC,KAAc,EAAU,EAAE,CAC9C,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAElE;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAC/B,MAAc,EACd,MAAc,EACd,OAAuB,EAAE,EACK,EAAE;IAChC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,kBAAkB,CAAC;IACvD,MAAM,GAAG,GAAG,GAAG,MAAM,kBAAkB,CAAC;IACxC,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC,CAAC;IAC9D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAC3B,MAAM,EAAE,KAAK;YACb,OAAO,EAAE,EAAE,kBAAkB,EAAE,MAAM,EAAE;YACvC,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO,SAAS,CAAC;QAC9B,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA4B,CAAC;QAC3D,OAAO;YACL,WAAW,EAAE,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC;YAC3C,UAAU,EAAE,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC;YACzC,YAAY,EAAE,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC;YAC7C,UAAU,EAAE,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC;SAC1C,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;AACH,CAAC,CAAC;AAEF,iEAAiE;AACjE,MAAM,YAAY,GAAG,CAAC,MAAc,EAAU,EAAE,CAC9C,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;AAE7C,sCAAsC;AACtC,MAAM,SAAS,GAAG,CAAC,GAAW,EAAU,EAAE,CACxC,IAAI,GAAG,CAAC,cAAc,CAAC,OAAO,EAAE;IAC9B,qBAAqB,EAAE,CAAC;IACxB,qBAAqB,EAAE,CAAC;CACzB,CAAC,EAAE,CAAC;AAEP;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,OAAgB,EAAU,EAAE;IAC5D,MAAM,SAAS,GACb,OAAO,CAAC,YAAY,IAAI,CAAC;QACzB,CAAC,OAAO,CAAC,WAAW,IAAI,CAAC,IAAI,OAAO,CAAC,UAAU,IAAI,CAAC,CAAC,CAAC;IACxD,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,2EAA2E,CAAC;IACrF,CAAC;IACD,MAAM,MAAM,GACV,OAAO,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7E,OAAO,iBAAiB,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,YAAY,CACtE,OAAO,CAAC,WAAW,CACpB,4BAA4B,MAAM,GAAG,CAAC;AACzC,CAAC,CAAC"}