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.
Files changed (93) hide show
  1. package/dist/cli.cjs +95 -27
  2. package/dist/index.cjs +70 -7
  3. package/dist/index.mjs +70 -7
  4. package/dist/types/index.d.ts +2789 -40
  5. package/package.json +3 -1
  6. package/dist/types/checkReport.d.ts +0 -154
  7. package/dist/types/claudeShim.d.ts +0 -114
  8. package/dist/types/cli/bool.d.ts +0 -8
  9. package/dist/types/cli/commandDeps.d.ts +0 -39
  10. package/dist/types/cli/envBool.d.ts +0 -11
  11. package/dist/types/cli/pairs.d.ts +0 -19
  12. package/dist/types/cliError.d.ts +0 -27
  13. package/dist/types/codex/http.d.ts +0 -15
  14. package/dist/types/config/classify.d.ts +0 -49
  15. package/dist/types/config/load.d.ts +0 -42
  16. package/dist/types/config/schema.d.ts +0 -746
  17. package/dist/types/config/store.d.ts +0 -46
  18. package/dist/types/configProfilesStore.d.ts +0 -61
  19. package/dist/types/configure.d.ts +0 -170
  20. package/dist/types/credential.d.ts +0 -136
  21. package/dist/types/credentialCache.d.ts +0 -46
  22. package/dist/types/directoryRulesStore.d.ts +0 -43
  23. package/dist/types/doctorReport.d.ts +0 -117
  24. package/dist/types/frontdoor/capability.d.ts +0 -19
  25. package/dist/types/frontdoor/capture.d.ts +0 -58
  26. package/dist/types/frontdoor/connect.d.ts +0 -209
  27. package/dist/types/frontdoor/connectEffects.d.ts +0 -3
  28. package/dist/types/frontdoor/custody.d.ts +0 -32
  29. package/dist/types/frontdoor/ensure.d.ts +0 -36
  30. package/dist/types/frontdoor/headroomHop.d.ts +0 -22
  31. package/dist/types/frontdoor/pipeline.d.ts +0 -109
  32. package/dist/types/frontdoor/probe.d.ts +0 -13
  33. package/dist/types/frontdoor/realFrontDoorPort.d.ts +0 -5
  34. package/dist/types/frontdoor/route.d.ts +0 -112
  35. package/dist/types/frontdoor/server.d.ts +0 -44
  36. package/dist/types/frontdoor/state.d.ts +0 -57
  37. package/dist/types/frontdoor/supervisor.d.ts +0 -48
  38. package/dist/types/frontdoor/tap.d.ts +0 -9
  39. package/dist/types/frontdoor/trust.d.ts +0 -30
  40. package/dist/types/frontdoor/x509.d.ts +0 -11
  41. package/dist/types/headroom/ensure.d.ts +0 -31
  42. package/dist/types/headroom/headers.d.ts +0 -11
  43. package/dist/types/headroom/settings.d.ts +0 -13
  44. package/dist/types/headroom/source.d.ts +0 -8
  45. package/dist/types/headroom/state.d.ts +0 -77
  46. package/dist/types/headroom/supervisor.d.ts +0 -107
  47. package/dist/types/identityStore.d.ts +0 -85
  48. package/dist/types/launchWiring.d.ts +0 -49
  49. package/dist/types/launcher/argv.d.ts +0 -42
  50. package/dist/types/launcher/cascade.d.ts +0 -42
  51. package/dist/types/launcher/cliOverride.d.ts +0 -38
  52. package/dist/types/launcher/extraFlags.d.ts +0 -6
  53. package/dist/types/launcher/farm.d.ts +0 -168
  54. package/dist/types/launcher/flags.d.ts +0 -96
  55. package/dist/types/launcher/guard.d.ts +0 -57
  56. package/dist/types/launcher/identity.d.ts +0 -95
  57. package/dist/types/launcher/lock.d.ts +0 -41
  58. package/dist/types/launcher/pool.d.ts +0 -44
  59. package/dist/types/launcher/ports.d.ts +0 -135
  60. package/dist/types/launcher/spawn.d.ts +0 -20
  61. package/dist/types/launcher.d.ts +0 -98
  62. package/dist/types/legacy.d.ts +0 -29
  63. package/dist/types/pathNorm.d.ts +0 -14
  64. package/dist/types/paths.d.ts +0 -79
  65. package/dist/types/poolPickReport.d.ts +0 -44
  66. package/dist/types/poolStore.d.ts +0 -18
  67. package/dist/types/providersStore.d.ts +0 -137
  68. package/dist/types/realCredentialCache.d.ts +0 -11
  69. package/dist/types/realPorts.d.ts +0 -109
  70. package/dist/types/resolve/conditions.d.ts +0 -37
  71. package/dist/types/resolve/decide.d.ts +0 -45
  72. package/dist/types/resolve/extends.d.ts +0 -41
  73. package/dist/types/resolve/flatten.d.ts +0 -13
  74. package/dist/types/resolve/match.d.ts +0 -58
  75. package/dist/types/resolve/pipeline.d.ts +0 -33
  76. package/dist/types/resolve/plan.d.ts +0 -57
  77. package/dist/types/resolve/projects.d.ts +0 -61
  78. package/dist/types/resolve/reconcile.d.ts +0 -80
  79. package/dist/types/resolve/types.d.ts +0 -159
  80. package/dist/types/resolve/walk.d.ts +0 -85
  81. package/dist/types/resolve/walkPolicy.d.ts +0 -15
  82. package/dist/types/usage/account.d.ts +0 -20
  83. package/dist/types/usage/middleware.d.ts +0 -17
  84. package/dist/types/usage/pick.d.ts +0 -62
  85. package/dist/types/usage/plan.d.ts +0 -18
  86. package/dist/types/usage/poolPick.d.ts +0 -31
  87. package/dist/types/usage/preflight.d.ts +0 -20
  88. package/dist/types/usage/rateLimit.d.ts +0 -25
  89. package/dist/types/usage/read.d.ts +0 -70
  90. package/dist/types/usage/scan.d.ts +0 -24
  91. package/dist/types/usage/schema.d.ts +0 -318
  92. package/dist/types/usage/store.d.ts +0 -43
  93. package/dist/types/versionDiscovery.d.ts +0 -47
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-shim",
3
- "version": "7.13.1",
3
+ "version": "7.14.0",
4
4
  "description": "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
