mirror of
https://github.com/qwibitai/nanoclaw.git
synced 2026-06-12 18:11:51 +08:00
6591062fbb
The original approach passed ANTHROPIC_AUTH_TOKEN into the container
as an env var and disabled the proxy for the custom host (NO_PROXY) —
which works, but bypasses OneCLI entirely for that credential. The
container holds the raw secret, the gateway loses audit/rotation, and
we lose the rest of the vault's protections for this cohort.
OneCLI-native version: store the token as a generic secret with header
injection (--header-name Authorization --value-format 'Bearer {value}'
+ host-pattern matching the base URL hostname). The container only
needs ANTHROPIC_BASE_URL plus a placeholder ANTHROPIC_AUTH_TOKEN — the
proxy rewrites the Authorization header on the wire.
setup/lib/setup-config.ts — adds --anthropic-auth-token alongside the
existing --anthropic-base-url.
setup/auto.ts — runAuthStep short-circuits the auth-method prompt when
both NANOCLAW_ANTHROPIC_BASE_URL and NANOCLAW_ANTHROPIC_AUTH_TOKEN are
set: creates the OneCLI generic secret, writes ANTHROPIC_BASE_URL to
.env (so the runtime reads it), and appends `import './claude.js';` to
src/providers/index.ts (so the provider only registers when the user
has configured a custom endpoint — no branching for everyone else).
src/providers/claude.ts — drops ANTHROPIC_AUTH_TOKEN/NO_PROXY
passthrough. Reads ANTHROPIC_BASE_URL from .env, sets a placeholder
ANTHROPIC_AUTH_TOKEN in container env so the SDK includes an
Authorization header for OneCLI to overwrite.
src/providers/index.ts — removes the unconditional import; setup
appends it on demand.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
143 lines
4.1 KiB
TypeScript
143 lines
4.1 KiB
TypeScript
/**
|
|
* Setup-time advanced-config registry.
|
|
*
|
|
* One source of truth for: CLI flags, env-var names, the advanced-settings
|
|
* screen, and `--help` output. The flag parser, env reader, and UI screen
|
|
* all consume this list and write resolved values back to `process.env` so
|
|
* existing step code keeps reading env vars unchanged.
|
|
*
|
|
* Default name conventions (overridable per entry):
|
|
* key 'fooBar' → envVar 'NANOCLAW_FOO_BAR' → flag '--foo-bar'
|
|
*
|
|
* Surface levels:
|
|
* 'flag' — CLI flag + env var only (debug/internal knobs)
|
|
* 'flag+ui' — also shown in the advanced-settings screen
|
|
*/
|
|
|
|
export type EntrySurface = 'flag' | 'flag+ui';
|
|
|
|
interface BaseEntry {
|
|
/** Canonical camelCase key. */
|
|
key: string;
|
|
/** Override of the auto-derived NANOCLAW_<UPPER_SNAKE> env var. */
|
|
envVar?: string;
|
|
/** Override of the auto-derived --kebab-case flag. */
|
|
flag?: string;
|
|
label: string;
|
|
help: string;
|
|
surface: EntrySurface;
|
|
/** UI section header. Entries without a group land in 'Other'. */
|
|
group?: string;
|
|
/** Mask in UI, redact in logs. */
|
|
secret?: boolean;
|
|
}
|
|
|
|
interface StringEntry extends BaseEntry {
|
|
type: 'string' | 'url';
|
|
default?: string;
|
|
placeholder?: string;
|
|
validate?: (v: string) => string | undefined;
|
|
}
|
|
|
|
interface EnumEntry extends BaseEntry {
|
|
type: 'enum';
|
|
options: { value: string; label: string; hint?: string }[];
|
|
default?: string;
|
|
}
|
|
|
|
interface BoolEntry extends BaseEntry {
|
|
type: 'boolean';
|
|
default?: boolean;
|
|
}
|
|
|
|
interface IntEntry extends BaseEntry {
|
|
type: 'integer';
|
|
default?: number;
|
|
min?: number;
|
|
max?: number;
|
|
}
|
|
|
|
export type Entry = StringEntry | EnumEntry | BoolEntry | IntEntry;
|
|
|
|
const httpUrl = (v: string): string | undefined =>
|
|
/^https?:\/\/\S+/.test(v) ? undefined : 'Must be http(s)://…';
|
|
|
|
export const CONFIG: Entry[] = [
|
|
{
|
|
key: 'onecliApiHost',
|
|
label: 'OneCLI vault URL',
|
|
help: 'Use a remote OneCLI vault instead of installing one locally.',
|
|
surface: 'flag+ui',
|
|
group: 'OneCLI',
|
|
type: 'url',
|
|
default: 'https://app.onecli.sh',
|
|
placeholder: 'https://app.onecli.sh',
|
|
validate: httpUrl,
|
|
},
|
|
{
|
|
key: 'onecliApiToken',
|
|
label: 'OneCLI access token',
|
|
help: 'Bearer token for the remote vault. Required if --onecli-api-host is set.',
|
|
surface: 'flag+ui',
|
|
group: 'OneCLI',
|
|
type: 'string',
|
|
secret: true,
|
|
placeholder: 'oc_…',
|
|
validate: (v) => (v.startsWith('oc_') ? undefined : 'Must start with oc_'),
|
|
},
|
|
{
|
|
key: 'anthropicBaseUrl',
|
|
label: 'Anthropic API base URL',
|
|
help: 'Use a proxy or alternative endpoint instead of api.anthropic.com.',
|
|
surface: 'flag+ui',
|
|
group: 'Anthropic',
|
|
type: 'url',
|
|
placeholder: 'https://api.anthropic.com',
|
|
validate: httpUrl,
|
|
},
|
|
{
|
|
key: 'anthropicAuthToken',
|
|
label: 'Anthropic auth token',
|
|
help: 'Bearer token for the custom Anthropic endpoint. Used together with --anthropic-base-url.',
|
|
surface: 'flag+ui',
|
|
group: 'Anthropic',
|
|
type: 'string',
|
|
secret: true,
|
|
validate: (v) => (v.trim() ? undefined : 'Required'),
|
|
},
|
|
|
|
// Existing env-var knobs — flag-only so they don't clutter the UI screen.
|
|
{
|
|
key: 'skip',
|
|
envVar: 'NANOCLAW_SKIP',
|
|
label: 'Skip steps',
|
|
help: 'Comma-separated step names to skip (debugging only).',
|
|
surface: 'flag',
|
|
type: 'string',
|
|
},
|
|
{
|
|
key: 'displayName',
|
|
envVar: 'NANOCLAW_DISPLAY_NAME',
|
|
label: 'Display name',
|
|
help: 'Skip the "what should your assistant call you?" prompt.',
|
|
surface: 'flag',
|
|
type: 'string',
|
|
},
|
|
];
|
|
|
|
// ─── name derivation ───────────────────────────────────────────────────
|
|
|
|
export function envVarFor(e: Entry): string {
|
|
if (e.envVar) return e.envVar;
|
|
return `NANOCLAW_${e.key.replace(/[A-Z]/g, (c) => `_${c}`).toUpperCase()}`;
|
|
}
|
|
|
|
export function flagFor(e: Entry): string {
|
|
if (e.flag) return e.flag;
|
|
return `--${e.key.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`)}`;
|
|
}
|
|
|
|
export function findByFlag(flag: string): Entry | null {
|
|
return CONFIG.find((e) => flagFor(e) === flag) ?? null;
|
|
}
|