export type ClientId = 'claude-code' | 'cursor' | 'copilot' | 'windsurf' | 'agents' | 'opencode' | 'hermes' | 'grok' | 'antigravity'; export declare const CLIENT_NATIVE_PATHS: Record; export declare const CANONICAL_CLIENT: ClientId; /** * SMI-5894 (Wave 1 Step 5): human-readable label per client, used by * post-install tips/guidance so the messaging names the actual install * target (e.g. "mention it in Cursor:") instead of unconditionally saying * "Claude Code" regardless of `SKILLSMITH_CLIENT`/`--client`. Lives here * (not in the CLI's `CLIENT_SNIPPETS` table) so both `@skillsmith/core` * (shared install/uninstall tip generation) and any MCP-side caller can use * it without introducing a core -> cli dependency. */ export declare const CLIENT_DISPLAY_LABELS: Record; export declare const CLIENT_IDS: ReadonlyArray; export declare function getCanonicalInstallPath(): string; export declare function getInstallPath(client?: ClientId): string; export declare function assertClientId(value: unknown): asserts value is ClientId; export declare function resolveClientId(raw: string | undefined): ClientId; /** * Resolve the active client from `SKILLSMITH_CLIENT` (or any explicit * override). Returns the matching install path. Computed at call time so * a process that mutates `SKILLSMITH_CLIENT` at runtime sees the new * value — used by the MCP server to pick `~/.cursor/skills/` etc. */ export declare function resolveClientPath(override?: string | undefined): string; /** * Returns the filesystem presence status of every known harness. * * A harness is considered "present" when its skill directory exists on disk. * This lets the cross-harness inventory (SMI-5390) report a harness as * "installed but zero skills" rather than omitting it entirely. * * Synchronous and O(CLIENT_IDS.length) — safe to call on the startup path. * * @see SMI-5390 */ export declare function enumerateHarnessPresence(): Array<{ harness: ClientId; present: boolean; path: string; }>; /** * SMI-5980 (Wave 3): where a per-skill companion-subagent file is written for * a given `ClientId`. * * **Deliberately NOT derived from `AGENT_SHIM_TARGETS`** (agent-harness-targets.ts). * That table encodes complete, singular shim-file targets (fixed filenames like * `skillsmith-agent.md`, `null` entries for some tools) for a *different* * command (`sklx agent install`'s one-time named-agent shim), keyed by the * narrower `HarnessId` enum (5 members) rather than `ClientId` (8 members). * This is a new, purpose-built map for the per-skill companion-subagent file * that `SkillInstallationService.install()` / `sklx author subagent` can * generate for ANY installed skill, one file per skill, not a single fixed * shim. * * `fileMode` has two values: * - `'flat'` — one file directly inside `dir`, named by substituting `{name}` * in `filenamePattern`. Used by every client except Antigravity. * - `'directory-package'` (SMI-5982 Wave 6, Antigravity) — a per-skill * subdirectory `//` containing a fixed-name file * (`filenamePattern`, always `'agent.md'` for this mode — no `{name}` * substitution, the name lives in the directory segment instead). See * {@link resolveCompanionAgentPath} for the resolution logic per mode. */ export interface CompanionAgentTarget { dir: string; fileMode: 'flat' | 'directory-package'; filenamePattern: string; } /** * Populated conservatively per the SMI-5980 plan review, to fix the * hardcoding/architecture bug (making this resolvable per client at all) * WITHOUT inventing new, unverified per-client directory values: * * - `claude-code`: today's actual confirmed hardcoded value * (`~/.claude/agents/-specialist.md`) — this must exactly match * pre-Wave-3 behavior (`skill-installation.io.ts`'s prior * `path.join(os.homedir(), '.claude', 'agents')` literal and * `author/utils.ts`'s prior `ensureAgentsDirectory()` default). * - `copilot`: `AGENT_SHIM_TARGETS.copilot` (agent-harness-targets.ts) has a * real, non-null entry for the SAME underlying tool — * `~/.copilot/agents/skillsmith-agent.agent.md`. Both its DIRECTORY * (`~/.copilot/agents/`) AND its `.agent.md` EXTENSION are cited here as * independent evidence (corroborated by shims.ts's own doc comment: * "Copilot `.agent.md` (Copilot cloud-agent + CLI surfaces, which do not * read `.claude/agents`)") — PR-review finding (BLOCKING): a plain * `-specialist.md` suffix here previously risked writing a companion file * Copilot's own surfaces don't discover at all. Per-skill naming is * `.agent.md`, not `-specialist.md`. * - `opencode`: `AGENT_SHIM_TARGETS.opencode` likewise has a real, non-null * entry — `~/.config/opencode/agents/skillsmith-agent.md` (plural * `agents/`, Step-6 verified against opencode.ai/docs/agents/ per that * table's own header comment). Its DIRECTORY * (`~/.config/opencode/agents/`) is cited here as independent evidence of * OpenCode's own agents-dir convention, filename likewise not reused. * - `cursor`: `AGENT_SHIM_TARGETS.cursor` is `null` — NOT a directory value, * just documentation that Cursor 2.4+ reads `.claude/agents/` natively * (per that table's own comment). That happens to coincide with the * default below, but it is not being "cited as evidence" for a distinct * value — cursor defaults like any client with no independent evidence. * - `windsurf`, `agents`, `hermes`, `grok`: none of these are even members * of the narrower `HarnessId` enum `AGENT_SHIM_TARGETS` is keyed on, so * there is no table entry to consult either way. Every one of these * defaults to today's actual behavior — the same `~/.claude/agents/` * value every client gets today. * - `antigravity` (SMI-5982 Wave 6): NOT a `HarnessId` member either, but * unlike the clients above, it does NOT default to the shared * `~/.claude/agents/` value — Antigravity has its own independently * web-verified convention (live search against * antigravity.google/docs/cli/commands/agents, 2026-08-11), and it is a * directory-package, not a flat file. No existing global-vs-project * install-mode distinction exists anywhere in this CLI (grepped * `--global`/`--project`/`isGlobal`/`globalScope`, zero hits) — this * entry therefore defaults to PROJECT-scoped (`.agents/agents//agent.md`, * relative to the invocation directory, i.e. `dir` here is a RELATIVE * path, unlike every other entry's `homedir()`-anchored absolute path). * Global scope (`~/.gemini/config/agents//agent.md`) is an explicit * fast-follow, not implemented here — see the SMI-5982 Linear comment. */ export declare const COMPANION_AGENT_TARGETS: Record; /** Resolve the companion-agent target descriptor for `client` (default: canonical). */ export declare function getCompanionAgentTarget(client?: ClientId): CompanionAgentTarget; /** * Resolve just the companion-agent output directory for `client` (default: * canonical). For `fileMode: 'directory-package'` clients (Antigravity), this * is the SHARED PARENT of every skill's own `/` package, not the final * per-skill directory — use {@link resolveCompanionAgentPath} (and its * `path.dirname()`) to get the actual per-skill directory a file lands in. */ export declare function resolveCompanionAgentDir(client?: ClientId): string; /** * Resolve the full on-disk companion-subagent file path for `client` + * `skillName` (default client: canonical / `claude-code`). * * Two `fileMode`s (SMI-5982 Wave 6): * - `'flat'`: `/` — one file * directly inside the shared client agents dir (all clients but Antigravity). * - `'directory-package'`: `//` — a * per-skill subdirectory containing a fixed-name file (Antigravity only * today; `filenamePattern` carries no `{name}` token in this mode, since * the skill name is the directory segment instead). * * SMI-5982 code-review fix #1 (BLOCKING, cwd-dependent resolution): Antigravity's * `dir` is the only RELATIVE entry in `COMPANION_AGENT_TARGETS` — every other * client's `dir` is `homedir()`-anchored absolute. A relative `dir` used to be * resolved IMPLICITLY by whichever `fs` call eventually consumed the returned * path, against that call's `process.cwd()` at THAT moment. For a short-lived * CLI process cwd is genuinely the user's invocation directory, but for the * long-running MCP server cwd is fixed at server launch and generally does * NOT track the calling editor/agent's actual project — silently writing into * an unrelated directory. `baseDir` makes the resolution root an explicit, * caller-controlled parameter instead: every caller now decides what "cwd" * means for its own lifecycle, rather than the process's ambient cwd deciding * for it. Applied unconditionally via `isAbsolute()` (not gated to * `directory-package` mode) so the function stays correct if a future client * ever adds a relative `flat`-mode `dir` too — today's flat-mode clients are * all absolute already, so this is a no-op for them. * * SMI-5982 code-review fix #2 (BLOCKING, path traversal): in `directory-package` * mode, `skillName` becomes ITS OWN path segment (`//...`), so * an unsanitized `skillName === '..'` would `path.join`-normalize to * `/agent.md` — escaping the intended companion-agent * namespace entirely. `flat` mode never had this exact exposure (`skillName` * there is embedded INSIDE a suffixed filename via `.replace()`, a literal * filename component, not a traversal directive). Every current caller of * `writeInstallFiles()` already sanitizes `skillName` upstream, but this is a * general, exported, reusable function with no validation of its own — per * this codebase's own stated principle (see `skillNameFromSkillId()`'s doc * comment, skill-installation.content.ts): the actual disk-write boundary is * the last line of defense regardless of what any upstream caller does, since * a future caller could bypass upstream sanitization entirely. * * PR-review fix (BLOCKING, SMI-5982 follow-up): the previous `baseDir: string = * process.cwd()` default only closed the bug for callers that happened to run in * a short-lived process whose cwd IS the caller's real project — the MCP * `install_skill` tool fix (this same PR) proved that out. It did nothing for * every OTHER production call site, including the long-running MCP server's * `private_registry_manage(action:"install")` path, which never threaded a * `companionBaseDir` through and would silently keep resolving against the * server process's ambient `process.cwd()`. `baseDir` is now **required** * (`string | undefined`, no default) whenever `target.fileMode === * 'directory-package'` — every current `directory-package` client * (Antigravity, today the only one) has a relative `dir`, so this throws * unless a caller explicitly opts in with a real base directory. Gated on * `fileMode` alone (not also `isAbsolute(target.dir)`) so the requirement is * structural for the whole mode, not conditional on today's particular * client happening to have a relative `dir` — a future `directory-package` * client added with an absolute `dir` still must not silently accept a * missing `baseDir`. This closes the class of bug BY CONSTRUCTION for every * current and future caller, instead of requiring every call site to be * individually audited (the exact mistake the first fix commit made). * `flat`-mode clients are entirely unaffected: the guard below can never * fire for them regardless of whether `baseDir` is passed. */ export declare function resolveCompanionAgentPath(skillName: string, client?: ClientId, baseDir?: string): string; //# sourceMappingURL=paths.d.ts.map