docbridge 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -1
- package/README.md +18 -21
- package/dist/bin/darwin-arm64/SHA256SUMS +2 -2
- package/dist/bin/darwin-arm64/docbridge-swift-scanner +0 -0
- package/dist/bin/darwin-arm64/docbridge_dart_scanner +0 -0
- package/dist/bin/linux-x64/SHA256SUMS +1 -1
- package/dist/bin/linux-x64/docbridge-swift-scanner +0 -0
- package/dist/index.js +94 -25
- package/docs/user/agent-integration.md +34 -8
- package/docs/user/annotations.md +131 -10
- package/docs/user/commands.md +8 -0
- package/docs/user/configuration.md +9 -0
- package/docs/user/getting-started.md +5 -1
- package/docs/user/link-review.md +53 -0
- package/docs/user/linking-workflow.md +70 -0
- package/docs/user/troubleshooting.md +30 -22
- package/package.json +1 -1
- package/templates/skills/README.md +16 -23
- package/templates/skills/docbridge/SKILL.md +126 -0
- package/templates/skills/docbridge-adopt/SKILL.md +0 -96
- package/templates/skills/docbridge-annotate/SKILL.md +0 -99
- package/templates/skills/docbridge-link/SKILL.md +0 -80
- package/templates/skills/docbridge-review/SKILL.md +0 -62
- package/templates/skills/docbridge-sync/SKILL.md +0 -68
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,42 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.8.0] - 2026-08-18
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- The VS Code-compatible extension `salan70.docbridge` is published on Visual
|
|
15
|
+
Studio Marketplace.
|
|
16
|
+
- Packaged user docs now cover linking workflow and semantic link review
|
|
17
|
+
(`docbridge docs show linking-workflow`, `docbridge docs show link-review`),
|
|
18
|
+
plus supported and unsupported `@doc` declaration forms, the heading-anchor
|
|
19
|
+
algorithm, and named link-authoring diagnostic codes.
|
|
20
|
+
- Human-readable `docbridge check` output ends with a pointer to
|
|
21
|
+
`docbridge docs show troubleshooting`. `check --json` is unchanged.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- `docbridge init` and `docbridge init-with-agent` install one skill,
|
|
26
|
+
`docbridge`, instead of the five companion skills. The skill routes adopt,
|
|
27
|
+
discover-and-link, annotate, review, and sync work; facts about the binary
|
|
28
|
+
come from `docbridge docs show`.
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- `just package-vsix` bundles `vscode-languageclient` into the editor client.
|
|
33
|
+
Packaging with `--no-dependencies` previously omitted the module, so the
|
|
34
|
+
installed VSIX failed to activate.
|
|
35
|
+
- `docs/user/annotations.md` no longer claims GitHub-style numeric suffixes for
|
|
36
|
+
duplicate headings. Duplicate anchors in one file are `duplicate_doc_anchor`.
|
|
37
|
+
|
|
38
|
+
### Upgrading
|
|
39
|
+
|
|
40
|
+
- Existing installs keep the five legacy skill directories
|
|
41
|
+
(`docbridge-adopt`, `docbridge-annotate`, `docbridge-link`,
|
|
42
|
+
`docbridge-review`, `docbridge-sync`) until `docbridge init --force` is run.
|
|
43
|
+
Review locally edited copies first. Symlinked skill directories are reported
|
|
44
|
+
and left untouched.
|
|
45
|
+
|
|
10
46
|
## [0.7.0] - 2026-08-16
|
|
11
47
|
|
|
12
48
|
### Added
|
|
@@ -315,7 +351,8 @@ Initial release of the SpecLink CLI.
|
|
|
315
351
|
- `speclink check` command with `--root`, `--json`, and `--audit` options.
|
|
316
352
|
- `speclink --version` (alias `-v`) and `speclink --help` (alias `-h`).
|
|
317
353
|
|
|
318
|
-
[Unreleased]: https://github.com/salan70/docbridge/compare/v0.
|
|
354
|
+
[Unreleased]: https://github.com/salan70/docbridge/compare/v0.8.0...HEAD
|
|
355
|
+
[0.8.0]: https://github.com/salan70/docbridge/releases/tag/v0.8.0
|
|
319
356
|
[0.7.0]: https://github.com/salan70/docbridge/releases/tag/v0.7.0
|
|
320
357
|
[0.6.1]: https://github.com/salan70/docbridge/releases/tag/v0.6.1
|
|
321
358
|
[0.6.0]: https://github.com/salan70/docbridge/releases/tag/v0.6.0
|
package/README.md
CHANGED
|
@@ -40,9 +40,8 @@ Run first-time setup in the project root:
|
|
|
40
40
|
bunx docbridge init
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
For agent-guided adoption, install `docbridge
|
|
44
|
-
The
|
|
45
|
-
DocBridge skills after scope is confirmed:
|
|
43
|
+
For agent-guided adoption, install the `docbridge` skill and print setup
|
|
44
|
+
commands. The skill routes adopt, link, review, and sync work:
|
|
46
45
|
|
|
47
46
|
```sh
|
|
48
47
|
bunx docbridge init-with-agent
|
|
@@ -316,11 +315,10 @@ DocBridge's link graph is built to be consumed by AI coding agents:
|
|
|
316
315
|
- [docs/integrations](docs/integrations) — recipes for Claude Code, Codex,
|
|
317
316
|
and CI: gate triage with `docbridge related --gate`, counterpart content with
|
|
318
317
|
`docbridge context`, and PR reporting.
|
|
319
|
-
- [templates/skills](templates/skills) — distributable
|
|
320
|
-
`docbridge init
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
`docbridge-sync`.
|
|
318
|
+
- [templates/skills](templates/skills) — the distributable `docbridge` skill
|
|
319
|
+
installed by `docbridge init` and `docbridge init-with-agent`. Facts about
|
|
320
|
+
the binary live in `docbridge docs show`. Existing five-skill installs remain
|
|
321
|
+
until `docbridge init --force`.
|
|
324
322
|
|
|
325
323
|
This repository dogfoods the skills under `.claude/` and `.agents/`, and keeps
|
|
326
324
|
its guardrail in the Git `pre-commit` hook under `.githooks/` rather than in
|
|
@@ -340,24 +338,24 @@ options; the project root comes from the editor's `initialize` request.
|
|
|
340
338
|
`docbridge check` is unchanged.
|
|
341
339
|
|
|
342
340
|
A VS Code-compatible extension lives in [editors/vscode](editors/vscode). It
|
|
343
|
-
packages the language server into a VSIX for VS Code and Cursor.
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
`
|
|
347
|
-
|
|
341
|
+
packages the language server into a VSIX for VS Code and Cursor. Install
|
|
342
|
+
[`salan70.docbridge`](https://marketplace.visualstudio.com/items?itemName=salan70.docbridge)
|
|
343
|
+
from VS Code Marketplace. Bun must be available to the editor; set
|
|
344
|
+
`docbridge.bunPath` if the GUI cannot find `bun` on `PATH`.
|
|
345
|
+
|
|
346
|
+
Contributors can still stage the supported `dist/bin/darwin-arm64` and
|
|
347
|
+
`dist/bin/linux-x64` scanner artifacts and build a local VSIX:
|
|
348
348
|
|
|
349
349
|
```sh
|
|
350
350
|
just package-vsix
|
|
351
351
|
just verify-vsix
|
|
352
352
|
```
|
|
353
353
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
is
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
concrete consumer requires a long-lived tool server. Full LSP behavior is specified in
|
|
360
|
-
[docs/specs/lsp.md](docs/specs/lsp.md).
|
|
354
|
+
Registry publication remains manual (`VSCE_PAT=<token> just
|
|
355
|
+
publish-vscode-extension`). Open VSX delivery is out of scope. Zed integration
|
|
356
|
+
is tracked separately and is not yet implemented. MCP delivery is out of scope
|
|
357
|
+
until a concrete consumer requires a long-lived tool server. Full LSP behavior
|
|
358
|
+
is specified in [docs/specs/lsp.md](docs/specs/lsp.md).
|
|
361
359
|
|
|
362
360
|
## Diagnostics
|
|
363
361
|
|
|
@@ -417,7 +415,6 @@ Completed v0.1–v0.6 capabilities are documented above and in
|
|
|
417
415
|
|
|
418
416
|
Remaining editor delivery work:
|
|
419
417
|
|
|
420
|
-
- Publish the first verified VSIX to VS Code Marketplace
|
|
421
418
|
- Follow-up automation for GitHub Release VSIX attachment and registry
|
|
422
419
|
publishing after the manual flow is proven
|
|
423
420
|
- Add a separate Zed integration path
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
4b0ab3efbe865e9fb0cc48a6a0d37146c72a4255479e1c78c27b6c20e7e62604 docbridge-swift-scanner
|
|
2
|
+
c764c46477f522c8a82b62e629ff69907c0511fbc58b005ee6eba04d0e08dbef docbridge_dart_scanner
|
|
3
3
|
a1b129d980c981a2d24f0c9682e614a9695d4e9f9b8174d61b0dacb3fc9e3c79 docbridge-rust-scanner
|
|
Binary file
|
|
Binary file
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
|
|
1
|
+
9b7f3eea8df6ec2a07bd243a46b149fe3468240c6e0293390dc58594140519de docbridge-swift-scanner
|
|
2
2
|
095c4c172da615be155bee15dcce7b99faaf2a8bb26f3cad3e0b17881495ddf2 docbridge_dart_scanner
|
|
3
3
|
d89a1146ed10dcb01151ef5351a746862c3955286431c47f3cf91cf6639866ba docbridge-rust-scanner
|
|
Binary file
|
package/dist/index.js
CHANGED
|
@@ -175581,7 +175581,7 @@ import { join as join9, resolve as resolve4 } from "node:path";
|
|
|
175581
175581
|
// package.json
|
|
175582
175582
|
var package_default = {
|
|
175583
175583
|
name: "docbridge",
|
|
175584
|
-
version: "0.
|
|
175584
|
+
version: "0.8.0",
|
|
175585
175585
|
description: "A CLI that links Markdown specifications and code declarations. Runs on Node.js and Bun.",
|
|
175586
175586
|
keywords: [
|
|
175587
175587
|
"bun",
|
|
@@ -179143,18 +179143,18 @@ import { readdirSync as readdirSync3, readFileSync as readFileSync4 } from "node
|
|
|
179143
179143
|
import { join as join6 } from "node:path";
|
|
179144
179144
|
|
|
179145
179145
|
// src/core/init-plan.ts
|
|
179146
|
-
import { existsSync as existsSync2, readdirSync as readdirSync2, readFileSync as readFileSync3, realpathSync as realpathSync2 } from "node:fs";
|
|
179146
|
+
import { existsSync as existsSync2, lstatSync as lstatSync2, readdirSync as readdirSync2, readFileSync as readFileSync3, realpathSync as realpathSync2 } from "node:fs";
|
|
179147
179147
|
import { dirname as dirname3, join as join5, relative as relative3 } from "node:path";
|
|
179148
179148
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
179149
179149
|
var CONFIG_FILE_NAME2 = "docbridge.config.json";
|
|
179150
|
-
var INIT_SKILL_NAMES = [
|
|
179150
|
+
var INIT_SKILL_NAMES = ["docbridge"];
|
|
179151
|
+
var LEGACY_SKILL_NAMES = [
|
|
179151
179152
|
"docbridge-adopt",
|
|
179152
179153
|
"docbridge-annotate",
|
|
179153
179154
|
"docbridge-link",
|
|
179154
179155
|
"docbridge-review",
|
|
179155
179156
|
"docbridge-sync"
|
|
179156
179157
|
];
|
|
179157
|
-
var INIT_WITH_AGENT_SKILL_NAMES = ["docbridge-adopt"];
|
|
179158
179158
|
function planInitCommand(input) {
|
|
179159
179159
|
const packageRoot = input.packageRoot ?? resolvePackageRoot();
|
|
179160
179160
|
const existingConfig = readExistingConfig(input.projectRoot);
|
|
@@ -179198,16 +179198,16 @@ function planInitCommand(input) {
|
|
|
179198
179198
|
exitCode = 1;
|
|
179199
179199
|
}
|
|
179200
179200
|
const skillOps = planSkillOperations({
|
|
179201
|
-
command: input.command,
|
|
179202
179201
|
projectRoot: input.projectRoot,
|
|
179203
179202
|
packageRoot,
|
|
179204
179203
|
agentTarget,
|
|
179205
|
-
options: input.options
|
|
179204
|
+
options: input.options,
|
|
179205
|
+
messages
|
|
179206
179206
|
});
|
|
179207
179207
|
const agentGuidance = input.command === "init-with-agent" && agentTarget !== "none" ? buildAgentGuidance(input.projectRoot, agentTarget) : [];
|
|
179208
179208
|
if (input.command === "init-with-agent") {
|
|
179209
179209
|
nextSteps.push("Run the printed one-shot command or fallback prompt in your agent.");
|
|
179210
|
-
nextSteps.push("Let docbridge
|
|
179210
|
+
nextSteps.push("Let the docbridge skill confirm scope and create or improve docbridge.config.json.");
|
|
179211
179211
|
}
|
|
179212
179212
|
if (input.options.yes && input.command === "init" && configOps.length === 0 && existingConfig.rawText === undefined && (input.discovery.docs.ambiguous || input.discovery.code.ambiguous)) {
|
|
179213
179213
|
exitCode = 1;
|
|
@@ -179262,7 +179262,7 @@ function listDistributableSkills(packageRoot) {
|
|
|
179262
179262
|
} catch {
|
|
179263
179263
|
return [];
|
|
179264
179264
|
}
|
|
179265
|
-
return entries.filter((entry) => entry.startsWith("docbridge
|
|
179265
|
+
return entries.filter((entry) => entry.startsWith("docbridge")).filter((entry) => existsSync2(join5(skillsRoot, entry, "SKILL.md"))).toSorted();
|
|
179266
179266
|
}
|
|
179267
179267
|
function formatInitPlan(plan) {
|
|
179268
179268
|
const lines = [];
|
|
@@ -179359,16 +179359,20 @@ function planSkillOperations(input) {
|
|
|
179359
179359
|
if (input.agentTarget === "none") {
|
|
179360
179360
|
return [];
|
|
179361
179361
|
}
|
|
179362
|
-
const skillNames = input.command === "init" ? [...INIT_SKILL_NAMES] : [...INIT_WITH_AGENT_SKILL_NAMES];
|
|
179363
179362
|
const destinations = agentDestinations(input.agentTarget);
|
|
179364
179363
|
const availableSkills = new Set(listDistributableSkills(input.packageRoot));
|
|
179365
179364
|
const operations = [];
|
|
179366
179365
|
for (const destination of destinations) {
|
|
179367
|
-
for (const skillName of
|
|
179366
|
+
for (const skillName of INIT_SKILL_NAMES) {
|
|
179368
179367
|
if (!availableSkills.has(skillName)) {
|
|
179369
179368
|
continue;
|
|
179370
179369
|
}
|
|
179371
179370
|
const destinationDir = join5(input.projectRoot, destination, skillName);
|
|
179371
|
+
const path = relative3(input.projectRoot, destinationDir);
|
|
179372
|
+
if (isSymlink(destinationDir)) {
|
|
179373
|
+
input.messages.push(`Skill directory ${path} is a symlink and was left in place.`);
|
|
179374
|
+
continue;
|
|
179375
|
+
}
|
|
179372
179376
|
const exists = existsSync2(destinationDir);
|
|
179373
179377
|
let action;
|
|
179374
179378
|
let reason;
|
|
@@ -179384,10 +179388,44 @@ function planSkillOperations(input) {
|
|
|
179384
179388
|
}
|
|
179385
179389
|
operations.push({
|
|
179386
179390
|
action,
|
|
179387
|
-
path
|
|
179391
|
+
path,
|
|
179388
179392
|
reason
|
|
179389
179393
|
});
|
|
179390
179394
|
}
|
|
179395
|
+
operations.push(...planLegacySkillOperations({
|
|
179396
|
+
projectRoot: input.projectRoot,
|
|
179397
|
+
destination,
|
|
179398
|
+
options: input.options,
|
|
179399
|
+
messages: input.messages
|
|
179400
|
+
}));
|
|
179401
|
+
}
|
|
179402
|
+
return operations;
|
|
179403
|
+
}
|
|
179404
|
+
function planLegacySkillOperations(input) {
|
|
179405
|
+
const operations = [];
|
|
179406
|
+
const leftover = [];
|
|
179407
|
+
for (const skillName of LEGACY_SKILL_NAMES) {
|
|
179408
|
+
const destinationDir = join5(input.projectRoot, input.destination, skillName);
|
|
179409
|
+
const path = relative3(input.projectRoot, destinationDir);
|
|
179410
|
+
if (isSymlink(destinationDir)) {
|
|
179411
|
+
input.messages.push(`Skill directory ${path} is a symlink and was left in place.`);
|
|
179412
|
+
continue;
|
|
179413
|
+
}
|
|
179414
|
+
if (!existsSync2(destinationDir)) {
|
|
179415
|
+
continue;
|
|
179416
|
+
}
|
|
179417
|
+
if (input.options.force) {
|
|
179418
|
+
operations.push({
|
|
179419
|
+
action: input.options.dryRun ? "would-remove" : "remove",
|
|
179420
|
+
path,
|
|
179421
|
+
reason: "Remove leftover skill from the previous five-skill layout."
|
|
179422
|
+
});
|
|
179423
|
+
} else {
|
|
179424
|
+
leftover.push(path);
|
|
179425
|
+
}
|
|
179426
|
+
}
|
|
179427
|
+
if (leftover.length > 0) {
|
|
179428
|
+
input.messages.push(`Legacy DocBridge skill directories were left in place (${leftover.join(", ")}). Re-run with --force to remove them after reviewing local edits.`);
|
|
179391
179429
|
}
|
|
179392
179430
|
return operations;
|
|
179393
179431
|
}
|
|
@@ -179396,27 +179434,24 @@ function buildAgentGuidance(projectRoot, agentTarget) {
|
|
|
179396
179434
|
if (agentTarget === "codex" || agentTarget === "both") {
|
|
179397
179435
|
guidance.push({
|
|
179398
179436
|
agent: "codex",
|
|
179399
|
-
destination: ".agents/skills/docbridge
|
|
179400
|
-
oneShotCommand: `cd ${projectRoot} &&
|
|
179437
|
+
destination: ".agents/skills/docbridge/",
|
|
179438
|
+
oneShotCommand: `cd ${projectRoot} && codex --prompt "Use the docbridge skill to adopt DocBridge in this repository."`,
|
|
179401
179439
|
fallbackPrompt: buildFallbackPrompt(projectRoot, "codex")
|
|
179402
179440
|
});
|
|
179403
179441
|
}
|
|
179404
179442
|
if (agentTarget === "claude" || agentTarget === "both") {
|
|
179405
179443
|
guidance.push({
|
|
179406
179444
|
agent: "claude",
|
|
179407
|
-
destination: ".claude/skills/docbridge
|
|
179408
|
-
oneShotCommand: `cd ${projectRoot} && /docbridge
|
|
179445
|
+
destination: ".claude/skills/docbridge/",
|
|
179446
|
+
oneShotCommand: `cd ${projectRoot} && /docbridge adopt DocBridge in this repository`,
|
|
179409
179447
|
fallbackPrompt: buildFallbackPrompt(projectRoot, "claude")
|
|
179410
179448
|
});
|
|
179411
179449
|
}
|
|
179412
|
-
for (const entry of guidance) {
|
|
179413
|
-
entry.oneShotCommand = entry.oneShotCommand.replace("$docbridge_adopt_prompt", 'codex --prompt "Use the docbridge-adopt skill to adopt DocBridge in this repository."');
|
|
179414
|
-
}
|
|
179415
179450
|
return guidance;
|
|
179416
179451
|
}
|
|
179417
179452
|
function buildFallbackPrompt(projectRoot, agent) {
|
|
179418
|
-
const invocation = agent === "claude" ? "Use the docbridge
|
|
179419
|
-
return `${invocation} to adopt DocBridge in ${projectRoot}. Confirm docs and code scope, create or improve docbridge.config.json,
|
|
179453
|
+
const invocation = agent === "claude" ? "Use the docbridge skill" : "Use the docbridge skill from .agents/skills/docbridge";
|
|
179454
|
+
return `${invocation} to adopt DocBridge in ${projectRoot}. Confirm docs and code scope, create or improve docbridge.config.json, and suggest the next linking steps.`;
|
|
179420
179455
|
}
|
|
179421
179456
|
function resolveInitAgentTarget(discovery, options) {
|
|
179422
179457
|
if (options.agentTarget !== undefined) {
|
|
@@ -179481,12 +179516,21 @@ function agentDestinations(agentTarget) {
|
|
|
179481
179516
|
return [];
|
|
179482
179517
|
}
|
|
179483
179518
|
}
|
|
179519
|
+
function isSymlink(path) {
|
|
179520
|
+
try {
|
|
179521
|
+
return lstatSync2(path).isSymbolicLink();
|
|
179522
|
+
} catch {
|
|
179523
|
+
return false;
|
|
179524
|
+
}
|
|
179525
|
+
}
|
|
179484
179526
|
function formatFileOp(operation) {
|
|
179485
179527
|
let label = operation.action;
|
|
179486
179528
|
if (operation.action === "would-create") {
|
|
179487
179529
|
label = "would create";
|
|
179488
179530
|
} else if (operation.action === "would-overwrite") {
|
|
179489
179531
|
label = "would overwrite";
|
|
179532
|
+
} else if (operation.action === "would-remove") {
|
|
179533
|
+
label = "would remove";
|
|
179490
179534
|
}
|
|
179491
179535
|
const reason = operation.reason ? ` (${operation.reason})` : "";
|
|
179492
179536
|
return `- ${label} ${operation.path}${reason}`;
|
|
@@ -179859,9 +179903,9 @@ var COMMAND_DOCS = {
|
|
|
179859
179903
|
},
|
|
179860
179904
|
init: {
|
|
179861
179905
|
usage: "[options]",
|
|
179862
|
-
summary: "Use once per project to set up config and agent
|
|
179906
|
+
summary: "Use once per project to set up config and the agent skill.",
|
|
179863
179907
|
description: [
|
|
179864
|
-
"Create docbridge.config.json and install the DocBridge agent
|
|
179908
|
+
"Create docbridge.config.json and install the DocBridge agent skill.",
|
|
179865
179909
|
"Use it once per project, when adopting DocBridge. Run it with --dry-run",
|
|
179866
179910
|
"first to see what would be written."
|
|
179867
179911
|
].join(`
|
|
@@ -179878,7 +179922,7 @@ var COMMAND_DOCS = {
|
|
|
179878
179922
|
usage: "[options]",
|
|
179879
179923
|
summary: "Use to let a coding agent decide the setup instead of `init`.",
|
|
179880
179924
|
description: [
|
|
179881
|
-
"Install the docbridge
|
|
179925
|
+
"Install the docbridge skill and print the commands that let a coding",
|
|
179882
179926
|
"agent finish the setup.",
|
|
179883
179927
|
"Use it instead of `init` when an agent should decide the configuration",
|
|
179884
179928
|
"rather than accepting the defaults."
|
|
@@ -180021,7 +180065,15 @@ function hasHelpFlag(args) {
|
|
|
180021
180065
|
}
|
|
180022
180066
|
|
|
180023
180067
|
// src/cli/init.ts
|
|
180024
|
-
import {
|
|
180068
|
+
import {
|
|
180069
|
+
cpSync,
|
|
180070
|
+
lstatSync as lstatSync3,
|
|
180071
|
+
mkdirSync as mkdirSync2,
|
|
180072
|
+
readFileSync as readFileSync5,
|
|
180073
|
+
rmSync,
|
|
180074
|
+
statSync as statSync3,
|
|
180075
|
+
writeFileSync
|
|
180076
|
+
} from "node:fs";
|
|
180025
180077
|
import { join as join8, resolve as resolve3 } from "node:path";
|
|
180026
180078
|
|
|
180027
180079
|
// src/core/init-discovery.ts
|
|
@@ -180494,15 +180546,31 @@ function executeFileOperation(projectRoot, operation) {
|
|
|
180494
180546
|
}
|
|
180495
180547
|
}
|
|
180496
180548
|
function executeSkillOperation(projectRoot, packageRoot, operation) {
|
|
180549
|
+
const destinationDir = join8(projectRoot, operation.path);
|
|
180550
|
+
if (operation.action === "remove") {
|
|
180551
|
+
try {
|
|
180552
|
+
if (lstatSync3(destinationDir).isSymbolicLink()) {
|
|
180553
|
+
return;
|
|
180554
|
+
}
|
|
180555
|
+
} catch {
|
|
180556
|
+
return;
|
|
180557
|
+
}
|
|
180558
|
+
rmSync(destinationDir, { recursive: true, force: true });
|
|
180559
|
+
return;
|
|
180560
|
+
}
|
|
180497
180561
|
if (operation.action !== "create" && operation.action !== "overwrite") {
|
|
180498
180562
|
return;
|
|
180499
180563
|
}
|
|
180564
|
+
try {
|
|
180565
|
+
if (lstatSync3(destinationDir).isSymbolicLink()) {
|
|
180566
|
+
return;
|
|
180567
|
+
}
|
|
180568
|
+
} catch {}
|
|
180500
180569
|
const skillName = operation.path.split("/").at(-1);
|
|
180501
180570
|
if (skillName === undefined) {
|
|
180502
180571
|
return;
|
|
180503
180572
|
}
|
|
180504
180573
|
const sourceDir = join8(packageRoot, "templates", "skills", skillName);
|
|
180505
|
-
const destinationDir = join8(projectRoot, operation.path);
|
|
180506
180574
|
mkdirSync2(destinationDir, { recursive: true });
|
|
180507
180575
|
cpSync(sourceDir, destinationDir, { recursive: true, force: true });
|
|
180508
180576
|
}
|
|
@@ -180560,6 +180628,7 @@ function runCheck(options, io) {
|
|
|
180560
180628
|
|
|
180561
180629
|
` : "";
|
|
180562
180630
|
io.stdout(`${body}${formatSummary(result.summary)}
|
|
180631
|
+
See \`docbridge docs show troubleshooting\` for diagnostic codes and fixes.
|
|
180563
180632
|
`);
|
|
180564
180633
|
if (result.diagnostics.some((diagnostic) => diagnostic.code === "config_file_invalid")) {
|
|
180565
180634
|
const guidance = existsSync4(join9(projectRoot, CONFIG_FILE_NAME)) ? configRepairGuidance() : configSetupGuidance();
|
|
@@ -5,22 +5,32 @@ description: Wire DocBridge into coding agents, Git hooks, and CI.
|
|
|
5
5
|
# Agent Integration
|
|
6
6
|
|
|
7
7
|
DocBridge gives coding agents deterministic link data instead of asking them
|
|
8
|
-
to infer documentation relationships from filenames.
|
|
8
|
+
to infer documentation relationships from filenames. An agent can do the whole
|
|
9
|
+
job from `docbridge --help` plus `docbridge docs list` / `docbridge docs show`.
|
|
10
|
+
A project skill is an accelerator, not a prerequisite.
|
|
9
11
|
|
|
10
12
|
<!-- @code src/cli/init.ts#runInitWithAgent -->
|
|
11
13
|
|
|
12
|
-
##
|
|
14
|
+
## Invoking DocBridge
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
Run DocBridge with the project's native invocation: `docbridge` on `PATH`, a
|
|
17
|
+
repo recipe such as `just check`, or
|
|
18
|
+
`bun run /path/to/docbridge/src/cli/index.ts`.
|
|
19
|
+
|
|
20
|
+
`docbridge init` can create `docbridge.config.json` and copy the distributable
|
|
21
|
+
`docbridge` skill for Codex, Claude Code, or both. To let an agent decide the
|
|
22
|
+
scope, run:
|
|
16
23
|
|
|
17
24
|
```sh
|
|
18
25
|
docbridge init-with-agent --agent-target codex
|
|
19
26
|
```
|
|
20
27
|
|
|
21
28
|
Use `claude` or `both` for other supported targets. The command installs the
|
|
22
|
-
|
|
23
|
-
|
|
29
|
+
skill and prints the next command or prompt; it does not launch an agent
|
|
30
|
+
process.
|
|
31
|
+
|
|
32
|
+
<!-- @code src/core/context.ts#context -->
|
|
33
|
+
<!-- @code src/core/related.ts#related -->
|
|
24
34
|
|
|
25
35
|
## Editing workflow
|
|
26
36
|
|
|
@@ -36,8 +46,17 @@ After editing, inspect the change set:
|
|
|
36
46
|
git diff --name-only | docbridge related --stdin --gate
|
|
37
47
|
```
|
|
38
48
|
|
|
39
|
-
For every reported counterpart,
|
|
40
|
-
|
|
49
|
+
For every reported counterpart, choose one of three judgments:
|
|
50
|
+
|
|
51
|
+
- Update the counterpart when behavior, contract, format, or constraint
|
|
52
|
+
diverged.
|
|
53
|
+
- Leave it unchanged, with a written justification that cites the counterpart
|
|
54
|
+
content, when the change is internal and every documented statement still
|
|
55
|
+
holds.
|
|
56
|
+
- Fix the link itself when the annotation pair points at the wrong section or
|
|
57
|
+
symbol.
|
|
58
|
+
|
|
59
|
+
Do not detach a link only to silence the gate.
|
|
41
60
|
|
|
42
61
|
## Hooks
|
|
43
62
|
|
|
@@ -68,3 +87,10 @@ Run `docbridge check` over the whole project as the hard link-validity gate. A
|
|
|
68
87
|
pull-request workflow can additionally pass the base-to-head changed file list
|
|
69
88
|
to `related --stdin --gate` and attach `context` output for reviewers. Ensure
|
|
70
89
|
the checkout includes both commits needed for the diff.
|
|
90
|
+
|
|
91
|
+
## Read more
|
|
92
|
+
|
|
93
|
+
Run `docbridge docs list` for the full menu of packaged guides, then
|
|
94
|
+
`docbridge docs show <name>` for a page. Start with `getting-started`,
|
|
95
|
+
`annotations`, `linking-workflow`, `link-review`, `troubleshooting`, and
|
|
96
|
+
`commands`.
|
package/docs/user/annotations.md
CHANGED
|
@@ -7,6 +7,23 @@ description: Write @doc and @code annotations and valid link targets.
|
|
|
7
7
|
DocBridge links supported code declarations to Markdown headings. A complete
|
|
8
8
|
pair has `@doc` on the declaration and `@code` immediately before the heading.
|
|
9
9
|
|
|
10
|
+
<!-- @code src/core/links.ts#parseLinkTarget -->
|
|
11
|
+
|
|
12
|
+
## Target grammar
|
|
13
|
+
|
|
14
|
+
Both `@doc` and `@code` take a `file#fragment` target:
|
|
15
|
+
|
|
16
|
+
- The file path is project-root-relative and uses `/` separators.
|
|
17
|
+
- `./`, `../`, and absolute paths are invalid.
|
|
18
|
+
- The fragment is required. File-only, fragment-only, and same-file targets
|
|
19
|
+
are invalid.
|
|
20
|
+
- Optional text after the target is allowed and ignored
|
|
21
|
+
(`@doc docs/auth.md#login-spec human note`).
|
|
22
|
+
|
|
23
|
+
One declaration may carry multiple `@doc` tags, and one heading may carry
|
|
24
|
+
multiple `@code` comments. Each pair is an independent link. Duplicate
|
|
25
|
+
annotations from the same source to the same target produce `duplicate_link`.
|
|
26
|
+
|
|
10
27
|
## Code to documentation
|
|
11
28
|
|
|
12
29
|
Use a documentation path and heading anchor in a declaration's documentation
|
|
@@ -19,14 +36,106 @@ comment:
|
|
|
19
36
|
export function login(): void {}
|
|
20
37
|
```
|
|
21
38
|
|
|
22
|
-
|
|
23
|
-
|
|
39
|
+
```swift
|
|
40
|
+
/// @doc docs/auth.md#login-flow
|
|
41
|
+
public func login(email: String, password: String) {}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
```dart
|
|
45
|
+
/// @doc docs/auth.md#login-flow
|
|
46
|
+
void login(String email, String password) {}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
```rust
|
|
50
|
+
/// @doc docs/auth.md#login-flow
|
|
51
|
+
pub fn login(email: &str, password: &str) {}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Swift, Dart, and Rust use their normal documentation comment syntax. Paths are
|
|
55
|
+
relative to the configured project root.
|
|
56
|
+
|
|
57
|
+
An `@doc` on an unsupported declaration produces `unsupported_declaration`. The
|
|
58
|
+
same declaration without `@doc` is ignored.
|
|
59
|
+
|
|
60
|
+
### TypeScript
|
|
61
|
+
|
|
62
|
+
Supported top-level exported forms: `function`, `class`, `abstract class`,
|
|
63
|
+
`interface`, `type`, `enum`, `const enum`, `const` with a single declarator,
|
|
64
|
+
named default `function`/`class`, and their `declare` forms in `.ts` files.
|
|
65
|
+
Type members are also supported: class methods, properties, getters, setters,
|
|
66
|
+
constructors, and static members; interface property and method signatures;
|
|
67
|
+
and property and method signatures of a type alias written as an object type
|
|
68
|
+
literal.
|
|
69
|
+
|
|
70
|
+
By default, `public` and `protected` members are included; `private` members
|
|
71
|
+
are included only when `include.code.typescript.visibility` lists `private`.
|
|
72
|
+
TypeScript `visibility` applies only to type members. Top-level declarations
|
|
73
|
+
are scoped by `export`. Members excluded by visibility are not endpoints; an
|
|
74
|
+
`@doc` on one is `unsupported_declaration`.
|
|
75
|
+
|
|
76
|
+
Unsupported examples include anonymous default exports, multi-declarator
|
|
77
|
+
`const`, namespaces, re-exports, non-exported declarations, members whose name
|
|
78
|
+
is not a plain identifier, enum members, index signatures, call and construct
|
|
79
|
+
signatures, and constructor parameter properties.
|
|
80
|
+
|
|
81
|
+
Canonical IDs omit parameter signatures (`AuthService.login`,
|
|
82
|
+
`AuthService.constructor`).
|
|
83
|
+
|
|
84
|
+
### Swift
|
|
85
|
+
|
|
86
|
+
Supported forms include top-level and member `class`, `struct`, `enum`,
|
|
87
|
+
`protocol`, and `actor`; top-level and member `func`, `var`, `let`, and
|
|
88
|
+
`init`; and members declared in extensions, canonicalized as members of the
|
|
89
|
+
extended type.
|
|
90
|
+
|
|
91
|
+
By default only `public` and `open` declarations are included. `internal`
|
|
92
|
+
declarations are included when `include.code.swift.visibility` lists
|
|
93
|
+
`internal`. An `@doc` on a visibility-excluded declaration is
|
|
94
|
+
`unsupported_declaration`.
|
|
95
|
+
|
|
96
|
+
Member IDs are type-qualified and include argument labels, for example
|
|
97
|
+
`AuthService.login(email:password:)`, `AuthService.refresh(_:)`, and
|
|
98
|
+
`AuthService.init(email:password:)`.
|
|
99
|
+
|
|
100
|
+
### Dart
|
|
101
|
+
|
|
102
|
+
Supported forms include top-level functions, getters, setters, and variables;
|
|
103
|
+
`class`, `enum`, `mixin`, and their members; and members declared in
|
|
104
|
+
extensions, canonicalized as members of the extended type.
|
|
105
|
+
|
|
106
|
+
Only public declarations are scanned. Dart marks library-private names with a
|
|
107
|
+
leading `_`, so an endpoint is excluded when any segment of its canonical ID
|
|
108
|
+
starts with `_`, including a public member of a `_Private` type.
|
|
109
|
+
`include.code.dart.visibility` accepts only `public`. An `@doc` on a
|
|
110
|
+
visibility-excluded declaration is `unsupported_declaration`.
|
|
111
|
+
|
|
112
|
+
Member IDs omit parameter signatures (`AuthService.login`). Setters carry a
|
|
113
|
+
trailing `=` (`AuthService.token=`). The unnamed constructor is
|
|
114
|
+
`AuthService.new`; named constructors keep their name (`AuthService.guest`).
|
|
115
|
+
|
|
116
|
+
### Rust
|
|
117
|
+
|
|
118
|
+
Supported forms are `mod` (including nested modules), `struct`, `enum`, free
|
|
119
|
+
`fn`, and inherent `impl` methods. Trait definitions, trait-impl methods,
|
|
120
|
+
macros, const/static items, unions, and extern blocks are unsupported.
|
|
121
|
+
|
|
122
|
+
By default only unrestricted `pub` declarations are included. A plain `fn` or
|
|
123
|
+
`struct` without `pub` is not an endpoint. Non-`pub` items are included when
|
|
124
|
+
`include.code.rust.visibility` lists `private`. An `@doc` on a
|
|
125
|
+
visibility-excluded declaration is `unsupported_declaration`.
|
|
126
|
+
|
|
127
|
+
Canonical IDs use `::` path qualification, for example `normalize`,
|
|
128
|
+
`TypingEngine`, `TypingEngine::advance`, and `domain::typing`.
|
|
24
129
|
|
|
25
130
|
<!-- @code src/core/markdown.ts#scanMarkdown -->
|
|
26
131
|
|
|
27
132
|
## Documentation to code
|
|
28
133
|
|
|
29
|
-
Place
|
|
134
|
+
Place a standalone HTML comment immediately before the linked heading. The
|
|
135
|
+
comment may be indented by 0 to 3 spaces; 4 or more spaces are ignored. The
|
|
136
|
+
trimmed comment body must start with `@code`. Blank lines between the comment
|
|
137
|
+
and the heading are allowed. Any other text in between produces
|
|
138
|
+
`dangling_code_annotation`.
|
|
30
139
|
|
|
31
140
|
```md
|
|
32
141
|
<!-- @code src/auth.ts#login -->
|
|
@@ -35,16 +144,28 @@ Place an HTML comment immediately before the linked heading:
|
|
|
35
144
|
```
|
|
36
145
|
|
|
37
146
|
The code fragment is the canonical symbol ID emitted by the language scanner.
|
|
38
|
-
|
|
39
|
-
their type-qualified identity. TypeScript member IDs omit parameter signatures,
|
|
40
|
-
Swift member IDs include argument labels, Dart member IDs omit parameter
|
|
41
|
-
signatures, and Rust member IDs use `::` path qualification.
|
|
147
|
+
Use that ID exactly in the `@code` target.
|
|
42
148
|
|
|
43
149
|
## Anchors and reciprocity
|
|
44
150
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
151
|
+
Anchors come from ATX headings (`#` through `######`) only. Setext headings
|
|
152
|
+
have no anchors. Empty headings do not create linkable anchors; a `@code`
|
|
153
|
+
attached to an empty heading is `dangling_code_annotation`.
|
|
154
|
+
|
|
155
|
+
The algorithm:
|
|
156
|
+
|
|
157
|
+
1. Take the heading text after the `#` markers.
|
|
158
|
+
2. Lowercase with JavaScript `toLowerCase()`.
|
|
159
|
+
3. Collapse runs of whitespace and punctuation to `-`. Unicode letters and
|
|
160
|
+
numbers are preserved.
|
|
161
|
+
4. Strip leading and trailing `-`.
|
|
162
|
+
|
|
163
|
+
Example: `## Login Spec (v2)` becomes `#login-spec-v2`. `# Login Flow`
|
|
164
|
+
becomes `#login-flow`.
|
|
165
|
+
|
|
166
|
+
Duplicate non-empty anchors in the same Markdown file produce
|
|
167
|
+
`duplicate_doc_anchor`. The same anchor in different files is allowed.
|
|
168
|
+
DocBridge does not add GitHub-style numeric suffixes.
|
|
48
169
|
|
|
49
170
|
Each direction is validated independently. A target can resolve while still
|
|
50
171
|
reporting a missing reciprocal annotation. Run `docbridge check` to validate
|