buddy-agent-harness 0.4.0 → 0.4.1
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/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.cursor-plugin/plugin.json +1 -1
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{init.command-mGE18Jv0.mjs → init.command-c0fBv15T.mjs} +8 -6
- package/dist/init.command-c0fBv15T.mjs.map +1 -0
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/skills/doctor/SKILL.md +2 -2
- package/skills/init/SKILL.md +1 -1
- package/src/diagnose-bridges/doctor-guidance.ts +7 -5
- package/dist/init.command-mGE18Jv0.mjs.map +0 -1
package/dist/cli.mjs
CHANGED
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/harness-registry/harness-registry.ts","../src/diagnose-bridges/git-bridge-state.ts","../src/diagnose-bridges/diagnose-bridges.ts","../src/diagnose-bridges/doctor.command.ts","../src/diagnose-bridges/doctor-guidance.ts","../src/initialize-harnesses/init.command.ts","../src/initialize-harnesses/initialize-harnesses.ts"],"mappings":";;KAGY;;;;;KAaA;EACX,MAAM;EACN;EACA;;EAEA,aAAa;;;;;;;;;;;;cAaD,0BAA0B;;;;KC7B3B;;;KCEA;KACA;KAEA;EACX,SAAS;;EAET;EACA,MAAM;EACN,QAAQ;;KAGG;EACX;EACA;;EAEA;;KAGW;EACX;EACA,WAAW;;KAGA;EACX;EACA,YAAY;;EAEZ;;KAGW;EACX,SAAS;EACT,YAAY;EACZ,UAAU;;;;;;;iBA8EK,kBAAkB,MAAM,WAAW,WAAgB,OAAO,kBAAkB;;;cC7E/E,eAAe,MAAI;;;;;;;;;KClCpB;KAWA;EACX,SAAS;;EAET;;;;;EAKA,OAAO,cAAc;;;;;;EAMrB,YAAY;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/harness-registry/harness-registry.ts","../src/diagnose-bridges/git-bridge-state.ts","../src/diagnose-bridges/diagnose-bridges.ts","../src/diagnose-bridges/doctor.command.ts","../src/diagnose-bridges/doctor-guidance.ts","../src/initialize-harnesses/init.command.ts","../src/initialize-harnesses/initialize-harnesses.ts"],"mappings":";;KAGY;;;;;KAaA;EACX,MAAM;EACN;EACA;;EAEA,aAAa;;;;;;;;;;;;cAaD,0BAA0B;;;;KC7B3B;;;KCEA;KACA;KAEA;EACX,SAAS;;EAET;EACA,MAAM;EACN,QAAQ;;KAGG;EACX;EACA;;EAEA;;KAGW;EACX;EACA,WAAW;;KAGA;EACX;EACA,YAAY;;EAEZ;;KAGW;EACX,SAAS;EACT,YAAY;EACZ,UAAU;;;;;;;iBA8EK,kBAAkB,MAAM,WAAW,WAAgB,OAAO,kBAAkB;;;cC7E/E,eAAe,MAAI;;;;;;;;;KClCpB;KAWA;EACX,SAAS;;EAET;;;;;EAKA,OAAO,cAAc;;;;;;EAMrB,YAAY;;cAqDA,wBAAwB;cAmExB;WACZ;WACA;;;;;;;iBAae,kBAAkB;;;cChKrB,aAAa,MAAI;cA0DjB,gBAAgB,MAAI;iBAMjB,WAAW;EAAgB,WAAW,gBAAgB;;;;KCnE1D;EACX;EACA,YAAY;EACZ;EACA;;KAEW;EACX;EACA,WAAW;EACX,QAAQ;EACR,QAAQ;;EAER;IAAc,MAAM;IAAa,YAAY;;EAC7C;EACA;;iBAGe,sBACf,MACA,WAAW,WACX,MACA,SACE,oBAAoB"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as doctorCommand, c as doctorSkill, i as initializeHarnesses, l as renderDoctorSkill, n as harnessCommand, o as diagnoseBridges, r as initCommand, s as doctorRepairs, t as activate, u as harnessRegistry } from "./init.command-
|
|
1
|
+
import { a as doctorCommand, c as doctorSkill, i as initializeHarnesses, l as renderDoctorSkill, n as harnessCommand, o as diagnoseBridges, r as initCommand, s as doctorRepairs, t as activate, u as harnessRegistry } from "./init.command-c0fBv15T.mjs";
|
|
2
2
|
export { activate, diagnoseBridges, doctorCommand, doctorRepairs, doctorSkill, harnessCommand, harnessRegistry, initCommand, initializeHarnesses, renderDoctorSkill };
|
|
@@ -154,11 +154,13 @@ const skillInvocation = (version) => `npx -y ${commandInvocation}@^${version}`;
|
|
|
154
154
|
*/
|
|
155
155
|
const launcherFor = (subcommand) => `scripts/${subcommand}.mjs`;
|
|
156
156
|
/**
|
|
157
|
-
* How a skill names its launcher
|
|
158
|
-
*
|
|
159
|
-
*
|
|
157
|
+
* How a skill names its launcher: the path as the skill sees it, resolved by the agent against the
|
|
158
|
+
* directory it read the `SKILL.md` from.
|
|
159
|
+
*
|
|
160
|
+
* `node` stays in front. The launcher ships without an executable bit, and its shebang does nothing
|
|
161
|
+
* on Windows, so naming the file alone would not run it.
|
|
160
162
|
*/
|
|
161
|
-
const launcherInvocation = (subcommand) => `node
|
|
163
|
+
const launcherInvocation = (subcommand) => `node ${launcherFor(subcommand)}`;
|
|
162
164
|
/** How the skill hands a repair back to `init`. */
|
|
163
165
|
const initSkillInvocation = "/buddy-agent-harness:init";
|
|
164
166
|
const doctorRepairs = [
|
|
@@ -252,7 +254,7 @@ Diagnose it:
|
|
|
252
254
|
${launcherInvocation("doctor")}
|
|
253
255
|
\`\`\`
|
|
254
256
|
|
|
255
|
-
|
|
257
|
+
That path is relative to this skill's own directory. The launcher runs the CLI that shipped beside it against the current working directory, so nothing is downloaded. Fall back to \`${skillInvocation(version)} doctor\` when the launcher cannot be resolved or run, which is the case when the plugin was installed from git rather than npm and its dependencies were never installed.
|
|
256
258
|
|
|
257
259
|
The command is read-only. It never repairs anything, so it is safe to run at any point, including from a session-start hook.
|
|
258
260
|
|
|
@@ -709,4 +711,4 @@ function activate({ addCommand }) {
|
|
|
709
711
|
//#endregion
|
|
710
712
|
export { doctorCommand as a, doctorSkill as c, initializeHarnesses as i, renderDoctorSkill as l, harnessCommand as n, diagnoseBridges as o, initCommand as r, doctorRepairs as s, activate as t, harnessRegistry as u };
|
|
711
713
|
|
|
712
|
-
//# sourceMappingURL=init.command-
|
|
714
|
+
//# sourceMappingURL=init.command-c0fBv15T.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.command-c0fBv15T.mjs","names":[],"sources":["../src/command-output/command-output.ts","../src/harness-registry/harness-registry.ts","../src/diagnose-bridges/directory-files.ts","../src/diagnose-bridges/doctor-guidance.ts","../src/diagnose-bridges/git-bridge-state.ts","../src/diagnose-bridges/diagnose-bridges.ts","../src/diagnose-bridges/doctor.command.ts","../src/skill-projection/skill-projection.ts","../src/initialize-harnesses/initialize-harnesses.ts","../src/initialize-harnesses/init.command.ts"],"sourcesContent":["import { sep } from 'node:path'\nimport { encode } from '@toon-format/toon'\n\nexport type OutputFormat = 'json' | 'toon' | 'text'\n\nconst formats: readonly OutputFormat[] = ['toon', 'json', 'text']\n\n/** Rejects anything but the supported formats so an unknown value never falls back silently. */\nexport function parseFormat(value: string | undefined): OutputFormat {\n\tif (!formats.includes(value as OutputFormat)) throw new Error('--format must be toon, json, or text.')\n\treturn value as OutputFormat\n}\n\n/** The single stdout boundary: internal logic stays on plain objects, encoding happens here. */\nexport function writeResult(value: object, format: OutputFormat): void {\n\tprocess.stdout.write(`${encodeResult(value, format)}\\n`)\n}\n\nfunction encodeResult(value: object, format: OutputFormat): string {\n\tif (format === 'json') return JSON.stringify(value)\n\treturn format === 'text' ? renderText(value) : encode(value)\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction cell(value: unknown): string {\n\treturn value === undefined ? '' : String(value)\n}\n\n/** A header row plus one row per record, every column padded to its widest cell. */\nfunction table(rows: Record<string, unknown>[]): string[] {\n\tconst columns = [...new Set(rows.flatMap((row) => Object.keys(row)))]\n\tconst widths = columns.map((column) => Math.max(column.length, ...rows.map((row) => cell(row[column]).length)))\n\tconst line = (values: string[]) =>\n\t\t` ${values.map((value, index) => value.padEnd(widths[index] as number)).join(' ')}`.trimEnd()\n\treturn [line(columns), ...rows.map((row) => line(columns.map((column) => cell(row[column]))))]\n}\n\n/**\n * The same result rendered for a person rather than for an agent: scalars as `key: value`, records\n * as an aligned table, and everything else as a bulleted list. TOON stays the default because it is\n * what an agent parses; this is for reading over someone's shoulder.\n */\nexport function renderText(value: object): string {\n\tconst blocks = Object.entries(value).map(([key, item]) => {\n\t\tif (!Array.isArray(item)) return [`${key}: ${isRecord(item) ? JSON.stringify(item) : String(item)}`]\n\t\tif (!item.length) return [`${key}: (none)`]\n\t\tconst body = item.every(isRecord) ? table(item) : item.map((entry) => ` - ${String(entry)}`)\n\t\treturn [`${key}:`, ...body]\n\t})\n\n\t// A blank line wherever a multi-line block meets its neighbour, so a following scalar does not\n\t// read as another row of the table above it.\n\treturn blocks\n\t\t.flatMap((block, index) => {\n\t\t\tconst previous = blocks[index - 1]\n\t\t\treturn previous && (previous.length > 1 || block.length > 1) ? ['', ...block] : block\n\t\t})\n\t\t.join('\\n')\n}\n\n/** AXI §10: the executable's absolute path, with the user's home directory collapsed to `~`. */\nexport function binPath(home: string, executable: string | undefined): string {\n\tif (!executable) return 'buddy-agent-harness'\n\treturn home && executable.startsWith(home + sep) ? `~${executable.slice(home.length)}` : executable\n}\n","import { lstatSync } from 'node:fs'\nimport { join } from 'node:path'\n\nexport type HarnessName =\n\t| 'claude-code'\n\t| 'cursor'\n\t| 'codex'\n\t| 'copilot-cli'\n\t| 'gemini-cli'\n\t| 'devin-desktop'\n\t| 'windsurf'\n\n/**\n * `skillsDirectory` is the projection target a harness needs to see `.agents/skills`.\n * A harness that reads `.agents/skills` natively has none, and is never projected into.\n */\nexport type Harness = {\n\tname: HarnessName\n\tdetect: string\n\tskillsDirectory?: string\n\t/** Set when this name has been superseded; the value is the name that replaces it. */\n\tdeprecated?: HarnessName\n}\n\n/**\n * Codex, Cursor, Copilot CLI, and Devin Desktop read `.agents/skills` directly, so they need no\n * projection. Only Claude Code and Gemini CLI read solely their own directory.\n *\n * `windsurf` is the former name of Devin Desktop, rebranded 2026-06-02. It is retained as a\n * deprecated alias: Devin still scans the legacy `.windsurf/skills` path, so its projection keeps\n * working, but new repositories should enable `devin-desktop` and have nothing written for them.\n *\n * See `.research/agentic-configuration-standards/` for the per-harness sources.\n */\nexport const harnessRegistry: readonly Harness[] = [\n\t{ name: 'claude-code', detect: '.claude', skillsDirectory: '.claude/skills' },\n\t{ name: 'cursor', detect: '.cursor' },\n\t{ name: 'codex', detect: '.codex' },\n\t{ name: 'copilot-cli', detect: '.github/skills' },\n\t{ name: 'gemini-cli', detect: '.gemini', skillsDirectory: '.gemini/skills' },\n\t{ name: 'devin-desktop', detect: '.devin' },\n\t{ name: 'windsurf', detect: '.windsurf', skillsDirectory: '.windsurf/skills', deprecated: 'devin-desktop' },\n]\n\n/** Enabled whether or not the repository already contains their directories. */\nconst defaultHarnesses: readonly HarnessName[] = ['claude-code', 'cursor']\n\nfunction directoryExists(path: string): boolean {\n\ttry {\n\t\treturn lstatSync(path).isDirectory()\n\t} catch {\n\t\treturn false\n\t}\n}\n\n/** The default harnesses, plus the preferred ones, plus every harness whose directory is present. */\nexport function selectHarnesses(root: string, preferred: readonly HarnessName[]): Harness[] {\n\tconst enabled = new Set<HarnessName>([...defaultHarnesses, ...preferred])\n\treturn harnessRegistry.filter((harness) => enabled.has(harness.name) || directoryExists(join(root, harness.detect)))\n}\n","import { readdirSync } from 'node:fs'\nimport { join, posix, relative, sep } from 'node:path'\n\n/**\n * Every file below `directory`, as paths relative to it, POSIX-separated and sorted. A directory\n * that does not exist reads as empty: `doctor` never creates one to look at it.\n */\nexport function filesUnder(directory: string): string[] {\n\ttry {\n\t\treturn readdirSync(directory, { recursive: true, withFileTypes: true })\n\t\t\t.filter((entry) => entry.isFile())\n\t\t\t.map((entry) => relative(directory, join(entry.parentPath, entry.name)).split(sep).join(posix.sep))\n\t\t\t.sort()\n\t} catch {\n\t\treturn []\n\t}\n}\n","/**\n * The one place `doctor`'s guidance is written. The command reads `detail` and `repair` to fill its\n * `findings` and `help` sections; `skills/doctor/SKILL.md` is generated from the same table by\n * `scripts/generate-skills.ts`, so the shipped skill cannot drift from what the command says.\n */\n\n/** Every way a bridge can fail, in the order `doctor` reports them. */\nexport type BridgeProblem =\n\t| 'no-canonical'\n\t| 'missing'\n\t| 'degraded'\n\t| 'stale'\n\t| 'diverged-bridge'\n\t| 'diverged-canonical'\n\t| 'diverged-both'\n\t| 'diverged-unknown'\n\t| 'unpinned-copy'\n\nexport type Repair = {\n\tproblem: BridgeProblem\n\t/** What `doctor` prints in the `findings` row for this problem. */\n\tdetail: string\n\t/**\n\t * The command that fixes it, for `doctor`'s own output. `path` is the repository-relative bridge\n\t * path; `cli` is how to invoke this tool.\n\t */\n\trepair(path: string, cli: string): string\n\t/**\n\t * What the shipped skill tells an agent to do instead. A repair that rebuilds a bridge delegates\n\t * to the `init` skill rather than calling the `init` command, because rebuilding can move\n\t * user-authored skills and that judgment is the `init` skill's, not `doctor`'s.\n\t */\n\tskillRepair(path: string): string\n}\n\n/** How the command names itself. */\nexport const commandInvocation = 'buddy-agent-harness'\n/**\n * How a skill invokes the command. A skill may run without the binary on PATH, so it goes through\n * `npx`, pinned to the caret range of the version that generated the skill.\n *\n * The pin is what makes the shipped guidance honest. A skill states the findings and flags of the\n * version it was generated from, so an unpinned `npx` — which resolves whatever is latest — can\n * hand an agent a table that does not describe the CLI it just ran. The caret keeps patches\n * flowing and stops at the next breaking line.\n */\nexport const skillInvocation = (version: string) => `npx -y ${commandInvocation}@^${version}`\n\n/**\n * The launcher a skill ships, named for the subcommand it runs so a stack trace or a process list\n * says which one it was. One script per command, beside the `SKILL.md` that documents it.\n */\nexport const launcherFor = (subcommand: string) => `scripts/${subcommand}.mjs`\n\n/**\n * How a skill names its launcher: the path as the skill sees it, resolved by the agent against the\n * directory it read the `SKILL.md` from.\n *\n * `node` stays in front. The launcher ships without an executable bit, and its shebang does nothing\n * on Windows, so naming the file alone would not run it.\n */\nexport const launcherInvocation = (subcommand: string) => `node ${launcherFor(subcommand)}`\n\n/**\n * The launcher written into a skill's `scripts/` directory. It resolves the CLI from its own\n * location rather than the working directory, so the skill runs the copy it shipped with and\n * fetches nothing. The repository it inspects is still the working directory, unchanged.\n */\nexport function renderSkillLauncher(subcommand: string): string {\n\treturn `#!/usr/bin/env node\n// Generated from src/diagnose-bridges/doctor-guidance.ts by scripts/generate-skills.ts. Do not edit by hand.\nimport { dirname, join } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\n// <package>/skills/<skill>/scripts/${subcommand}.mjs: four levels up is the package root.\nconst packageRoot = dirname(dirname(dirname(dirname(fileURLToPath(import.meta.url)))))\n\nprocess.argv.splice(2, 0, '${subcommand}')\nawait import(join(packageRoot, 'bin', '${commandInvocation}.mjs'))\n`\n}\n\n/** How the skill hands a repair back to `init`. */\nexport const initSkillInvocation = '/buddy-agent-harness:init'\n\nexport const doctorRepairs: readonly Repair[] = [\n\t{\n\t\tproblem: 'no-canonical',\n\t\tdetail: 'the canonical skill directory does not exist, so no bridge can resolve',\n\t\trepair: (_path, cli) => `${cli} init`,\n\t\tskillRepair: () => `run \\`${initSkillInvocation}\\`, which creates \\`.agents/skills\\` and the bridges`,\n\t},\n\t{\n\t\tproblem: 'missing',\n\t\tdetail: 'no bridge at this path — the harness sees zero project skills',\n\t\trepair: (_path, cli) => `${cli} init`,\n\t\tskillRepair: () => `run \\`${initSkillInvocation}\\``,\n\t},\n\t{\n\t\tproblem: 'degraded',\n\t\tdetail: 'expected a directory but found a regular file — checkout without core.symlinks',\n\t\trepair: (_path, cli) => `${cli} init --copy --force`,\n\t\tskillRepair: () => `run \\`${initSkillInvocation} --copy --force\\``,\n\t},\n\t{\n\t\tproblem: 'stale',\n\t\tdetail: 'symlink does not resolve to .agents/skills',\n\t\trepair: (_path, cli) => `${cli} init --force`,\n\t\tskillRepair: () => `run \\`${initSkillInvocation} --force\\``,\n\t},\n\t{\n\t\tproblem: 'diverged-bridge',\n\t\tdetail: 'only the bridge changed since the two last agreed — an agent wrote through the copy',\n\t\trepair: (path, cli) =>\n\t\t\t`replace .agents/skills with ${path} to keep the newer edit and then run ${cli} init --force`,\n\t\tskillRepair: (path) =>\n\t\t\t`replace .agents/skills with ${path} to keep the newer edit, then run \\`${initSkillInvocation} --force\\``,\n\t},\n\t{\n\t\tproblem: 'diverged-canonical',\n\t\tdetail: 'only .agents/skills changed since the two last agreed — the copy is stale',\n\t\trepair: (_path, cli) => `${cli} init --copy --force`,\n\t\tskillRepair: () => `run \\`${initSkillInvocation} --copy --force\\``,\n\t},\n\t{\n\t\tproblem: 'diverged-both',\n\t\tdetail: 'both sides changed since they last agreed — rebuilding would discard one of them',\n\t\trepair: (path) => `git diff --no-index .agents/skills ${path} and reconcile by hand`,\n\t\tskillRepair: (path) => `run \\`git diff --no-index .agents/skills ${path}\\` and reconcile by hand`,\n\t},\n\t{\n\t\tproblem: 'diverged-unknown',\n\t\tdetail: 'contents differ and no commit where they agreed was found — which side moved is unknown',\n\t\trepair: (path) => `git diff --no-index .agents/skills ${path} and reconcile by hand`,\n\t\tskillRepair: (path) => `run \\`git diff --no-index .agents/skills ${path}\\` and reconcile by hand`,\n\t},\n\t{\n\t\tproblem: 'unpinned-copy',\n\t\tdetail: 'tracked copy without the skip-worktree bit — the tree is dirty with content that must not be committed',\n\t\t// The index entry is the tracked symlink on a Windows checkout but the individual files in a\n\t\t// committed copy, so the paths are read back from git rather than assumed.\n\t\trepair: (path) => `git ls-files -z ${path} | xargs -0 git update-index --skip-worktree`,\n\t\tskillRepair: (path) => `run \\`git ls-files -z ${path} | xargs -0 git update-index --skip-worktree\\``,\n\t},\n]\n\nconst repairsByProblem = new Map(doctorRepairs.map((entry) => [entry.problem, entry]))\n\nexport function repairFor(problem: BridgeProblem): Repair {\n\treturn repairsByProblem.get(problem) as Repair\n}\n\nexport const doctorSkill = {\n\tname: 'doctor',\n\tdescription:\n\t\t'Use this skill when a repository loads no project skills, when skills are missing after a clone, or when checking whether the agent configuration bridges into .claude/skills and the other harness directories still resolve.',\n} as const\n\n/** Written into the generated skill so a reader knows not to edit it in place. */\nexport const generatedSkillWarning =\n\t'<!-- Generated from src/diagnose-bridges/doctor-guidance.ts by scripts/generate-skills.ts. Do not edit by hand. -->'\n\n/**\n * The shipped `doctor` skill, rendered from the same table the command prints. `version` is the\n * package version the skill ships with; it pins the `npx` invocation so the table and the CLI that\n * produced it stay on the same breaking line.\n */\nexport function renderDoctorSkill(version: string): string {\n\t// A repair may itself contain a pipe, which would otherwise end the table cell early.\n\tconst cell = (value: string) => value.replaceAll('|', '\\\\|')\n\tconst rows = doctorRepairs\n\t\t.map((entry) => `| \\`${entry.problem}\\` | ${entry.detail} | ${cell(entry.skillRepair('<path>'))} |`)\n\t\t.join('\\n')\n\n\treturn `---\nname: ${doctorSkill.name}\ndescription: ${doctorSkill.description}\n---\n\n${generatedSkillWarning}\n\n# Harness Doctor\n\n\\`.agents/skills\\` is the canonical skill directory. Harnesses that cannot read it — Claude Code and Gemini CLI — get a bridge pointing at it, normally a directory symlink. A bridge that stops resolving is silent: the harness finds nothing and loads zero project skills, with no warning anywhere.\n\nDiagnose it:\n\n\\`\\`\\`sh\n${launcherInvocation('doctor')}\n\\`\\`\\`\n\nThat path is relative to this skill's own directory. The launcher runs the CLI that shipped beside it against the current working directory, so nothing is downloaded. Fall back to \\`${skillInvocation(version)} doctor\\` when the launcher cannot be resolved or run, which is the case when the plugin was installed from git rather than npm and its dependencies were never installed.\n\nThe command is read-only. It never repairs anything, so it is safe to run at any point, including from a session-start hook.\n\n## Reading the report\n\n\\`bridges\\` lists every bridge \\`init\\` would create for this repository, each with a \\`status\\` of \\`ok\\`, \\`missing\\`, \\`degraded\\`, \\`stale\\`, or \\`diverged\\`. \\`findings\\` explains each problem and \\`help\\` names its repair. Apply the repair from the table below, then re-run \\`doctor\\`.\n\n\\`help\\` names the \\`init\\` command for a person at a shell. Do not run it yourself. Rebuilding a bridge can move skills a user wrote, and that judgment belongs to the \\`init\\` skill — hand the repair to \\`${initSkillInvocation}\\` instead.\n\nWhen every bridge resolves, \\`findings\\` says so outright rather than being empty.\n\nThe default output is TOON, which is what you parse. Add \\`--format text\\` when you need to show the same report to a person, or \\`--format json\\`.\n\n## Findings and their repairs\n\n| Finding | What it means | Repair |\n| --- | --- | --- |\n${rows}\n\nSubstitute the reported bridge path for \\`<path>\\`.\n\n## The Windows case\n\nThe common failure is \\`degraded\\`. Creating a symlink on Windows needs a privilege most accounts do not have, and Git for Windows gates it separately with \\`core.symlinks\\`, which its installer leaves off. With \\`core.symlinks=false\\` git does not error — it writes the symlink out as a regular file whose contents are the target path. \\`${initSkillInvocation} --copy --force\\` rebuilds the bridges as real directories on that machine.\n\nA copy is a snapshot rather than a live projection, and an agent that edits a skill through it writes into the copy instead of into \\`.agents/skills\\`. That is what the \\`diverged\\` findings catch.\n\n## Rules\n\n- Never repair a \\`diverged-both\\` or \\`diverged-unknown\\` bridge by re-running \\`init\\`. Rebuilding overwrites whichever side holds the newer edit. Reconcile the two directories first.\n- Edit skills at \\`.agents/skills/<name>/SKILL.md\\`. Editing through a bridge is only safe when that bridge is a symlink.\n- Do not add bridges to \\`.gitignore\\`. An untracked bridge swallows a real edit silently.\n`\n}\n","import { execFileSync } from 'node:child_process'\nimport { join } from 'node:path'\nimport { filesUnder } from './directory-files.ts'\n\n/** Which side of a diverged bridge moved since the last commit where the two agreed. */\nexport type DivergenceDirection = 'bridge' | 'canonical' | 'both' | 'unknown'\n\n/** Whether a path is tracked, and if so whether its skip-worktree bit is still set. */\nexport type TrackingState = 'untracked' | 'tracked' | 'skip-worktree'\n\nfunction git(root: string, args: string[], input?: string): string | undefined {\n\ttry {\n\t\treturn execFileSync('git', args, {\n\t\t\tcwd: root,\n\t\t\tencoding: 'utf8',\n\t\t\t...(input === undefined ? {} : { input }),\n\t\t\tstdio: ['pipe', 'pipe', 'pipe'],\n\t\t})\n\t} catch {\n\t\treturn undefined\n\t}\n}\n\nfunction lines(output: string | undefined): string[] {\n\treturn (output ?? '').split('\\n').filter(Boolean)\n}\n\n/**\n * Reads git state for the two sides of a bridge. Every method degrades to \"cannot tell\" rather than\n * throwing, so `doctor` still reports on a tarball, a worktree without git, or a repository with no\n * commits.\n */\nexport class GitBridgeState {\n\t/** Path of `root` relative to the repository root, `''` at the top, `undefined` outside a repository. */\n\tprivate readonly prefix: string | undefined\n\n\tconstructor(private readonly root: string) {\n\t\tthis.prefix = git(root, ['rev-parse', '--show-prefix'])?.trim()\n\t}\n\n\t/**\n\t * `init --copy` marks a bridge skip-worktree so a machine-local copy over a tracked symlink stops\n\t * showing as a pending change. The bit is a hint that some checkouts clear, so it is verified\n\t * rather than assumed.\n\t */\n\ttrackingOf(path: string): TrackingState {\n\t\tif (this.prefix === undefined) return 'untracked'\n\t\tconst entries = lines(git(this.root, ['ls-files', '-v', '--', path]))\n\t\tif (!entries.length) return 'untracked'\n\t\treturn entries.every((entry) => entry.startsWith('S')) ? 'skip-worktree' : 'tracked'\n\t}\n\n\t/**\n\t * Names the side that moved by finding the newest commit whose two trees agreed, then asking which\n\t * of the working directories still matches it.\n\t */\n\tdirectionOf(bridge: string, canonical: string): DivergenceDirection {\n\t\tif (this.prefix === undefined) return 'unknown'\n\t\tconst base = this.lastAgreedTree(bridge, canonical)\n\t\tif (base === undefined) return 'unknown'\n\t\tconst bridgeMoved = !this.matchesTree(bridge, base)\n\t\tconst canonicalMoved = !this.matchesTree(canonical, base)\n\t\tif (bridgeMoved && canonicalMoved) return 'both'\n\t\tif (bridgeMoved) return 'bridge'\n\t\treturn 'canonical'\n\t}\n\n\t/** The tree of the newest commit where both paths held identical content. */\n\tprivate lastAgreedTree(bridge: string, canonical: string): string | undefined {\n\t\tfor (const commit of lines(git(this.root, ['rev-list', '-n', '200', 'HEAD', '--', bridge, canonical]))) {\n\t\t\tconst bridgeObject = git(this.root, ['rev-parse', '-q', '--verify', `${commit}:${this.prefix}${bridge}`])?.trim()\n\t\t\tif (!bridgeObject) continue\n\t\t\tconst canonicalObject = git(this.root, [\n\t\t\t\t'rev-parse',\n\t\t\t\t'-q',\n\t\t\t\t'--verify',\n\t\t\t\t`${commit}:${this.prefix}${canonical}`,\n\t\t\t])?.trim()\n\t\t\tif (bridgeObject === canonicalObject) return bridgeObject\n\t\t}\n\t\treturn undefined\n\t}\n\n\t/**\n\t * Compares a working directory against a git tree by object id. `hash-object` is used rather than\n\t * hashing in-process so the comparison follows whatever object format the repository uses.\n\t */\n\tprivate matchesTree(directory: string, tree: string): boolean {\n\t\tconst expected = new Map(\n\t\t\tlines(git(this.root, ['ls-tree', '-r', tree])).map((entry) => {\n\t\t\t\tconst [meta, path] = entry.split('\\t')\n\t\t\t\treturn [path, (meta as string).split(' ')[2] as string] as const\n\t\t\t}),\n\t\t)\n\t\tconst files = filesUnder(join(this.root, directory))\n\t\tif (files.length !== expected.size || files.some((file) => !expected.has(file))) return false\n\t\tconst hashed = lines(\n\t\t\tgit(this.root, ['hash-object', '--stdin-paths'], files.map((file) => join(directory, file)).join('\\n')),\n\t\t)\n\t\treturn hashed.length === files.length && files.every((file, index) => expected.get(file) === hashed[index])\n\t}\n}\n","import { lstatSync, readFileSync, readlinkSync, statSync } from 'node:fs'\nimport { dirname, join, relative } from 'node:path'\nimport { type Harness, type HarnessName, selectHarnesses } from '../harness-registry/harness-registry.ts'\nimport { filesUnder } from './directory-files.ts'\nimport { type BridgeProblem, repairFor } from './doctor-guidance.ts'\nimport { type DivergenceDirection, GitBridgeState } from './git-bridge-state.ts'\n\nexport type BridgeKind = 'symlink' | 'copy' | 'file' | 'none'\nexport type BridgeStatus = 'ok' | 'missing' | 'degraded' | 'stale' | 'diverged'\n\nexport type BridgeReport = {\n\tharness: HarnessName\n\t/** Repository-relative, as the harness registry declares it. */\n\tpath: string\n\tkind: BridgeKind\n\tstatus: BridgeStatus\n}\n\nexport type BridgeFinding = {\n\tpath: string\n\tdetail: string\n\t/** The command that repairs this finding, already carrying the bridge path. */\n\trepair: string\n}\n\nexport type DivergenceReport = {\n\tpath: string\n\tdirection: DivergenceDirection\n}\n\nexport type DiagnoseOptions = {\n\troot: string\n\tharnesses?: HarnessName[]\n\t/** How to name this tool in the repair commands. */\n\tcli: string\n}\n\nexport type DiagnoseResult = {\n\tbridges: BridgeReport[]\n\tdivergence: DivergenceReport[]\n\tfindings: BridgeFinding[]\n}\n\nconst canonicalPath = '.agents/skills'\n\nfunction pathState(target: string): 'missing' | 'symlink' | 'directory' | 'file' {\n\ttry {\n\t\tconst stats = lstatSync(target)\n\t\tif (stats.isSymbolicLink()) return 'symlink'\n\t\treturn stats.isDirectory() ? 'directory' : 'file'\n\t} catch {\n\t\treturn 'missing'\n\t}\n}\n\nfunction isDirectory(path: string): boolean {\n\ttry {\n\t\treturn statSync(path).isDirectory()\n\t} catch {\n\t\treturn false\n\t}\n}\n\n/** The same test `init` uses to decide a projection is already correct, plus that it still resolves. */\nfunction resolvesToCanonical(target: string, canonical: string): boolean {\n\treturn readlinkSync(target) === relative(dirname(target), canonical) && isDirectory(target)\n}\n\nfunction sameContent(left: string, right: string): boolean {\n\tconst leftFiles = filesUnder(left)\n\tconst rightFiles = filesUnder(right)\n\treturn (\n\t\tleftFiles.length === rightFiles.length &&\n\t\tleftFiles.every(\n\t\t\t(file, index) =>\n\t\t\t\trightFiles[index] === file && readFileSync(join(left, file)).equals(readFileSync(join(right, file))),\n\t\t)\n\t)\n}\n\ntype Inspection = {\n\tkind: BridgeKind\n\tstatus: BridgeStatus\n\tproblem?: BridgeProblem\n\tdirection?: DivergenceDirection\n}\n\nfunction inspect(target: string, path: string, canonical: string, git: GitBridgeState): Inspection {\n\tswitch (pathState(target)) {\n\t\tcase 'missing':\n\t\t\treturn { kind: 'none', status: 'missing', problem: 'missing' }\n\t\t// The flagship Windows failure: git with `core.symlinks=false` writes the link out as a\n\t\t// regular file holding the target path, and the harness silently loads nothing.\n\t\tcase 'file':\n\t\t\treturn { kind: 'file', status: 'degraded', problem: 'degraded' }\n\t\tcase 'symlink':\n\t\t\treturn resolvesToCanonical(target, canonical)\n\t\t\t\t? { kind: 'symlink', status: 'ok' }\n\t\t\t\t: { kind: 'symlink', status: 'stale', problem: 'stale' }\n\t\tdefault: {\n\t\t\tif (!sameContent(target, canonical)) {\n\t\t\t\tconst direction = git.directionOf(path, canonicalPath)\n\t\t\t\treturn { kind: 'copy', status: 'diverged', problem: `diverged-${direction}`, direction }\n\t\t\t}\n\t\t\t// A copy over a tracked symlink only stays out of `git status` while its skip-worktree bit\n\t\t\t// survives, and some checkout and merge operations clear it.\n\t\t\treturn git.trackingOf(path) === 'tracked'\n\t\t\t\t? { kind: 'copy', status: 'ok', problem: 'unpinned-copy' }\n\t\t\t\t: { kind: 'copy', status: 'ok' }\n\t\t}\n\t}\n}\n\n/**\n * Reports whether every bridge `init` would create for this repository still resolves into\n * `.agents/skills`. Read-only: nothing is created, moved, or repaired, so the caller decides what\n * to run from the repair each finding carries.\n */\nexport function diagnoseBridges({ root, harnesses: preferred = [], cli }: DiagnoseOptions): DiagnoseResult {\n\tconst canonical = join(root, '.agents', 'skills')\n\tconst git = new GitBridgeState(root)\n\tconst bridged = selectHarnesses(root, preferred).filter((harness): harness is Harness & { skillsDirectory: string } =>\n\t\tBoolean(harness.skillsDirectory),\n\t)\n\n\tconst bridges: BridgeReport[] = []\n\tconst divergence: DivergenceReport[] = []\n\tconst findings: BridgeFinding[] = []\n\n\tif (!isDirectory(canonical)) {\n\t\tconst { detail, repair } = repairFor('no-canonical')\n\t\tfindings.push({ path: canonicalPath, detail, repair: repair(canonicalPath, cli) })\n\t}\n\n\tfor (const harness of bridged) {\n\t\tconst path = harness.skillsDirectory\n\t\tconst inspection = inspect(join(root, path), path, canonical, git)\n\t\tbridges.push({ harness: harness.name, path, kind: inspection.kind, status: inspection.status })\n\t\tif (inspection.direction) divergence.push({ path, direction: inspection.direction })\n\t\tif (inspection.problem) {\n\t\t\tconst { detail, repair } = repairFor(inspection.problem)\n\t\t\tfindings.push({ path, detail, repair: repair(path, cli) })\n\t\t}\n\t}\n\n\treturn { bridges, divergence, findings }\n}\n","import { homedir } from 'node:os'\nimport type { cli } from 'clibuilder'\nimport { command, z } from 'clibuilder'\nimport { binPath, parseFormat, writeResult } from '../command-output/command-output.ts'\nimport { type HarnessName, harnessRegistry } from '../harness-registry/harness-registry.ts'\nimport { type DiagnoseResult, diagnoseBridges } from './diagnose-bridges.ts'\nimport { commandInvocation } from './doctor-guidance.ts'\n\ntype DoctorReport = {\n\tbin: string\n\tbridges: DiagnoseResult['bridges']\n\tdivergence?: DiagnoseResult['divergence']\n\t/** The repair is lifted out into `help`, so a finding row stays to the diagnosis itself. */\n\tfindings: Omit<DiagnoseResult['findings'][number], 'repair'>[] | string\n\thelp?: string[]\n}\n\n/**\n * AXI §5: the healthy answer states the zero with context, so an agent does not re-run with other\n * flags to confirm that an empty section really meant \"nothing wrong\".\n */\nexport function buildReport(bin: string, result: DiagnoseResult): DoctorReport {\n\tif (!result.findings.length) {\n\t\tconst count = result.bridges.length\n\t\treturn {\n\t\t\tbin,\n\t\t\tbridges: result.bridges,\n\t\t\tfindings:\n\t\t\t\tcount === 1 ? '0 problems found — the 1 bridge resolves' : `0 problems found — all ${count} bridges resolve`,\n\t\t}\n\t}\n\n\treturn {\n\t\tbin,\n\t\tbridges: result.bridges,\n\t\t...(result.divergence.length ? { divergence: result.divergence } : {}),\n\t\tfindings: result.findings.map(({ path, detail }) => ({ path, detail })),\n\t\thelp: [...new Set(result.findings.map((finding) => `Run \\`${finding.repair}\\``))],\n\t}\n}\n\nexport const doctorCommand: cli.Command = command({\n\tname: 'doctor',\n\tdescription: 'Report whether the harness skill bridges in this repository still resolve. Read-only.',\n\toptions: {\n\t\troot: {\n\t\t\tdescription: 'Repository or package directory. Defaults to the current directory.',\n\t\t\ttype: z.optional(z.string()),\n\t\t},\n\t\tharness: {\n\t\t\tdescription: 'Comma-separated harnesses to check in addition to Claude Code and Cursor, e.g. codex,gemini-cli.',\n\t\t\ttype: z.optional(z.string()),\n\t\t},\n\t\tformat: {\n\t\t\tdescription: 'Output format: toon (default), json, or text for a human-readable report.',\n\t\t\ttype: z.optional(z.string()),\n\t\t\tdefault: 'toon',\n\t\t},\n\t},\n\trun(args) {\n\t\ttry {\n\t\t\tconst format = parseFormat(args.format)\n\t\t\tconst requested = args.harness\n\t\t\t\t?.split(',')\n\t\t\t\t.map((name) => name.trim())\n\t\t\t\t.filter(Boolean)\n\t\t\tconst unsupported = requested?.filter((name) => !harnessRegistry.some((harness) => harness.name === name))\n\t\t\tif (unsupported?.length)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Unsupported harness: ${unsupported.join(', ')}. Supported: ${harnessRegistry\n\t\t\t\t\t\t.map((harness) => harness.name)\n\t\t\t\t\t\t.join(', ')}.`,\n\t\t\t\t)\n\t\t\tconst result = diagnoseBridges({\n\t\t\t\troot: args.root ?? process.cwd(),\n\t\t\t\t...(requested?.length ? { harnesses: requested as HarnessName[] } : {}),\n\t\t\t\tcli: commandInvocation,\n\t\t\t})\n\t\t\t// Exit stays 0 even with findings: the diagnosis succeeded, and a non-zero code reads to an\n\t\t\t// agent as \"this command is broken, try something else\".\n\t\t\twriteResult(buildReport(binPath(homedir(), process.argv[1]), result), format)\n\t\t} catch (error) {\n\t\t\tprocess.stderr.write(`error: ${error instanceof Error ? error.message : 'Harness diagnosis failed.'}\\n`)\n\t\t\tprocess.exitCode = 1\n\t\t}\n\t},\n})\n","import { cpSync, lstatSync, mkdirSync, readdirSync, readlinkSync, rmSync, symlinkSync } from 'node:fs'\nimport { dirname, join, relative } from 'node:path'\nimport type { Harness, HarnessName } from '../harness-registry/harness-registry.ts'\n\nfunction skillNames(skillsDirectory: string): string[] {\n\treturn readdirSync(skillsDirectory, { withFileTypes: true })\n\t\t.filter((entry) => entry.isDirectory())\n\t\t.map((entry) => entry.name)\n\t\t.sort()\n}\n\nfunction pathOccupied(path: string): boolean {\n\ttry {\n\t\tlstatSync(path)\n\t\treturn true\n\t} catch {\n\t\treturn false\n\t}\n}\n\nfunction isCorrectLink(target: string, source: string): boolean {\n\treturn lstatSync(target).isSymbolicLink() && readlinkSync(target) === relative(dirname(target), source)\n}\n\n/** Creates the canonical directory when absent, so a fresh repository reports zero skills. */\nexport function countSkills(canonicalSkills: string): number {\n\tmkdirSync(canonicalSkills, { recursive: true })\n\treturn skillNames(canonicalSkills).length\n}\n\nexport type ProjectSkillsOptions = {\n\troot: string\n\tcanonicalSkills: string\n\tharnesses: readonly Harness[]\n\tcopy: boolean\n\tforce: boolean\n}\n\n/**\n * Points every harness that cannot read `.agents/skills` at the canonical directory. Symlinking is\n * preferred; a platform that refuses the link falls back to a copy. Returns the projected harnesses.\n */\nexport function projectSkills({ root, canonicalSkills, harnesses, copy, force }: ProjectSkillsOptions): HarnessName[] {\n\tconst projections = harnesses\n\t\t.filter((harness) => harness.skillsDirectory)\n\t\t.map((harness) => ({\n\t\t\tharness,\n\t\t\ttarget: join(root, harness.skillsDirectory as string),\n\t\t}))\n\n\tconst conflicts = projections\n\t\t.filter(({ target }) => pathOccupied(target) && !isCorrectLink(target, canonicalSkills))\n\t\t.map(({ target }) => target)\n\n\tif (conflicts.length && !force) {\n\t\tthrow new Error(\n\t\t\t`Refusing to replace existing skill targets:\\n${conflicts.map((target) => `- ${target}`).join('\\n')}`,\n\t\t)\n\t}\n\n\tfor (const { target } of projections) {\n\t\tmkdirSync(dirname(target), { recursive: true })\n\t\tif (pathOccupied(target) && isCorrectLink(target, canonicalSkills)) continue\n\t\tif (pathOccupied(target)) rmSync(target, { recursive: true, force: true })\n\t\tif (copy) {\n\t\t\tcpSync(canonicalSkills, target, { recursive: true })\n\t\t\tcontinue\n\t\t}\n\t\ttry {\n\t\t\tsymlinkSync(relative(dirname(target), canonicalSkills), target, 'junction')\n\t\t} catch (error) {\n\t\t\tif (pathOccupied(target)) throw error\n\t\t\tcpSync(canonicalSkills, target, { recursive: true })\n\t\t}\n\t}\n\n\treturn projections.map(({ harness }) => harness.name)\n}\n","import { join } from 'node:path'\nimport { type HarnessName, selectHarnesses } from '../harness-registry/harness-registry.ts'\nimport { countSkills, projectSkills } from '../skill-projection/skill-projection.ts'\n\nexport type InitializeOptions = {\n\troot: string\n\tharnesses?: HarnessName[]\n\tcopy?: boolean\n\tforce?: boolean\n}\nexport type InitializeResult = {\n\troot: string\n\tharnesses: HarnessName[]\n\tnative: HarnessName[]\n\tlinked: HarnessName[]\n\t/** Enabled harnesses whose name has been superseded, as `{ name, replacedBy }`. */\n\tdeprecated: { name: HarnessName; replacedBy: HarnessName }[]\n\tskills: number\n\tcopied: boolean\n}\n\nexport function initializeHarnesses({\n\troot,\n\tharnesses: preferred = [],\n\tcopy = false,\n\tforce = false,\n}: InitializeOptions): InitializeResult {\n\tconst canonicalSkills = join(root, '.agents', 'skills')\n\tconst skills = countSkills(canonicalSkills)\n\tconst harnesses = selectHarnesses(root, preferred)\n\tconst linked = projectSkills({ root, canonicalSkills, harnesses, copy, force })\n\n\treturn {\n\t\troot,\n\t\tharnesses: harnesses.map((harness) => harness.name),\n\t\tnative: harnesses.filter((harness) => !harness.skillsDirectory).map((harness) => harness.name),\n\t\tlinked,\n\t\tdeprecated: harnesses\n\t\t\t.filter((harness) => harness.deprecated)\n\t\t\t.map((harness) => ({ name: harness.name, replacedBy: harness.deprecated as HarnessName })),\n\t\tskills,\n\t\tcopied: copy,\n\t}\n}\n","import type { cli } from 'clibuilder'\nimport { command, z } from 'clibuilder'\nimport { parseFormat, writeResult } from '../command-output/command-output.ts'\nimport { doctorCommand } from '../diagnose-bridges/doctor.command.ts'\nimport { type HarnessName, harnessRegistry } from '../harness-registry/harness-registry.ts'\nimport { initializeHarnesses } from './initialize-harnesses.ts'\n\nexport const initCommand: cli.Command = command({\n\tname: 'init',\n\tdescription: 'Set up canonical agent skills for the harnesses already enabled in a repository.',\n\toptions: {\n\t\troot: {\n\t\t\tdescription: 'Repository or package directory. Defaults to the current directory.',\n\t\t\ttype: z.optional(z.string()),\n\t\t},\n\t\tharness: {\n\t\t\tdescription: 'Comma-separated harnesses to enable in addition to Claude Code and Cursor, e.g. codex,gemini-cli.',\n\t\t\ttype: z.optional(z.string()),\n\t\t},\n\t\tcopy: {\n\t\t\tdescription: 'Copy skills instead of linking them.',\n\t\t\ttype: z.optional(z.boolean()),\n\t\t},\n\t\tforce: {\n\t\t\tdescription: 'Replace conflicting target skill directories.',\n\t\t\ttype: z.optional(z.boolean()),\n\t\t},\n\t\tformat: {\n\t\t\tdescription: 'Output format: toon (default), json, or text for a human-readable report.',\n\t\t\ttype: z.optional(z.string()),\n\t\t\tdefault: 'toon',\n\t\t},\n\t},\n\trun(args) {\n\t\ttry {\n\t\t\tconst format = parseFormat(args.format)\n\t\t\tconst requested = args.harness\n\t\t\t\t?.split(',')\n\t\t\t\t.map((name) => name.trim())\n\t\t\t\t.filter(Boolean)\n\t\t\tconst unsupported = requested?.filter((name) => !harnessRegistry.some((harness) => harness.name === name))\n\t\t\tif (unsupported?.length)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Unsupported harness: ${unsupported.join(', ')}. Supported: ${harnessRegistry\n\t\t\t\t\t\t.map((harness) => harness.name)\n\t\t\t\t\t\t.join(', ')}.`,\n\t\t\t\t)\n\t\t\twriteResult(\n\t\t\t\tinitializeHarnesses({\n\t\t\t\t\troot: args.root ?? process.cwd(),\n\t\t\t\t\t...(requested?.length ? { harnesses: requested as HarnessName[] } : {}),\n\t\t\t\t\t...(args.copy === undefined ? {} : { copy: args.copy }),\n\t\t\t\t\t...(args.force === undefined ? {} : { force: args.force }),\n\t\t\t\t}),\n\t\t\t\tformat,\n\t\t\t)\n\t\t} catch (error) {\n\t\t\tprocess.stderr.write(`error: ${error instanceof Error ? error.message : 'Harness initialization failed.'}\\n`)\n\t\t\tprocess.exitCode = 1\n\t\t}\n\t},\n})\n\n// Named for the package rather than shortened to `harness`: `repobuddy` mounts every plugin into one\n// command namespace, where `harness` is generic enough to collide with another plugin's.\nexport const harnessCommand: cli.Command = command({\n\tname: 'agent-harness',\n\tdescription: 'Commands for configuring agent harness compatibility.',\n\tcommands: [initCommand, doctorCommand],\n})\n\nexport function activate({ addCommand }: { addCommand(command: typeof harnessCommand): void }): void {\n\taddCommand(harnessCommand)\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
package/plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
|
|
3
3
|
"name": "buddy-agent-harness",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.1",
|
|
5
5
|
"description": "Initialize standards-based agent configuration across agent harnesses",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "repobuddy"
|
package/skills/doctor/SKILL.md
CHANGED
|
@@ -12,10 +12,10 @@ description: Use this skill when a repository loads no project skills, when skil
|
|
|
12
12
|
Diagnose it:
|
|
13
13
|
|
|
14
14
|
```sh
|
|
15
|
-
node
|
|
15
|
+
node scripts/doctor.mjs
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
That path is relative to this skill's own directory. The launcher runs the CLI that shipped beside it against the current working directory, so nothing is downloaded. Fall back to `npx -y buddy-agent-harness@^0.4.1 doctor` when the launcher cannot be resolved or run, which is the case when the plugin was installed from git rather than npm and its dependencies were never installed.
|
|
19
19
|
|
|
20
20
|
The command is read-only. It never repairs anything, so it is safe to run at any point, including from a session-start hook.
|
|
21
21
|
|
package/skills/init/SKILL.md
CHANGED
|
@@ -65,7 +65,7 @@ One case does need asking even though it only creates a file: a nested `AGENTS.m
|
|
|
65
65
|
1. Scaffold the baseline in `references/standard.md`: `.agents/`, `.agents/skills/`, and a root `AGENTS.md` if absent. Never clobber an existing one. `references/agents-md.md` decides what belongs in that file — a repository with no instruction content still needs one derived and confirmed, not an empty heading.
|
|
66
66
|
2. Move approved skills and commands to `.agents/skills/<name>/SKILL.md`, preferring `git mv` so history follows. Fix frontmatter per `references/frontmatter.md` — this is where cross-harness portability is won or lost.
|
|
67
67
|
3. Merge approved instruction content into `AGENTS.md`, preserving the author's wording. Append; do not restructure. Replace a harness file with a pointer only where approved. Content only some tasks need belongs in a skill, not in `AGENTS.md`.
|
|
68
|
-
4. Run `node
|
|
68
|
+
4. Run `node scripts/init.mjs` at the repository root, resolving that path against this skill's own directory. The launcher runs the CLI that shipped beside it, so nothing is downloaded; fall back to `npx -y buddy-agent-harness@^0.4.1 init` when the path cannot be resolved. It links `.agents/skills` into the harnesses that need it and skips those that read it natively. Add harnesses the user names with `--harness codex,gemini-cli`.
|
|
69
69
|
5. If the command reports a conflict, resolve the named target and retry. Use `--force` only to replace that exact projection; use `--copy` only where links are unavailable — a copy is a snapshot, not a live projection, so say so when you fall back.
|
|
70
70
|
6. Apply the instruction bridges `init` does not write. Claude Code reads `CLAUDE.md`, not `AGENTS.md` — create a `CLAUDE.md` containing `@AGENTS.md`. Gemini CLI needs `AGENTS.md` added to `context.fileName` in `.gemini/settings.json`. Both are detailed in the matching `references/harnesses/<harness>.md`; apply only the ones you enabled. Where nested `AGENTS.md` files exist, write the same stub in each directory holding one — `references/agents-md.md` covers the one case that stops for approval first.
|
|
71
71
|
7. If any bridge now exists, write or restore the non-material region in `AGENTS.md` per `references/agents-md.md`, unless the markers are present and empty. Without it, an agent asked to change a skill edits `.claude/skills/<name>/SKILL.md` — which a link resolves back to canonical, but a copy silently forks. Skip this when every enabled harness reads `.agents/skills/` natively; with no bridge there is nothing to warn about.
|
|
@@ -53,11 +53,13 @@ export const skillInvocation = (version: string) => `npx -y ${commandInvocation}
|
|
|
53
53
|
export const launcherFor = (subcommand: string) => `scripts/${subcommand}.mjs`
|
|
54
54
|
|
|
55
55
|
/**
|
|
56
|
-
* How a skill names its launcher
|
|
57
|
-
*
|
|
58
|
-
*
|
|
56
|
+
* How a skill names its launcher: the path as the skill sees it, resolved by the agent against the
|
|
57
|
+
* directory it read the `SKILL.md` from.
|
|
58
|
+
*
|
|
59
|
+
* `node` stays in front. The launcher ships without an executable bit, and its shebang does nothing
|
|
60
|
+
* on Windows, so naming the file alone would not run it.
|
|
59
61
|
*/
|
|
60
|
-
export const launcherInvocation = (subcommand: string) => `node
|
|
62
|
+
export const launcherInvocation = (subcommand: string) => `node ${launcherFor(subcommand)}`
|
|
61
63
|
|
|
62
64
|
/**
|
|
63
65
|
* The launcher written into a skill's `scripts/` directory. It resolves the CLI from its own
|
|
@@ -187,7 +189,7 @@ Diagnose it:
|
|
|
187
189
|
${launcherInvocation('doctor')}
|
|
188
190
|
\`\`\`
|
|
189
191
|
|
|
190
|
-
|
|
192
|
+
That path is relative to this skill's own directory. The launcher runs the CLI that shipped beside it against the current working directory, so nothing is downloaded. Fall back to \`${skillInvocation(version)} doctor\` when the launcher cannot be resolved or run, which is the case when the plugin was installed from git rather than npm and its dependencies were never installed.
|
|
191
193
|
|
|
192
194
|
The command is read-only. It never repairs anything, so it is safe to run at any point, including from a session-start hook.
|
|
193
195
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"init.command-mGE18Jv0.mjs","names":[],"sources":["../src/command-output/command-output.ts","../src/harness-registry/harness-registry.ts","../src/diagnose-bridges/directory-files.ts","../src/diagnose-bridges/doctor-guidance.ts","../src/diagnose-bridges/git-bridge-state.ts","../src/diagnose-bridges/diagnose-bridges.ts","../src/diagnose-bridges/doctor.command.ts","../src/skill-projection/skill-projection.ts","../src/initialize-harnesses/initialize-harnesses.ts","../src/initialize-harnesses/init.command.ts"],"sourcesContent":["import { sep } from 'node:path'\nimport { encode } from '@toon-format/toon'\n\nexport type OutputFormat = 'json' | 'toon' | 'text'\n\nconst formats: readonly OutputFormat[] = ['toon', 'json', 'text']\n\n/** Rejects anything but the supported formats so an unknown value never falls back silently. */\nexport function parseFormat(value: string | undefined): OutputFormat {\n\tif (!formats.includes(value as OutputFormat)) throw new Error('--format must be toon, json, or text.')\n\treturn value as OutputFormat\n}\n\n/** The single stdout boundary: internal logic stays on plain objects, encoding happens here. */\nexport function writeResult(value: object, format: OutputFormat): void {\n\tprocess.stdout.write(`${encodeResult(value, format)}\\n`)\n}\n\nfunction encodeResult(value: object, format: OutputFormat): string {\n\tif (format === 'json') return JSON.stringify(value)\n\treturn format === 'text' ? renderText(value) : encode(value)\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction cell(value: unknown): string {\n\treturn value === undefined ? '' : String(value)\n}\n\n/** A header row plus one row per record, every column padded to its widest cell. */\nfunction table(rows: Record<string, unknown>[]): string[] {\n\tconst columns = [...new Set(rows.flatMap((row) => Object.keys(row)))]\n\tconst widths = columns.map((column) => Math.max(column.length, ...rows.map((row) => cell(row[column]).length)))\n\tconst line = (values: string[]) =>\n\t\t` ${values.map((value, index) => value.padEnd(widths[index] as number)).join(' ')}`.trimEnd()\n\treturn [line(columns), ...rows.map((row) => line(columns.map((column) => cell(row[column]))))]\n}\n\n/**\n * The same result rendered for a person rather than for an agent: scalars as `key: value`, records\n * as an aligned table, and everything else as a bulleted list. TOON stays the default because it is\n * what an agent parses; this is for reading over someone's shoulder.\n */\nexport function renderText(value: object): string {\n\tconst blocks = Object.entries(value).map(([key, item]) => {\n\t\tif (!Array.isArray(item)) return [`${key}: ${isRecord(item) ? JSON.stringify(item) : String(item)}`]\n\t\tif (!item.length) return [`${key}: (none)`]\n\t\tconst body = item.every(isRecord) ? table(item) : item.map((entry) => ` - ${String(entry)}`)\n\t\treturn [`${key}:`, ...body]\n\t})\n\n\t// A blank line wherever a multi-line block meets its neighbour, so a following scalar does not\n\t// read as another row of the table above it.\n\treturn blocks\n\t\t.flatMap((block, index) => {\n\t\t\tconst previous = blocks[index - 1]\n\t\t\treturn previous && (previous.length > 1 || block.length > 1) ? ['', ...block] : block\n\t\t})\n\t\t.join('\\n')\n}\n\n/** AXI §10: the executable's absolute path, with the user's home directory collapsed to `~`. */\nexport function binPath(home: string, executable: string | undefined): string {\n\tif (!executable) return 'buddy-agent-harness'\n\treturn home && executable.startsWith(home + sep) ? `~${executable.slice(home.length)}` : executable\n}\n","import { lstatSync } from 'node:fs'\nimport { join } from 'node:path'\n\nexport type HarnessName =\n\t| 'claude-code'\n\t| 'cursor'\n\t| 'codex'\n\t| 'copilot-cli'\n\t| 'gemini-cli'\n\t| 'devin-desktop'\n\t| 'windsurf'\n\n/**\n * `skillsDirectory` is the projection target a harness needs to see `.agents/skills`.\n * A harness that reads `.agents/skills` natively has none, and is never projected into.\n */\nexport type Harness = {\n\tname: HarnessName\n\tdetect: string\n\tskillsDirectory?: string\n\t/** Set when this name has been superseded; the value is the name that replaces it. */\n\tdeprecated?: HarnessName\n}\n\n/**\n * Codex, Cursor, Copilot CLI, and Devin Desktop read `.agents/skills` directly, so they need no\n * projection. Only Claude Code and Gemini CLI read solely their own directory.\n *\n * `windsurf` is the former name of Devin Desktop, rebranded 2026-06-02. It is retained as a\n * deprecated alias: Devin still scans the legacy `.windsurf/skills` path, so its projection keeps\n * working, but new repositories should enable `devin-desktop` and have nothing written for them.\n *\n * See `.research/agentic-configuration-standards/` for the per-harness sources.\n */\nexport const harnessRegistry: readonly Harness[] = [\n\t{ name: 'claude-code', detect: '.claude', skillsDirectory: '.claude/skills' },\n\t{ name: 'cursor', detect: '.cursor' },\n\t{ name: 'codex', detect: '.codex' },\n\t{ name: 'copilot-cli', detect: '.github/skills' },\n\t{ name: 'gemini-cli', detect: '.gemini', skillsDirectory: '.gemini/skills' },\n\t{ name: 'devin-desktop', detect: '.devin' },\n\t{ name: 'windsurf', detect: '.windsurf', skillsDirectory: '.windsurf/skills', deprecated: 'devin-desktop' },\n]\n\n/** Enabled whether or not the repository already contains their directories. */\nconst defaultHarnesses: readonly HarnessName[] = ['claude-code', 'cursor']\n\nfunction directoryExists(path: string): boolean {\n\ttry {\n\t\treturn lstatSync(path).isDirectory()\n\t} catch {\n\t\treturn false\n\t}\n}\n\n/** The default harnesses, plus the preferred ones, plus every harness whose directory is present. */\nexport function selectHarnesses(root: string, preferred: readonly HarnessName[]): Harness[] {\n\tconst enabled = new Set<HarnessName>([...defaultHarnesses, ...preferred])\n\treturn harnessRegistry.filter((harness) => enabled.has(harness.name) || directoryExists(join(root, harness.detect)))\n}\n","import { readdirSync } from 'node:fs'\nimport { join, posix, relative, sep } from 'node:path'\n\n/**\n * Every file below `directory`, as paths relative to it, POSIX-separated and sorted. A directory\n * that does not exist reads as empty: `doctor` never creates one to look at it.\n */\nexport function filesUnder(directory: string): string[] {\n\ttry {\n\t\treturn readdirSync(directory, { recursive: true, withFileTypes: true })\n\t\t\t.filter((entry) => entry.isFile())\n\t\t\t.map((entry) => relative(directory, join(entry.parentPath, entry.name)).split(sep).join(posix.sep))\n\t\t\t.sort()\n\t} catch {\n\t\treturn []\n\t}\n}\n","/**\n * The one place `doctor`'s guidance is written. The command reads `detail` and `repair` to fill its\n * `findings` and `help` sections; `skills/doctor/SKILL.md` is generated from the same table by\n * `scripts/generate-skills.ts`, so the shipped skill cannot drift from what the command says.\n */\n\n/** Every way a bridge can fail, in the order `doctor` reports them. */\nexport type BridgeProblem =\n\t| 'no-canonical'\n\t| 'missing'\n\t| 'degraded'\n\t| 'stale'\n\t| 'diverged-bridge'\n\t| 'diverged-canonical'\n\t| 'diverged-both'\n\t| 'diverged-unknown'\n\t| 'unpinned-copy'\n\nexport type Repair = {\n\tproblem: BridgeProblem\n\t/** What `doctor` prints in the `findings` row for this problem. */\n\tdetail: string\n\t/**\n\t * The command that fixes it, for `doctor`'s own output. `path` is the repository-relative bridge\n\t * path; `cli` is how to invoke this tool.\n\t */\n\trepair(path: string, cli: string): string\n\t/**\n\t * What the shipped skill tells an agent to do instead. A repair that rebuilds a bridge delegates\n\t * to the `init` skill rather than calling the `init` command, because rebuilding can move\n\t * user-authored skills and that judgment is the `init` skill's, not `doctor`'s.\n\t */\n\tskillRepair(path: string): string\n}\n\n/** How the command names itself. */\nexport const commandInvocation = 'buddy-agent-harness'\n/**\n * How a skill invokes the command. A skill may run without the binary on PATH, so it goes through\n * `npx`, pinned to the caret range of the version that generated the skill.\n *\n * The pin is what makes the shipped guidance honest. A skill states the findings and flags of the\n * version it was generated from, so an unpinned `npx` — which resolves whatever is latest — can\n * hand an agent a table that does not describe the CLI it just ran. The caret keeps patches\n * flowing and stops at the next breaking line.\n */\nexport const skillInvocation = (version: string) => `npx -y ${commandInvocation}@^${version}`\n\n/**\n * The launcher a skill ships, named for the subcommand it runs so a stack trace or a process list\n * says which one it was. One script per command, beside the `SKILL.md` that documents it.\n */\nexport const launcherFor = (subcommand: string) => `scripts/${subcommand}.mjs`\n\n/**\n * How a skill names its launcher. `<skill>` is the skill's own directory, substituted by the agent\n * reading the file, because the working directory is the repository under inspection rather than\n * the skill.\n */\nexport const launcherInvocation = (subcommand: string) => `node \"<skill>/${launcherFor(subcommand)}\"`\n\n/**\n * The launcher written into a skill's `scripts/` directory. It resolves the CLI from its own\n * location rather than the working directory, so the skill runs the copy it shipped with and\n * fetches nothing. The repository it inspects is still the working directory, unchanged.\n */\nexport function renderSkillLauncher(subcommand: string): string {\n\treturn `#!/usr/bin/env node\n// Generated from src/diagnose-bridges/doctor-guidance.ts by scripts/generate-skills.ts. Do not edit by hand.\nimport { dirname, join } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\n// <package>/skills/<skill>/scripts/${subcommand}.mjs: four levels up is the package root.\nconst packageRoot = dirname(dirname(dirname(dirname(fileURLToPath(import.meta.url)))))\n\nprocess.argv.splice(2, 0, '${subcommand}')\nawait import(join(packageRoot, 'bin', '${commandInvocation}.mjs'))\n`\n}\n\n/** How the skill hands a repair back to `init`. */\nexport const initSkillInvocation = '/buddy-agent-harness:init'\n\nexport const doctorRepairs: readonly Repair[] = [\n\t{\n\t\tproblem: 'no-canonical',\n\t\tdetail: 'the canonical skill directory does not exist, so no bridge can resolve',\n\t\trepair: (_path, cli) => `${cli} init`,\n\t\tskillRepair: () => `run \\`${initSkillInvocation}\\`, which creates \\`.agents/skills\\` and the bridges`,\n\t},\n\t{\n\t\tproblem: 'missing',\n\t\tdetail: 'no bridge at this path — the harness sees zero project skills',\n\t\trepair: (_path, cli) => `${cli} init`,\n\t\tskillRepair: () => `run \\`${initSkillInvocation}\\``,\n\t},\n\t{\n\t\tproblem: 'degraded',\n\t\tdetail: 'expected a directory but found a regular file — checkout without core.symlinks',\n\t\trepair: (_path, cli) => `${cli} init --copy --force`,\n\t\tskillRepair: () => `run \\`${initSkillInvocation} --copy --force\\``,\n\t},\n\t{\n\t\tproblem: 'stale',\n\t\tdetail: 'symlink does not resolve to .agents/skills',\n\t\trepair: (_path, cli) => `${cli} init --force`,\n\t\tskillRepair: () => `run \\`${initSkillInvocation} --force\\``,\n\t},\n\t{\n\t\tproblem: 'diverged-bridge',\n\t\tdetail: 'only the bridge changed since the two last agreed — an agent wrote through the copy',\n\t\trepair: (path, cli) =>\n\t\t\t`replace .agents/skills with ${path} to keep the newer edit and then run ${cli} init --force`,\n\t\tskillRepair: (path) =>\n\t\t\t`replace .agents/skills with ${path} to keep the newer edit, then run \\`${initSkillInvocation} --force\\``,\n\t},\n\t{\n\t\tproblem: 'diverged-canonical',\n\t\tdetail: 'only .agents/skills changed since the two last agreed — the copy is stale',\n\t\trepair: (_path, cli) => `${cli} init --copy --force`,\n\t\tskillRepair: () => `run \\`${initSkillInvocation} --copy --force\\``,\n\t},\n\t{\n\t\tproblem: 'diverged-both',\n\t\tdetail: 'both sides changed since they last agreed — rebuilding would discard one of them',\n\t\trepair: (path) => `git diff --no-index .agents/skills ${path} and reconcile by hand`,\n\t\tskillRepair: (path) => `run \\`git diff --no-index .agents/skills ${path}\\` and reconcile by hand`,\n\t},\n\t{\n\t\tproblem: 'diverged-unknown',\n\t\tdetail: 'contents differ and no commit where they agreed was found — which side moved is unknown',\n\t\trepair: (path) => `git diff --no-index .agents/skills ${path} and reconcile by hand`,\n\t\tskillRepair: (path) => `run \\`git diff --no-index .agents/skills ${path}\\` and reconcile by hand`,\n\t},\n\t{\n\t\tproblem: 'unpinned-copy',\n\t\tdetail: 'tracked copy without the skip-worktree bit — the tree is dirty with content that must not be committed',\n\t\t// The index entry is the tracked symlink on a Windows checkout but the individual files in a\n\t\t// committed copy, so the paths are read back from git rather than assumed.\n\t\trepair: (path) => `git ls-files -z ${path} | xargs -0 git update-index --skip-worktree`,\n\t\tskillRepair: (path) => `run \\`git ls-files -z ${path} | xargs -0 git update-index --skip-worktree\\``,\n\t},\n]\n\nconst repairsByProblem = new Map(doctorRepairs.map((entry) => [entry.problem, entry]))\n\nexport function repairFor(problem: BridgeProblem): Repair {\n\treturn repairsByProblem.get(problem) as Repair\n}\n\nexport const doctorSkill = {\n\tname: 'doctor',\n\tdescription:\n\t\t'Use this skill when a repository loads no project skills, when skills are missing after a clone, or when checking whether the agent configuration bridges into .claude/skills and the other harness directories still resolve.',\n} as const\n\n/** Written into the generated skill so a reader knows not to edit it in place. */\nexport const generatedSkillWarning =\n\t'<!-- Generated from src/diagnose-bridges/doctor-guidance.ts by scripts/generate-skills.ts. Do not edit by hand. -->'\n\n/**\n * The shipped `doctor` skill, rendered from the same table the command prints. `version` is the\n * package version the skill ships with; it pins the `npx` invocation so the table and the CLI that\n * produced it stay on the same breaking line.\n */\nexport function renderDoctorSkill(version: string): string {\n\t// A repair may itself contain a pipe, which would otherwise end the table cell early.\n\tconst cell = (value: string) => value.replaceAll('|', '\\\\|')\n\tconst rows = doctorRepairs\n\t\t.map((entry) => `| \\`${entry.problem}\\` | ${entry.detail} | ${cell(entry.skillRepair('<path>'))} |`)\n\t\t.join('\\n')\n\n\treturn `---\nname: ${doctorSkill.name}\ndescription: ${doctorSkill.description}\n---\n\n${generatedSkillWarning}\n\n# Harness Doctor\n\n\\`.agents/skills\\` is the canonical skill directory. Harnesses that cannot read it — Claude Code and Gemini CLI — get a bridge pointing at it, normally a directory symlink. A bridge that stops resolving is silent: the harness finds nothing and loads zero project skills, with no warning anywhere.\n\nDiagnose it:\n\n\\`\\`\\`sh\n${launcherInvocation('doctor')}\n\\`\\`\\`\n\n\\`<skill>\\` is this skill's own directory. The launcher runs the CLI that shipped beside it against the current working directory, so nothing is downloaded. Fall back to \\`${skillInvocation(version)} doctor\\` when that path cannot be resolved, or when the plugin was installed from git rather than npm and its dependencies were never installed.\n\nThe command is read-only. It never repairs anything, so it is safe to run at any point, including from a session-start hook.\n\n## Reading the report\n\n\\`bridges\\` lists every bridge \\`init\\` would create for this repository, each with a \\`status\\` of \\`ok\\`, \\`missing\\`, \\`degraded\\`, \\`stale\\`, or \\`diverged\\`. \\`findings\\` explains each problem and \\`help\\` names its repair. Apply the repair from the table below, then re-run \\`doctor\\`.\n\n\\`help\\` names the \\`init\\` command for a person at a shell. Do not run it yourself. Rebuilding a bridge can move skills a user wrote, and that judgment belongs to the \\`init\\` skill — hand the repair to \\`${initSkillInvocation}\\` instead.\n\nWhen every bridge resolves, \\`findings\\` says so outright rather than being empty.\n\nThe default output is TOON, which is what you parse. Add \\`--format text\\` when you need to show the same report to a person, or \\`--format json\\`.\n\n## Findings and their repairs\n\n| Finding | What it means | Repair |\n| --- | --- | --- |\n${rows}\n\nSubstitute the reported bridge path for \\`<path>\\`.\n\n## The Windows case\n\nThe common failure is \\`degraded\\`. Creating a symlink on Windows needs a privilege most accounts do not have, and Git for Windows gates it separately with \\`core.symlinks\\`, which its installer leaves off. With \\`core.symlinks=false\\` git does not error — it writes the symlink out as a regular file whose contents are the target path. \\`${initSkillInvocation} --copy --force\\` rebuilds the bridges as real directories on that machine.\n\nA copy is a snapshot rather than a live projection, and an agent that edits a skill through it writes into the copy instead of into \\`.agents/skills\\`. That is what the \\`diverged\\` findings catch.\n\n## Rules\n\n- Never repair a \\`diverged-both\\` or \\`diverged-unknown\\` bridge by re-running \\`init\\`. Rebuilding overwrites whichever side holds the newer edit. Reconcile the two directories first.\n- Edit skills at \\`.agents/skills/<name>/SKILL.md\\`. Editing through a bridge is only safe when that bridge is a symlink.\n- Do not add bridges to \\`.gitignore\\`. An untracked bridge swallows a real edit silently.\n`\n}\n","import { execFileSync } from 'node:child_process'\nimport { join } from 'node:path'\nimport { filesUnder } from './directory-files.ts'\n\n/** Which side of a diverged bridge moved since the last commit where the two agreed. */\nexport type DivergenceDirection = 'bridge' | 'canonical' | 'both' | 'unknown'\n\n/** Whether a path is tracked, and if so whether its skip-worktree bit is still set. */\nexport type TrackingState = 'untracked' | 'tracked' | 'skip-worktree'\n\nfunction git(root: string, args: string[], input?: string): string | undefined {\n\ttry {\n\t\treturn execFileSync('git', args, {\n\t\t\tcwd: root,\n\t\t\tencoding: 'utf8',\n\t\t\t...(input === undefined ? {} : { input }),\n\t\t\tstdio: ['pipe', 'pipe', 'pipe'],\n\t\t})\n\t} catch {\n\t\treturn undefined\n\t}\n}\n\nfunction lines(output: string | undefined): string[] {\n\treturn (output ?? '').split('\\n').filter(Boolean)\n}\n\n/**\n * Reads git state for the two sides of a bridge. Every method degrades to \"cannot tell\" rather than\n * throwing, so `doctor` still reports on a tarball, a worktree without git, or a repository with no\n * commits.\n */\nexport class GitBridgeState {\n\t/** Path of `root` relative to the repository root, `''` at the top, `undefined` outside a repository. */\n\tprivate readonly prefix: string | undefined\n\n\tconstructor(private readonly root: string) {\n\t\tthis.prefix = git(root, ['rev-parse', '--show-prefix'])?.trim()\n\t}\n\n\t/**\n\t * `init --copy` marks a bridge skip-worktree so a machine-local copy over a tracked symlink stops\n\t * showing as a pending change. The bit is a hint that some checkouts clear, so it is verified\n\t * rather than assumed.\n\t */\n\ttrackingOf(path: string): TrackingState {\n\t\tif (this.prefix === undefined) return 'untracked'\n\t\tconst entries = lines(git(this.root, ['ls-files', '-v', '--', path]))\n\t\tif (!entries.length) return 'untracked'\n\t\treturn entries.every((entry) => entry.startsWith('S')) ? 'skip-worktree' : 'tracked'\n\t}\n\n\t/**\n\t * Names the side that moved by finding the newest commit whose two trees agreed, then asking which\n\t * of the working directories still matches it.\n\t */\n\tdirectionOf(bridge: string, canonical: string): DivergenceDirection {\n\t\tif (this.prefix === undefined) return 'unknown'\n\t\tconst base = this.lastAgreedTree(bridge, canonical)\n\t\tif (base === undefined) return 'unknown'\n\t\tconst bridgeMoved = !this.matchesTree(bridge, base)\n\t\tconst canonicalMoved = !this.matchesTree(canonical, base)\n\t\tif (bridgeMoved && canonicalMoved) return 'both'\n\t\tif (bridgeMoved) return 'bridge'\n\t\treturn 'canonical'\n\t}\n\n\t/** The tree of the newest commit where both paths held identical content. */\n\tprivate lastAgreedTree(bridge: string, canonical: string): string | undefined {\n\t\tfor (const commit of lines(git(this.root, ['rev-list', '-n', '200', 'HEAD', '--', bridge, canonical]))) {\n\t\t\tconst bridgeObject = git(this.root, ['rev-parse', '-q', '--verify', `${commit}:${this.prefix}${bridge}`])?.trim()\n\t\t\tif (!bridgeObject) continue\n\t\t\tconst canonicalObject = git(this.root, [\n\t\t\t\t'rev-parse',\n\t\t\t\t'-q',\n\t\t\t\t'--verify',\n\t\t\t\t`${commit}:${this.prefix}${canonical}`,\n\t\t\t])?.trim()\n\t\t\tif (bridgeObject === canonicalObject) return bridgeObject\n\t\t}\n\t\treturn undefined\n\t}\n\n\t/**\n\t * Compares a working directory against a git tree by object id. `hash-object` is used rather than\n\t * hashing in-process so the comparison follows whatever object format the repository uses.\n\t */\n\tprivate matchesTree(directory: string, tree: string): boolean {\n\t\tconst expected = new Map(\n\t\t\tlines(git(this.root, ['ls-tree', '-r', tree])).map((entry) => {\n\t\t\t\tconst [meta, path] = entry.split('\\t')\n\t\t\t\treturn [path, (meta as string).split(' ')[2] as string] as const\n\t\t\t}),\n\t\t)\n\t\tconst files = filesUnder(join(this.root, directory))\n\t\tif (files.length !== expected.size || files.some((file) => !expected.has(file))) return false\n\t\tconst hashed = lines(\n\t\t\tgit(this.root, ['hash-object', '--stdin-paths'], files.map((file) => join(directory, file)).join('\\n')),\n\t\t)\n\t\treturn hashed.length === files.length && files.every((file, index) => expected.get(file) === hashed[index])\n\t}\n}\n","import { lstatSync, readFileSync, readlinkSync, statSync } from 'node:fs'\nimport { dirname, join, relative } from 'node:path'\nimport { type Harness, type HarnessName, selectHarnesses } from '../harness-registry/harness-registry.ts'\nimport { filesUnder } from './directory-files.ts'\nimport { type BridgeProblem, repairFor } from './doctor-guidance.ts'\nimport { type DivergenceDirection, GitBridgeState } from './git-bridge-state.ts'\n\nexport type BridgeKind = 'symlink' | 'copy' | 'file' | 'none'\nexport type BridgeStatus = 'ok' | 'missing' | 'degraded' | 'stale' | 'diverged'\n\nexport type BridgeReport = {\n\tharness: HarnessName\n\t/** Repository-relative, as the harness registry declares it. */\n\tpath: string\n\tkind: BridgeKind\n\tstatus: BridgeStatus\n}\n\nexport type BridgeFinding = {\n\tpath: string\n\tdetail: string\n\t/** The command that repairs this finding, already carrying the bridge path. */\n\trepair: string\n}\n\nexport type DivergenceReport = {\n\tpath: string\n\tdirection: DivergenceDirection\n}\n\nexport type DiagnoseOptions = {\n\troot: string\n\tharnesses?: HarnessName[]\n\t/** How to name this tool in the repair commands. */\n\tcli: string\n}\n\nexport type DiagnoseResult = {\n\tbridges: BridgeReport[]\n\tdivergence: DivergenceReport[]\n\tfindings: BridgeFinding[]\n}\n\nconst canonicalPath = '.agents/skills'\n\nfunction pathState(target: string): 'missing' | 'symlink' | 'directory' | 'file' {\n\ttry {\n\t\tconst stats = lstatSync(target)\n\t\tif (stats.isSymbolicLink()) return 'symlink'\n\t\treturn stats.isDirectory() ? 'directory' : 'file'\n\t} catch {\n\t\treturn 'missing'\n\t}\n}\n\nfunction isDirectory(path: string): boolean {\n\ttry {\n\t\treturn statSync(path).isDirectory()\n\t} catch {\n\t\treturn false\n\t}\n}\n\n/** The same test `init` uses to decide a projection is already correct, plus that it still resolves. */\nfunction resolvesToCanonical(target: string, canonical: string): boolean {\n\treturn readlinkSync(target) === relative(dirname(target), canonical) && isDirectory(target)\n}\n\nfunction sameContent(left: string, right: string): boolean {\n\tconst leftFiles = filesUnder(left)\n\tconst rightFiles = filesUnder(right)\n\treturn (\n\t\tleftFiles.length === rightFiles.length &&\n\t\tleftFiles.every(\n\t\t\t(file, index) =>\n\t\t\t\trightFiles[index] === file && readFileSync(join(left, file)).equals(readFileSync(join(right, file))),\n\t\t)\n\t)\n}\n\ntype Inspection = {\n\tkind: BridgeKind\n\tstatus: BridgeStatus\n\tproblem?: BridgeProblem\n\tdirection?: DivergenceDirection\n}\n\nfunction inspect(target: string, path: string, canonical: string, git: GitBridgeState): Inspection {\n\tswitch (pathState(target)) {\n\t\tcase 'missing':\n\t\t\treturn { kind: 'none', status: 'missing', problem: 'missing' }\n\t\t// The flagship Windows failure: git with `core.symlinks=false` writes the link out as a\n\t\t// regular file holding the target path, and the harness silently loads nothing.\n\t\tcase 'file':\n\t\t\treturn { kind: 'file', status: 'degraded', problem: 'degraded' }\n\t\tcase 'symlink':\n\t\t\treturn resolvesToCanonical(target, canonical)\n\t\t\t\t? { kind: 'symlink', status: 'ok' }\n\t\t\t\t: { kind: 'symlink', status: 'stale', problem: 'stale' }\n\t\tdefault: {\n\t\t\tif (!sameContent(target, canonical)) {\n\t\t\t\tconst direction = git.directionOf(path, canonicalPath)\n\t\t\t\treturn { kind: 'copy', status: 'diverged', problem: `diverged-${direction}`, direction }\n\t\t\t}\n\t\t\t// A copy over a tracked symlink only stays out of `git status` while its skip-worktree bit\n\t\t\t// survives, and some checkout and merge operations clear it.\n\t\t\treturn git.trackingOf(path) === 'tracked'\n\t\t\t\t? { kind: 'copy', status: 'ok', problem: 'unpinned-copy' }\n\t\t\t\t: { kind: 'copy', status: 'ok' }\n\t\t}\n\t}\n}\n\n/**\n * Reports whether every bridge `init` would create for this repository still resolves into\n * `.agents/skills`. Read-only: nothing is created, moved, or repaired, so the caller decides what\n * to run from the repair each finding carries.\n */\nexport function diagnoseBridges({ root, harnesses: preferred = [], cli }: DiagnoseOptions): DiagnoseResult {\n\tconst canonical = join(root, '.agents', 'skills')\n\tconst git = new GitBridgeState(root)\n\tconst bridged = selectHarnesses(root, preferred).filter((harness): harness is Harness & { skillsDirectory: string } =>\n\t\tBoolean(harness.skillsDirectory),\n\t)\n\n\tconst bridges: BridgeReport[] = []\n\tconst divergence: DivergenceReport[] = []\n\tconst findings: BridgeFinding[] = []\n\n\tif (!isDirectory(canonical)) {\n\t\tconst { detail, repair } = repairFor('no-canonical')\n\t\tfindings.push({ path: canonicalPath, detail, repair: repair(canonicalPath, cli) })\n\t}\n\n\tfor (const harness of bridged) {\n\t\tconst path = harness.skillsDirectory\n\t\tconst inspection = inspect(join(root, path), path, canonical, git)\n\t\tbridges.push({ harness: harness.name, path, kind: inspection.kind, status: inspection.status })\n\t\tif (inspection.direction) divergence.push({ path, direction: inspection.direction })\n\t\tif (inspection.problem) {\n\t\t\tconst { detail, repair } = repairFor(inspection.problem)\n\t\t\tfindings.push({ path, detail, repair: repair(path, cli) })\n\t\t}\n\t}\n\n\treturn { bridges, divergence, findings }\n}\n","import { homedir } from 'node:os'\nimport type { cli } from 'clibuilder'\nimport { command, z } from 'clibuilder'\nimport { binPath, parseFormat, writeResult } from '../command-output/command-output.ts'\nimport { type HarnessName, harnessRegistry } from '../harness-registry/harness-registry.ts'\nimport { type DiagnoseResult, diagnoseBridges } from './diagnose-bridges.ts'\nimport { commandInvocation } from './doctor-guidance.ts'\n\ntype DoctorReport = {\n\tbin: string\n\tbridges: DiagnoseResult['bridges']\n\tdivergence?: DiagnoseResult['divergence']\n\t/** The repair is lifted out into `help`, so a finding row stays to the diagnosis itself. */\n\tfindings: Omit<DiagnoseResult['findings'][number], 'repair'>[] | string\n\thelp?: string[]\n}\n\n/**\n * AXI §5: the healthy answer states the zero with context, so an agent does not re-run with other\n * flags to confirm that an empty section really meant \"nothing wrong\".\n */\nexport function buildReport(bin: string, result: DiagnoseResult): DoctorReport {\n\tif (!result.findings.length) {\n\t\tconst count = result.bridges.length\n\t\treturn {\n\t\t\tbin,\n\t\t\tbridges: result.bridges,\n\t\t\tfindings:\n\t\t\t\tcount === 1 ? '0 problems found — the 1 bridge resolves' : `0 problems found — all ${count} bridges resolve`,\n\t\t}\n\t}\n\n\treturn {\n\t\tbin,\n\t\tbridges: result.bridges,\n\t\t...(result.divergence.length ? { divergence: result.divergence } : {}),\n\t\tfindings: result.findings.map(({ path, detail }) => ({ path, detail })),\n\t\thelp: [...new Set(result.findings.map((finding) => `Run \\`${finding.repair}\\``))],\n\t}\n}\n\nexport const doctorCommand: cli.Command = command({\n\tname: 'doctor',\n\tdescription: 'Report whether the harness skill bridges in this repository still resolve. Read-only.',\n\toptions: {\n\t\troot: {\n\t\t\tdescription: 'Repository or package directory. Defaults to the current directory.',\n\t\t\ttype: z.optional(z.string()),\n\t\t},\n\t\tharness: {\n\t\t\tdescription: 'Comma-separated harnesses to check in addition to Claude Code and Cursor, e.g. codex,gemini-cli.',\n\t\t\ttype: z.optional(z.string()),\n\t\t},\n\t\tformat: {\n\t\t\tdescription: 'Output format: toon (default), json, or text for a human-readable report.',\n\t\t\ttype: z.optional(z.string()),\n\t\t\tdefault: 'toon',\n\t\t},\n\t},\n\trun(args) {\n\t\ttry {\n\t\t\tconst format = parseFormat(args.format)\n\t\t\tconst requested = args.harness\n\t\t\t\t?.split(',')\n\t\t\t\t.map((name) => name.trim())\n\t\t\t\t.filter(Boolean)\n\t\t\tconst unsupported = requested?.filter((name) => !harnessRegistry.some((harness) => harness.name === name))\n\t\t\tif (unsupported?.length)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Unsupported harness: ${unsupported.join(', ')}. Supported: ${harnessRegistry\n\t\t\t\t\t\t.map((harness) => harness.name)\n\t\t\t\t\t\t.join(', ')}.`,\n\t\t\t\t)\n\t\t\tconst result = diagnoseBridges({\n\t\t\t\troot: args.root ?? process.cwd(),\n\t\t\t\t...(requested?.length ? { harnesses: requested as HarnessName[] } : {}),\n\t\t\t\tcli: commandInvocation,\n\t\t\t})\n\t\t\t// Exit stays 0 even with findings: the diagnosis succeeded, and a non-zero code reads to an\n\t\t\t// agent as \"this command is broken, try something else\".\n\t\t\twriteResult(buildReport(binPath(homedir(), process.argv[1]), result), format)\n\t\t} catch (error) {\n\t\t\tprocess.stderr.write(`error: ${error instanceof Error ? error.message : 'Harness diagnosis failed.'}\\n`)\n\t\t\tprocess.exitCode = 1\n\t\t}\n\t},\n})\n","import { cpSync, lstatSync, mkdirSync, readdirSync, readlinkSync, rmSync, symlinkSync } from 'node:fs'\nimport { dirname, join, relative } from 'node:path'\nimport type { Harness, HarnessName } from '../harness-registry/harness-registry.ts'\n\nfunction skillNames(skillsDirectory: string): string[] {\n\treturn readdirSync(skillsDirectory, { withFileTypes: true })\n\t\t.filter((entry) => entry.isDirectory())\n\t\t.map((entry) => entry.name)\n\t\t.sort()\n}\n\nfunction pathOccupied(path: string): boolean {\n\ttry {\n\t\tlstatSync(path)\n\t\treturn true\n\t} catch {\n\t\treturn false\n\t}\n}\n\nfunction isCorrectLink(target: string, source: string): boolean {\n\treturn lstatSync(target).isSymbolicLink() && readlinkSync(target) === relative(dirname(target), source)\n}\n\n/** Creates the canonical directory when absent, so a fresh repository reports zero skills. */\nexport function countSkills(canonicalSkills: string): number {\n\tmkdirSync(canonicalSkills, { recursive: true })\n\treturn skillNames(canonicalSkills).length\n}\n\nexport type ProjectSkillsOptions = {\n\troot: string\n\tcanonicalSkills: string\n\tharnesses: readonly Harness[]\n\tcopy: boolean\n\tforce: boolean\n}\n\n/**\n * Points every harness that cannot read `.agents/skills` at the canonical directory. Symlinking is\n * preferred; a platform that refuses the link falls back to a copy. Returns the projected harnesses.\n */\nexport function projectSkills({ root, canonicalSkills, harnesses, copy, force }: ProjectSkillsOptions): HarnessName[] {\n\tconst projections = harnesses\n\t\t.filter((harness) => harness.skillsDirectory)\n\t\t.map((harness) => ({\n\t\t\tharness,\n\t\t\ttarget: join(root, harness.skillsDirectory as string),\n\t\t}))\n\n\tconst conflicts = projections\n\t\t.filter(({ target }) => pathOccupied(target) && !isCorrectLink(target, canonicalSkills))\n\t\t.map(({ target }) => target)\n\n\tif (conflicts.length && !force) {\n\t\tthrow new Error(\n\t\t\t`Refusing to replace existing skill targets:\\n${conflicts.map((target) => `- ${target}`).join('\\n')}`,\n\t\t)\n\t}\n\n\tfor (const { target } of projections) {\n\t\tmkdirSync(dirname(target), { recursive: true })\n\t\tif (pathOccupied(target) && isCorrectLink(target, canonicalSkills)) continue\n\t\tif (pathOccupied(target)) rmSync(target, { recursive: true, force: true })\n\t\tif (copy) {\n\t\t\tcpSync(canonicalSkills, target, { recursive: true })\n\t\t\tcontinue\n\t\t}\n\t\ttry {\n\t\t\tsymlinkSync(relative(dirname(target), canonicalSkills), target, 'junction')\n\t\t} catch (error) {\n\t\t\tif (pathOccupied(target)) throw error\n\t\t\tcpSync(canonicalSkills, target, { recursive: true })\n\t\t}\n\t}\n\n\treturn projections.map(({ harness }) => harness.name)\n}\n","import { join } from 'node:path'\nimport { type HarnessName, selectHarnesses } from '../harness-registry/harness-registry.ts'\nimport { countSkills, projectSkills } from '../skill-projection/skill-projection.ts'\n\nexport type InitializeOptions = {\n\troot: string\n\tharnesses?: HarnessName[]\n\tcopy?: boolean\n\tforce?: boolean\n}\nexport type InitializeResult = {\n\troot: string\n\tharnesses: HarnessName[]\n\tnative: HarnessName[]\n\tlinked: HarnessName[]\n\t/** Enabled harnesses whose name has been superseded, as `{ name, replacedBy }`. */\n\tdeprecated: { name: HarnessName; replacedBy: HarnessName }[]\n\tskills: number\n\tcopied: boolean\n}\n\nexport function initializeHarnesses({\n\troot,\n\tharnesses: preferred = [],\n\tcopy = false,\n\tforce = false,\n}: InitializeOptions): InitializeResult {\n\tconst canonicalSkills = join(root, '.agents', 'skills')\n\tconst skills = countSkills(canonicalSkills)\n\tconst harnesses = selectHarnesses(root, preferred)\n\tconst linked = projectSkills({ root, canonicalSkills, harnesses, copy, force })\n\n\treturn {\n\t\troot,\n\t\tharnesses: harnesses.map((harness) => harness.name),\n\t\tnative: harnesses.filter((harness) => !harness.skillsDirectory).map((harness) => harness.name),\n\t\tlinked,\n\t\tdeprecated: harnesses\n\t\t\t.filter((harness) => harness.deprecated)\n\t\t\t.map((harness) => ({ name: harness.name, replacedBy: harness.deprecated as HarnessName })),\n\t\tskills,\n\t\tcopied: copy,\n\t}\n}\n","import type { cli } from 'clibuilder'\nimport { command, z } from 'clibuilder'\nimport { parseFormat, writeResult } from '../command-output/command-output.ts'\nimport { doctorCommand } from '../diagnose-bridges/doctor.command.ts'\nimport { type HarnessName, harnessRegistry } from '../harness-registry/harness-registry.ts'\nimport { initializeHarnesses } from './initialize-harnesses.ts'\n\nexport const initCommand: cli.Command = command({\n\tname: 'init',\n\tdescription: 'Set up canonical agent skills for the harnesses already enabled in a repository.',\n\toptions: {\n\t\troot: {\n\t\t\tdescription: 'Repository or package directory. Defaults to the current directory.',\n\t\t\ttype: z.optional(z.string()),\n\t\t},\n\t\tharness: {\n\t\t\tdescription: 'Comma-separated harnesses to enable in addition to Claude Code and Cursor, e.g. codex,gemini-cli.',\n\t\t\ttype: z.optional(z.string()),\n\t\t},\n\t\tcopy: {\n\t\t\tdescription: 'Copy skills instead of linking them.',\n\t\t\ttype: z.optional(z.boolean()),\n\t\t},\n\t\tforce: {\n\t\t\tdescription: 'Replace conflicting target skill directories.',\n\t\t\ttype: z.optional(z.boolean()),\n\t\t},\n\t\tformat: {\n\t\t\tdescription: 'Output format: toon (default), json, or text for a human-readable report.',\n\t\t\ttype: z.optional(z.string()),\n\t\t\tdefault: 'toon',\n\t\t},\n\t},\n\trun(args) {\n\t\ttry {\n\t\t\tconst format = parseFormat(args.format)\n\t\t\tconst requested = args.harness\n\t\t\t\t?.split(',')\n\t\t\t\t.map((name) => name.trim())\n\t\t\t\t.filter(Boolean)\n\t\t\tconst unsupported = requested?.filter((name) => !harnessRegistry.some((harness) => harness.name === name))\n\t\t\tif (unsupported?.length)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Unsupported harness: ${unsupported.join(', ')}. Supported: ${harnessRegistry\n\t\t\t\t\t\t.map((harness) => harness.name)\n\t\t\t\t\t\t.join(', ')}.`,\n\t\t\t\t)\n\t\t\twriteResult(\n\t\t\t\tinitializeHarnesses({\n\t\t\t\t\troot: args.root ?? process.cwd(),\n\t\t\t\t\t...(requested?.length ? { harnesses: requested as HarnessName[] } : {}),\n\t\t\t\t\t...(args.copy === undefined ? {} : { copy: args.copy }),\n\t\t\t\t\t...(args.force === undefined ? {} : { force: args.force }),\n\t\t\t\t}),\n\t\t\t\tformat,\n\t\t\t)\n\t\t} catch (error) {\n\t\t\tprocess.stderr.write(`error: ${error instanceof Error ? error.message : 'Harness initialization failed.'}\\n`)\n\t\t\tprocess.exitCode = 1\n\t\t}\n\t},\n})\n\n// Named for the package rather than shortened to `harness`: `repobuddy` mounts every plugin into one\n// command namespace, where `harness` is generic enough to collide with another plugin's.\nexport const harnessCommand: cli.Command = command({\n\tname: 'agent-harness',\n\tdescription: 'Commands for configuring agent harness compatibility.',\n\tcommands: [initCommand, doctorCommand],\n})\n\nexport function activate({ addCommand }: { addCommand(command: typeof harnessCommand): void }): void {\n\taddCommand(harnessCommand)\n}\n"],"mappings":"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"}
|