@orcareplay/adapters 0.1.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.
- package/dist/claude-code.d.ts +37 -0
- package/dist/claude-code.d.ts.map +1 -0
- package/dist/claude-code.js +103 -0
- package/dist/claude-code.js.map +1 -0
- package/dist/codex.d.ts +36 -0
- package/dist/codex.d.ts.map +1 -0
- package/dist/codex.js +128 -0
- package/dist/codex.js.map +1 -0
- package/dist/contract.d.ts +41 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +373 -0
- package/dist/contract.js.map +1 -0
- package/dist/detect.d.ts +47 -0
- package/dist/detect.d.ts.map +1 -0
- package/dist/detect.js +123 -0
- package/dist/detect.js.map +1 -0
- package/dist/env.d.ts +31 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +54 -0
- package/dist/env.js.map +1 -0
- package/dist/generic-openai.d.ts +8 -0
- package/dist/generic-openai.d.ts.map +1 -0
- package/dist/generic-openai.js +31 -0
- package/dist/generic-openai.js.map +1 -0
- package/dist/grok.d.ts +23 -0
- package/dist/grok.d.ts.map +1 -0
- package/dist/grok.js +50 -0
- package/dist/grok.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-config.d.ts +17 -0
- package/dist/mcp-config.d.ts.map +1 -0
- package/dist/mcp-config.js +62 -0
- package/dist/mcp-config.js.map +1 -0
- package/dist/node.d.ts +20 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +60 -0
- package/dist/node.js.map +1 -0
- package/dist/openclaw.d.ts +19 -0
- package/dist/openclaw.d.ts.map +1 -0
- package/dist/openclaw.js +43 -0
- package/dist/openclaw.js.map +1 -0
- package/dist/opencode.d.ts +9 -0
- package/dist/opencode.d.ts.map +1 -0
- package/dist/opencode.js +52 -0
- package/dist/opencode.js.map +1 -0
- package/dist/registry.d.ts +19 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +82 -0
- package/dist/registry.js.map +1 -0
- package/dist/scaffold.d.ts +26 -0
- package/dist/scaffold.d.ts.map +1 -0
- package/dist/scaffold.js +125 -0
- package/dist/scaffold.js.map +1 -0
- package/dist/session.d.ts +47 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +112 -0
- package/dist/session.js.map +1 -0
- package/package.json +18 -0
package/dist/env.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Placeholder key for runs where the user has no credential in the environment. The proxy is
|
|
3
|
+
* holding the real one (or serving from a trace), but SDK clients refuse to start without
|
|
4
|
+
* *something* — so an obviously-fake value beats an empty string that looks like a real key.
|
|
5
|
+
*/
|
|
6
|
+
export const PLACEHOLDER_KEY = 'orca-recorded';
|
|
7
|
+
/** An env var set to the empty string is unset for our purposes: an empty key breaks clients. */
|
|
8
|
+
export function readEnv(env, name) {
|
|
9
|
+
const value = env[name];
|
|
10
|
+
return value !== undefined && value !== '' ? value : undefined;
|
|
11
|
+
}
|
|
12
|
+
/** Joins a path onto the proxy url without producing `//`, whether or not the base ends in `/`. */
|
|
13
|
+
export function proxyBase(proxyUrl, path = '') {
|
|
14
|
+
const base = proxyUrl.replace(/\/+$/, '');
|
|
15
|
+
return path ? `${base}/${path.replace(/^\/+/, '')}` : base;
|
|
16
|
+
}
|
|
17
|
+
/** Copies `name` from the run environment into the launch overlay, or a placeholder if unset. */
|
|
18
|
+
export function passKey(target, env, name) {
|
|
19
|
+
target[name] = readEnv(env, name) ?? PLACEHOLDER_KEY;
|
|
20
|
+
}
|
|
21
|
+
/** Copies `name` only if it is actually set — used for optional tokens we must not invent. */
|
|
22
|
+
export function passThrough(target, env, name) {
|
|
23
|
+
const value = readEnv(env, name);
|
|
24
|
+
if (value !== undefined)
|
|
25
|
+
target[name] = value;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Point base-URL variables orca does not know about at the proxy.
|
|
29
|
+
*
|
|
30
|
+
* Read from `ORCA_BASE_URL_VARS`: a comma-separated list of variable names, each optionally with
|
|
31
|
+
* `=<path>` when the origin is not OpenAI-shaped. `/v1` is the default suffix because that is what
|
|
32
|
+
* an OpenAI-compatible override wants, and it is what every example in the wild ends in.
|
|
33
|
+
*
|
|
34
|
+
* This exists because enumerating them is hopeless. Hermes alone overrides per provider —
|
|
35
|
+
* `NOVITA_BASE_URL`, `GLM_BASE_URL`, `KIMI_BASE_URL`, `MINIMAX_BASE_URL`, `HF_BASE_URL`,
|
|
36
|
+
* `NEBIUS_BASE_URL` and a dozen more in one `.env.example` — and a list of names baked in here
|
|
37
|
+
* would be stale the week after it was written. A harness the author has never heard of is the
|
|
38
|
+
* normal case, so it gets a mechanism rather than a pull request.
|
|
39
|
+
*
|
|
40
|
+
* The variable is consumed, never forwarded: it names other variables and means nothing downstream.
|
|
41
|
+
*/
|
|
42
|
+
export function applyNamedBaseUrls(target, env, proxyUrl) {
|
|
43
|
+
for (const entry of (readEnv(env, 'ORCA_BASE_URL_VARS') ?? '').split(',')) {
|
|
44
|
+
const [rawName, rawPath] = entry.split('=');
|
|
45
|
+
const name = (rawName ?? '').trim();
|
|
46
|
+
if (name === '')
|
|
47
|
+
continue;
|
|
48
|
+
// A path of `/` means the bare origin. `proxyBase` would otherwise leave the separator behind
|
|
49
|
+
// and hand the harness `http://host:port/`, which some clients then join into a double slash.
|
|
50
|
+
const path = (rawPath ?? 'v1').trim().replace(/^\/+|\/+$/g, '');
|
|
51
|
+
target[name] = proxyBase(proxyUrl, path);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=env.js.map
|
package/dist/env.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,eAAe,CAAC;AAE/C,iGAAiG;AACjG,MAAM,UAAU,OAAO,CAAC,GAAuC,EAAE,IAAY;IAC3E,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC;IACxB,OAAO,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACjE,CAAC;AAED,mGAAmG;AACnG,MAAM,UAAU,SAAS,CAAC,QAAgB,EAAE,IAAI,GAAG,EAAE;IACnD,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC1C,OAAO,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7D,CAAC;AAED,iGAAiG;AACjG,MAAM,UAAU,OAAO,CACrB,MAA8B,EAC9B,GAAuC,EACvC,IAAY;IAEZ,MAAM,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,eAAe,CAAC;AACvD,CAAC;AAED,8FAA8F;AAC9F,MAAM,UAAU,WAAW,CACzB,MAA8B,EAC9B,GAAuC,EACvC,IAAY;IAEZ,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACjC,IAAI,KAAK,KAAK,SAAS;QAAE,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;AAChD,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,kBAAkB,CAChC,MAA8B,EAC9B,GAAuC,EACvC,QAAgB;IAEhB,KAAK,MAAM,KAAK,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,oBAAoB,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1E,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC5C,MAAM,IAAI,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACpC,IAAI,IAAI,KAAK,EAAE;YAAE,SAAS;QAC1B,8FAA8F;QAC9F,8FAA8F;QAC9F,MAAM,IAAI,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;QAChE,MAAM,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC3C,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Adapter } from '@orcareplay/plugin-api';
|
|
2
|
+
/**
|
|
3
|
+
* The escape hatch for any agent nobody has written an adapter for: the user supplies the command,
|
|
4
|
+
* and every base-url variable in common use is redirected at once. `detect` is always false — an
|
|
5
|
+
* adapter that cannot know what it is launching must never be chosen automatically.
|
|
6
|
+
*/
|
|
7
|
+
export declare const genericOpenAiAdapter: Adapter;
|
|
8
|
+
//# sourceMappingURL=generic-openai.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generic-openai.d.ts","sourceRoot":"","sources":["../src/generic-openai.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAyB,MAAM,wBAAwB,CAAC;AAG7E;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,EAAE,OA2BlC,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { applyNamedBaseUrls, passKey, passThrough, proxyBase } from './env.js';
|
|
2
|
+
/**
|
|
3
|
+
* The escape hatch for any agent nobody has written an adapter for: the user supplies the command,
|
|
4
|
+
* and every base-url variable in common use is redirected at once. `detect` is always false — an
|
|
5
|
+
* adapter that cannot know what it is launching must never be chosen automatically.
|
|
6
|
+
*/
|
|
7
|
+
export const genericOpenAiAdapter = {
|
|
8
|
+
id: 'generic-openai',
|
|
9
|
+
async detect(_cwd) {
|
|
10
|
+
return false;
|
|
11
|
+
},
|
|
12
|
+
async prepare(ctx) {
|
|
13
|
+
const [command, ...args] = ctx.userArgs;
|
|
14
|
+
if (command === undefined || command === '') {
|
|
15
|
+
throw new Error('generic-openai needs the command to run: orca record generic-openai -- <command> [args...]');
|
|
16
|
+
}
|
|
17
|
+
const env = {
|
|
18
|
+
OPENAI_BASE_URL: proxyBase(ctx.proxyUrl, 'v1'),
|
|
19
|
+
// Pre-1.0 OpenAI SDKs and many ports read OPENAI_API_BASE instead.
|
|
20
|
+
OPENAI_API_BASE: proxyBase(ctx.proxyUrl, 'v1'),
|
|
21
|
+
ANTHROPIC_BASE_URL: proxyBase(ctx.proxyUrl),
|
|
22
|
+
};
|
|
23
|
+
passKey(env, ctx.env, 'OPENAI_API_KEY');
|
|
24
|
+
// Only passed on if the user already had one: an invented Anthropic key could flip an unknown
|
|
25
|
+
// agent's provider auto-selection and change which model it calls.
|
|
26
|
+
passThrough(env, ctx.env, 'ANTHROPIC_API_KEY');
|
|
27
|
+
applyNamedBaseUrls(env, ctx.env, ctx.proxyUrl);
|
|
28
|
+
return { command, args, env };
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=generic-openai.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generic-openai.js","sourceRoot":"","sources":["../src/generic-openai.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE/E;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAY;IAC3C,EAAE,EAAE,gBAAgB;IAEpB,KAAK,CAAC,MAAM,CAAC,IAAY;QACvB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,GAAkB;QAC9B,MAAM,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC;QACxC,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,EAAE,EAAE,CAAC;YAC5C,MAAM,IAAI,KAAK,CACb,4FAA4F,CAC7F,CAAC;QACJ,CAAC;QACD,MAAM,GAAG,GAA2B;YAClC,eAAe,EAAE,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC;YAC9C,mEAAmE;YACnE,eAAe,EAAE,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC;YAC9C,kBAAkB,EAAE,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC;SAC5C,CAAC;QACF,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;QACxC,8FAA8F;QAC9F,mEAAmE;QACnE,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,mBAAmB,CAAC,CAAC;QAC/C,kBAAkB,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC/C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;IAChC,CAAC;CACF,CAAC"}
|
package/dist/grok.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { HOOK_FILENAME } from '@orcareplay/node-instrument';
|
|
2
|
+
import type { Adapter } from '@orcareplay/plugin-api';
|
|
3
|
+
/**
|
|
4
|
+
* grok-cli — the community coding agent for xAI's Grok API.
|
|
5
|
+
*
|
|
6
|
+
* It documents `GROK_BASE_URL` (default `https://api.x.ai/v1`), so the ordinary redirect works and
|
|
7
|
+
* this adapter is mostly that one variable. Two details are not ordinary:
|
|
8
|
+
*
|
|
9
|
+
* The `/v1` is part of the documented default, so the replacement carries it — drop it and every
|
|
10
|
+
* request lands one path segment short.
|
|
11
|
+
*
|
|
12
|
+
* And it runs on Bun with sub-agents on by default. A sub-agent that builds its own client would
|
|
13
|
+
* slip past a variable its parent read, so the fetch hook goes in as well, with `api.x.ai` added
|
|
14
|
+
* to the allowlist — it is not one of the hook's default hosts, so without that line the hook
|
|
15
|
+
* would be installed and inert. Bun ignores `--require` inside `NODE_OPTIONS`, which is why
|
|
16
|
+
* `BUN_OPTIONS` is set alongside it.
|
|
17
|
+
*
|
|
18
|
+
* Its Telegram remote control is the same process reading the same variable, so "the grok bot" is
|
|
19
|
+
* captured by this adapter too, with nothing extra.
|
|
20
|
+
*/
|
|
21
|
+
export declare const grokAdapter: Adapter;
|
|
22
|
+
export { HOOK_FILENAME };
|
|
23
|
+
//# sourceMappingURL=grok.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grok.d.ts","sourceRoot":"","sources":["../src/grok.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EAId,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,OAAO,EAAyB,MAAM,wBAAwB,CAAC;AAO7E;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,WAAW,EAAE,OA0BzB,CAAC;AAEF,OAAO,EAAE,aAAa,EAAE,CAAC"}
|
package/dist/grok.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { HOOK_FILENAME, bunOptionsWithHook, nodeOptionsWithHook, writeFetchHook, } from '@orcareplay/node-instrument';
|
|
2
|
+
import { applyNamedBaseUrls, passThrough, proxyBase, readEnv } from './env.js';
|
|
3
|
+
import { detectAgent } from './detect.js';
|
|
4
|
+
/** xAI's origin, which grok-cli reaches whenever something bypasses `GROK_BASE_URL`. */
|
|
5
|
+
const XAI_HOST = 'api.x.ai';
|
|
6
|
+
/**
|
|
7
|
+
* grok-cli — the community coding agent for xAI's Grok API.
|
|
8
|
+
*
|
|
9
|
+
* It documents `GROK_BASE_URL` (default `https://api.x.ai/v1`), so the ordinary redirect works and
|
|
10
|
+
* this adapter is mostly that one variable. Two details are not ordinary:
|
|
11
|
+
*
|
|
12
|
+
* The `/v1` is part of the documented default, so the replacement carries it — drop it and every
|
|
13
|
+
* request lands one path segment short.
|
|
14
|
+
*
|
|
15
|
+
* And it runs on Bun with sub-agents on by default. A sub-agent that builds its own client would
|
|
16
|
+
* slip past a variable its parent read, so the fetch hook goes in as well, with `api.x.ai` added
|
|
17
|
+
* to the allowlist — it is not one of the hook's default hosts, so without that line the hook
|
|
18
|
+
* would be installed and inert. Bun ignores `--require` inside `NODE_OPTIONS`, which is why
|
|
19
|
+
* `BUN_OPTIONS` is set alongside it.
|
|
20
|
+
*
|
|
21
|
+
* Its Telegram remote control is the same process reading the same variable, so "the grok bot" is
|
|
22
|
+
* captured by this adapter too, with nothing extra.
|
|
23
|
+
*/
|
|
24
|
+
export const grokAdapter = {
|
|
25
|
+
id: 'grok',
|
|
26
|
+
aliases: ['grok-cli'],
|
|
27
|
+
async detect(_cwd) {
|
|
28
|
+
return detectAgent(['grok'], ['.grok']);
|
|
29
|
+
},
|
|
30
|
+
async prepare(ctx) {
|
|
31
|
+
const hookPath = await writeFetchHook(ctx.runDir);
|
|
32
|
+
const hosts = readEnv(ctx.env, 'ORCA_INSTRUMENT_HOSTS');
|
|
33
|
+
const env = {
|
|
34
|
+
GROK_BASE_URL: proxyBase(ctx.proxyUrl, 'v1'),
|
|
35
|
+
ORCA_PROXY_URL: ctx.proxyUrl,
|
|
36
|
+
// Added to whatever the operator asked for rather than replacing it: naming one host should
|
|
37
|
+
// not silently drop xAI, which is the only host this adapter exists to catch.
|
|
38
|
+
ORCA_INSTRUMENT_HOSTS: hosts === undefined ? XAI_HOST : `${hosts},${XAI_HOST}`,
|
|
39
|
+
NODE_OPTIONS: nodeOptionsWithHook(hookPath, readEnv(ctx.env, 'NODE_OPTIONS')),
|
|
40
|
+
BUN_OPTIONS: bunOptionsWithHook(hookPath, readEnv(ctx.env, 'BUN_OPTIONS')),
|
|
41
|
+
};
|
|
42
|
+
// Never invented: grok-cli refuses to start without a key and says so clearly, which is a
|
|
43
|
+
// better failure than a run that silently authenticates as nobody.
|
|
44
|
+
passThrough(env, ctx.env, 'GROK_API_KEY');
|
|
45
|
+
applyNamedBaseUrls(env, ctx.env, ctx.proxyUrl);
|
|
46
|
+
return { command: 'grok', args: [...ctx.userArgs], env, tempFiles: [hookPath] };
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
export { HOOK_FILENAME };
|
|
50
|
+
//# sourceMappingURL=grok.js.map
|
package/dist/grok.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grok.js","sourceRoot":"","sources":["../src/grok.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,GACf,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,wFAAwF;AACxF,MAAM,QAAQ,GAAG,UAAU,CAAC;AAE5B;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,WAAW,GAAY;IAClC,EAAE,EAAE,MAAM;IACV,OAAO,EAAE,CAAC,UAAU,CAAC;IAErB,KAAK,CAAC,MAAM,CAAC,IAAY;QACvB,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAC1C,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,GAAkB;QAC9B,MAAM,QAAQ,GAAG,MAAM,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAClD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,uBAAuB,CAAC,CAAC;QACxD,MAAM,GAAG,GAA2B;YAClC,aAAa,EAAE,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC;YAC5C,cAAc,EAAE,GAAG,CAAC,QAAQ;YAC5B,4FAA4F;YAC5F,8EAA8E;YAC9E,qBAAqB,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,QAAQ,EAAE;YAC9E,YAAY,EAAE,mBAAmB,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;YAC7E,WAAW,EAAE,kBAAkB,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;SAC3E,CAAC;QACF,0FAA0F;QAC1F,mEAAmE;QACnE,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;QAC1C,kBAAkB,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC;IAClF,CAAC;CACF,CAAC;AAEF,OAAO,EAAE,aAAa,EAAE,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export * from './claude-code.js';
|
|
2
|
+
export * from './codex.js';
|
|
3
|
+
export * from './contract.js';
|
|
4
|
+
export * from './detect.js';
|
|
5
|
+
export * from './env.js';
|
|
6
|
+
export * from './generic-openai.js';
|
|
7
|
+
export * from './grok.js';
|
|
8
|
+
export * from './node.js';
|
|
9
|
+
export * from './openclaw.js';
|
|
10
|
+
export * from './mcp-config.js';
|
|
11
|
+
export * from './opencode.js';
|
|
12
|
+
export * from './registry.js';
|
|
13
|
+
export * from './scaffold.js';
|
|
14
|
+
export * from './session.js';
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,qBAAqB,CAAC;AACpC,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export * from './claude-code.js';
|
|
2
|
+
export * from './codex.js';
|
|
3
|
+
export * from './contract.js';
|
|
4
|
+
export * from './detect.js';
|
|
5
|
+
export * from './env.js';
|
|
6
|
+
export * from './generic-openai.js';
|
|
7
|
+
export * from './grok.js';
|
|
8
|
+
export * from './node.js';
|
|
9
|
+
export * from './openclaw.js';
|
|
10
|
+
export * from './mcp-config.js';
|
|
11
|
+
export * from './opencode.js';
|
|
12
|
+
export * from './registry.js';
|
|
13
|
+
export * from './scaffold.js';
|
|
14
|
+
export * from './session.js';
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,qBAAqB,CAAC;AACpC,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Result of rewriting an agent's MCP config to launch its stdio servers through the shim. */
|
|
2
|
+
export interface McpRewrite {
|
|
3
|
+
/** A new config value. The input is never mutated. */
|
|
4
|
+
config: unknown;
|
|
5
|
+
/** Server names now launching through the shim. */
|
|
6
|
+
rewritten: string[];
|
|
7
|
+
/** Server names deliberately left alone — HTTP/SSE transports, or shapes we do not recognise. */
|
|
8
|
+
skipped: string[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Rewrites `{ mcpServers: { name: { command, args, env } } }` so each stdio server launches under
|
|
12
|
+
* the JSON-RPC tee. Servers reached over HTTP/SSE are left untouched — they are already captured
|
|
13
|
+
* by the HTTP proxy — but they are reported rather than silently dropped, because an MCP server
|
|
14
|
+
* that quietly stops appearing in a trace is indistinguishable from one that was never used.
|
|
15
|
+
*/
|
|
16
|
+
export declare function rewriteMcpConfig(config: unknown, shimCommand: string, shimArgs: string[]): McpRewrite;
|
|
17
|
+
//# sourceMappingURL=mcp-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-config.d.ts","sourceRoot":"","sources":["../src/mcp-config.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,MAAM,WAAW,UAAU;IACzB,sDAAsD;IACtD,MAAM,EAAE,OAAO,CAAC;IAChB,mDAAmD;IACnD,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,iGAAiG;IACjG,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAmBD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,OAAO,EACf,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAAE,GACjB,UAAU,CA8CZ"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
function isObject(value) {
|
|
2
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* A server is already wrapped when it points at *this* shim and carries the `--name ... --`
|
|
6
|
+
* separator we generate. Matching on the shim command as well as the separator keeps a real
|
|
7
|
+
* server whose own argv happens to contain `--` from being mistaken for our wrapper.
|
|
8
|
+
*/
|
|
9
|
+
function isWrapped(entry, shimCommand) {
|
|
10
|
+
if (entry['command'] !== shimCommand)
|
|
11
|
+
return false;
|
|
12
|
+
const args = entry['args'];
|
|
13
|
+
return Array.isArray(args) && args.includes('--name') && args.includes('--');
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Rewrites `{ mcpServers: { name: { command, args, env } } }` so each stdio server launches under
|
|
17
|
+
* the JSON-RPC tee. Servers reached over HTTP/SSE are left untouched — they are already captured
|
|
18
|
+
* by the HTTP proxy — but they are reported rather than silently dropped, because an MCP server
|
|
19
|
+
* that quietly stops appearing in a trace is indistinguishable from one that was never used.
|
|
20
|
+
*/
|
|
21
|
+
export function rewriteMcpConfig(config, shimCommand, shimArgs) {
|
|
22
|
+
const rewritten = [];
|
|
23
|
+
const skipped = [];
|
|
24
|
+
if (!isObject(config) || !isObject(config['mcpServers'])) {
|
|
25
|
+
return { config, rewritten, skipped };
|
|
26
|
+
}
|
|
27
|
+
const { mcpServers: servers, ...rest } = config;
|
|
28
|
+
const nextServers = {};
|
|
29
|
+
for (const [name, raw] of Object.entries(servers)) {
|
|
30
|
+
if (!isObject(raw)) {
|
|
31
|
+
nextServers[name] = raw;
|
|
32
|
+
skipped.push(name);
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
const entry = structuredClone(raw);
|
|
36
|
+
if (isWrapped(entry, shimCommand)) {
|
|
37
|
+
nextServers[name] = entry;
|
|
38
|
+
rewritten.push(name);
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (typeof entry['url'] === 'string') {
|
|
42
|
+
nextServers[name] = entry;
|
|
43
|
+
skipped.push(name);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (typeof entry['command'] !== 'string') {
|
|
47
|
+
nextServers[name] = entry;
|
|
48
|
+
skipped.push(name);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const original = entry['command'];
|
|
52
|
+
const originalArgs = Array.isArray(entry['args']) ? entry['args'] : [];
|
|
53
|
+
nextServers[name] = {
|
|
54
|
+
...entry,
|
|
55
|
+
command: shimCommand,
|
|
56
|
+
args: [...shimArgs, '--name', name, '--', original, ...originalArgs],
|
|
57
|
+
};
|
|
58
|
+
rewritten.push(name);
|
|
59
|
+
}
|
|
60
|
+
return { config: { ...structuredClone(rest), mcpServers: nextServers }, rewritten, skipped };
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=mcp-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-config.js","sourceRoot":"","sources":["../src/mcp-config.ts"],"names":[],"mappings":"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"}
|
package/dist/node.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { HOOK_FILENAME } from '@orcareplay/node-instrument';
|
|
2
|
+
import type { Adapter } from '@orcareplay/plugin-api';
|
|
3
|
+
/**
|
|
4
|
+
* A JS agent that never reads a base-URL variable.
|
|
5
|
+
*
|
|
6
|
+
* Every other adapter here redirects an environment variable and stops. That covers most
|
|
7
|
+
* harnesses and misses a whole class: `@ai-sdk/openai` takes its origin as a constructor argument
|
|
8
|
+
* and reads nothing from the environment, so a Vercel AI SDK agent under `orca record` runs
|
|
9
|
+
* perfectly, exits 0, and writes an empty trace. The same is true of any agent that hardcodes a
|
|
10
|
+
* base URL, which is most of them once someone has pinned a gateway in code.
|
|
11
|
+
*
|
|
12
|
+
* So this one redirects at the only place all of them agree on — `globalThis.fetch` — by writing
|
|
13
|
+
* a self-contained preload into the run directory and pointing `NODE_OPTIONS` at it. It is a
|
|
14
|
+
* separate adapter rather than a change to `generic-openai` because `NODE_OPTIONS` reaches every
|
|
15
|
+
* Node process the agent spawns, and that is a real cost: worth paying when you know your agent
|
|
16
|
+
* needs it, not worth imposing on someone recording a Python harness.
|
|
17
|
+
*/
|
|
18
|
+
export declare const nodeAdapter: Adapter;
|
|
19
|
+
export { HOOK_FILENAME };
|
|
20
|
+
//# sourceMappingURL=node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EAId,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,OAAO,EAAyB,MAAM,wBAAwB,CAAC;AAG7E;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,WAAW,EAAE,OA6CzB,CAAC;AAEF,OAAO,EAAE,aAAa,EAAE,CAAC"}
|
package/dist/node.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { HOOK_FILENAME, bunOptionsWithHook, nodeOptionsWithHook, writeFetchHook, } from '@orcareplay/node-instrument';
|
|
2
|
+
import { applyNamedBaseUrls, passKey, passThrough, proxyBase, readEnv } from './env.js';
|
|
3
|
+
/**
|
|
4
|
+
* A JS agent that never reads a base-URL variable.
|
|
5
|
+
*
|
|
6
|
+
* Every other adapter here redirects an environment variable and stops. That covers most
|
|
7
|
+
* harnesses and misses a whole class: `@ai-sdk/openai` takes its origin as a constructor argument
|
|
8
|
+
* and reads nothing from the environment, so a Vercel AI SDK agent under `orca record` runs
|
|
9
|
+
* perfectly, exits 0, and writes an empty trace. The same is true of any agent that hardcodes a
|
|
10
|
+
* base URL, which is most of them once someone has pinned a gateway in code.
|
|
11
|
+
*
|
|
12
|
+
* So this one redirects at the only place all of them agree on — `globalThis.fetch` — by writing
|
|
13
|
+
* a self-contained preload into the run directory and pointing `NODE_OPTIONS` at it. It is a
|
|
14
|
+
* separate adapter rather than a change to `generic-openai` because `NODE_OPTIONS` reaches every
|
|
15
|
+
* Node process the agent spawns, and that is a real cost: worth paying when you know your agent
|
|
16
|
+
* needs it, not worth imposing on someone recording a Python harness.
|
|
17
|
+
*/
|
|
18
|
+
export const nodeAdapter = {
|
|
19
|
+
id: 'node',
|
|
20
|
+
// What people will actually type. The adapter is not specific to the Vercel AI SDK, but that is
|
|
21
|
+
// the name someone reaches for when their trace came back empty.
|
|
22
|
+
aliases: ['vercel-ai', 'ai-sdk'],
|
|
23
|
+
async detect(_cwd) {
|
|
24
|
+
// Never automatic. Like `generic-openai`, this adapter does not know what it would be
|
|
25
|
+
// launching, and an adapter that cannot know must not claim the workspace.
|
|
26
|
+
return false;
|
|
27
|
+
},
|
|
28
|
+
async prepare(ctx) {
|
|
29
|
+
const [command, ...args] = ctx.userArgs;
|
|
30
|
+
if (command === undefined || command === '') {
|
|
31
|
+
throw new Error('node needs the command to run: orca record node -- <command> [args...], ' +
|
|
32
|
+
'e.g. orca record node -- node agent.mjs');
|
|
33
|
+
}
|
|
34
|
+
const hookPath = await writeFetchHook(ctx.runDir);
|
|
35
|
+
const env = {
|
|
36
|
+
// Read by the hook. Absent, the hook is inert — which is what makes the file safe to leave
|
|
37
|
+
// on disk in a run directory someone later opens.
|
|
38
|
+
ORCA_PROXY_URL: ctx.proxyUrl,
|
|
39
|
+
NODE_OPTIONS: nodeOptionsWithHook(hookPath, readEnv(ctx.env, 'NODE_OPTIONS')),
|
|
40
|
+
// Bun accepts NODE_OPTIONS but ignores `--require` in it, so a Bun-based agent — grok-cli is
|
|
41
|
+
// the one people hit — ran uninstrumented and its traffic went to the provider unrecorded.
|
|
42
|
+
// Setting both costs nothing: each runtime reads only its own.
|
|
43
|
+
BUN_OPTIONS: bunOptionsWithHook(hookPath, readEnv(ctx.env, 'BUN_OPTIONS')),
|
|
44
|
+
// Belt and braces. One agent may use an SDK's default client for one provider and a
|
|
45
|
+
// hardcoded origin for another, and orca has no way to tell which from the outside.
|
|
46
|
+
OPENAI_BASE_URL: proxyBase(ctx.proxyUrl, 'v1'),
|
|
47
|
+
OPENAI_API_BASE: proxyBase(ctx.proxyUrl, 'v1'),
|
|
48
|
+
ANTHROPIC_BASE_URL: proxyBase(ctx.proxyUrl),
|
|
49
|
+
};
|
|
50
|
+
// An extra origin to redirect — an Azure deployment, a self-hosted gateway the agent pins in
|
|
51
|
+
// code. Passed through rather than invented so the default stays the two provider hosts.
|
|
52
|
+
passThrough(env, ctx.env, 'ORCA_INSTRUMENT_HOSTS');
|
|
53
|
+
passKey(env, ctx.env, 'OPENAI_API_KEY');
|
|
54
|
+
passThrough(env, ctx.env, 'ANTHROPIC_API_KEY');
|
|
55
|
+
applyNamedBaseUrls(env, ctx.env, ctx.proxyUrl);
|
|
56
|
+
return { command, args, env, tempFiles: [hookPath] };
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
export { HOOK_FILENAME };
|
|
60
|
+
//# sourceMappingURL=node.js.map
|
package/dist/node.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.js","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,GACf,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAE,kBAAkB,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExF;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,WAAW,GAAY;IAClC,EAAE,EAAE,MAAM;IACV,gGAAgG;IAChG,iEAAiE;IACjE,OAAO,EAAE,CAAC,WAAW,EAAE,QAAQ,CAAC;IAEhC,KAAK,CAAC,MAAM,CAAC,IAAY;QACvB,sFAAsF;QACtF,2EAA2E;QAC3E,OAAO,KAAK,CAAC;IACf,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,GAAkB;QAC9B,MAAM,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC;QACxC,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,EAAE,EAAE,CAAC;YAC5C,MAAM,IAAI,KAAK,CACb,0EAA0E;gBACxE,yCAAyC,CAC5C,CAAC;QACJ,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAClD,MAAM,GAAG,GAA2B;YAClC,2FAA2F;YAC3F,kDAAkD;YAClD,cAAc,EAAE,GAAG,CAAC,QAAQ;YAC5B,YAAY,EAAE,mBAAmB,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;YAC7E,6FAA6F;YAC7F,2FAA2F;YAC3F,+DAA+D;YAC/D,WAAW,EAAE,kBAAkB,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;YAC1E,oFAAoF;YACpF,oFAAoF;YACpF,eAAe,EAAE,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC;YAC9C,eAAe,EAAE,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC;YAC9C,kBAAkB,EAAE,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC;SAC5C,CAAC;QACF,6FAA6F;QAC7F,yFAAyF;QACzF,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,uBAAuB,CAAC,CAAC;QACnD,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;QACxC,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,mBAAmB,CAAC,CAAC;QAC/C,kBAAkB,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC/C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC;IACvD,CAAC;CACF,CAAC;AAEF,OAAO,EAAE,aAAa,EAAE,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Adapter } from '@orcareplay/plugin-api';
|
|
2
|
+
/**
|
|
3
|
+
* OpenClaw — a multi-channel gateway that runs coding agents on your behalf.
|
|
4
|
+
*
|
|
5
|
+
* It is a different shape from every other adapter here: OpenClaw does not do the coding, it
|
|
6
|
+
* *launches* Claude Code, Codex or opencode as child processes and drives them from a chat app. So
|
|
7
|
+
* there are two kinds of model traffic in one run, and both have to be caught.
|
|
8
|
+
*
|
|
9
|
+
* The gateway's own calls read no base-URL variable that its documentation names, so they are
|
|
10
|
+
* caught the way the Vercel AI SDK is: the fetch hook, installed through `NODE_OPTIONS`.
|
|
11
|
+
*
|
|
12
|
+
* The coding agent's calls are caught by the ordinary variables — not because OpenClaw reads them,
|
|
13
|
+
* but because a child process inherits its parent's environment, so the Claude Code that OpenClaw
|
|
14
|
+
* spawns sees `ANTHROPIC_BASE_URL` exactly as it would if you had run it yourself. That is a
|
|
15
|
+
* property of the OS, not of orca, and it is why this adapter sets variables the launched program
|
|
16
|
+
* ignores.
|
|
17
|
+
*/
|
|
18
|
+
export declare const openClawAdapter: Adapter;
|
|
19
|
+
//# sourceMappingURL=openclaw.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openclaw.d.ts","sourceRoot":"","sources":["../src/openclaw.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAyB,MAAM,wBAAwB,CAAC;AAI7E;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,eAAe,EAAE,OAwB7B,CAAC"}
|
package/dist/openclaw.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { bunOptionsWithHook, nodeOptionsWithHook, writeFetchHook, } from '@orcareplay/node-instrument';
|
|
2
|
+
import { applyNamedBaseUrls, passThrough, proxyBase, readEnv } from './env.js';
|
|
3
|
+
import { detectAgent } from './detect.js';
|
|
4
|
+
/**
|
|
5
|
+
* OpenClaw — a multi-channel gateway that runs coding agents on your behalf.
|
|
6
|
+
*
|
|
7
|
+
* It is a different shape from every other adapter here: OpenClaw does not do the coding, it
|
|
8
|
+
* *launches* Claude Code, Codex or opencode as child processes and drives them from a chat app. So
|
|
9
|
+
* there are two kinds of model traffic in one run, and both have to be caught.
|
|
10
|
+
*
|
|
11
|
+
* The gateway's own calls read no base-URL variable that its documentation names, so they are
|
|
12
|
+
* caught the way the Vercel AI SDK is: the fetch hook, installed through `NODE_OPTIONS`.
|
|
13
|
+
*
|
|
14
|
+
* The coding agent's calls are caught by the ordinary variables — not because OpenClaw reads them,
|
|
15
|
+
* but because a child process inherits its parent's environment, so the Claude Code that OpenClaw
|
|
16
|
+
* spawns sees `ANTHROPIC_BASE_URL` exactly as it would if you had run it yourself. That is a
|
|
17
|
+
* property of the OS, not of orca, and it is why this adapter sets variables the launched program
|
|
18
|
+
* ignores.
|
|
19
|
+
*/
|
|
20
|
+
export const openClawAdapter = {
|
|
21
|
+
id: 'openclaw',
|
|
22
|
+
async detect(_cwd) {
|
|
23
|
+
return detectAgent(['openclaw'], ['.openclaw', '.config/openclaw']);
|
|
24
|
+
},
|
|
25
|
+
async prepare(ctx) {
|
|
26
|
+
const hookPath = await writeFetchHook(ctx.runDir);
|
|
27
|
+
const env = {
|
|
28
|
+
ORCA_PROXY_URL: ctx.proxyUrl,
|
|
29
|
+
NODE_OPTIONS: nodeOptionsWithHook(hookPath, readEnv(ctx.env, 'NODE_OPTIONS')),
|
|
30
|
+
BUN_OPTIONS: bunOptionsWithHook(hookPath, readEnv(ctx.env, 'BUN_OPTIONS')),
|
|
31
|
+
// For the coding agents it spawns, which inherit this environment and do read them.
|
|
32
|
+
ANTHROPIC_BASE_URL: proxyBase(ctx.proxyUrl),
|
|
33
|
+
OPENAI_BASE_URL: proxyBase(ctx.proxyUrl, 'v1'),
|
|
34
|
+
OPENAI_API_BASE: proxyBase(ctx.proxyUrl, 'v1'),
|
|
35
|
+
};
|
|
36
|
+
passThrough(env, ctx.env, 'ORCA_INSTRUMENT_HOSTS');
|
|
37
|
+
passThrough(env, ctx.env, 'ANTHROPIC_API_KEY');
|
|
38
|
+
passThrough(env, ctx.env, 'OPENAI_API_KEY');
|
|
39
|
+
applyNamedBaseUrls(env, ctx.env, ctx.proxyUrl);
|
|
40
|
+
return { command: 'openclaw', args: [...ctx.userArgs], env, tempFiles: [hookPath] };
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=openclaw.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openclaw.js","sourceRoot":"","sources":["../src/openclaw.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,GACf,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,eAAe,GAAY;IACtC,EAAE,EAAE,UAAU;IAEd,KAAK,CAAC,MAAM,CAAC,IAAY;QACvB,OAAO,WAAW,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,WAAW,EAAE,kBAAkB,CAAC,CAAC,CAAC;IACtE,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,GAAkB;QAC9B,MAAM,QAAQ,GAAG,MAAM,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAClD,MAAM,GAAG,GAA2B;YAClC,cAAc,EAAE,GAAG,CAAC,QAAQ;YAC5B,YAAY,EAAE,mBAAmB,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;YAC7E,WAAW,EAAE,kBAAkB,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;YAC1E,oFAAoF;YACpF,kBAAkB,EAAE,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC;YAC3C,eAAe,EAAE,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC;YAC9C,eAAe,EAAE,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC;SAC/C,CAAC;QACF,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,uBAAuB,CAAC,CAAC;QACnD,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,mBAAmB,CAAC,CAAC;QAC/C,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;QAC5C,kBAAkB,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC/C,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC;IACtF,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Adapter } from '@orcareplay/plugin-api';
|
|
2
|
+
/** Whether OpenCode has credentials of its own, independent of the environment. */
|
|
3
|
+
export declare function opencodeHasOwnAuth(): boolean;
|
|
4
|
+
/**
|
|
5
|
+
* OpenCode picks its provider per model, so both origins are redirected: whichever protocol the
|
|
6
|
+
* chosen model speaks, the traffic lands on the proxy.
|
|
7
|
+
*/
|
|
8
|
+
export declare const openCodeAdapter: Adapter;
|
|
9
|
+
//# sourceMappingURL=opencode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opencode.d.ts","sourceRoot":"","sources":["../src/opencode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAyB,MAAM,wBAAwB,CAAC;AAY7E,mFAAmF;AACnF,wBAAgB,kBAAkB,IAAI,OAAO,CAE5C;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,OAmC7B,CAAC"}
|
package/dist/opencode.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { detectAgent, homeDirHas } from './detect.js';
|
|
2
|
+
import { passKey, passThrough, proxyBase, readEnv } from './env.js';
|
|
3
|
+
/**
|
|
4
|
+
* Where OpenCode keeps the credentials `opencode auth login` writes.
|
|
5
|
+
*
|
|
6
|
+
* Both locations, because the data directory moved and an installation that predates the move
|
|
7
|
+
* still has the old one. Finding either means the harness can authenticate on its own.
|
|
8
|
+
*/
|
|
9
|
+
const OPENCODE_AUTH_PATHS = ['.local/share/opencode/auth.json', '.config/opencode/auth.json'];
|
|
10
|
+
/** Whether OpenCode has credentials of its own, independent of the environment. */
|
|
11
|
+
export function opencodeHasOwnAuth() {
|
|
12
|
+
return OPENCODE_AUTH_PATHS.some(homeDirHas);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* OpenCode picks its provider per model, so both origins are redirected: whichever protocol the
|
|
16
|
+
* chosen model speaks, the traffic lands on the proxy.
|
|
17
|
+
*/
|
|
18
|
+
export const openCodeAdapter = {
|
|
19
|
+
id: 'opencode',
|
|
20
|
+
async detect(_cwd) {
|
|
21
|
+
return detectAgent(['opencode'], ['.config/opencode', '.opencode']);
|
|
22
|
+
},
|
|
23
|
+
async prepare(ctx) {
|
|
24
|
+
const env = {
|
|
25
|
+
OPENAI_BASE_URL: proxyBase(ctx.proxyUrl, 'v1'),
|
|
26
|
+
ANTHROPIC_BASE_URL: proxyBase(ctx.proxyUrl),
|
|
27
|
+
};
|
|
28
|
+
// Which credentials OpenCode can see is part of how it chooses a provider, so handing it a
|
|
29
|
+
// placeholder for the provider the user has *not* configured can change which model the run
|
|
30
|
+
// calls — a recorded run that answers differently from the same command uninstrumented is the
|
|
31
|
+
// worst kind of capture bug. With no credential at all there is no choice to flip, and a
|
|
32
|
+
// client that refuses to start without a key helps nobody, so placeholders stand in.
|
|
33
|
+
//
|
|
34
|
+
// Unless OpenCode has signed in on its own. `opencode auth login` writes a credential file the
|
|
35
|
+
// environment knows nothing about, and inventing both variables in front of it is the failure
|
|
36
|
+
// Claude Code showed plainly: the harness prefers the environment, authenticates with a key
|
|
37
|
+
// that is not real, and the run dies before it starts. There is no provider choice to protect
|
|
38
|
+
// there either — the credential file already made it.
|
|
39
|
+
const hasAny = readEnv(ctx.env, 'OPENAI_API_KEY') !== undefined ||
|
|
40
|
+
readEnv(ctx.env, 'ANTHROPIC_API_KEY') !== undefined;
|
|
41
|
+
if (hasAny || opencodeHasOwnAuth()) {
|
|
42
|
+
passThrough(env, ctx.env, 'OPENAI_API_KEY');
|
|
43
|
+
passThrough(env, ctx.env, 'ANTHROPIC_API_KEY');
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
passKey(env, ctx.env, 'OPENAI_API_KEY');
|
|
47
|
+
passKey(env, ctx.env, 'ANTHROPIC_API_KEY');
|
|
48
|
+
}
|
|
49
|
+
return { command: 'opencode', args: [...ctx.userArgs], env };
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
//# sourceMappingURL=opencode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opencode.js","sourceRoot":"","sources":["../src/opencode.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEpE;;;;;GAKG;AACH,MAAM,mBAAmB,GAAG,CAAC,iCAAiC,EAAE,4BAA4B,CAAC,CAAC;AAE9F,mFAAmF;AACnF,MAAM,UAAU,kBAAkB;IAChC,OAAO,mBAAmB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AAC9C,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAY;IACtC,EAAE,EAAE,UAAU;IAEd,KAAK,CAAC,MAAM,CAAC,IAAY;QACvB,OAAO,WAAW,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,kBAAkB,EAAE,WAAW,CAAC,CAAC,CAAC;IACtE,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,GAAkB;QAC9B,MAAM,GAAG,GAA2B;YAClC,eAAe,EAAE,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC;YAC9C,kBAAkB,EAAE,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC;SAC5C,CAAC;QACF,2FAA2F;QAC3F,4FAA4F;QAC5F,8FAA8F;QAC9F,yFAAyF;QACzF,qFAAqF;QACrF,EAAE;QACF,+FAA+F;QAC/F,8FAA8F;QAC9F,4FAA4F;QAC5F,8FAA8F;QAC9F,sDAAsD;QACtD,MAAM,MAAM,GACV,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,gBAAgB,CAAC,KAAK,SAAS;YAChD,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,mBAAmB,CAAC,KAAK,SAAS,CAAC;QACtD,IAAI,MAAM,IAAI,kBAAkB,EAAE,EAAE,CAAC;YACnC,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;YAC5C,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,mBAAmB,CAAC,CAAC;QACjD,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;YACxC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,mBAAmB,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC;IAC/D,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Adapter } from '@orcareplay/plugin-api';
|
|
2
|
+
export declare class AdapterRegistry {
|
|
3
|
+
#private;
|
|
4
|
+
register(adapter: Adapter): void;
|
|
5
|
+
get(id: string): Adapter;
|
|
6
|
+
/** Canonical ids. This is the id space a manifest is written in. */
|
|
7
|
+
ids(): string[];
|
|
8
|
+
/**
|
|
9
|
+
* Everything a user may type, canonical ids with their aliases attached.
|
|
10
|
+
*
|
|
11
|
+
* Error messages and help text use this rather than `ids()`: someone who just typed `claude`
|
|
12
|
+
* needs to see that `claude` is spelled `claude`, not be shown a list that omits it.
|
|
13
|
+
*/
|
|
14
|
+
names(): string[];
|
|
15
|
+
/** First adapter that claims the workspace. A detector that throws is treated as "no". */
|
|
16
|
+
detect(cwd: string): Promise<Adapter | undefined>;
|
|
17
|
+
}
|
|
18
|
+
export declare function defaultAdapters(): AdapterRegistry;
|
|
19
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAStD,qBAAa,eAAe;;IAK1B,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAuBhC,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAYxB,oEAAoE;IACpE,GAAG,IAAI,MAAM,EAAE;IAIf;;;;;OAKG;IACH,KAAK,IAAI,MAAM,EAAE;IASjB,0FAA0F;IACpF,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC;CAUxD;AAED,wBAAgB,eAAe,IAAI,eAAe,CAUjD"}
|