5
5
  "license": "MIT",
6
6
  "author": "Joseph Mearman <joseph@mearman.co.uk>",
@@ -74,6 +74,8 @@
74
74
  "jiti": "^2.7.0",
75
75
  "knip": "^6.35.1",
76
76
  "lint-staged": "^17.5.0",
77
+ "rollup": "4.64.0",
78
+ "rollup-plugin-dts": "6.5.1",
77
79
  "semantic-release": "^25.0.9",
78
80
  "turbo": "^2.10.12",
79
81
  "typescript": "^6.0.3",
@@ -1,154 +0,0 @@
1
- import { type CategoryClassification, type CategoryClassificationOverlay, type Identity, type Provider } from "./config/schema";
2
- import { type CredentialSummary } from "./credential";
3
- import { type AmbientCredentialGuardResult } from "./launcher/guard";
4
- import type { ConfigProfileDecisionSource, IdentityDecisionSource } from "./launcher/identity";
5
- import type { FarmFs, RunPort } from "./launcher/ports";
6
- import type { LayoutPaths } from "./paths";
7
- import type { PoolPickReport } from "./poolPickReport";
8
- import { type EncodingAmbiguity } from "./resolve/projects";
9
- import { type ResolvedState } from "./resolve/pipeline";
10
- import type { CascadeInput } from "./resolve/walk";
11
- import type { Decision, EntryFacts, FlattenedCascade } from "./resolve/types";
12
- /**
13
- * Flags every `history/projects/` entries rule in scope whose encoded form could plausibly correspond to more than one real path.
14
- *
15
- * Reuses `src/resolve/projects.ts`'s own `detectEncodingAmbiguity` rather than reimplementing the detection — this function's whole job is recovering the as-written fragments from the flattened cascade's compiled rules and handing them to that function, plus the real project directory names already present in the fact manifest so the report can say how many a pattern actually matches today.
16
- */
17
- export declare function flagAmbiguousEncodings(flattened: FlattenedCascade, facts: EntryFacts): EncodingAmbiguity[];
18
- /** Renders one entry's resolved decision as a single explanatory line, for `agent-shim check`'s printout. */
19
- export declare function formatDecision(decision: Decision): string;
20
- /** The result of looking up the macOS Keychain service name Claude Code is actually using for one identity's farm. */
21
- export interface KeychainLookupResult {
22
- readonly checked: true;
23
- readonly found: boolean;
24
- readonly serviceName?: string;
25
- readonly note: string;
26
- }
27
- /**
28
- * Looks up the macOS Keychain entry Claude Code is using for one identity's configuration directory, via `security find-generic-password`, run through the injected `RunPort` so no test ever shells out for real.
29
- *
30
- * This is real OS state: the exact account/service naming Claude Code uses in the Keychain is empirically observed (per this project's README), not a documented contract, so genuinely exercising this against a real Keychain is a manual/integration check on a macOS runner, never something a unit test fakes convincingly — a unit test here can only prove that this function parses `security`'s own output shape correctly, not that the shape matches what a real installation produces.
31
- */
32
- export declare function lookupKeychainService(run: RunPort, farmRoot: string): KeychainLookupResult;
33
- /** One file's reported settings exposure: names and counts only, never the underlying values. */
34
- export interface SettingsExposureReport {
35
- readonly file: string;
36
- readonly envKeyNames: readonly string[];
37
- readonly hookEventNames: readonly string[];
38
- readonly hookCommandCount: number;
39
- }
40
- /** Inputs to `inspectSettingsExposure`. */
41
- export interface InspectSettingsExposureParams {
42
- /** Whether the `settings` category resolves shared for this launch — the advisory only has anything to report when it does. */
43
- readonly settingsShared: boolean;
44
- /** Raw file contents keyed by filename (`settings.json`, `settings.local.json`), undefined when the file does not exist. */
45
- readonly files: Readonly<Record<string, string | undefined>>;
46
- }
47
- /**
48
- * Reports how many `env` keys and `hooks` commands `settings.json`/`settings.local.json` would share, by name and count only — never a value, per the README's own warning that a hook command or an `env` entry there can easily hold a real secret with nothing in Claude Code's own documentation warning against it.
49
- *
50
- * Returns nothing at all when `settingsShared` is false, and nothing for a file whose `env`/`hooks` fields are both empty or absent — the whole point of this advisory is to be silent unless there is something worth a second look.
51
- */
52
- export declare function inspectSettingsExposure(params: InspectSettingsExposureParams): SettingsExposureReport[];
53
- /** The provider the cascade selects for this directory, as the wiring layer loaded it: its definition, or why it could not be used (no such provider, an invalid or old-format file). */
54
- type CheckProviderInput = {
55
- readonly name: string;
56
- readonly definition: Provider;
57
- readonly problem?: never;
58
- } | {
59
- readonly name: string;
60
- readonly definition?: never;
61
- readonly problem: string;
62
- };
63
- /**
64
- * Which credential a launch here would use, by source kind and target only: a selected provider's credential block always wins; otherwise the identity's own credential block; otherwise the login stored in the identity's directory.
65
- */
66
- interface CredentialReport {
67
- readonly applies: "provider" | "identity" | "stored-login";
68
- readonly provider?: {
69
- readonly name: string;
70
- readonly credential?: CredentialSummary;
71
- readonly problem?: string;
72
- };
73
- readonly identity?: CredentialSummary;
74
- }
75
- /** Inputs to `runCheck` — everything already loaded/injected, exactly like the resolver core and the launcher: nothing in this function touches a real filesystem, git repository, clock, or environment itself. */
76
- export interface RunCheckParams {
77
- readonly cwd: string;
78
- readonly home: string;
79
- readonly claudeHome: string;
80
- readonly env: Readonly<Record<string, string | undefined>>;
81
- readonly branch?: string;
82
- readonly branchDetached?: boolean;
83
- readonly nowMs: number;
84
- /** Used only to build the fact manifest by reading the canonical `~/.claude` tree — `runCheck` never mutates the farm and never spawns anything. */
85
- readonly farmFs: FarmFs;
86
- readonly cascade: CascadeInput;
87
- readonly classification: {
88
- readonly defaults: CategoryClassification;
89
- readonly overlay?: CategoryClassificationOverlay;
90
- };
91
- readonly identityName?: string;
92
- readonly identitySource: IdentityDecisionSource;
93
- /** The pool the launch selected and how it ranks right now, when it named a pool instead of an identity; `identityName` is then the member it would pick. */
94
- readonly poolPick?: PoolPickReport;
95
- readonly configProfileName?: string;
96
- readonly configProfileSource: ConfigProfileDecisionSource;
97
- /** The resolved identity's own `identity.json`, when one was found. */
98
- readonly identity?: Identity;
99
- /** Raw `settings.json`/`settings.local.json` contents, keyed by filename, undefined when a file does not exist. */
100
- readonly settingsFiles: Readonly<Record<string, string | undefined>>;
101
- /** Runs `security find-generic-password` for the Keychain diagnostic. Omit to skip that diagnostic entirely (e.g. off macOS, or when no identity/farm root is known). */
102
- readonly run?: RunPort;
103
- /** The identity's own farm root — `security`'s lookup account. Required alongside `run` for the Keychain diagnostic to run at all. */
104
- readonly farmRoot?: string;
105
- /** `process.platform` in real use; the Keychain diagnostic only ever runs when this is `"darwin"`. */
106
- readonly platform: string;
107
- /** The provider a launch here would route through (`launch.provider` in the cascade), when one is selected. */
108
- readonly provider?: CheckProviderInput;
109
- }
110
- /** Everything `agent-shim check` reports about one directory/identity, without touching the farm or spawning anything. */
111
- export interface CheckReport {
112
- readonly identityName?: string;
113
- readonly identitySource: IdentityDecisionSource;
114
- readonly poolPick?: PoolPickReport;
115
- readonly configProfileName?: string;
116
- readonly configProfileSource: ConfigProfileDecisionSource;
117
- readonly resolved: ResolvedState;
118
- readonly decisionLines: readonly string[];
119
- readonly projectEncodingAmbiguities: readonly EncodingAmbiguity[];
120
- readonly ambientCredential: AmbientCredentialGuardResult;
121
- readonly keychain?: KeychainLookupResult;
122
- readonly settingsExposure: readonly SettingsExposureReport[];
123
- readonly credential: CredentialReport;
124
- }
125
- /**
126
- * Resolves the full cascade for one directory/identity and reports everything `agent-shim check` documents: every entry's resolved state and which layer/condition decided it, any ambiguous `history/projects/` encoding in scope, and the three always-on diagnostics (ambient-credential exposure, macOS Keychain service name, settings-secrets exposure).
127
- *
128
- * Deliberately reuses the same cascade machinery a real launch uses — `resolveDecisions` and `buildEntryFacts` — rather than reimplementing any part of resolution. The one thing this function never does that a launch does is touch the farm or spawn anything: it only reads the canonical `~/.claude` tree to build the fact manifest resolution needs, and every other input (cascade, classification, settings file contents, the Keychain lookup) is handed in already loaded.
129
- */
130
- export declare function runCheck(params: RunCheckParams): CheckReport;
131
- /** Renders a full `CheckReport` as plain text lines, in the order `agent-shim check` prints them. */
132
- export declare function formatCheckReport(report: CheckReport): string[];
133
- /**
134
- * The `check --json` form of a report: every field the text form prints, as plain data (no `Map`s, no compiled matchers), so a script can read the same verdicts a person would.
135
- */
136
- export declare function checkReportToJson(report: CheckReport): Record<string, unknown>;
137
- /**
138
- * Whether a report carries anything `check --strict` fails on: a resolver diagnostic of warning or error severity, an ambiguous `history/projects/` encoding, an ambient credential a launch would refuse, or a selected provider a launch could not use. Informational diagnostics and the settings-exposure advisory (names and counts only, for a person to review) never fail it.
139
- */
140
- export declare function checkReportHasWarnings(report: CheckReport): boolean;
141
- /** What `collectCheckReport` needs from its caller. */
142
- export interface CollectCheckReportParams {
143
- readonly paths: LayoutPaths;
144
- /** The directory a launch would run in; resolved against the working directory by the caller. */
145
- readonly cwd: string;
146
- /** The identity to check, as `--identity` names it; absent means the identity a launch there would resolve. */
147
- readonly identity?: string;
148
- readonly env: NodeJS.ProcessEnv;
149
- }
150
- /**
151
- * Resolves what a launch in `params.cwd` would share or hide, and why, against this machine: the edge adapter that reads the real filesystem, clock, git and keychain, resolves the identity, configuration profile and cascade exactly as a launch does, and hands the facts to the pure `runCheck`. Never touches the farm or spawns claude.
152
- */
153
- export declare function collectCheckReport(params: CollectCheckReportParams): CheckReport;
154
- export {};
@@ -1,114 +0,0 @@
1
- import type { Command } from "commander";
2
- import { z } from "zod";
3
- import { type CommandDeps } from "./cli/commandDeps";
4
- import { CliError } from "./cliError";
5
- import type { LayoutPaths } from "./paths";
6
- export declare const ClaudeShimStateSchema: z.ZodObject<{
7
- targetPath: z.ZodString;
8
- method: z.ZodEnum<{
9
- copy: "copy";
10
- hardlink: "hardlink";
11
- }>;
12
- installedAtMs: z.ZodNumber;
13
- }, z.core.$strict>;
14
- export type ClaudeShimState = z.infer<typeof ClaudeShimStateSchema>;
15
- /** Raised by enableClaudeShim/disableClaudeShim when the target path exists but doesn't look like agent-shim's own doing (no matching claude-shim.json marker, and not a hardlink of the currently-running executable) — refuses rather than silently clobbering or deleting something an installer never created. Bypassed by --force. */
16
- export declare class ForeignClaudeEntryError extends CliError {
17
- readonly targetPath: string;
18
- readonly action: "enable" | "disable";
19
- constructor(targetPath: string, action: "enable" | "disable");
20
- }
21
- /** Raised by enableClaudeShim when the running executable cannot possibly be turned into a directly-runnable `claude` command: an npm/Node install of agent-shim on Windows, which has no bundled .exe and no shebang-based dispatch the way POSIX does. Not bypassed by --force — this isn't a safety refusal, it's "this would produce a broken file." */
22
- export declare class UnsupportedShimSourceError extends CliError {
23
- readonly contentSourcePath: string;
24
- constructor(contentSourcePath: string);
25
- }
26
- /**
27
- * The exact filename to create: `claude.exe` when the running executable is itself a `.exe` (Windows needs the extension to recognise it as directly executable at all), `claude` for every other case.
28
- *
29
- * Deliberately not "preserve whatever extension the source has" — an npm install's own file is `cli.cjs`, and a bare `claude` (not `claude.cjs`) is what makes it invocable as the expected command on POSIX, where a shebang plus the executable bit is what matters, not the filename's extension.
30
- */
31
- export declare function claudeTargetFilename(ownExecutablePath: string): string;
32
- /** The same rule generalised to any command name this tool owns, so `doctor`'s PATH-resolution check can ask "what filename would a bare `agent-shim` be" without restating the Windows `.exe` condition and letting the two drift apart. */
33
- export declare function commandFilename(ownExecutablePath: string, commandName: string): string;
34
- /**
35
- * `cli.ts`'s own name-dispatch check: is `invokedName` (the basename of however this binary was invoked) one of the two names `shim enable` ever creates, per `claudeTargetFilename` above? `path.basename` includes the file extension, so a bare `=== "claude"` comparison never matches the Windows case, where the file must be named `claude.exe` to be directly invocable at all.
36
- *
37
- * Confirmed as a real, previously-undetected bug against an actual Scoop install: the shim-placement and hardlink-source bugs fixed in prior releases had never let a Windows `claude.exe` invocation reach this far before, so this exact mismatch never surfaced until the shim itself finally worked end-to-end — invoking the newly-created `claude.exe` fell through to agent-shim's own CLI (printing its own `--version`) instead of the launcher.
38
- */
39
- export declare function isInvokedAsClaude(invokedName: string): boolean;
40
- /**
41
- * The directories `discoverClaudeBinary`'s PATH-fallback search must exclude to avoid recursively discovering/spawning this very tool: wherever the running executable itself lives, plus wherever `shim enable` last placed a `claude`-named copy, when that's a *different* directory (i.e. `--dir` was used). Without folding the recorded shim directory in here too, `agent-shim run`/`agent-shim doctor` would only exclude their own directory, not a `--dir`-placed shim living elsewhere on PATH.
42
- */
43
- export declare function resolveOwnInstallDirs(paths: LayoutPaths, ownExecutablePath: string): string[];
44
- /** Where `shim enable` places `claude` absent a --dir override: alongside the running executable. */
45
- export declare function resolveClaudeTargetPath(ownExecutablePath: string, dir?: string): string;
46
- /** The two low-level fs calls the hardlink-then-copy-fallback needs, matching `src/config/store.ts`'s own `StoreFs`/`nodeStoreFs`-with-a-real-default pattern — the one seam in this file that isn't plain `node:fs`, added so the EXDEV fallback branch gets real unit coverage without a genuine cross-filesystem test rig. */
47
- export interface LinkFs {
48
- readonly link: (existingPath: string, newPath: string) => void;
49
- readonly copyFile: (src: string, dest: string) => void;
50
- readonly chmod: (target: string, mode: number) => void;
51
- }
52
- /** Inputs to `enableClaudeShim`. */
53
- export interface EnableShimParams {
54
- readonly paths: LayoutPaths;
55
- /** `realOwnExecutablePath()` (see realPorts.ts) — the PATH-visible location `claude` should be placed alongside, supplied by the wiring layer. Deliberately separate from `contentSourcePath` below: for a Scoop install, this is `~/scoop/shims/agent-shim.exe` (Scoop's own proxy binary, not agent-shim's real content), and using it as the link/copy source would hardlink that proxy instead of the genuine executable. */
56
- readonly ownExecutablePath: string;
57
- /** `realContentSourcePath()` (see realPorts.ts) — the actual file whose content is this running process, used as the hardlink/copy source and for "is the existing target mine" inode comparisons. */
58
- readonly contentSourcePath: string;
59
- /** process.platform, supplied by the wiring layer — only used for the Windows/npm-source guard. */
60
- readonly platform: string;
61
- readonly dir?: string;
62
- readonly force: boolean;
63
- }
64
- type EnableShimAction = "enabled" | "reenabled";
65
- export interface EnableShimResult {
66
- readonly action: EnableShimAction;
67
- readonly targetPath: string;
68
- readonly method: "hardlink" | "copy";
69
- }
70
- /**
71
- * Creates a `claude`-named hardlink (falling back to a copy on a cross-device filesystem) of the currently running `agent-shim` executable, so `claude @<name>` works directly instead of needing `agent-shim run`.
72
- *
73
- * A target that already exists is only ever overwritten when it's provably agent-shim's own doing — either it shares an inode with the currently-running executable (covers a pre-existing install from before this feature existed, where no marker could possibly exist yet), or claude-shim.json records this exact target path (covers refreshing after a agent-shim upgrade, when the old target's inode no longer matches the new binary's content). Anything else is refused unless `force` is set — this could otherwise silently delete or overwrite someone's genuine, unrelated `claude` binary.
74
- */
75
- export declare function enableClaudeShim(params: EnableShimParams, linkFs?: LinkFs): EnableShimResult;
76
- type DisableShimAction = "disabled" | "not-enabled";
77
- export interface DisableShimResult {
78
- readonly action: DisableShimAction;
79
- readonly targetPath: string;
80
- }
81
- export interface DisableShimParams {
82
- readonly paths: LayoutPaths;
83
- /** `realOwnExecutablePath()` — the PATH-visible location, used to derive the default target path. */
84
- readonly ownExecutablePath: string;
85
- /** `realContentSourcePath()` — used for the "is the existing target mine" inode comparison; see `EnableShimParams` for why this must be separate from `ownExecutablePath`. */
86
- readonly contentSourcePath: string;
87
- readonly dir?: string;
88
- readonly force: boolean;
89
- }
90
- /** The inverse of `enableClaudeShim`: removes the `claude` command it created, using the same "is this ours" safety check. A no-op, not an error, when nothing is enabled — including clearing a dangling marker whose target has since been deleted by other means. */
91
- export declare function disableClaudeShim(params: DisableShimParams): DisableShimResult;
92
- export type PathShadowStatus = {
93
- readonly status: "ok";
94
- } | {
95
- readonly status: "not-on-path";
96
- } | {
97
- readonly status: "shadowed";
98
- readonly by: string;
99
- };
100
- export interface FindPathShadowParams {
101
- readonly pathDirs: readonly string[];
102
- readonly targetDir: string;
103
- readonly targetFilename: string;
104
- readonly findExecutableInDir: (dir: string, name: string) => string | undefined;
105
- }
106
- /** Would something else on PATH run before the just-enabled `claude`? Reuses the exact PATH-scan semantics `discoverClaudeBinary`'s own fallback already uses (via the injected `findExecutableInDir`), rather than shelling out to `command -v` — this answers a more directly relevant question ("would this tool's own binary discovery find this file first") without spawning a process at all. */
107
- export declare function findPathShadow(params: FindPathShadowParams): PathShadowStatus;
108
- /**
109
- * Registers `agent-shim shim enable`/`agent-shim shim disable` onto `program`.
110
- *
111
- * `shim` is a deliberate noun-group, matching `identity`/`profile`/`rule`: it names the actual mechanism (a PATH-level executable that dispatches by invoked name, the same concept Scoop itself calls a "shim"), so `enable`/`disable` read as toggling one clearly-scoped thing rather than "installing"/"uninstalling" software, which could be misread as installing Claude Code itself.
112
- */
113
- export declare function registerShimCommand(program: Command, deps: CommandDeps): void;
114
- export {};
@@ -1,8 +0,0 @@
1
- /**
2
- * The one boolean vocabulary every agent-shim input shares, CLI flag values and environment variables alike: `true` and `1` mean true, `false` and `0` mean false, and nothing else is a boolean (no case folding, no `yes`/`no`).
3
- *
4
- * Lives in a module with no imports so both `src/cli/parsers.ts` (which raises on anything else) and `src/cliError.ts` (which must never raise while reporting another failure) can share it without an import cycle.
5
- * @param input - The raw text.
6
- * @returns The boolean it spells, or undefined when it spells none.
7
- */
8
- export declare function parseBoolWord(input: string): boolean | undefined;
@@ -1,39 +0,0 @@
1
- import type { Command } from "commander";
2
- import type { PromptsPort } from "../configure";
3
- import type { LayoutPaths } from "../paths";
4
- /**
5
- * What every `agent-shim` command's registration needs from `buildProgram`: where the config tree lives, the prompt surface, whether standard input is a terminal those prompts can run on, and how to end the process.
6
- *
7
- * `isInteractive` is a function rather than a snapshot so the real wiring reads `process.stdin.isTTY` at the moment a command runs, and a test can script both answers against the same program.
8
- */
9
- export interface CommandDeps {
10
- readonly paths: LayoutPaths;
11
- readonly prompts: PromptsPort;
12
- readonly isInteractive: () => boolean;
13
- /** Ends the process with `code` immediately. Only the long-running `__headroom-supervisor` and `__codex-supervisor` need it (a signal must terminate it, and its servers would otherwise keep the event loop alive); every other command sets `process.exitCode` or throws, so its output is never truncated. */
14
- readonly exit: (code: number) => never;
15
- }
16
- /** Prints `value` as indented JSON on standard output: the one `--json` output format every `list`, `show`, `check`, `doctor` and `headroom status` command shares. */
17
- export declare function printJson(value: unknown): void;
18
- /** What a mutating command did, as the one object `--json` prints in place of its text output. */
19
- export interface MutationReport {
20
- readonly action: "created" | "updated" | "removed" | "selected";
21
- /** The noun the command works on: `identity`, `profile`, `provider`, `pool` or `rule`. */
22
- readonly kind: string;
23
- readonly name: string;
24
- /** The stored object after the change; absent for a removal and for a selection. */
25
- readonly value?: unknown;
26
- }
27
- /** Reports a mutating command's outcome: the `MutationReport` as JSON under `--json`, otherwise whatever `printText` prints. */
28
- export declare function reportMutation(json: boolean | undefined, report: MutationReport, printText: () => void): void;
29
- /**
30
- * Appends an `Examples:` block to `command`'s help output, one `$ agent-shim ...` line per entry. Every command registers at least one, so `--help` on any of them shows a runnable invocation, not just its option list.
31
- */
32
- export declare function withExamples(command: Command, examples: readonly string[]): Command;
33
- /**
34
- * The confirmation every destructive `remove` verb shares. `--yes` skips it; otherwise a terminal gets a yes/no prompt (declining throws `PromptCancelledError`), and a non-terminal throws `MissingInputError` naming `--yes`, since deleting without either would be a silent destructive default.
35
- * @param deps - The prompt surface and terminal check.
36
- * @param yes - Whether `--yes` was passed.
37
- * @param description - What would be removed, phrased to follow "Remove ", e.g. `identity "work" and its directory`.
38
- */
39
- export declare function confirmRemoval(deps: CommandDeps, yes: boolean | undefined, description: string): Promise<void>;
@@ -1,11 +0,0 @@
1
- import { UsageError } from "../cliError";
2
- /** Raised when a boolean environment variable holds something outside the shared vocabulary. */
3
- export declare class InvalidEnvBoolError extends UsageError {
4
- readonly variable: string;
5
- readonly value: string;
6
- constructor(variable: string, value: string);
7
- }
8
- /**
9
- * Reads a boolean environment variable with the same vocabulary a CLI flag value uses. Unset and the empty string both mean "not given" (undefined), consistent with how every other agent-shim environment variable treats the empty string; anything outside the vocabulary throws `InvalidEnvBoolError` rather than silently reading as false.
10
- */
11
- export declare function parseEnvBool(variable: string, value: string | undefined): boolean | undefined;
@@ -1,19 +0,0 @@
1
- /** One `<key>=<value>` pair, as parsed by `parsePair`. */
2
- export interface ParsedPair {
3
- readonly key: string;
4
- readonly value: string;
5
- }
6
- /**
7
- * Splits `input` on its *first* `=` into a key and a value. The value may itself contain further `=` characters (they stay part of the value); only the first `=` is treated as the separator.
8
- *
9
- * Throws when there is no `=` at all, or when the key half is empty (`=true`, or a leading `=`).
10
- */
11
- export declare function parsePair(input: string): ParsedPair;
12
- /** Parses `input` as a boolean in the shared vocabulary (`true`/`1`, `false`/`0`); throws on anything else. */
13
- export declare function parseBool(input: string): boolean;
14
- /**
15
- * Parses a comma-separated list of `<key>=<bool>` pairs into a plain object, e.g. `"history=true,knowledge=false"` becomes `{ history: true, knowledge: false }`. Used only for the list-valued environment variables; flags repeat instead.
16
- *
17
- * An empty string parses to `{}`. A key repeated within the same list is not an error: the later occurrence wins, matching how a plain object literal with a repeated key behaves.
18
- */
19
- export declare function parseBoolPairList(input: string): Record<string, boolean>;
@@ -1,27 +0,0 @@
1
- /** Exit status for every expected failure that is not a usage error: a missing identity, an invalid config file, a refused launch. */
2
- export declare const EXIT_FAILURE = 1;
3
- /** Exit status for a usage error: an unknown command or option, a malformed flag value, or required input missing with no terminal to prompt on. */
4
- export declare const EXIT_USAGE = 2;
5
- /**
6
- * Base class for every error this CLI throws to represent an expected, user-facing failure: bad input, a missing identity/profile/rule, a malformed config file. `reportFatalError` prints this class as `agent-shim: <message>` with no stack trace and exits with `exitCode`; anything that does not extend it is an unexpected bug, reported by message alone unless `AGENT_SHIM_DEBUG` asks for the stack.
7
- */
8
- export declare abstract class CliError extends Error {
9
- /** The process exit status this failure maps to. `EXIT_FAILURE` unless a subclass says otherwise. */
10
- readonly exitCode: number;
11
- }
12
- /** A usage error: the command line itself is wrong or incomplete. Exits `EXIT_USAGE`. */
13
- export declare class UsageError extends CliError {
14
- readonly exitCode: number;
15
- constructor(message: string);
16
- }
17
- /**
18
- * Raised when a command needs input it would prompt for on a terminal, but standard input is not one. Names the option (or argument) that supplies the input non-interactively, so a script's failure says exactly what to add.
19
- */
20
- export declare class MissingInputError extends UsageError {
21
- readonly option: string;
22
- constructor(option: string, what: string);
23
- }
24
- /** Raised when the user cancels an interactive prompt that a command cannot continue without. */
25
- export declare class PromptCancelledError extends CliError {
26
- constructor();
27
- }
@@ -1,15 +0,0 @@
1
- /** The HTTP statuses the codex route and its listener answer with, named so every use says what it means. */
2
- export declare const HTTP_STATUS: {
3
- readonly ok: 200;
4
- readonly badRequest: 400;
5
- readonly unauthorized: 401;
6
- readonly forbidden: 403;
7
- readonly notFound: 404;
8
- readonly methodNotAllowed: 405;
9
- readonly payloadTooLarge: 413;
10
- readonly tooManyRequests: 429;
11
- /** Not sent to anyone: the client is gone. Recorded for a response abandoned because the client disconnected, following the convention nginx uses for the same case. */
12
- readonly clientClosedRequest: 499;
13
- readonly internalServerError: 500;
14
- readonly badGateway: 502;
15
- };
@@ -1,49 +0,0 @@
1
- import { type CategoryClassification, type CategoryClassificationOverlay, type CategoryName } from "./schema";
2
- import type { LayoutPaths } from "../paths";
3
- /** Which map a classification pattern came from. A `local` pattern is an answer the user gave to an "unclassified entry" prompt; a `default` pattern is shipped with the tool. */
4
- type ClassificationSource = "default" | "local";
5
- /** One compiled classification pattern: which category it assigns, where it came from, and how specific it is. */
6
- export interface ClassificationPattern {
7
- readonly pattern: string;
8
- readonly category: CategoryName;
9
- readonly source: ClassificationSource;
10
- /** True when the pattern contains no glob metacharacter, so it can only ever match one literal name. */
11
- readonly isExact: boolean;
12
- /** Position of the pattern within its own category list, used only as the final deterministic tie-break. */
13
- readonly ordinal: number;
14
- readonly matches: (name: string) => boolean;
15
- }
16
- /** The outcome of classifying a set of real top-level `~/.claude` entry names. */
17
- export interface ClassifyResult {
18
- /** Every input name mapped to its category, or to null when nothing in either map recognises it. */
19
- readonly classification: ReadonlyMap<string, CategoryName | null>;
20
- /** The input names that nothing recognised, in input order. These are the names `agent-shim configure` prompts about. */
21
- readonly unclassified: readonly string[];
22
- /** For each classified name, the pattern that decided it — used by `agent-shim check` to explain a classification. */
23
- readonly decidedBy: ReadonlyMap<string, ClassificationPattern>;
24
- }
25
- /** True when `pattern` contains no glob metacharacter, so it matches exactly one literal name. */
26
- export declare function isExactPattern(pattern: string): boolean;
27
- /** Compiles a shipped classification map plus an optional local overlay into one flat, ranked pattern list. */
28
- export declare function compileClassificationPatterns(defaults: CategoryClassification, overlay?: CategoryClassificationOverlay): ClassificationPattern[];
29
- /** The classification input every real call site needs: the shipped defaults plus this user's own local overlay, when one exists. */
30
- export interface LoadedClassification {
31
- readonly defaults: CategoryClassification;
32
- readonly overlay?: CategoryClassificationOverlay;
33
- }
34
- /**
35
- * Loads the classification input `classifyEntries` needs — the shipped `categories.default.json`, plus `categories.local.json` when the user has answered at least one "unclassified entry" prompt.
36
- *
37
- * Real-wired convenience over reading and validating the two files. Every command that classifies anything (`cli.ts`'s farm runtime, `check`, `configure`, `identity resolve-conflicts`) was independently repeating this exact pair of `readJson`/`.parse()` calls before this existed; centralising it here means the four command files stay thin call sites rather than each holding its own copy of a validation step that never varies between them.
38
- */
39
- export declare function loadClassification(paths: LayoutPaths): LoadedClassification;
40
- /**
41
- * Classifies a list of real top-level `~/.claude` entry names against the shipped category map plus an optional local overlay.
42
- *
43
- * An unrecognised name maps to `null` rather than being silently assumed safe or silently dropped: the resolver treats it as not-shared and reports it, and `agent-shim configure` prompts for an answer that is then written to the local overlay.
44
- */
45
- export declare function classifyEntries(names: readonly string[], options: {
46
- defaults: CategoryClassification;
47
- overlay?: CategoryClassificationOverlay;
48
- }): ClassifyResult;
49
- export {};
@@ -1,42 +0,0 @@
1
- import { type PublicExplorerSync } from "cosmiconfig";
2
- import type { z } from "zod";
3
- import { CliError } from "../cliError";
4
- /**
5
- * A configuration file that has been read, parsed, and validated.
6
- *
7
- * `entryOrder` and `ruleEntryOrders` capture each `entries` object's own key insertion order as an explicit ordinal array, taken from the *raw* parsed value before Zod ever sees it. This is not paranoia about JSON key ordering: `schema.parse()` returns a fresh deep clone, and relying on key order implicitly surviving that clone would make the resolver's same-layer source-order tie-break depend on an implementation detail of a third-party library. Capturing it explicitly at load time makes it data.
8
- */
9
- export interface LoadedFile<T> {
10
- readonly filepath: string;
11
- readonly config: T;
12
- /** Key insertion order of the file's own top-level `entries` object; empty when the file has none. */
13
- readonly entryOrder: readonly string[];
14
- /** For a directory-rules file: the key insertion order of each rule's `entries` object, indexed the same as `rules[]`. Empty for every other file shape. */
15
- readonly ruleEntryOrders: readonly (readonly string[])[];
16
- }
17
- /**
18
- * Builds the cosmiconfig explorer used for every read.
19
- *
20
- * Only `load(filepath)` is ever called on it — never `search()`. `search()` stops at the first config file found while walking upward, and this design needs the exact opposite: every ancestor collected, shallowest-first. `src/resolve/walk.ts` does its own directory walk and this module loads each level it visits, so cosmiconfig contributes its format flexibility (JSON, YAML, JS) without its traversal semantics.
21
- */
22
- export declare function createExplorer(moduleName?: string): PublicExplorerSync;
23
- /** Reads the key insertion order of `value.entries`, when `value` is an object carrying an `entries` object. */
24
- export declare function captureEntryOrder(value: unknown): readonly string[];
25
- /** Reads the per-rule key insertion order of a directory-rules file's `rules[].entries` objects. */
26
- export declare function captureRuleEntryOrders(value: unknown): readonly (readonly string[])[];
27
- /** Raised when a config file exists but fails Zod validation, so the caller can report the offending path alongside the issue list. */
28
- export declare class ConfigValidationError extends CliError {
29
- readonly filepath: string;
30
- readonly issues: readonly z.core.$ZodIssue[];
31
- constructor(filepath: string, issues: readonly z.core.$ZodIssue[]);
32
- }
33
- /** Injected reader for a single config file, so tests never touch a real filesystem. Returns undefined when the file does not exist. */
34
- export type ConfigFileReader = (filepath: string) => unknown;
35
- /** A cosmiconfig-backed reader: loads and parses one file by path, returning undefined when it is missing or empty. */
36
- export declare function cosmiconfigReader(explorer?: Readonly<PublicExplorerSync>): ConfigFileReader;
37
- /**
38
- * Loads one config file by exact path, validates it against `schema`, and captures its entries key order.
39
- *
40
- * Returns undefined when the file does not exist or is empty. Throws ConfigValidationError when it exists but does not validate — a malformed config is never silently ignored or half-applied.
41
- */
42
- export declare function loadConfigFile<S extends z.ZodType>(filepath: string, schema: S, read?: ConfigFileReader): LoadedFile<z.infer<S>> | undefined;