@sailresearch/code 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/README.md +87 -0
- package/bin/sail-code.js +7 -0
- package/package.json +30 -0
- package/src/cli.js +166 -0
- package/src/constants.js +177 -0
- package/src/credentials.js +283 -0
- package/src/login.js +453 -0
- package/src/run.js +328 -0
- package/src/setup.js +482 -0
- package/src/toml.js +143 -0
package/README.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# @sailresearch/code
|
|
2
|
+
|
|
3
|
+
Run [Claude Code](https://code.claude.com) on **GLM-5.2** via
|
|
4
|
+
[Sail](https://sailresearch.com) — one command, no Anthropic account.
|
|
5
|
+
|
|
6
|
+
```sh
|
|
7
|
+
npx @sailresearch/code
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
That's it. On first run it opens a browser to mint a Sail API key (or reuses
|
|
11
|
+
`SAIL_API_KEY` / an existing `sail auth login` credential from `~/.sail`),
|
|
12
|
+
sets the routing environment, and launches `claude`. A freshly minted key is
|
|
13
|
+
saved to `~/.sail` (like `sail auth login`); your Claude Code setup is left
|
|
14
|
+
untouched. Set `SAIL_API_KEY` in your environment to skip the browser flow and
|
|
15
|
+
persist nothing.
|
|
16
|
+
|
|
17
|
+
Claude Code itself must be installed (`npm install -g @anthropic-ai/claude-code`).
|
|
18
|
+
|
|
19
|
+
## Persistent setup / VS Code
|
|
20
|
+
|
|
21
|
+
To make `claude` route to Sail without the launcher (for VS Code, or a bare
|
|
22
|
+
`claude`), persist the env block:
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
npx @sailresearch/code setup # writes ~/.claude/settings.json (backed up)
|
|
26
|
+
npx @sailresearch/code setup --revert # restores the backup
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Notes:
|
|
30
|
+
|
|
31
|
+
- After `setup`, `sail-code` runs still win over the persisted values (the
|
|
32
|
+
launcher passes its env as command-line settings, which outrank settings
|
|
33
|
+
files) — so `--mode`/`--model` flags keep working.
|
|
34
|
+
- `setup` (default `--user`) writes the **lowest-precedence** settings file, so
|
|
35
|
+
a repo that ships its own `.claude/settings.json` with a conflicting
|
|
36
|
+
`ANTHROPIC_BASE_URL` / provider selector still outranks it inside that repo —
|
|
37
|
+
run `setup --project` there. Elsewhere, bare `claude` routes to Sail.
|
|
38
|
+
- **VS Code:** extension sessions read the persisted env block, but the
|
|
39
|
+
extension's own pre-launch login check does not. If you have no saved
|
|
40
|
+
Anthropic login, also set `claudeCode.disableLoginPrompt: true` and
|
|
41
|
+
`claudeCode.environmentVariables` in VS Code's user settings — `setup`
|
|
42
|
+
prints the exact snippet.
|
|
43
|
+
- `setup --project` writes the repo-local `.claude/settings.local.json`
|
|
44
|
+
instead — Claude Code's personal, not-shared project settings. It holds your
|
|
45
|
+
API key, so `setup` also adds it to `.claude/.gitignore`; keep it out of
|
|
46
|
+
commits. Claude Code applies project settings only after you've trusted the
|
|
47
|
+
folder in its first-run prompt.
|
|
48
|
+
|
|
49
|
+
## Choosing models
|
|
50
|
+
|
|
51
|
+
```sh
|
|
52
|
+
npx @sailresearch/code --model zai-org/GLM-5.2-FP8 --background-model openai/gpt-oss-120b
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Both tiers default to GLM-5.2. `--background-model` moves Claude Code's
|
|
56
|
+
haiku/background tier (titles, summaries) to a cheaper model from the
|
|
57
|
+
[Sail catalog](https://docs.sailresearch.com/models).
|
|
58
|
+
|
|
59
|
+
## Passing flags to claude
|
|
60
|
+
|
|
61
|
+
Everything after `--` goes to `claude` untouched:
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
npx @sailresearch/code -- --resume
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## How it works
|
|
68
|
+
|
|
69
|
+
Claude Code speaks the Anthropic Messages API to whatever
|
|
70
|
+
`ANTHROPIC_BASE_URL` points at. Sail serves that API for GLM-5.2 (system
|
|
71
|
+
prompts, tools, streaming included), so the launcher only sets environment
|
|
72
|
+
variables — see them with `npx @sailresearch/code env`. Your Anthropic
|
|
73
|
+
credentials are never involved or touched.
|
|
74
|
+
|
|
75
|
+
Claude Code's own non-model traffic (update checks, error reports, usage
|
|
76
|
+
telemetry) still goes to Anthropic endpoints; set
|
|
77
|
+
`CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1` before launching if you need
|
|
78
|
+
that off (it also disables auto-updates).
|
|
79
|
+
|
|
80
|
+
The native Claude Code desktop app reads routing only from managed (MDM)
|
|
81
|
+
configuration and is not supported; use the terminal or VS Code.
|
|
82
|
+
|
|
83
|
+
If you're signed into an enterprise **Claude apps gateway**, that session
|
|
84
|
+
outranks `ANTHROPIC_AUTH_TOKEN`, so `claude` keeps using the gateway instead
|
|
85
|
+
of Sail — run `/logout` first (ordinary Pro/Max users aren't affected).
|
|
86
|
+
|
|
87
|
+
Docs: https://docs.sailresearch.com/claude-code
|
package/bin/sail-code.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sailresearch/code",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Run Claude Code on GLM-5.2 via Sail — one command, no Anthropic account.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Sail Research",
|
|
7
|
+
"homepage": "https://docs.sailresearch.com/claude-code",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/sailresearchco/sail-code.git"
|
|
11
|
+
},
|
|
12
|
+
"type": "module",
|
|
13
|
+
"publishConfig": {
|
|
14
|
+
"access": "public"
|
|
15
|
+
},
|
|
16
|
+
"bin": {
|
|
17
|
+
"sail-code": "bin/sail-code.js"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"bin/",
|
|
21
|
+
"src/",
|
|
22
|
+
"README.md"
|
|
23
|
+
],
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=18.17"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"test": "node --test"
|
|
29
|
+
}
|
|
30
|
+
}
|
package/src/cli.js
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Argument parsing and dispatch for `sail-code`.
|
|
3
|
+
*
|
|
4
|
+
* Everything after a literal `--` is passed to `claude` untouched. Flags
|
|
5
|
+
* before it belong to sail-code; unknown ones are an error (not silently
|
|
6
|
+
* forwarded) so a typo can't change which tool interprets a flag.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { createRequire } from "node:module";
|
|
10
|
+
|
|
11
|
+
import { DEFAULT_MODEL, MODE_VALUES, buildClaudeEnv } from "./constants.js";
|
|
12
|
+
import { maskSecret, resolveTarget } from "./credentials.js";
|
|
13
|
+
import { browserLogin } from "./login.js";
|
|
14
|
+
import { resolveCredentials, run } from "./run.js";
|
|
15
|
+
import { revert, setup } from "./setup.js";
|
|
16
|
+
|
|
17
|
+
const require = createRequire(import.meta.url);
|
|
18
|
+
|
|
19
|
+
const HELP = `sail-code — run Claude Code on GLM-5.2 via Sail (no Anthropic account)
|
|
20
|
+
|
|
21
|
+
Usage:
|
|
22
|
+
sail-code [flags] [-- <claude args...>] Launch claude routed to Sail
|
|
23
|
+
sail-code setup [--user|--project] Persist routing into settings
|
|
24
|
+
[--revert] (--project → gitignored local file)
|
|
25
|
+
sail-code login Log in and store a Sail API key
|
|
26
|
+
sail-code env Print the env block (key masked)
|
|
27
|
+
|
|
28
|
+
Flags:
|
|
29
|
+
--model <id> Main model (default ${DEFAULT_MODEL})
|
|
30
|
+
--background-model <id> Background/haiku-tier model (default: same as --model)
|
|
31
|
+
--mode <name> Sail environment: ${MODE_VALUES.join(" | ")}
|
|
32
|
+
-h, --help Show this help
|
|
33
|
+
-v, --version Show the version
|
|
34
|
+
|
|
35
|
+
Credentials resolve from SAIL_API_KEY, then ~/.sail (shared with the Sail
|
|
36
|
+
CLI), then a browser login. Docs: https://docs.sailresearch.com/claude-code`;
|
|
37
|
+
|
|
38
|
+
/** Parse argv (post-node, post-script). Exported for tests. */
|
|
39
|
+
export function parseArgs(argv) {
|
|
40
|
+
const parsed = {
|
|
41
|
+
command: "run",
|
|
42
|
+
model: undefined,
|
|
43
|
+
backgroundModel: undefined,
|
|
44
|
+
modeFlag: undefined,
|
|
45
|
+
scope: undefined,
|
|
46
|
+
revert: false,
|
|
47
|
+
help: false,
|
|
48
|
+
version: false,
|
|
49
|
+
claudeArgs: [],
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const sep = argv.indexOf("--");
|
|
53
|
+
const own = sep === -1 ? argv : argv.slice(0, sep);
|
|
54
|
+
parsed.claudeArgs = sep === -1 ? [] : argv.slice(sep + 1);
|
|
55
|
+
|
|
56
|
+
const takesValue = {
|
|
57
|
+
"--model": "model",
|
|
58
|
+
"--background-model": "backgroundModel",
|
|
59
|
+
"--mode": "modeFlag",
|
|
60
|
+
};
|
|
61
|
+
let commandSeen = false;
|
|
62
|
+
|
|
63
|
+
for (let i = 0; i < own.length; i++) {
|
|
64
|
+
const arg = own[i];
|
|
65
|
+
if (!arg.startsWith("-")) {
|
|
66
|
+
if (commandSeen)
|
|
67
|
+
throw new Error(
|
|
68
|
+
`unexpected argument "${arg}" (use -- to pass args to claude)`,
|
|
69
|
+
);
|
|
70
|
+
if (!["setup", "login", "env", "run"].includes(arg)) {
|
|
71
|
+
throw new Error(
|
|
72
|
+
`unknown command "${arg}" (expected setup, login, or env)`,
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
parsed.command = arg;
|
|
76
|
+
commandSeen = true;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (arg in takesValue) {
|
|
80
|
+
const value = own[++i];
|
|
81
|
+
if (value === undefined || value.startsWith("-")) {
|
|
82
|
+
throw new Error(`${arg} requires a value`);
|
|
83
|
+
}
|
|
84
|
+
parsed[takesValue[arg]] = value;
|
|
85
|
+
} else if (arg === "--user") parsed.scope = "user";
|
|
86
|
+
else if (arg === "--project") parsed.scope = "project";
|
|
87
|
+
else if (arg === "--revert") parsed.revert = true;
|
|
88
|
+
else if (arg === "-h" || arg === "--help") parsed.help = true;
|
|
89
|
+
else if (arg === "-v" || arg === "--version") parsed.version = true;
|
|
90
|
+
else
|
|
91
|
+
throw new Error(`unknown flag "${arg}" (flags for claude go after --)`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (parsed.modeFlag && !MODE_VALUES.includes(parsed.modeFlag)) {
|
|
95
|
+
throw new Error(
|
|
96
|
+
`unknown --mode "${parsed.modeFlag}" (expected one of: ${MODE_VALUES.join(", ")})`,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
if (parsed.scope && parsed.command !== "setup") {
|
|
100
|
+
throw new Error(`--${parsed.scope} only applies to setup`);
|
|
101
|
+
}
|
|
102
|
+
return parsed;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export async function main() {
|
|
106
|
+
const args = parseArgs(process.argv.slice(2));
|
|
107
|
+
|
|
108
|
+
if (args.help) {
|
|
109
|
+
console.log(HELP);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (args.version) {
|
|
113
|
+
console.log(require("../package.json").version);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
let exitCode = 0;
|
|
118
|
+
switch (args.command) {
|
|
119
|
+
case "login": {
|
|
120
|
+
const target = resolveTarget({ modeFlag: args.modeFlag });
|
|
121
|
+
await browserLogin({
|
|
122
|
+
expectedTarget: target.apiUrl,
|
|
123
|
+
expectedSource: target.source,
|
|
124
|
+
});
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
case "setup":
|
|
128
|
+
exitCode = args.revert
|
|
129
|
+
? revert({ scope: args.scope ?? "user" })
|
|
130
|
+
: await setup({
|
|
131
|
+
scope: args.scope ?? "user",
|
|
132
|
+
modeFlag: args.modeFlag,
|
|
133
|
+
model: args.model,
|
|
134
|
+
backgroundModel: args.backgroundModel,
|
|
135
|
+
});
|
|
136
|
+
break;
|
|
137
|
+
case "env": {
|
|
138
|
+
const { apiKey, apiUrl } = await resolveCredentials({
|
|
139
|
+
modeFlag: args.modeFlag,
|
|
140
|
+
});
|
|
141
|
+
const env = buildClaudeEnv({
|
|
142
|
+
apiUrl,
|
|
143
|
+
apiKey,
|
|
144
|
+
model: args.model,
|
|
145
|
+
backgroundModel: args.backgroundModel,
|
|
146
|
+
});
|
|
147
|
+
for (const [key, value] of Object.entries(env)) {
|
|
148
|
+
const shown =
|
|
149
|
+
key === "ANTHROPIC_AUTH_TOKEN" ? maskSecret(value) : value;
|
|
150
|
+
console.log(`${key}=${shown}`);
|
|
151
|
+
}
|
|
152
|
+
console.error(
|
|
153
|
+
"\n(ANTHROPIC_AUTH_TOKEN is masked; it is your SAIL_API_KEY value)",
|
|
154
|
+
);
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
default:
|
|
158
|
+
exitCode = await run({
|
|
159
|
+
modeFlag: args.modeFlag,
|
|
160
|
+
model: args.model,
|
|
161
|
+
backgroundModel: args.backgroundModel,
|
|
162
|
+
claudeArgs: args.claudeArgs,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
if (exitCode !== 0) process.exit(exitCode);
|
|
166
|
+
}
|
package/src/constants.js
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared constants: the GLM model default, Sail environment targets, and the
|
|
3
|
+
* single source of truth for the Claude Code environment block.
|
|
4
|
+
*
|
|
5
|
+
* Every surface that configures Claude Code (the `run` exec path, the `setup`
|
|
6
|
+
* settings.json path, and the `env` printout) must build its variables through
|
|
7
|
+
* `buildClaudeEnv` so the three can never drift.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export const DEFAULT_MODEL = "zai-org/GLM-5.2-FP8";
|
|
11
|
+
|
|
12
|
+
/** Public API targets by mode name, mirroring the Sail CLI's mode map. */
|
|
13
|
+
export const MODE_API_URLS = {
|
|
14
|
+
prod: "https://api.sailresearch.com",
|
|
15
|
+
dev: "https://dev.sailresearch.com",
|
|
16
|
+
staging: "https://staging.sailresearch.com",
|
|
17
|
+
local: "http://localhost:8080",
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const MODE_VALUES = Object.keys(MODE_API_URLS);
|
|
21
|
+
|
|
22
|
+
/** Web app that serves the browser login handoff (`/cli-auth`). */
|
|
23
|
+
export const DEFAULT_APP_URL = "https://app.sailresearch.com";
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Claude Code reads the Anthropic Messages endpoint as `{base}/v1/messages`,
|
|
27
|
+
* so the base URL must be the bare API host (no `/v1` suffix).
|
|
28
|
+
*
|
|
29
|
+
* `ANTHROPIC_AUTH_TOKEN` (not `ANTHROPIC_API_KEY`) is required: Sail
|
|
30
|
+
* authenticates with `Authorization: Bearer` and rejects the Anthropic
|
|
31
|
+
* `x-api-key` header that `ANTHROPIC_API_KEY` would select.
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* Capabilities declared for aliases pinned to the DEFAULT (GLM) model.
|
|
35
|
+
* Claude Code enables effort/thinking by matching the model ID against known
|
|
36
|
+
* patterns; a custom ID like `zai-org/GLM-5.2-FP8` matches none, so those
|
|
37
|
+
* features are silently DISABLED — `/effort` selections and
|
|
38
|
+
* `CLAUDE_CODE_EFFORT_LEVEL` get dropped before the request. Declaring
|
|
39
|
+
* `_SUPPORTED_CAPABILITIES` is the documented primary fix for pinned custom
|
|
40
|
+
* models. GLM-5.2 is a reasoning model and Sail maps Anthropic `thinking` →
|
|
41
|
+
* reasoning and `output_config.effort` → reasoning effort, so both are real.
|
|
42
|
+
* Deliberately conservative: no xhigh/max effort or adaptive/interleaved
|
|
43
|
+
* thinking claims until validated end-to-end.
|
|
44
|
+
*/
|
|
45
|
+
export const DEFAULT_MODEL_CAPABILITIES = "effort,thinking";
|
|
46
|
+
|
|
47
|
+
export function buildClaudeEnv({ apiUrl, apiKey, model, backgroundModel }) {
|
|
48
|
+
const base = String(apiUrl ?? "").replace(/\/+$/, "");
|
|
49
|
+
const main = model || DEFAULT_MODEL;
|
|
50
|
+
const background = backgroundModel || main;
|
|
51
|
+
// Only aliases pinned to the KNOWN default model get a capabilities
|
|
52
|
+
// declaration — for a user-overridden --model/--background-model we can't
|
|
53
|
+
// know what the model supports, and `_SUPPORTED_CAPABILITIES` disables
|
|
54
|
+
// everything unlisted, so guessing wrong would be worse than Claude Code's
|
|
55
|
+
// built-in detection.
|
|
56
|
+
const capabilities = {};
|
|
57
|
+
for (const [alias, m] of [
|
|
58
|
+
["OPUS", main],
|
|
59
|
+
["SONNET", main],
|
|
60
|
+
["HAIKU", background],
|
|
61
|
+
["FABLE", main],
|
|
62
|
+
]) {
|
|
63
|
+
if (m === DEFAULT_MODEL) {
|
|
64
|
+
capabilities[`ANTHROPIC_DEFAULT_${alias}_MODEL_SUPPORTED_CAPABILITIES`] =
|
|
65
|
+
DEFAULT_MODEL_CAPABILITIES;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
ANTHROPIC_BASE_URL: base,
|
|
70
|
+
ANTHROPIC_AUTH_TOKEN: apiKey,
|
|
71
|
+
// Pin the startup model. Without this, a saved /model choice (persisted
|
|
72
|
+
// into settings.json) or the model restored by --resume wins startup
|
|
73
|
+
// resolution, and a `fable` alias or full claude-* ID would reach Sail
|
|
74
|
+
// unmapped. Precedence keeps mid-session /model switching working:
|
|
75
|
+
// /model (session) > --model > ANTHROPIC_MODEL > settings model field.
|
|
76
|
+
ANTHROPIC_MODEL: main,
|
|
77
|
+
ANTHROPIC_DEFAULT_OPUS_MODEL: main,
|
|
78
|
+
ANTHROPIC_DEFAULT_SONNET_MODEL: main,
|
|
79
|
+
ANTHROPIC_DEFAULT_HAIKU_MODEL: background,
|
|
80
|
+
ANTHROPIC_DEFAULT_FABLE_MODEL: main,
|
|
81
|
+
// Declare effort/thinking for aliases pinned to the default GLM model
|
|
82
|
+
// (see DEFAULT_MODEL_CAPABILITIES). Custom overrides get no declaration.
|
|
83
|
+
...capabilities,
|
|
84
|
+
// Pin subagents to the main Sail model. CLAUDE_CODE_SUBAGENT_MODEL is the
|
|
85
|
+
// highest-priority subagent model source — it outranks a subagent's
|
|
86
|
+
// frontmatter `model:` and the alias remaps above — so a value inherited
|
|
87
|
+
// from the user's shell or a settings file (e.g. a stale `claude-sonnet-*`
|
|
88
|
+
// from a prior Anthropic/Bedrock setup) would otherwise make every
|
|
89
|
+
// delegated subagent request an unmapped model from Sail and fail. Setting
|
|
90
|
+
// it to the resolved main model neutralizes that inherited value on every
|
|
91
|
+
// surface (this rides the exec env and the highest-precedence --settings
|
|
92
|
+
// layer, and setup persists it) and also routes custom subagents whose
|
|
93
|
+
// frontmatter pins a full claude-* ID onto GLM instead of failing.
|
|
94
|
+
// Trade-off: per-subagent frontmatter tiers and --background-model don't
|
|
95
|
+
// apply to subagents under sail-code; they all run on the main model.
|
|
96
|
+
CLAUDE_CODE_SUBAGENT_MODEL: main,
|
|
97
|
+
// Sail turn times can exceed Claude Code's default request timeout.
|
|
98
|
+
API_TIMEOUT_MS: "3000000",
|
|
99
|
+
// Disable the separate 5-minute stream-idle watchdog. It's independent of
|
|
100
|
+
// API_TIMEOUT_MS (that's the whole-request cap; this fires when no bytes
|
|
101
|
+
// arrive for 5 min) and is ACTIVE by default on custom `ANTHROPIC_BASE_URL`
|
|
102
|
+
// connections like Sail. A throughput-optimized Sail turn can queue longer
|
|
103
|
+
// than 5 min before streaming (standard/flex completion windows), so
|
|
104
|
+
// without this it would be aborted mid-turn despite the raised request
|
|
105
|
+
// timeout. "0" disables it (documented for slow gateways).
|
|
106
|
+
API_FORCE_IDLE_TIMEOUT: "0",
|
|
107
|
+
// MCP tool search needs server-side tool_reference expansion, which Sail
|
|
108
|
+
// does not implement; force it off so Claude Code loads MCP tool schemas
|
|
109
|
+
// upfront (those Sail passes through). Explicit "false" (vs unset) also
|
|
110
|
+
// lets setup/revert clean up any previously persisted value.
|
|
111
|
+
ENABLE_TOOL_SEARCH: "false",
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** The env keys this tool owns in settings.json — used by setup/revert. */
|
|
116
|
+
export const OWNED_ENV_KEYS = Object.keys(
|
|
117
|
+
buildClaudeEnv({ apiUrl: "", apiKey: "" }),
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Provider-selection env vars that outrank ANTHROPIC_AUTH_TOKEN in Claude
|
|
122
|
+
* Code's auth precedence. If the user's shell has any of these from another
|
|
123
|
+
* Claude Code setup, an unscrubbed child would route to Bedrock / Vertex /
|
|
124
|
+
* Foundry / Mantle / Claude-Platform-on-AWS instead of Sail. `run` strips them
|
|
125
|
+
* from the spawned env. We strip only the selector, not the ancillary provider
|
|
126
|
+
* vars (`ANTHROPIC_AWS_*`, `AWS_REGION`, cloud creds): those are inert once the
|
|
127
|
+
* selector is gone, and some are too broad to safely drop from the child.
|
|
128
|
+
*/
|
|
129
|
+
export const CONFLICTING_PROVIDER_VARS = [
|
|
130
|
+
"CLAUDE_CODE_USE_BEDROCK",
|
|
131
|
+
"CLAUDE_CODE_USE_VERTEX",
|
|
132
|
+
"CLAUDE_CODE_USE_FOUNDRY",
|
|
133
|
+
"CLAUDE_CODE_USE_MANTLE",
|
|
134
|
+
"CLAUDE_CODE_USE_ANTHROPIC_AWS",
|
|
135
|
+
];
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Env vars that inject extra HTTP headers into every Anthropic request.
|
|
139
|
+
* Claude Code merges `ANTHROPIC_CUSTOM_HEADERS` onto outgoing requests, so a
|
|
140
|
+
* value left over from another gateway setup (e.g. an `x-portkey-api-key`)
|
|
141
|
+
* would be sent to Sail once we overlay `ANTHROPIC_BASE_URL` — leaking a
|
|
142
|
+
* stale third-party secret and possibly mutating the Sail request. We only
|
|
143
|
+
* own the base URL and token, not arbitrary headers, so strip these from the
|
|
144
|
+
* spawned env alongside the provider selectors.
|
|
145
|
+
*/
|
|
146
|
+
export const HEADER_INJECTION_VARS = ["ANTHROPIC_CUSTOM_HEADERS"];
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Companion vars that customize a pinned alias model's display and
|
|
150
|
+
* capabilities. They are keyed to the ALIAS, not the concrete model id, so
|
|
151
|
+
* once we repoint `ANTHROPIC_DEFAULT_<ALIAS>_MODEL` to GLM a value inherited
|
|
152
|
+
* from another setup applies to GLM. `_SUPPORTED_CAPABILITIES` is the
|
|
153
|
+
* dangerous one: when set it enables only the listed capabilities and
|
|
154
|
+
* *disables the rest* for that pinned model, so a stale value can hide
|
|
155
|
+
* behavior GLM supports (or advertise ones it doesn't); `_NAME`/`_DESCRIPTION`
|
|
156
|
+
* just mislabel it in the picker. We scrub INHERITED values of these from the
|
|
157
|
+
* spawned child env (`run`) and the persisted settings (`setup`) — our own
|
|
158
|
+
* env block then declares `_SUPPORTED_CAPABILITIES` for aliases pinned to the
|
|
159
|
+
* default GLM model (see DEFAULT_MODEL_CAPABILITIES), and that declaration
|
|
160
|
+
* also rides the temp `--settings` layer, which outranks a companion var
|
|
161
|
+
* living in a settings file. For user-overridden models nothing is declared
|
|
162
|
+
* (built-in detection), and NAME/DESCRIPTION are never set. Empty string is
|
|
163
|
+
* NOT a documented "unset" for these — for `_SUPPORTED_CAPABILITIES` it could
|
|
164
|
+
* read as "no capabilities", worse than leaving it — so inherited values are
|
|
165
|
+
* deleted, never emptied. Residual gap: with a custom --model, a companion
|
|
166
|
+
* var in a *settings file* during `run` can't be cleared by our layers.
|
|
167
|
+
*/
|
|
168
|
+
export const MODEL_ALIAS_COMPANION_VARS = [
|
|
169
|
+
"OPUS",
|
|
170
|
+
"SONNET",
|
|
171
|
+
"HAIKU",
|
|
172
|
+
"FABLE",
|
|
173
|
+
].flatMap((alias) => [
|
|
174
|
+
`ANTHROPIC_DEFAULT_${alias}_MODEL_NAME`,
|
|
175
|
+
`ANTHROPIC_DEFAULT_${alias}_MODEL_DESCRIPTION`,
|
|
176
|
+
`ANTHROPIC_DEFAULT_${alias}_MODEL_SUPPORTED_CAPABILITIES`,
|
|
177
|
+
]);
|