/** * The coding agents JAM knows how to register itself with, for this user * rather than for a repository. * * Both keep user-level MCP registration in a file of their own - Claude Code * in `~/.claude.json`, Codex in `~/.codex/config.toml` - and JAM parses * neither. Editing another program's live state file is how you corrupt it; * each of these ships a command for exactly this, so JAM uses it. */ export type HostId = "claude-code" | "codex"; export type HostCommand = { command: string; args: string[]; }; export type HostState = { id: HostId; /** Whether the host's own CLI is on PATH and answering. */ cliAvailable: boolean; /** Whether it already has a `jam` entry registered for this user. */ hasJamEntry: boolean; /** * The launcher pin that entry actually runs, when the listing shows it. * * An entry existing is not the same as an entry being current: a pin written * by an older release keeps running that release's server, which serves a * different set of tools. Reading only the name made a stale registration * indistinguishable from a good one, and setup then reported * `already_configured` over it. */ entryVersion?: string; /** The entry is present but does not run the launcher this release registers. */ entryStale?: boolean; /** The entry runs the global `jam` executable rather than an npx pin. */ entryBare?: boolean; }; export type HostRunResult = { status: number | null; /** True when the command could not be run at all. */ failed: boolean; stdout: string; }; /** Injected by tests. Nothing in this module may reach a real CLI unasked. */ export type HostRunner = (command: HostCommand) => HostRunResult; export declare const defaultHostRunner: HostRunner; /** * A runner that only sees what is persistently installed on this machine. * * Under `npx --yes @jam-mcp/bootstrap@X`, PATH carries npx's cache * `node_modules/.bin` - which contains a `jam` shim that vanishes when npx * exits. Any measurement of "does a global jam exist" through the normal PATH * therefore lies during bootstrap, which is exactly when the answer matters * most. This runner strips those entries first. */ export declare const persistentHostRunner: HostRunner; export declare function hostRegistration(id: HostId, options?: { bare?: boolean; version?: string; }): HostCommand | undefined; /** The removal that has to precede re-registering an entry this host already has. */ export declare function hostUnregistration(id: HostId): HostCommand | undefined; /** * Is `jam` in this listing? * * Both CLIs exit 0 whether or not a server exists, so the exit code says * nothing and the name column is the only signal available. Matched as the * first token of a line so a server called `jam-something`, or the word * appearing in a URL, cannot be mistaken for it. * * ponytail: this reads another program's table. If either changes its listing * format the effect is a redundant registration attempt, not a wrong one - * `mcp add` on an existing entry writes the same launcher line back. */ export declare function listsJamEntry(stdout: string): boolean; /** The listing line for `jam`, ANSI stripped, or null when there is none. */ export declare function jamEntryLine(stdout: string): string | null; /** The launcher version a listing line runs, when the line names one. */ export declare function entryLauncherVersion(line: string): string | undefined; /** * Does this entry run the persistent `jam` executable rather than an npx pin? * * `jam: jam serve`, `jam: /usr/local/bin/jam serve`, `jam: C:\...\jam.cmd serve` * all count; an npx line never does - its command token is `npx`. A bare entry * carries no version in the listing, so its staleness has to be measured from * the executable it would actually run (bareJamVersion), not from the line. */ export declare function isBareJamEntry(line: string): boolean; /** * The version a bare `jam` registration actually runs, measured by asking the * executable itself. `runtime status --json` answers from ~/.jam/config.yaml * and the resolved build - the same resolution the registered entry performs. * * undefined when `jam` is not on PATH or does not answer: a registration that * cannot be measured counts as stale, same as an unreadable pin. * * Measured through persistentHostRunner by default: under an npx bootstrap * the ordinary PATH resolves `jam` to npx's own ephemeral cache shim, and a * bare registration decided on that evidence dies as soon as npx exits. */ export declare function bareJamVersion(run?: HostRunner): string | undefined; /** Is this measured launcher version the one this release registers? */ export declare function preferBareRegistration(version: string | undefined): boolean; /** * Does this entry run the launcher this release registers? * * An npx pin answers from the line itself. A bare `jam` line names no version, * so the caller passes what the executable measured (`bareVersion`) - without * it, bare stays stale. Anything else - an older pin, an unpinned spec, a line * whose command JAM cannot read - counts as stale. That direction is * deliberate: `mcp add` rewrites the same entry, so a needless repair costs * one command, while a missed one leaves the agent talking to a server nobody * tested it against. */ export declare function isEntryStale(line: string, bareVersion?: string): boolean; /** * Ask each host what it has, and whether it is there at all. * * Read-only by construction: `mcp list` reports. A host that cannot be reached * is recorded as unavailable rather than assumed empty - so planning has * something to refuse rather than something to guess. */ export declare function detectHosts(run?: HostRunner): HostState[]; /** How a person would do it by hand, for the hosts JAM could not reach. */ export declare function describeHostCommand({ command, args }: HostCommand): string;