/** * Which agent tools a project is set up for, and where each one looks for its skills. * * The GDK is a bring-your-own-agent product, but for most of its life the scaffold wrote to * `.claude/skills/` and nothing else — so a creator on Cursor, Codex or Kiro received a directory of * skill files their agent never opened, and `bitmagic upgrade`, the only route by which an existing * project learns about a new CLI capability, kept refreshing files nobody read. * * ── Why `.agents/skills/` is unconditional ─────────────────────────────────────────────────────── * * Cursor, Codex, GitHub Copilot, Cline and OpenCode all load `.agents/skills/` by themselves, and * all of them read the root `AGENTS.md` this scaffold already writes. So writing that one directory * into every project supports five agents with no flag to pass and no environment to sniff — which * is the whole point, because neither of the alternatives survives contact: * * - Detection cannot be built honestly. `../telemetry/command-context.ts` states the policy — * an agent gets a marker here only once that marker is verified against the real thing, because * a guessed variable never fires and misleads whoever reads the table next — and `CLAUDECODE` is * the only marker anyone has verified. An `init` run by Cursor's agent proves nothing, so * detection-as-default would silently produce a Cursor-less project. * - A required flag cannot be relied on either. The GDK bootstrap that runs `bitmagic init` is * read BY the agent, so it could pass its own id — but nothing upgrades an installed copy of * that bootstrap (see `agent-plugin/README.md`), so a creator on last month's copy would get * nothing, and the failure is silent. * * What is left for this table is therefore narrow: agents that read a VENDOR directory and nothing * else. Claude Code (`.claude/skills/`) is one, and it is unconditional too — every project on disk * today has that directory, and an upgrade that stopped writing it would be the first destructive * thing the command has ever done. Kiro (`.kiro/skills/`) is the other, and it is the only reason * `--agent` exists: an unasked-for `.kiro/` is pure noise in a project that does not use Kiro. * * ── Why the directory, not the agent, is the unit ──────────────────────────────────────────────── * * Four agents map onto three directories, so every caller works in terms of the deduped set of * DIRECTORIES (`skillDirsFor`). Writing per agent instead would put the same files into * `.agents/skills/` twice for a creator who named both Cursor and Codex. */ export type AgentId = 'claude-code' | 'cursor' | 'codex' | 'kiro'; export interface AgentTarget { id: AgentId; /** How the agent is named in output a creator reads. */ label: string; /** * The agent's own skills directory, or absent when it reads `SHARED_SKILLS_DIR` itself — in which * case there is nothing to write for it and `--agent ` is a no-op we report rather than * refuse. Relative to the project root, POSIX-separated. */ skillsDir?: string; /** Where this agent reads its startup instructions. Output copy only; nothing branches on it. */ instructions: string; } /** * The directory every agent following the AGENTS.md / agent-skills convention reads by itself. * Written into every project whatever agent scaffolded it — see the file header. */ export declare const SHARED_SKILLS_DIR = ".agents/skills"; /** * Declaration order is output order, so the file set a project receives is a function of WHICH * agents were selected and not of how they were typed. */ export declare const AGENT_TARGETS: readonly AgentTarget[]; export declare const AGENT_IDS: readonly AgentId[]; /** * In every project's set, and not removable. * * `--agent` adds; it never takes away. Both of the unconditional directories are already on disk in * every existing project (`.claude/skills/`) or are what makes five agents work for free * (`.agents/skills/`), and `upgrade` has never deleted a file under a skills directory. */ export declare const ALWAYS_AGENTS: readonly AgentId[]; /** * `--agent`'s help text, shared by `init` and `upgrade` so the two cannot describe the same flag * differently. It names what the flag is FOR, because the honest answer is "usually nothing": the * default already covers every agent but Kiro. */ export declare const AGENT_FLAG_DESCRIPTION: string; export declare function isAgentId(value: unknown): value is AgentId; export declare function agentTarget(id: AgentId): AgentTarget; /** In table order, each agent once. */ export declare function dedupeAgents(agents: readonly AgentId[]): AgentId[]; /** * "Cursor", "Cursor and Codex", "Cursor, Codex and Kiro" — for a sentence a creator reads, not a * list a parser does. Exported because the scaffolded AGENTS.md joins its skills directories the * same way, and two hand-written copies of this join is how the two come to punctuate differently. */ export declare function joinWithAnd(items: readonly string[]): string; /** The agents named, in table order, as a clause for a sentence a creator reads. */ export declare function agentLabels(agents: readonly AgentId[]): string; /** * `--agent kiro,cursor` → `['cursor', 'kiro']`, unioned with the always-present set. * * Comma-separated rather than a repeatable flag because citty's string args are single-valued. An * unknown id is a hard error naming the valid ones: a typo that silently scaffolded the default set * would look like the flag working, and the creator would find out when their agent loaded nothing. */ export declare function parseAgentFlag(raw: string | undefined): AgentId[]; /** The `agents` field of a `bitmagic.json`, keeping only ids this CLI recognises. */ export declare function readRecordedAgents(value: unknown): AgentId[]; /** Values in a project's `agents` field that this CLI does not recognise — reported, never fatal. */ export declare function unrecognisedAgents(value: unknown): string[]; /** * The directories to write, deduped and in a stable order, always starting with the shared one. * * A duplicate here would double-write a file and list its path twice in `UpgradeResult.replaced`, * so the dedupe is load-bearing rather than tidiness: `--agent cursor,codex` names two agents that * share a directory. */ export declare function skillDirsFor(agents: readonly AgentId[]): string[]; /** * The directory `AGENTS.md` names when it cross-references a skill. * * Every project has more than one copy of the shipped skills, but `AGENTS.md` is ONE file at the * root read by every agent in the project, so it has to name a single path — and the only honest * choice is the one that exists in every project and that most agents load from. Its Layout section * names the other copies, so a Claude Code reader still learns where its own loader looks. */ export declare const PRIMARY_SKILLS_DIR = ".agents/skills"; /** * The agents named by `--agent` that this scaffold writes nothing extra for, because the directory * and the instructions file they read are already unconditional. * * Accepting such a flag and explaining it beats refusing one a creator reasonably typed. */ export declare function noOpAgents(agents: readonly AgentId[]): AgentId[]; /** Which agents load a given skills directory, as a clause for a sentence the creator reads. */ export declare function describeSkillsDir(dir: string): string;