agent-shim 7.13.1 → 7.14.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/cli.cjs +95 -27
- package/dist/index.cjs +70 -7
- package/dist/index.mjs +70 -7
- package/dist/types/index.d.ts +2789 -40
- package/package.json +3 -1
- package/dist/types/checkReport.d.ts +0 -154
- package/dist/types/claudeShim.d.ts +0 -114
- package/dist/types/cli/bool.d.ts +0 -8
- package/dist/types/cli/commandDeps.d.ts +0 -39
- package/dist/types/cli/envBool.d.ts +0 -11
- package/dist/types/cli/pairs.d.ts +0 -19
- package/dist/types/cliError.d.ts +0 -27
- package/dist/types/codex/http.d.ts +0 -15
- package/dist/types/config/classify.d.ts +0 -49
- package/dist/types/config/load.d.ts +0 -42
- package/dist/types/config/schema.d.ts +0 -746
- package/dist/types/config/store.d.ts +0 -46
- package/dist/types/configProfilesStore.d.ts +0 -61
- package/dist/types/configure.d.ts +0 -170
- package/dist/types/credential.d.ts +0 -136
- package/dist/types/credentialCache.d.ts +0 -46
- package/dist/types/directoryRulesStore.d.ts +0 -43
- package/dist/types/doctorReport.d.ts +0 -117
- package/dist/types/frontdoor/capability.d.ts +0 -19
- package/dist/types/frontdoor/capture.d.ts +0 -58
- package/dist/types/frontdoor/connect.d.ts +0 -209
- package/dist/types/frontdoor/connectEffects.d.ts +0 -3
- package/dist/types/frontdoor/custody.d.ts +0 -32
- package/dist/types/frontdoor/ensure.d.ts +0 -36
- package/dist/types/frontdoor/headroomHop.d.ts +0 -22
- package/dist/types/frontdoor/pipeline.d.ts +0 -109
- package/dist/types/frontdoor/probe.d.ts +0 -13
- package/dist/types/frontdoor/realFrontDoorPort.d.ts +0 -5
- package/dist/types/frontdoor/route.d.ts +0 -112
- package/dist/types/frontdoor/server.d.ts +0 -44
- package/dist/types/frontdoor/state.d.ts +0 -57
- package/dist/types/frontdoor/supervisor.d.ts +0 -48
- package/dist/types/frontdoor/tap.d.ts +0 -9
- package/dist/types/frontdoor/trust.d.ts +0 -30
- package/dist/types/frontdoor/x509.d.ts +0 -11
- package/dist/types/headroom/ensure.d.ts +0 -31
- package/dist/types/headroom/headers.d.ts +0 -11
- package/dist/types/headroom/settings.d.ts +0 -13
- package/dist/types/headroom/source.d.ts +0 -8
- package/dist/types/headroom/state.d.ts +0 -77
- package/dist/types/headroom/supervisor.d.ts +0 -107
- package/dist/types/identityStore.d.ts +0 -85
- package/dist/types/launchWiring.d.ts +0 -49
- package/dist/types/launcher/argv.d.ts +0 -42
- package/dist/types/launcher/cascade.d.ts +0 -42
- package/dist/types/launcher/cliOverride.d.ts +0 -38
- package/dist/types/launcher/extraFlags.d.ts +0 -6
- package/dist/types/launcher/farm.d.ts +0 -168
- package/dist/types/launcher/flags.d.ts +0 -96
- package/dist/types/launcher/guard.d.ts +0 -57
- package/dist/types/launcher/identity.d.ts +0 -95
- package/dist/types/launcher/lock.d.ts +0 -41
- package/dist/types/launcher/pool.d.ts +0 -44
- package/dist/types/launcher/ports.d.ts +0 -135
- package/dist/types/launcher/spawn.d.ts +0 -20
- package/dist/types/launcher.d.ts +0 -98
- package/dist/types/legacy.d.ts +0 -29
- package/dist/types/pathNorm.d.ts +0 -14
- package/dist/types/paths.d.ts +0 -79
- package/dist/types/poolPickReport.d.ts +0 -44
- package/dist/types/poolStore.d.ts +0 -18
- package/dist/types/providersStore.d.ts +0 -137
- package/dist/types/realCredentialCache.d.ts +0 -11
- package/dist/types/realPorts.d.ts +0 -109
- package/dist/types/resolve/conditions.d.ts +0 -37
- package/dist/types/resolve/decide.d.ts +0 -45
- package/dist/types/resolve/extends.d.ts +0 -41
- package/dist/types/resolve/flatten.d.ts +0 -13
- package/dist/types/resolve/match.d.ts +0 -58
- package/dist/types/resolve/pipeline.d.ts +0 -33
- package/dist/types/resolve/plan.d.ts +0 -57
- package/dist/types/resolve/projects.d.ts +0 -61
- package/dist/types/resolve/reconcile.d.ts +0 -80
- package/dist/types/resolve/types.d.ts +0 -159
- package/dist/types/resolve/walk.d.ts +0 -85
- package/dist/types/resolve/walkPolicy.d.ts +0 -15
- package/dist/types/usage/account.d.ts +0 -20
- package/dist/types/usage/middleware.d.ts +0 -17
- package/dist/types/usage/pick.d.ts +0 -62
- package/dist/types/usage/plan.d.ts +0 -18
- package/dist/types/usage/poolPick.d.ts +0 -31
- package/dist/types/usage/preflight.d.ts +0 -20
- package/dist/types/usage/rateLimit.d.ts +0 -25
- package/dist/types/usage/read.d.ts +0 -70
- package/dist/types/usage/scan.d.ts +0 -24
- package/dist/types/usage/schema.d.ts +0 -318
- package/dist/types/usage/store.d.ts +0 -43
- package/dist/types/versionDiscovery.d.ts +0 -47
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { type CredentialCache, type CredentialSource, type CredentialTarget, type Identity } from "./config/schema";
|
|
2
|
-
import { CliError } from "./cliError";
|
|
3
|
-
import type { LayoutPaths } from "./paths";
|
|
4
|
-
/** Raised by any operation that requires an identity to already exist, when it does not. */
|
|
5
|
-
export declare class IdentityNotFoundError extends CliError {
|
|
6
|
-
readonly name: string;
|
|
7
|
-
constructor(name: string);
|
|
8
|
-
}
|
|
9
|
-
/** Raised by `addIdentity` when an identity with the given name already has an `identity.json`. */
|
|
10
|
-
export declare class IdentityAlreadyExistsError extends CliError {
|
|
11
|
-
readonly identityName: string;
|
|
12
|
-
constructor(identityName: string);
|
|
13
|
-
}
|
|
14
|
-
/** Raised by `addIdentity` when `name` fails `IdentitySchema`'s own naming rule — it must start with a letter or number and may then contain letters, numbers, dots, hyphens, underscores, and at signs, so an email address names an identity directly while a *leading* `@` stays invalid (it would collide with the `@name` selector syntax's first-`@` split). */
|
|
15
|
-
export declare class InvalidIdentityNameError extends CliError {
|
|
16
|
-
readonly attemptedName: string;
|
|
17
|
-
constructor(attemptedName: string);
|
|
18
|
-
}
|
|
19
|
-
export declare function identityExists(paths: LayoutPaths, name: string): boolean;
|
|
20
|
-
/** Reads and validates one identity's `identity.json`, or undefined when it does not exist. */
|
|
21
|
-
export declare function readIdentity(paths: LayoutPaths, name: string): Identity | undefined;
|
|
22
|
-
/**
|
|
23
|
-
* Creates a new identity: validates `name` against `IdentitySchema`'s own naming rule and writes a fresh `identity.json` with `allowAmbientCredential: false` and no `defaultConfigProfile`.
|
|
24
|
-
*
|
|
25
|
-
* Throws `IdentityAlreadyExistsError` if an identity with this name already has an `identity.json` — `add` never silently overwrites an existing identity. Throws `InvalidIdentityNameError` when `name` fails `IdentitySchema`'s naming rule, rather than letting the underlying `ZodError` escape as an unhandled crash.
|
|
26
|
-
*/
|
|
27
|
-
export declare function addIdentity(paths: LayoutPaths, name: string): Identity;
|
|
28
|
-
/**
|
|
29
|
-
* Persists `name` as the active identity, written atomically as plain text (not JSON — this file is read by `decideIdentity` in `src/launcher/identity.ts` via a simple UTF-8 read-and-trim, matching the README's documented `~/.agent-shim/active-identity` file).
|
|
30
|
-
*
|
|
31
|
-
* `name` may be a `pool:<name>` selector, which makes launches pick a member of that pool. Throws `IdentityNotFoundError` when no identity with this name exists yet, and `PoolNotFoundError` for a pool that is not defined: selecting either would silently persist a name nothing else can ever load.
|
|
32
|
-
*/
|
|
33
|
-
export declare function useIdentity(paths: LayoutPaths, name: string): void;
|
|
34
|
-
/** Reads the persisted active-identity file, or undefined when none is set. */
|
|
35
|
-
export declare function readActiveIdentity(paths: LayoutPaths): string | undefined;
|
|
36
|
-
/**
|
|
37
|
-
* Whether a directory name directly under `identitiesDir` names an actual identity, rather than one of agent-shim's own farm directories.
|
|
38
|
-
*
|
|
39
|
-
* `IdentitySchema` requires an identity name to start with a letter or digit, so a leading `.` can only be a resync's own bookkeeping: a `.<identity>.scratch.<suffix>` tree still being built, or a `.<identity>.previous.<suffix>` superseded farm retained for `agent-shim identity resolve-conflicts`. Neither is an identity, and neither should be reported as a broken one for lacking an `identity.json` a resync never put there.
|
|
40
|
-
*/
|
|
41
|
-
export declare function isIdentityDirectoryName(name: string): boolean;
|
|
42
|
-
/** One identity as reported by `listIdentities`, whose `identity.json` parsed and validated cleanly. */
|
|
43
|
-
export interface IdentityListEntry {
|
|
44
|
-
readonly name: string;
|
|
45
|
-
readonly identity: Identity;
|
|
46
|
-
readonly isActive: boolean;
|
|
47
|
-
readonly problem?: never;
|
|
48
|
-
}
|
|
49
|
-
/** One identity whose `identity.json` is present but unreadable — malformed JSON, or valid JSON this version's `IdentitySchema` rejects. `problem` carries the reason, already flattened onto a single line. */
|
|
50
|
-
export interface UnreadableIdentityListEntry {
|
|
51
|
-
readonly name: string;
|
|
52
|
-
readonly identity?: never;
|
|
53
|
-
readonly isActive: boolean;
|
|
54
|
-
readonly problem: string;
|
|
55
|
-
}
|
|
56
|
-
/** Either shape `listIdentities` can report, discriminated by which of `identity`/`problem` is present rather than by a tag field — the two are never simultaneously satisfiable. */
|
|
57
|
-
export type IdentityListing = IdentityListEntry | UnreadableIdentityListEntry;
|
|
58
|
-
/**
|
|
59
|
-
* Lists every identity under `identitiesDir`, marking which one (if any) is currently active.
|
|
60
|
-
*
|
|
61
|
-
* One identity whose `identity.json` cannot be read is reported as its own `UnreadableIdentityListEntry` rather than aborting the whole listing. A single bad file blocking `identity list` outright is exactly the failure mode that hides every *other* identity from view at the moment the user most needs to see them — and the file need not even be corrupt to land here, since a name written by a newer agent-shim whose naming rule has since widened is rejected outright by an older binary's own copy of `IdentitySchema`.
|
|
62
|
-
*/
|
|
63
|
-
export declare function listIdentities(paths: LayoutPaths): readonly IdentityListing[];
|
|
64
|
-
/**
|
|
65
|
-
* Sets `identity`'s `defaultConfigProfile` field, or clears it when `profileName` is undefined. Throws `IdentityNotFoundError` when the identity does not exist. Whether the profile exists is the caller's concern: `identity set --default-profile` checks it first.
|
|
66
|
-
*/
|
|
67
|
-
export declare function setDefaultConfigProfile(paths: LayoutPaths, identityName: string, profileName: string | undefined): Identity;
|
|
68
|
-
/**
|
|
69
|
-
* Patches `identity`'s `allowAmbientCredential` field. Throws `IdentityNotFoundError` when the identity does not exist.
|
|
70
|
-
*/
|
|
71
|
-
export declare function setAllowAmbientCredential(paths: LayoutPaths, identityName: string, allow: boolean): Identity;
|
|
72
|
-
/** The change `setIdentityCredential` makes: new sources and/or a new target for the credential block, or `false` to remove the block and return the identity to its stored login. */
|
|
73
|
-
export type IdentityCredentialChange = {
|
|
74
|
-
readonly sources?: readonly CredentialSource[];
|
|
75
|
-
readonly target?: CredentialTarget;
|
|
76
|
-
readonly cache?: CredentialCache | false;
|
|
77
|
-
} | false;
|
|
78
|
-
/**
|
|
79
|
-
* Sets, changes or removes `identityName`'s credential block. New `sources` replace the whole ordered list (the order is the meaning); a `target` alone keeps the existing sources, and so needs a credential block to exist already. Throws `IdentityNotFoundError` when the identity does not exist, and `UsageError` when only a target is given for an identity with no credential yet.
|
|
80
|
-
*/
|
|
81
|
-
export declare function setIdentityCredential(paths: LayoutPaths, identityName: string, change: IdentityCredentialChange): Identity;
|
|
82
|
-
/**
|
|
83
|
-
* Deletes identity `name` entirely: its directory under `identitiesDir` (the farm, its `identity.json`, and whatever that farm holds unshared, credentials included), its resync lock, any scratch or superseded farm a resync left behind, and the active-identity selection when it names this identity. Data shared into `~/.claude` stays there, since the farm only ever symlinks to it. Throws `IdentityNotFoundError` when the identity does not exist.
|
|
84
|
-
*/
|
|
85
|
-
export declare function removeIdentity(paths: LayoutPaths, name: string): void;
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { CliError } from "./cliError";
|
|
2
|
-
import type { Pool } from "./config/schema";
|
|
3
|
-
import { type FarmRuntime, type LaunchPlan, type PrepareLaunchParams } from "./launcher";
|
|
4
|
-
import type { LogPort, ProcPort } from "./launcher/ports";
|
|
5
|
-
import { type LayoutPaths } from "./paths";
|
|
6
|
-
import { type DaemonSpawner } from "./realPorts";
|
|
7
|
-
/** Builds the farm runtime the launcher's resync step needs for a launch in `cwd`, wired to real filesystem, clock, git, and process facilities, plus the directory-scoped selections the launcher needs before it can resync anything. */
|
|
8
|
-
export declare function buildFarmRuntime(paths: LayoutPaths, cwd: string): {
|
|
9
|
-
runtime: FarmRuntime;
|
|
10
|
-
directoryIdentity?: string;
|
|
11
|
-
directoryConfigProfile?: string;
|
|
12
|
-
globalDefaultConfigProfile?: string;
|
|
13
|
-
pools?: Readonly<Record<string, Pool>>;
|
|
14
|
-
};
|
|
15
|
-
/** Everything `realPrepareLaunchParams` takes beyond the state root: the process facts to launch against, the farm runtime for the directory, and whether a missing configuration profile was knowingly chosen. */
|
|
16
|
-
export interface RealLaunchOptions {
|
|
17
|
-
readonly proc: ProcPort;
|
|
18
|
-
readonly farm: ReturnType<typeof buildFarmRuntime>;
|
|
19
|
-
readonly log: LogPort;
|
|
20
|
-
/** Starts the front door and headroom daemons when a launch needs them: the command line spawns itself, a library host names the agent-shim executable. */
|
|
21
|
-
readonly spawnDaemon: DaemonSpawner;
|
|
22
|
-
readonly allowMissingConfigProfile?: boolean;
|
|
23
|
-
}
|
|
24
|
-
/** The launcher's inputs wired to this machine: the real filesystem, daemon ports, credential resolver and `claude` binary discovery. */
|
|
25
|
-
export declare function realPrepareLaunchParams(paths: LayoutPaths, options: RealLaunchOptions): PrepareLaunchParams;
|
|
26
|
-
/** Raised by `prepareClaudeLaunch` when the launch is refused: no identity, a missing profile, an ambient credential, an unresolvable credential and the like. `message` is what the launcher logged; `exitCode` is the status the command line would have exited with. */
|
|
27
|
-
export declare class LaunchRefusedError extends CliError {
|
|
28
|
-
readonly exitCode: number;
|
|
29
|
-
constructor(message: string, exitCode: number);
|
|
30
|
-
}
|
|
31
|
-
/** What `prepareClaudeLaunch` needs from its caller. */
|
|
32
|
-
export interface PrepareClaudeLaunchOptions {
|
|
33
|
-
/** The arguments after `agent-shim run`, exactly as the command line takes them: `@name`, launch flags, then the arguments for `claude`. */
|
|
34
|
-
readonly argv: readonly string[];
|
|
35
|
-
/** The directory the launch is for. */
|
|
36
|
-
readonly cwd: string;
|
|
37
|
-
/** The environment the launch inherits; a variable it sets is what the child sees. */
|
|
38
|
-
readonly env: Readonly<Record<string, string | undefined>>;
|
|
39
|
-
/** The state root; defaults to the one the command line resolves. */
|
|
40
|
-
readonly paths?: LayoutPaths;
|
|
41
|
-
/** The path of the agent-shim executable, used to start the front door and headroom daemons when the launch routes through them. Without it such a launch is refused: this process is not agent-shim, and re-running it would run the host program again. */
|
|
42
|
-
readonly agentShim?: string;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Resolves a launch for `options.cwd` on this machine and returns what to spawn, so another tool can start `claude` as an identity, through a provider, with the same sharing rules the command line applies, without shelling out. It performs the effects the child depends on: the identity's farm is resynced, and the front door and headroom are brought up and this process registered with them. Call `release` on the plan when the child has exited.
|
|
46
|
-
*
|
|
47
|
-
* A refused launch throws `LaunchRefusedError` carrying the launcher's own message. Interactive offers (creating a missing identity or profile on a terminal) belong to the command line and are not made here.
|
|
48
|
-
*/
|
|
49
|
-
export declare function prepareClaudeLaunch(options: PrepareClaudeLaunchOptions): LaunchPlan;
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { UsageError } from "../cliError";
|
|
2
|
-
/** The result of parsing the launcher's own argv: the identity selection, any one-off `agent-shim` flags, and everything left to forward. */
|
|
3
|
-
export interface ParsedLauncherArgv {
|
|
4
|
-
/** The identity named by a leading `@name` positional at argv[0] or by `--identity <name>`, when either was present. */
|
|
5
|
-
readonly identity?: string;
|
|
6
|
-
/** An explicit `--config-profile <name>` flag, when one was present. */
|
|
7
|
-
readonly configProfile?: string;
|
|
8
|
-
/** The last `--provider <name>` or `--no-provider` occurrence: a provider name, or `false` when `--no-provider` opted this launch out of any provider the cascade selects. Undefined when neither was given. */
|
|
9
|
-
readonly provider?: string | false;
|
|
10
|
-
/** The last `--headroom`/`--no-headroom` occurrence, when either was given. */
|
|
11
|
-
readonly headroom?: boolean;
|
|
12
|
-
/** The last `--track-usage`/`--no-track-usage` occurrence, when either was given. */
|
|
13
|
-
readonly trackUsage?: boolean;
|
|
14
|
-
/** The last `--wait`/`--no-wait` occurrence, when either was given: with a pool selected and every member refused, sleep until the earliest returns instead of refusing the launch. */
|
|
15
|
-
readonly wait?: boolean;
|
|
16
|
-
/** The last `--skip-permissions`/`--no-skip-permissions` occurrence, when either was given. */
|
|
17
|
-
readonly skipPermissions?: boolean;
|
|
18
|
-
/** The last `--remote-control`/`--no-remote-control` occurrence, when either was given. */
|
|
19
|
-
readonly remoteControl?: boolean;
|
|
20
|
-
/** Every `--category <cat>=<bool>` flag's raw value, in the order given: later values win on key collision when merged. */
|
|
21
|
-
readonly categoryFlags: readonly string[];
|
|
22
|
-
/** Every `--share <path>` flag's value, in the order given. */
|
|
23
|
-
readonly shareFlags: readonly string[];
|
|
24
|
-
/** Every `--hide <path>` flag's value, in the order given. */
|
|
25
|
-
readonly hideFlags: readonly string[];
|
|
26
|
-
/** Everything else, unchanged and in order: every token from a `--` terminator onwards (the `--` included), and any `@`-prefixed token that appears anywhere other than argv[0]. */
|
|
27
|
-
readonly rest: readonly string[];
|
|
28
|
-
}
|
|
29
|
-
/** Raised when a launch names its identity twice, through both a leading `@name` and `--identity`, with different names. */
|
|
30
|
-
export declare class ConflictingIdentityError extends UsageError {
|
|
31
|
-
readonly positional: string;
|
|
32
|
-
readonly flag: string;
|
|
33
|
-
constructor(positional: string, flag: string);
|
|
34
|
-
}
|
|
35
|
-
/** Every flag `parseLauncherArgv` consumes, both forms of each boolean included: what `agent-shim completion` offers after `run`. */
|
|
36
|
-
export declare const LAUNCHER_FLAG_NAMES: readonly string[];
|
|
37
|
-
/**
|
|
38
|
-
* Parses the launcher's own argv for its identity selection and the one-off `agent-shim` launch flags (`--identity`, `--config-profile`, `--provider`/`--no-provider`, `--category`, `--share`, `--hide`, and the `--[no-]headroom`, `--[no-]track-usage`, `--[no-]skip-permissions`, `--[no-]remote-control`, `--[no-]wait` booleans). None of these are real Claude Code flags, so all are consumed here and never forwarded.
|
|
39
|
-
*
|
|
40
|
-
* `name` in `@name` and `--identity <name>` may also be `pool:<pool>`, which the launcher resolves to a member of that pool. The `@name` form is consumed ONLY at argv[0], never mid-argument-list; `--identity <name>` is its explicit form, and naming two different identities through both throws `ConflictingIdentityError`. The flags are recognised only before a `--` terminator: from `--` onwards every token is forwarded verbatim, so `claude mcp add n -- cmd --provider x` keeps `--provider x` for `cmd`. Valued flags accept both `--flag value` and `--flag=value` and take exactly one value per occurrence; `--category`, `--share` and `--hide` repeat to supply several, and every other flag's later occurrence wins. A valued flag with no value after it (the last token, or directly before `--`) is left in place, untouched, since there is nothing to pair it with.
|
|
41
|
-
*/
|
|
42
|
-
export declare function parseLauncherArgv(argv: readonly string[]): ParsedLauncherArgv;
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { type ConfigFileReader } from "../config/load";
|
|
2
|
-
import { type GlobalConfig } from "../config/schema";
|
|
3
|
-
import { type CascadeInput, type ReadablePredicate } from "../resolve/walk";
|
|
4
|
-
import type { LayoutPaths } from "../paths";
|
|
5
|
-
/** The committed, team-shared portable config file name. A level with none falls back to the former `.claude-use.json`, and likewise for the local file, see `src/legacy.ts`. */
|
|
6
|
-
export declare const PORTABLE_CONFIG_FILENAME = ".agent-shim.json";
|
|
7
|
-
/** Its gitignored, per-clone personal sibling. */
|
|
8
|
-
export declare const PORTABLE_LOCAL_CONFIG_FILENAME = ".agent-shim.local.json";
|
|
9
|
-
/** Inputs to `loadCascadeInput`. */
|
|
10
|
-
export interface LoadCascadeInputParams {
|
|
11
|
-
readonly paths: LayoutPaths;
|
|
12
|
-
readonly home: string;
|
|
13
|
-
/** The directory the cascade is being resolved for — already a real path, since resolving symlinks is the caller's job. */
|
|
14
|
-
readonly cwd: string;
|
|
15
|
-
readonly read: ConfigFileReader;
|
|
16
|
-
readonly isReadable?: ReadablePredicate;
|
|
17
|
-
/** The configuration profile the launcher's own precedence rules chose. */
|
|
18
|
-
readonly baseConfigProfile?: string;
|
|
19
|
-
readonly cliOverride?: CascadeInput["cliOverride"];
|
|
20
|
-
}
|
|
21
|
-
/** An assembled cascade input plus the global config it was built from, which the caller also needs for its own defaults. */
|
|
22
|
-
export interface LoadedCascade {
|
|
23
|
-
readonly input: CascadeInput;
|
|
24
|
-
readonly globalConfig?: GlobalConfig;
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Loads every configuration file one launch's cascade is built from, and assembles them into the `CascadeInput` the pure resolver consumes.
|
|
28
|
-
*
|
|
29
|
-
* This is the only place file reading and cascade composition meet. Everything it produces is already-loaded data: `src/resolve/` never opens a file, and this module never decides what any of it means.
|
|
30
|
-
*
|
|
31
|
-
* Files are read with `loadConfigFile`, which wraps cosmiconfig's `load(filepath)` — never its `search()`, which stops at the first config found while walking upward. This design needs the exact opposite: every ancestor collected, shallowest-first, each one composing on top of the last.
|
|
32
|
-
*/
|
|
33
|
-
export declare function loadCascadeInput(params: LoadCascadeInputParams): LoadedCascade;
|
|
34
|
-
/**
|
|
35
|
-
* Reads the deepest directory-level `identity` pin and `configProfile` selection that apply to a directory, without resolving the cascade.
|
|
36
|
-
*
|
|
37
|
-
* The launcher needs both *before* it can resync a farm — which identity a directory pins decides which farm there is to resync, and which profile it selects is an input to resolving that farm's contents — so they cannot come out of the resolved cascade itself.
|
|
38
|
-
*/
|
|
39
|
-
export declare function readDirectorySelections(loaded: LoadedCascade): {
|
|
40
|
-
identity?: string;
|
|
41
|
-
configProfile?: string;
|
|
42
|
-
};
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { type CategoryMap, type Entries } from "../config/schema";
|
|
2
|
-
import { CliError } from "../cliError";
|
|
3
|
-
/** Raised when a `--category`/`AGENT_SHIM_CATEGORY_OVERRIDE` key names something other than one of the four overridable categories. */
|
|
4
|
-
export declare class InvalidCliCategoryError extends CliError {
|
|
5
|
-
readonly categoryName: string;
|
|
6
|
-
constructor(categoryName: string);
|
|
7
|
-
}
|
|
8
|
-
/** Raised when a `--share`/`--hide`/`AGENT_SHIM_ENTRY_OVERRIDE` path is missing its required `<category>/` prefix. */
|
|
9
|
-
export declare class InvalidCliEntryKeyError extends CliError {
|
|
10
|
-
readonly key: string;
|
|
11
|
-
constructor(key: string);
|
|
12
|
-
}
|
|
13
|
-
/** Inputs to `buildCliOverride`: the raw, still-unparsed flag values `parseLauncherArgv` collected (one value per flag occurrence), plus the environment for their `AGENT_SHIM_*_OVERRIDE` alternatives. */
|
|
14
|
-
export interface BuildCliOverrideParams {
|
|
15
|
-
readonly env: Readonly<Record<string, string | undefined>>;
|
|
16
|
-
readonly providerFlag?: string;
|
|
17
|
-
readonly categoryFlags: readonly string[];
|
|
18
|
-
readonly shareFlags: readonly string[];
|
|
19
|
-
readonly hideFlags: readonly string[];
|
|
20
|
-
}
|
|
21
|
-
/** What a launch's one-off command-line/environment overrides resolve to: the `cliOverride` layer `src/resolve/walk.ts`'s `assembleCascade` composes last, so it beats every other layer. */
|
|
22
|
-
export interface CliOverride {
|
|
23
|
-
readonly categories?: CategoryMap;
|
|
24
|
-
readonly entries?: Entries;
|
|
25
|
-
readonly launch?: {
|
|
26
|
-
readonly provider?: string;
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Builds this launch's one-off category/entry overrides from `--category`/`--share`/`--hide` flags and their `AGENT_SHIM_CATEGORY_OVERRIDE`/`AGENT_SHIM_ENTRY_OVERRIDE` environment-variable alternatives.
|
|
31
|
-
*
|
|
32
|
-
* Each flag occurrence carries exactly one value (`--category history=true`, `--share knowledge/skills/commit`); the flags repeat rather than taking comma lists. The environment variables cannot repeat, so each holds a comma-separated list of `<key>=<bool>` pairs instead.
|
|
33
|
-
*
|
|
34
|
-
* The environment variable provides a base and the flags merge on top, later flag winning on key collision: the same "later occurrence wins" convention `agent-shim profile set --category`/`--entry` use, applied here because the flag and the environment variable are documented as equally-weighted alternatives for the same one-off override, not two different precedence tiers.
|
|
35
|
-
*
|
|
36
|
-
* Returns `undefined` when nothing at all was supplied, so a launch with no overrides adds no `cliOverride` layer rather than an empty no-op one. A malformed flag or environment value throws `UsageError`.
|
|
37
|
-
*/
|
|
38
|
-
export declare function buildCliOverride(params: BuildCliOverrideParams): CliOverride | undefined;
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Splits `$CLAUDE_EXTRA_FLAGS` into multiple argv entries on whitespace — confirmed against Joe's real dotfiles wrapper scripts, not a hypothetical requirement.
|
|
3
|
-
*
|
|
4
|
-
* `"--continue continue"` splits into `["--continue", "continue"]`, matching what wrappers like `cccc`/`mcc`/`occ`/`zcc`/`scc` rely on. Unset or empty input produces zero argv entries — `splitExtraFlags(undefined) === []` and `splitExtraFlags("") === []` — a naive `.split(" ")` would yield `[""]` for the empty case, a real bug this avoids rather than a hypothetical one. No wrapper script surveyed ever embeds a literal space inside one intended argument, so a plain whitespace split (collapsing any run of whitespace, not just a single space) is correct and sufficient; adding quote-aware parsing would only risk changing the meaning of a future value that happens to contain a quote character, for zero real benefit.
|
|
5
|
-
*/
|
|
6
|
-
export declare function splitExtraFlags(value: string | undefined): string[];
|
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
import type { CategoryClassification, CategoryClassificationOverlay } from "../config/schema";
|
|
2
|
-
import { type FarmManifest } from "../resolve/reconcile";
|
|
3
|
-
import { type ResolvedState } from "../resolve/pipeline";
|
|
4
|
-
import type { CascadeInput } from "../resolve/walk";
|
|
5
|
-
import type { Diagnostic, EntryFacts } from "../resolve/types";
|
|
6
|
-
import type { DescendPolicy } from "../resolve/walkPolicy";
|
|
7
|
-
import type { FarmFs } from "./ports";
|
|
8
|
-
/** The manifest file each farm carries at its own root, recording what that resync built. Named distinctly from anything Claude Code itself writes into a config directory. A farm built under the former name carries `LEGACY_FARM_MANIFEST_FILENAME` instead, which is read as a fallback and never carried into the next farm, whose resync writes this name. */
|
|
9
|
-
export declare const FARM_MANIFEST_FILENAME = ".agent-shim-farm.json";
|
|
10
|
-
/** Reads and validates the manifest at a farm root, or undefined when it is missing, unparseable, or does not validate. */
|
|
11
|
-
export declare function readFarmManifest(fs: FarmFs, farmRoot: string): FarmManifest | undefined;
|
|
12
|
-
/** Everything `buildEntryFacts` needs. Everything except the tree itself is injected, so the fact manifest is reproducible from a fake filesystem, a fake clock, and a fake branch. */
|
|
13
|
-
export interface BuildEntryFactsParams {
|
|
14
|
-
readonly fs: FarmFs;
|
|
15
|
-
readonly claudeHome: string;
|
|
16
|
-
readonly home: string;
|
|
17
|
-
readonly cwd: string;
|
|
18
|
-
readonly nowMs: number;
|
|
19
|
-
readonly env: Readonly<Record<string, string | undefined>>;
|
|
20
|
-
readonly branch?: string;
|
|
21
|
-
readonly branchDetached?: boolean;
|
|
22
|
-
/** Which directories the walk enters; see `descendPolicy`. A directory not entered is recorded as one entry with its own size and mtime only, so a caller that needs subtree aggregates passes a policy that enters everything. */
|
|
23
|
-
readonly descend: DescendPolicy;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Walks the canonical `~/.claude` and builds the `EntryFacts` manifest the pure resolver consumes.
|
|
27
|
-
*
|
|
28
|
-
* Two properties matter more than the walk itself. Symlinks are never followed: a directory symlink escaping the tree is one entry, not a subtree, which keeps the walk finite and matches how the farm links such an entry back. And every directory's `latestMtimeMs`/`totalSizeBytes` aggregate over its whole subtree rather than reporting its own inode, because a directory-scoped `newerThan` or `maxSizeBytes` condition asks about the data inside the directory — a directory's own mtime does not move when a file three levels down is rewritten.
|
|
29
|
-
*/
|
|
30
|
-
export declare function buildEntryFacts(params: BuildEntryFactsParams): EntryFacts;
|
|
31
|
-
/** Inputs to `carryOver`. */
|
|
32
|
-
export interface CarryOverParams {
|
|
33
|
-
readonly fs: FarmFs;
|
|
34
|
-
/** The superseded farm, already renamed aside. */
|
|
35
|
-
readonly previousRoot: string;
|
|
36
|
-
/** The new farm, already swapped into place. */
|
|
37
|
-
readonly farmRoot: string;
|
|
38
|
-
/**
|
|
39
|
-
* When given, a colliding name classified as `runtime` is resolved automatically rather than reported — see `CarryOverResult.autoResolved` for why that is always safe. Optional because a caller with no classification loaded (there is none, today) should get the old, fully-manual behaviour rather than a crash; every real call site passes it.
|
|
40
|
-
*/
|
|
41
|
-
readonly classification?: {
|
|
42
|
-
readonly defaults: CategoryClassification;
|
|
43
|
-
readonly overlay?: CategoryClassificationOverlay;
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
/** What `carryOver` moved, resolved on its own, and could not. */
|
|
47
|
-
export interface CarryOverResult {
|
|
48
|
-
/** Top-level names moved from the superseded farm into the new one. */
|
|
49
|
-
readonly carried: readonly string[];
|
|
50
|
-
/** Top-level names that collided but were resolved automatically because their category is `runtime` — see the doc comment on `carryOver` for why discarding the old copy is always safe here. */
|
|
51
|
-
readonly autoResolved: readonly string[];
|
|
52
|
-
/** Top-level names left behind because the new farm has its own entry of that name, and resolving them needs a human — everything that collided but was not classified `runtime`. */
|
|
53
|
-
readonly collided: readonly string[];
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Moves an identity's own locally-written state out of a superseded farm and into the new one.
|
|
57
|
-
*
|
|
58
|
-
* This is what makes a whole-directory swap safe at all. The farm root *is* `CLAUDE_CONFIG_DIR`, so it holds more than symlinks: the identity's own `identity.json`, the credentials file Claude Code writes on Linux and Windows, its `.claude.json`, its daemon and runtime state. None of that is shared, none of it is rebuildable, and a swap that simply replaced the directory would destroy all of it.
|
|
59
|
-
*
|
|
60
|
-
* Anything the previous resync built itself is skipped rather than carried: a symlink is a view of the canonical tree with no data of its own, and a directory the manifest records as materialised had its real children adopted into `~/.claude` before the swap ever started. Everything else is real local data and moves across by rename, so a credential file is relocated rather than duplicated — never briefly existing as two copies on disk.
|
|
61
|
-
*
|
|
62
|
-
* A name that exists in both is genuinely ambiguous in general — overwriting the new farm's own entry would discard whatever the resync just decided; overwriting the old one would discard data — so by default it is reported rather than resolved here, and the caller keeps the superseded farm on disk in that case.
|
|
63
|
-
*
|
|
64
|
-
* One category is not ambiguous, though: `runtime`'s own definition (see `config/categories.default.json`'s category table in the README) is specifically "live per-process or per-machine artifacts" — daemon locks, an MCP auth-needed cache, an update-check result — that make no sense being preserved across a swap at all, let alone fought over. When `classification` is given, a colliding name whose category resolves to `runtime` is discarded from the superseded copy and left exactly as the new farm already has it, with no data ever moved: `keep-new` is not a judgement call for this category, it is what the category already means. This needs only the name's *static* classification, never the resolved shared/not-shared decision for the current directory — a `runtime` entry is disposable whether or not this identity currently chooses to share it, so no cascade resolution is needed to make the call.
|
|
65
|
-
*
|
|
66
|
-
* Exported so `launcher/farmResolve.ts` can reuse this exact collision detection (and the same `runtime` auto-resolution) for `agent-shim identity resolve-conflicts`'s interactive pass, rather than a second implementation that could drift from this one.
|
|
67
|
-
*/
|
|
68
|
-
export declare function carryOver(params: CarryOverParams): CarryOverResult;
|
|
69
|
-
/** What recovery found and did. */
|
|
70
|
-
export interface RecoveryResult {
|
|
71
|
-
/** Abandoned scratch trees removed. */
|
|
72
|
-
readonly removedScratch: readonly string[];
|
|
73
|
-
/** Set when the farm root was missing and a superseded farm was restored into its place. */
|
|
74
|
-
readonly restoredFrom?: string;
|
|
75
|
-
/** Superseded farms whose carry-over was completed and which were then discarded. */
|
|
76
|
-
readonly completed: readonly string[];
|
|
77
|
-
/** Top-level names, across every superseded farm processed, resolved automatically because their category is `runtime` — see `carryOver`'s own doc comment for why that needs no human decision. */
|
|
78
|
-
readonly autoResolved: readonly string[];
|
|
79
|
-
/** Superseded farms left on disk because they still held colliding data a human still needs to decide. */
|
|
80
|
-
readonly retained: readonly string[];
|
|
81
|
-
/** True when recovery changed anything, in which case the farm cannot be assumed to match its own manifest. */
|
|
82
|
-
readonly recovered: boolean;
|
|
83
|
-
}
|
|
84
|
-
/** Inputs to `recoverFarm`: the lock-taking wrapper around `recoverInterruptedSwap`. */
|
|
85
|
-
export interface RecoverFarmParams {
|
|
86
|
-
readonly fs: FarmFs;
|
|
87
|
-
readonly identitiesDir: string;
|
|
88
|
-
readonly identity: string;
|
|
89
|
-
readonly now: () => number;
|
|
90
|
-
readonly lock: ResyncFarmParams["lock"];
|
|
91
|
-
readonly classification?: {
|
|
92
|
-
readonly defaults: CategoryClassification;
|
|
93
|
-
readonly overlay?: CategoryClassificationOverlay;
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* Runs `recoverInterruptedSwap` under the identity's own lock.
|
|
98
|
-
*
|
|
99
|
-
* This exists as its own entry point because recovery has to happen *before* the identity's `identity.json` is read, not merely before the farm is rebuilt: that file lives inside the farm root, so a crash between the swap's two renames leaves it sitting in a superseded directory where nothing will find it. Reading the identity first would silently launch with its `defaultConfigProfile` and `allowAmbientCredential` unset — the first of which decides what the farm is about to share.
|
|
100
|
-
*
|
|
101
|
-
* `resyncFarm` calls `recoverInterruptedSwap` directly rather than calling this, since it already holds the lock; taking it a second time from the same process would block against itself.
|
|
102
|
-
*/
|
|
103
|
-
export declare function recoverFarm(params: RecoverFarmParams): RecoveryResult;
|
|
104
|
-
/** Inputs to `resyncFarm`. */
|
|
105
|
-
export interface ResyncFarmParams {
|
|
106
|
-
readonly fs: FarmFs;
|
|
107
|
-
/** `~/.agent-shim/identities` — the farm root's parent, and where the lock, scratch trees, and superseded farms all live. */
|
|
108
|
-
readonly identitiesDir: string;
|
|
109
|
-
readonly identity: string;
|
|
110
|
-
/** The configuration profile this launch resolved to, recorded in the manifest for `agent-shim check`. */
|
|
111
|
-
readonly configProfile?: string;
|
|
112
|
-
/** The canonical `~/.claude` every farm symlink points back into. */
|
|
113
|
-
readonly claudeHome: string;
|
|
114
|
-
readonly home: string;
|
|
115
|
-
readonly cwd: string;
|
|
116
|
-
readonly env: Readonly<Record<string, string | undefined>>;
|
|
117
|
-
readonly branch?: string;
|
|
118
|
-
readonly branchDetached?: boolean;
|
|
119
|
-
readonly cascade: CascadeInput;
|
|
120
|
-
readonly classification: {
|
|
121
|
-
readonly defaults: CategoryClassification;
|
|
122
|
-
readonly overlay?: CategoryClassificationOverlay;
|
|
123
|
-
};
|
|
124
|
-
/** Reads the current time. Called repeatedly while waiting on the lock, then once more to stamp the build. */
|
|
125
|
-
readonly now: () => number;
|
|
126
|
-
/** Distinguishes this resync's scratch and superseded directory names from any other process's. `${pid}.${uuid}` in real use; a fixed string in tests. */
|
|
127
|
-
readonly uniqueSuffix: string;
|
|
128
|
-
readonly lock: {
|
|
129
|
-
readonly pid: number;
|
|
130
|
-
readonly isRunning: (pid: number) => boolean;
|
|
131
|
-
readonly sleep: (ms: number) => void;
|
|
132
|
-
readonly staleAfterMs?: number;
|
|
133
|
-
readonly retryDelayMs?: number;
|
|
134
|
-
readonly maxAttempts?: number;
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
/** The outcome of one resync. */
|
|
138
|
-
export interface ResyncFarmResult {
|
|
139
|
-
readonly farmRoot: string;
|
|
140
|
-
/** True when the resolved decision already matched what the farm's own manifest recorded, so nothing was written. */
|
|
141
|
-
readonly noOp: boolean;
|
|
142
|
-
/** The manifest the farm now carries — the newly written one, or the existing one on a no-op. */
|
|
143
|
-
readonly manifest: FarmManifest;
|
|
144
|
-
/** The fully resolved state, including the flattened cascade's launch flags, which the launcher goes on to use. */
|
|
145
|
-
readonly resolved: ResolvedState;
|
|
146
|
-
readonly adopted: readonly string[];
|
|
147
|
-
readonly recovery: RecoveryResult;
|
|
148
|
-
readonly diagnostics: readonly Diagnostic[];
|
|
149
|
-
readonly retainedPrevious?: string;
|
|
150
|
-
}
|
|
151
|
-
/**
|
|
152
|
-
* Brings one identity's farm into line with the cascade resolved for the current directory, and hands back everything the launcher needs to go on and spawn the real binary.
|
|
153
|
-
*
|
|
154
|
-
* The order below is fixed and each step depends on the one before it:
|
|
155
|
-
*
|
|
156
|
-
* 1. Take the per-identity lock, so two sessions under one identity in two directories cannot rewrite the same farm toward two different states at once.
|
|
157
|
-
* 2. Finish or undo any swap a previous launch was killed in the middle of, so everything after this point sees a coherent farm.
|
|
158
|
-
* 3. Read the previous manifest and, guided by it, list the parts of the still-live farm reconciliation is allowed to look at. This step only reads the farm; nothing mutates it.
|
|
159
|
-
* 4. Adopt anything Claude Code wrote into a materialised directory back into the canonical `~/.claude`.
|
|
160
|
-
* 5. **Then** build the fact manifest, from a canonical tree that now includes everything step 4 adopted. Building facts before adoption would make newly adopted data invisible to this resync and only visible on the next launch — the single most important ordering constraint in this module.
|
|
161
|
-
* 6. Resolve the cascade and plan the farm, both of them pure functions over those facts.
|
|
162
|
-
* 7. If the plan matches what the farm's manifest already records and step 4 adopted nothing, stop: no filesystem write happens at all. Launching repeatedly from the same directory with no configuration change is the overwhelmingly common case and it must stay cheap.
|
|
163
|
-
* 8. Otherwise build a scratch tree, write its manifest, and swap it into place.
|
|
164
|
-
* 9. Release the lock — before the real binary is spawned, never held across it.
|
|
165
|
-
*/
|
|
166
|
-
export declare function resyncFarm(params: ResyncFarmParams): ResyncFarmResult;
|
|
167
|
-
/** Turns a recovery result into the one diagnostic worth reporting about it, or nothing when there was nothing to recover. */
|
|
168
|
-
export declare function recoveryDiagnostics(recovery: RecoveryResult, identity: string): Diagnostic[];
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import type { LaunchFlags, Provider } from "../config/schema";
|
|
2
|
-
import { type ResolvedCredential } from "../credential";
|
|
3
|
-
import type { FrontDoorUp, HeadroomUp } from "./ports";
|
|
4
|
-
/** The fully resolved launch flags for one launch. */
|
|
5
|
-
export interface ResolvedLaunchFlags {
|
|
6
|
-
readonly skipPermissions: boolean;
|
|
7
|
-
readonly remoteControl: boolean;
|
|
8
|
-
readonly headroom: boolean;
|
|
9
|
-
/** Whether the launch routes through the front door so its requests are recorded, even with no provider and no headroom. */
|
|
10
|
-
readonly trackUsage: boolean;
|
|
11
|
-
}
|
|
12
|
-
/** The one-off command-line forms of the four boolean launch flags, each undefined when neither its positive nor its `--no-` form was given. */
|
|
13
|
-
interface LaunchFlagOverrides {
|
|
14
|
-
readonly skipPermissions?: boolean;
|
|
15
|
-
readonly remoteControl?: boolean;
|
|
16
|
-
readonly headroom?: boolean;
|
|
17
|
-
readonly trackUsage?: boolean;
|
|
18
|
-
}
|
|
19
|
-
/** Inputs to `resolveLaunchFlags`. */
|
|
20
|
-
export interface ResolveLaunchFlagsParams {
|
|
21
|
-
/** The cascade's resolved `launch` block, when a cascade was loaded for this launch. */
|
|
22
|
-
readonly cascade?: LaunchFlags;
|
|
23
|
-
/** The launch's own `--[no-]skip-permissions`, `--[no-]remote-control`, `--[no-]headroom` and `--[no-]track-usage` flags. */
|
|
24
|
-
readonly flags?: LaunchFlagOverrides;
|
|
25
|
-
readonly env: Readonly<Record<string, string | undefined>>;
|
|
26
|
-
/** What `trackUsage` is when no flag, environment variable or cascade setting says: off, except for a pool launch, whose pick reads the usage the front door records. */
|
|
27
|
-
readonly trackUsageDefault?: boolean;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Resolves `skipPermissions`/`remoteControl`/`headroom`/`trackUsage` for one launch. Each setting has the same three forms, decided in the same order: an explicit command-line flag outright, then its environment variable (`AGENT_SHIM_SKIP_PERMISSIONS`, `AGENT_SHIM_REMOTE_CONTROL`, `AGENT_SHIM_HEADROOM`, `AGENT_SHIM_TRACK_USAGE`), then the cascade, and OFF when none of them says otherwise (`trackUsageDefault` changes that one fallback). The flag outranks the environment variable because it is the more deliberate of the two one-off forms (typed on this very command line, not inherited from a shell profile), and both outrank the cascade because they are one-off overrides of it.
|
|
31
|
-
*
|
|
32
|
-
* Environment variables read with the shared boolean vocabulary (`true`/`1`, `false`/`0`), so `AGENT_SHIM_SKIP_PERMISSIONS=0` switches off a cascade's `skipPermissions: true` for one launch; any other value throws `InvalidEnvBoolError`.
|
|
33
|
-
*
|
|
34
|
-
* This default-off posture is a deliberate change from the legacy bash tool, which passed `--dangerously-skip-permissions` unconditionally on every launch.
|
|
35
|
-
*/
|
|
36
|
-
export declare function resolveLaunchFlags(params: ResolveLaunchFlagsParams): ResolvedLaunchFlags;
|
|
37
|
-
/**
|
|
38
|
-
* Builds the tool's own flag arguments from resolved launch flags.
|
|
39
|
-
*
|
|
40
|
-
* `--remote-control=` always carries a literal trailing `=` with an empty value — never bare `--remote-control` — confirmed as a deliberate fix in the legacy script's own git history to stop the flag from consuming the next positional argument as its value.
|
|
41
|
-
*/
|
|
42
|
-
export declare function buildFlagArgs(flags: ResolvedLaunchFlags): string[];
|
|
43
|
-
/** Inputs to `buildArgv`. */
|
|
44
|
-
export interface BuildArgvParams {
|
|
45
|
-
readonly toolFlags: readonly string[];
|
|
46
|
-
readonly extraFlags: readonly string[];
|
|
47
|
-
readonly passthrough: readonly string[];
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Assembles the final argv passed to the real `claude` binary: tool flags, then `$CLAUDE_EXTRA_FLAGS`, then the user's own forwarded arguments, in that exact order.
|
|
51
|
-
*
|
|
52
|
-
* Extra flags must land BEFORE the passthrough args — confirmed load-bearing against real wrapper scripts (`cpl`, `mp`, `zpl`) that set `CLAUDE_EXTRA_FLAGS="--print"` and then pass a positional prompt afterwards; reversing this order would feed the prompt to `--print` as if it were a flag value instead of a trailing positional.
|
|
53
|
-
*/
|
|
54
|
-
export declare function buildArgv(params: BuildArgvParams): string[];
|
|
55
|
-
/** The provider resolved for this launch, with its credential already resolved from the provider's credential block. */
|
|
56
|
-
export interface ResolvedProvider {
|
|
57
|
-
readonly name: string;
|
|
58
|
-
readonly definition: Provider;
|
|
59
|
-
readonly credential: ResolvedCredential;
|
|
60
|
-
}
|
|
61
|
-
/** A resolved provider with the base URL its sessions are sent to: the front door's provider-scoped address, which exists only once the door is up and is the same shape for both kinds (the door is what decides where the request goes from there). */
|
|
62
|
-
export interface RoutedProvider extends ResolvedProvider {
|
|
63
|
-
readonly baseUrl: string;
|
|
64
|
-
}
|
|
65
|
-
/** Inputs to `buildEnv`. */
|
|
66
|
-
export interface BuildEnvParams {
|
|
67
|
-
readonly baseEnv: Readonly<Record<string, string | undefined>>;
|
|
68
|
-
/** True when `CLAUDE_CONFIG_DIR` was already set and the escape hatch applied — `buildEnv` must leave it untouched in that case. */
|
|
69
|
-
readonly configDirEscapeHatch: boolean;
|
|
70
|
-
/** The identity name resolved for this launch, when one was resolved. */
|
|
71
|
-
readonly resolvedIdentityName?: string;
|
|
72
|
-
readonly identitiesDir: string;
|
|
73
|
-
/** The provider resolved for this launch, when one was resolved, with the base URL it routes to. Its credential is resolved by the caller because refusing an unusable one needs the caller's log/exit ports. */
|
|
74
|
-
readonly provider?: RoutedProvider;
|
|
75
|
-
/** The launching identity's own resolved credential, when it has a credential block and no provider was selected. A provider's credential authenticates against the provider's endpoint, so the identity's is never applied alongside one. */
|
|
76
|
-
readonly identityCredential?: ResolvedCredential;
|
|
77
|
-
/** The front door this launch routes through, when one is engaged (a provider is selected, or headroom resolved on). It is what the child talks to: its provider listener for a provider session, its CONNECT surface for an OAuth one. */
|
|
78
|
-
readonly frontdoor?: FrontDoorUp;
|
|
79
|
-
/** The headroom daemon this launch's requests must pass through (as the door's headroom hop), when headroom resolved on. The child never talks to it directly. */
|
|
80
|
-
readonly headroom?: HeadroomUp;
|
|
81
|
-
/** The per-launch session id, stamped into the session header the door identifies this launch's requests by. */
|
|
82
|
-
readonly sessionId: string;
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Builds the environment the real `claude` binary is spawned with.
|
|
86
|
-
*
|
|
87
|
-
* When the `CLAUDE_CONFIG_DIR`-already-set escape hatch applied, or no identity was resolved at all (a bare launch with no active identity, matching the legacy script's own "no profile means plain `~/.claude`" behaviour), `CLAUDE_CONFIG_DIR` is left untouched. Otherwise `CLAUDE_CONFIG_DIR` is set to the resolved identity's own directory under `identitiesDir` — farm population into that directory is Phase 5's job, not this function's.
|
|
88
|
-
*
|
|
89
|
-
* A resolved provider is applied regardless of the identity outcome, because it selects which API endpoint the child talks to, not which login's data it sees: `ANTHROPIC_BASE_URL` points at the provider's routed base URL (always the front door's provider-scoped address), `AGENT_SHIM_PROVIDER` names the provider for the statusline, the provider's own `env` entries land verbatim, and its resolved credential is exported as its target's variable (`credentialVariables`), with the other credential variables removed so an ambient one inherited from the parent cannot outrank it. Without a provider, an identity's own resolved credential is exported the same way. The token only ever reaches this environment, never the child's argv or a log line.
|
|
90
|
-
*
|
|
91
|
-
* A resolved front door is the whole of the child's routing, on top of the provider: `ANTHROPIC_CUSTOM_HEADERS` gains the launcher-injected session headers (identity, session id, the launch's capability token, and, when headroom resolved on, the headroom flag and the project identity headroom scopes memory to), merged with any headers the provider's own `env` or the parent environment already set. The door strips every one of them before anything leaves the machine; the token is what authorises the session's requests at the door in the first place. `NODE_EXTRA_CA_CERTS` points at the door's trust bundle in both modes, because the child reaches the door over TLS signed by agent-shim's CA either way. With a provider, the child's HTTPS base URL already names the door's provider listener, so a process that merely binds that port cannot present a certificate the child accepts. Without one (an OAuth launch), the base URL is left exactly as the parent environment had it, because Claude Code enables Remote Control and connectors only against the real `api.anthropic.com`; routing happens one layer down instead, with `HTTPS_PROXY` pointing the child at the door's CONNECT surface and carrying the launch's capability as its proxy credential (the surface refuses any CONNECT without a live one), so the child still believes it is talking to the real `api.anthropic.com` while the surface's terminated TLS feeds the routed paths to the same pipeline. `HEADROOM_PROXY_URL` names the headroom daemon for anything else that wants it; the child never talks to that daemon directly, the door's hop does.
|
|
92
|
-
*
|
|
93
|
-
* `$CLAUDE_EXTRA_FLAGS` is never stripped from the child's environment: some wrappers set it two process-levels up and rely on inheritance through a `claude` invoked from inside a running session.
|
|
94
|
-
*/
|
|
95
|
-
export declare function buildEnv(params: BuildEnvParams): Record<string, string | undefined>;
|
|
96
|
-
export {};
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import type { CredentialTargetVar } from "../config/schema";
|
|
2
|
-
/**
|
|
3
|
-
* The environment variables that authenticate Claude Code directly from the process environment, ahead of any stored identity credential. If any of these is set, every identity would silently authenticate as the same key/token/backend while it's set — defeating the entire premise of separate identities. Order here is also lookup order: `detectAmbientCredential` reports the first one found.
|
|
4
|
-
*/
|
|
5
|
-
export declare const AMBIENT_CREDENTIAL_VARS: readonly ["ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN", "CLAUDE_CODE_OAUTH_TOKEN", "CLAUDE_CODE_USE_BEDROCK", "CLAUDE_CODE_USE_VERTEX", "CLAUDE_CODE_USE_FOUNDRY"];
|
|
6
|
-
export type AmbientCredentialVar = (typeof AMBIENT_CREDENTIAL_VARS)[number];
|
|
7
|
-
/** Which guarded variable was found set, and to what. */
|
|
8
|
-
export interface AmbientCredentialDetection {
|
|
9
|
-
readonly variable: AmbientCredentialVar;
|
|
10
|
-
}
|
|
11
|
-
/** A credential this launch itself exports to the child: the variable it lands in and its value. */
|
|
12
|
-
export interface InjectedCredential {
|
|
13
|
-
readonly variable: CredentialTargetVar;
|
|
14
|
-
readonly token: string;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Detects whether any of `AMBIENT_CREDENTIAL_VARS` is set to a non-empty value in `env`, returning the first one found in declared order, or undefined when none are set.
|
|
18
|
-
*
|
|
19
|
-
* An empty string counts as unset, not set — confirmed load-bearing: one of Joe's real wrapper scripts (`o`, running Claude Code against OpenRouter) does `export ANTHROPIC_API_KEY=""` specifically to *clear* it so `ANTHROPIC_AUTH_TOKEN` takes effect instead, and this must never trip the guard.
|
|
20
|
-
*
|
|
21
|
-
* `injected`, when given, is the credential this launch exports for its own identity. Its variable holding exactly that value is not ambient: it is what a agent-shim launch of the same identity left in the environment of the session this one starts from (a `claude @work` run inside a `claude @work` session). The same variable holding any other value still counts.
|
|
22
|
-
*/
|
|
23
|
-
export declare function detectAmbientCredential(env: Readonly<Record<string, string | undefined>>, injected?: InjectedCredential): AmbientCredentialDetection | undefined;
|
|
24
|
-
/**
|
|
25
|
-
* Builds the exact refusal message: which variable was found, why it matters, and the two ways to opt in (a one-off env var, or a persistent per-identity setting). Mirrors the message documented in the project's README. `identityName` is included in the persistent-opt-in command when known; when no identity has been resolved yet (e.g. the `CLAUDE_CONFIG_DIR`-already-set escape hatch, or no identity resolved at all), a generic `<name>` placeholder is used instead, matching the README's own generic wording.
|
|
26
|
-
*/
|
|
27
|
-
export declare function formatAmbientCredentialGuardMessage(variable: AmbientCredentialVar, identityName?: string): string;
|
|
28
|
-
/** Inputs to the ambient-credential guard evaluation. */
|
|
29
|
-
export interface EvaluateAmbientCredentialGuardParams {
|
|
30
|
-
readonly env: Readonly<Record<string, string | undefined>>;
|
|
31
|
-
/** The active identity's own `allowAmbientCredential` setting from its `identity.json`, or false when no identity is known. */
|
|
32
|
-
readonly allowAmbientCredential: boolean;
|
|
33
|
-
/** True when `AGENT_SHIM_ALLOW_AMBIENT_CREDENTIAL=1` is set for this one invocation. */
|
|
34
|
-
readonly allowAmbientCredentialOverride: boolean;
|
|
35
|
-
/** The active identity's name, for the message's persistent-opt-in command. Undefined when no identity is known. */
|
|
36
|
-
readonly identityName?: string;
|
|
37
|
-
/**
|
|
38
|
-
* True when this launch routes through an API provider. The guard inspects the PARENT environment, before `buildEnv` runs; a provider launch has its `ANTHROPIC_AUTH_TOKEN` injected and its `ANTHROPIC_API_KEY` cleared by `buildEnv` itself, so an ambient credential in the parent environment never reaches the child and there is nothing left for this guard to protect against. Everything else about the guard (including `IdentitySchema.allowAmbientCredential`) is unchanged by this flag.
|
|
39
|
-
*/
|
|
40
|
-
readonly providerSelected?: boolean;
|
|
41
|
-
/** The launching identity's own credential, when its credential block resolved: see `detectAmbientCredential`. */
|
|
42
|
-
readonly injectedCredential?: InjectedCredential;
|
|
43
|
-
}
|
|
44
|
-
/** The result of one guard evaluation: either launch may proceed, or it must be refused with an explanatory message. */
|
|
45
|
-
export type AmbientCredentialGuardResult = {
|
|
46
|
-
readonly ok: true;
|
|
47
|
-
} | {
|
|
48
|
-
readonly ok: false;
|
|
49
|
-
readonly variable: AmbientCredentialVar;
|
|
50
|
-
readonly message: string;
|
|
51
|
-
};
|
|
52
|
-
/**
|
|
53
|
-
* Evaluates the ambient-credential guard: refuses unless no guarded variable is set, or the active identity opted in (`allowAmbientCredential: true`), or this one invocation opted in (`AGENT_SHIM_ALLOW_AMBIENT_CREDENTIAL=1`), or a provider takes over the child's credential (see `providerSelected`).
|
|
54
|
-
*
|
|
55
|
-
* This guard is about credential isolation, not identity/config-dir selection — it must still run even when the `CLAUDE_CONFIG_DIR`-already-set escape hatch applies (callers pass `allowAmbientCredential: false` and no `identityName` in that case, since there is no active identity to consult).
|
|
56
|
-
*/
|
|
57
|
-
export declare function evaluateAmbientCredentialGuard(params: EvaluateAmbientCredentialGuardParams): AmbientCredentialGuardResult;
|