@nikovirtala/adr 0.3.0 → 0.5.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.
Files changed (45) hide show
  1. package/README.md +62 -13
  2. package/dist/cli.js +208 -48
  3. package/dist/cli.js.map +1 -1
  4. package/dist/index.js +5 -3
  5. package/dist/init-CaKKCINh.js +651 -0
  6. package/dist/init-CaKKCINh.js.map +1 -0
  7. package/dist/{kind-DjvA3dyA.js → kind-C3DiBuUp.js} +44 -11
  8. package/dist/kind-C3DiBuUp.js.map +1 -0
  9. package/dist/kind.js +1 -1
  10. package/dist/list-CJi9vZqJ.js +58 -0
  11. package/dist/list-CJi9vZqJ.js.map +1 -0
  12. package/dist/{scope-CLqH-q1y.js → search-CTspg2pd.js} +644 -550
  13. package/dist/search-CTspg2pd.js.map +1 -0
  14. package/dist/server-D3ySzyj6.js +950 -0
  15. package/dist/server-D3ySzyj6.js.map +1 -0
  16. package/dist/types/cli/init.d.ts +5 -2
  17. package/dist/types/cli/list.d.ts +4 -1
  18. package/dist/types/cli/mcp.d.ts +6 -0
  19. package/dist/types/cli/search.d.ts +6 -0
  20. package/dist/types/cli/text.d.ts +6 -0
  21. package/dist/types/commit-actions.d.ts +23 -1
  22. package/dist/types/hooks.d.ts +3 -2
  23. package/dist/types/index.d.ts +7 -3
  24. package/dist/types/init.d.ts +16 -1
  25. package/dist/types/kind/rules.d.ts +23 -2
  26. package/dist/types/kind.d.ts +1 -1
  27. package/dist/types/log-index.d.ts +0 -18
  28. package/dist/types/log.d.ts +13 -0
  29. package/dist/types/mcp/policy.d.ts +33 -0
  30. package/dist/types/mcp/prompt.d.ts +7 -0
  31. package/dist/types/mcp/resources.d.ts +16 -0
  32. package/dist/types/mcp/server.d.ts +16 -0
  33. package/dist/types/mcp/text.d.ts +42 -0
  34. package/dist/types/mcp/tools.d.ts +27 -0
  35. package/dist/types/scope.d.ts +3 -1
  36. package/dist/types/search.d.ts +63 -0
  37. package/dist/types/skill.d.ts +5 -0
  38. package/dist/types/sources.d.ts +35 -0
  39. package/dist/types/templates/list.d.ts +31 -0
  40. package/dist/types/verify.d.ts +20 -4
  41. package/dist/types/views.d.ts +5 -1
  42. package/dist/types/write.d.ts +76 -5
  43. package/package.json +5 -2
  44. package/dist/kind-DjvA3dyA.js.map +0 -1
  45. package/dist/scope-CLqH-q1y.js.map +0 -1
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Architecture decision records kept as event logs in git, built on [`@nikovirtala/ledger`](https://www.npmjs.com/package/@nikovirtala/ledger). A decision is a Markdown body plus append-only event files. Its status (proposed, accepted, rejected, withdrawn, deprecated, superseded) is computed from the events, the body is frozen by its hash once accepted, and supersession chains always lead to the decision in force. See the [design doc](https://github.com/nikovirtala/ark/blob/main/docs/01-adr-v1.md).
4
4
 
5
- Released at 0.x. Phase 1 ("Core") brought the decision kind, the library and the `adr` CLI with `new`, `accept`, `supersede`, `list`, `show` and `verify`. Phase 2a ("Commands and Scope") adds `init`, `reject`, `withdraw`, `deprecate`, `note`, `link`, `scope` and `for`, `accept --copy-scope`, Conventional Commits messages for `--commit`, and `ARK_ON_BEHALF_OF` for agents. Phase 2b ("Guardrails") adds git hooks (`adr hooks`), a generated `index.md` that every write keeps fresh (`adr index`), display numbers in shallow clones read from that index, `list --since`, a recovery hint when git refuses a `--commit`, and verify checks for scope globs, code anchors, changes under inactive decisions and narrowed scopes.
5
+ Released at 0.x. Phase 1 ("Core") brought the decision kind, the library and the `adr` CLI with `new`, `accept`, `supersede`, `list`, `show` and `verify`. Phase 2a ("Commands and Scope") adds `init`, `reject`, `withdraw`, `deprecate`, `note`, `link`, `scope` and `for`, `accept --copy-scope`, Conventional Commits messages for `--commit`, and `ARK_ON_BEHALF_OF` for agents. Phase 2b ("Guardrails") adds git hooks (`adr hooks`), a generated `index.md` that every write keeps fresh (`adr index`), display numbers in shallow clones read from that index, `list --since`, a recovery hint when git refuses a `--commit`, and verify checks for scope globs, code anchors, changes under inactive decisions and narrowed scopes. 0.5.0 checks references into other repositories' decision logs against a local cache (`verify --fetch-sources`, `adr sources fetch`, `list --source`, `search --source`), re-checks every decision in `verify --staged` when a staged config or template changes, lets proposed decisions name code that doesn't exist yet, and names batches of staged events in default commit subjects.
6
6
 
7
7
  ## Install
8
8
 
@@ -32,6 +32,8 @@ Each decision has a canonical id (`k3f9q8a1`). Accepted decisions also get a num
32
32
  ```sh
33
33
  # Set up: write adr.toml and starter templates; never overwrites a file.
34
34
  adr init --template nygard --template madr --commit
35
+ adr init --skill # also the agent skill and an AGENTS.md pointer
36
+ adr init --skill --skill-dir .kiro/skills/adr
35
37
 
36
38
  # Propose: render a draft from a template, write the body and the proposed event, and stage them.
37
39
  adr new "Use Aurora for orders" --section context="We need SQL." --section scope=services/orders
@@ -67,10 +69,19 @@ adr list --since ORIG_HEAD # only decisions with events added si
67
69
  adr show ADR-0001 --history
68
70
  adr list --ref v1.2.0 # time travel: the log as of any ref
69
71
 
72
+ # Search ids, titles, bodies and notes: every word must match; active decisions unless --all.
73
+ adr search orders aurora
74
+ adr search dynamodb --all
75
+
70
76
  # Verify the log: the whole tree, a range, or the staged changes (for a pre-commit hook).
71
77
  adr verify
72
78
  adr verify --base origin/main --format github
73
79
  adr verify --staged
80
+ adr verify --fetch-sources # fetch [[sources]] first (CI, pre-push); a failed fetch exits 2
81
+
82
+ # Other repositories' decision logs, read from a local cache.
83
+ adr sources fetch [<name>]
84
+ adr list --source platform
74
85
 
75
86
  # The generated index (with [log] index = "committed"): regenerate it, or check that it is current.
76
87
  adr index
@@ -79,20 +90,25 @@ adr index --check
79
90
  # Git hooks: install adr in ledger's shared hook shims, or print the config for a hook manager.
80
91
  adr hooks install
81
92
  adr hooks print --manager lefthook
93
+
94
+ # The MCP server for agents, over stdio; start it from an MCP client (see "MCP server").
95
+ adr mcp
82
96
  ```
83
97
 
84
98
  - `new` takes `--template <name>` (default `nygard`; built-ins `nygard`, `madr`, `y-statement`, or your own `<root>/templates/<name>.md`), `--section <id>=<markdown>` (repeatable), `--supersedes <decision>` (repeatable), and `--edit`/`--no-edit`. It opens `$VISUAL` or `$EDITOR` with `--edit`, or by default in an interactive terminal; an editor failure never loses your edits and never commits content you didn't confirm.
85
99
  - `new --no-edit --commit` (or `--commit` with no editor) refuses a draft with unfilled required sections: exit 1, nothing written. Without `--commit` the draft is staged with a warning on stderr; after an editor, a draft that still has unfilled sections stays staged and isn't committed.
86
100
  - `accept` of a decision that supersedes others offers their scope globs: `--copy-scope` copies them in the same write, `--no-copy-scope` doesn't, and without either it asks `[y/N]` in a terminal and otherwise prints the `adr scope … --add …` command that would copy them.
87
- - `scope` takes `--set <glob>` (repeatable; replaces the set), `--add`/`--remove <glob>` (repeatable) or `--clear`, and stores the set sorted and deduplicated. It notes a glob that matches no tracked file and a narrowing of an accepted decision. verify requires the globs of proposed and accepted decisions to match tracked files (`scope/glob-unmatched`), so with hooks installed `adr scope <proposed> --set 'src/payments/**' --commit` for code not written yet writes and stages the scope, then fails in pre-commit with the recovery hint below, and its note says so. To finish it, commit the code the glob should match first (`git add` it, then `git commit -m "<subject>" -- <its paths>`) and then run the printed command, or `git add` the code and append its paths after `--` in the printed command. `scope --follow-renames [<decision>]` updates the globs of every decision (or one) for the staged renames, so a moved file stays governed, and only stages.
101
+ - `scope` takes `--set <glob>` (repeatable; replaces the set), `--add`/`--remove <glob>` (repeatable) or `--clear`, and stores the set sorted and deduplicated. It notes a glob that matches no tracked file and a narrowing of an accepted decision. verify requires the globs of accepted decisions to match tracked files (`scope/glob-unmatched`). A proposed decision's globs may name code that doesn't exist yet, because the decision is still planned, and the note says verify reports them once it is accepted; `adr accept` notes each glob that still matches nothing, so with hooks installed an `accept --commit` fails in pre-commit until the code is there. `scope --follow-renames [<decision>]` updates the globs of every decision (or one) for the staged renames, so a moved file stays governed, and only stages.
88
102
  - `for <path>…` lists the decisions governing each file, from scope globs and code anchors, with a warning for decisions that aren't in force. A code anchor is a comment such as `// adr:<id>` or `# adr:<source>:<id>`: the token counts only after a comment leader on the same line (a heuristic), and anchors in binary files, submodules, the log directory and files matched by `[scope] anchor_exclude` are not found.
89
- - Writes stage their files and don't commit, unless you pass `--commit` or set `auto_commit`. A commit holds every file of the decisions it touches (body, events, template), so `adr verify --ref <commit>` is clean, and never your unrelated staged work. It refuses with exit 2 when a file it needs has unstaged changes or isn't tracked. Its `ADR: <id>` and `ADR-Event: <type>` trailers name one event each, in a fixed order, whatever your `trailer.*` config.
90
- - `--commit` messages follow Conventional Commits: the subject comes from `[commit] subject` (default `docs(adr): {action} {title}`, for example `docs(adr): propose to use Aurora for orders`, `docs(adr): decide to use Aurora for orders`, `docs(adr): set the scope of ADR-0003`). The description starts with a lowercase letter and the rest keeps its natural casing (`Use` becomes `use`; `CLI`, `ARK_AGENT`, `GraphQL` and `Node 24` stay). `new`, `accept`, `reject` and `withdraw` name the decision by its title (`propose to`, `decide to`, `decide not to`, `withdraw the proposal to`), while `deprecate`, `supersede`, `note`, `link` and `scope` name it by its number or id. A title that would make the description longer than 72 characters is shortened with `…`, at a word boundary when one is near the limit, the body then starts with `Full title: <title>`, and a note says so; numbers and ids are never shortened. `-m/--message <text>` replaces the subject and body as given; a message that ends in its own trailer block as git reads it, such as `Co-authored-by:` or `Refs:` lines, gets adr's trailers appended to that paragraph. The trailers are always the last paragraph, so `git log --grep "ADR: <id>"` finds a decision's commits.
103
+ - Writes stage their files and don't commit, unless you pass `--commit` or set `auto_commit`. A commit holds every file of the decisions it touches (body, events, template), so `adr verify --ref <commit>` is clean, and never your unrelated staged work. It refuses with exit 2 when a file it needs has unstaged changes or isn't tracked. Its `ADR: <id>` and `ADR-Event: <type>` trailers come in one pair per decision and event type, in a fixed order, whatever your `trailer.*` config.
104
+ - `--commit` messages follow Conventional Commits: the subject comes from `[commit] subject` (default `docs(adr): {action} {title}`, for example `docs(adr): propose to use Aurora for orders`, `docs(adr): decide to use Aurora for orders`, `docs(adr): set the scope of ADR-0003`). The description starts with a lowercase letter and the rest keeps its natural casing (`Use` becomes `use`; `CLI`, `ARK_AGENT`, `GraphQL` and `Node 24` stay). `new`, `accept`, `reject` and `withdraw` name the decision by its title (`propose to`, `decide to`, `decide not to`, `withdraw the proposal to`), while `deprecate`, `supersede`, `note`, `link` and `scope` name it by its number or id. A title that would make the description longer than 72 characters is shortened with `…`, at a word boundary when one is near the limit, the body then starts with `Full title: <title>`, and a note says so, naming the 72-character limit of the description after `docs(adr):`; numbers and ids are never shortened. A commit that sweeps in staged events of other types names them together (`docs(adr): link and scope ADR-0003`, `update ADR-0003` beyond three verbs), and one that sweeps in a staged proposal or status change takes that event's title form (`docs(adr): propose to use SQS for jobs`). `-m/--message <text>` replaces the subject and body as given; a message that ends in its own trailer block as git reads it, such as `Co-authored-by:` or `Refs:` lines, gets adr's trailers appended to that paragraph. The trailers are always the last paragraph, so `git log --grep "ADR: <id>"` finds a decision's commits.
91
105
  - When git refuses a `--commit` (a failing hook, signing), the write stays written and staged, and adr exits 2 (`commit-failed`) with a recovery hint: git's error, the staged paths, the trailers, and the exact command that makes the commit, `git -C <top> commit --cleanup=whitespace -F <git dir>/ark/COMMIT_MSG --only -- <paths>`, with the full message saved in that file (edit it if needed, but keep the trailers). Don't run the adr command again: the log already holds the change, so a rerun would be refused, do nothing, or write it a second time. When `index.md` is among the paths, the hint ends with `Then run adr index --no-commit to restore other decisions' entries in docs/adr/index.md.` The notes the write would have reported are printed as warnings before the hint.
92
106
  - With `[log] index = "committed"`, every write keeps `<root>/index.md` current: the accepted and proposed decisions, then the superseded, deprecated, rejected and withdrawn ones, each with its number, linked title, status and date, and a last line recording the numbers. A `--commit` renders it from exactly the tree the commit holds and includes it whenever the commit changes it; the work-tree copy keeps other decisions' uncommitted entries. Numbers are projected: on a branch they are the numbers its acceptances will get once it merges, after main's (`[log] main_branch`), also when main was merged into the branch. When a write leaves the staged `index.md` listing another decision's untracked or unstaged files, it notes them, since the next plain commit's hook reports `index/stale` until they are staged. `adr index` regenerates and stages it, `adr index --commit` commits it as `docs(adr): regenerate the decision index`, and `adr index --check` exits 1 when it is stale or missing.
93
107
  - `list --since <rev>` lists only the decisions with event files added between `<rev>` and HEAD (or `--ref`), each with the new event types, such as `[new: accepted]`; it prints nothing when the log didn't change.
94
108
  - In a shallow clone, numbers need history the clone lacks. With a committed index, adr reads them from `index.md` in the commit being read (`--ref`, else HEAD) and notes `numbers come from docs/adr/index.md (shallow clone)`; without one, decisions display by id until you run `git fetch --unshallow`. Nothing is fetched automatically.
95
- - `hooks install` registers adr in ledger's shims, one per hook and shared with other ark tools: `pre-commit` runs `adr hooks run pre-commit`, `commit-msg` runs `adr hooks trailers` (adds `ADR:` and `ADR-Event:` trailers when event files are staged, unless the message has them or a merge is in progress), `pre-push` runs `adr verify --base @{upstream} --ref HEAD`, which checks the current branch's commits against its upstream whichever refs the push names (without an upstream, against `origin`'s default branch; with no remote, the whole log), and `post-merge` runs `adr list --since ORIG_HEAD`. It never overwrites a foreign hook (it writes the other hooks, exits 2 and names the line to add to that hook) and writes nothing when `core.hooksPath` is set (exit 2, pointing to `adr hooks print --manager lefthook|husky|pre-commit` for the hook manager in use). `hooks uninstall` removes adr from the shims. The pre-commit steps are rename following (`[hooks] scope_follow_renames`), the index (checked, or regenerated and staged with `[hooks] index = "stage"`), then `verify --staged`. The hook stages only into the commit's own index: for `git commit <paths>`, a rename that changes a decision's scope stops the commit and names the command to run. When the staged `index.md` lists decision files that aren't staged, the `index/stale` finding names them; stage them, or move them out of the work tree and run `adr index`.
109
+ - `hooks install` registers adr in ledger's shims, one per hook and shared with other ark tools: `pre-commit` runs `adr hooks run pre-commit`, `commit-msg` runs `adr hooks trailers` (adds `ADR:` and `ADR-Event:` trailers when event files are staged, unless the message has them or a merge is in progress), `pre-push` runs `adr verify --base @{upstream} --ref HEAD --fetch-sources` (rerun `adr hooks install` after upgrading from 0.4.x to get the flag), which checks the current branch's commits against its upstream whichever refs the push names (without an upstream, against `origin`'s default branch; with no remote, the whole log), and `post-merge` runs `adr list --since ORIG_HEAD`. It never overwrites a foreign hook (it writes the other hooks, exits 2 and names the line to add to that hook) and writes nothing when `core.hooksPath` is set (exit 2, pointing to `adr hooks print --manager lefthook|husky|pre-commit` for the hook manager in use). `hooks uninstall` removes adr from the shims. The pre-commit steps are rename following (`[hooks] scope_follow_renames`), the index (checked, or regenerated and staged with `[hooks] index = "stage"`), then `verify --staged`, which checks every decision when the staged changes touch `adr.toml` or the templates. The hook stages only into the commit's own index: for `git commit <paths>`, a rename that changes a decision's scope stops the commit and names the command to run. When the staged `index.md` lists decision files that aren't staged, the `index/stale` finding names them; stage them, or move them out of the work tree and run `adr index`.
110
+ - `search <query>…` joins its words and lists the decisions whose id, number, title, body or notes contain every one, case- and accent-insensitively (`Café` finds `cafe`), as substrings (`order` finds `orders`). Only proposed and accepted decisions are listed unless `--all`; a note counts the others that match. Each result has the best matching line of the body or a note. It reads the local log, or a cached source's with `--source <name>`.
111
+ - `init --skill` writes the agent skill to `.claude/skills/adr/SKILL.md`, or to `<dir>/SKILL.md` with `--skill-dir <dir>` (a directory inside the repository), and adds one line pointing at it to `AGENTS.md`, creating the file if needed. It never overwrites a SKILL.md (one that differs is kept, with a note), and a second run changes nothing. An `AGENTS.md` with unstaged changes, or not tracked, gets the line but isn't staged; with `--commit` it is refused (exit 2).
96
112
  - `show` leads with a state header. A decision that isn't in force says so and names what to read instead, for example `SUPERSEDED by ADR-0002 (accepted 2026-10-18). Do not apply this decision; read ADR-0002 instead.`
97
113
 
98
114
  Every command takes `--json`, `--root <dir>` (the log directory) and `--help`; reads also take `--ref <ref>`, and writes refuse it.
@@ -103,7 +119,7 @@ Every command takes `--json`, `--root <dir>` (the log directory) and `--help`; r
103
119
  - **1**: failing findings from `verify` (or `index --check`, or a hook), or a write the log's rules forbid (an illegal transition, a draft that fails its template lint, an agent's acceptance, an unaccepted successor). Nothing is written, and the findings are in the output.
104
120
  - **2**: the tool can't run: bad usage (unknown command, flag or decision, a missing argument, `--ref` on a write), config, environment or internal errors. Nothing is written, except when git refuses a `--commit` (`commit-failed`): the write is then staged and the error says how to finish the commit.
105
121
 
106
- With `--json`, stdout carries exactly one JSON document: `adr-list/v1` (with `since`, `null` without `--since`), `adr-show/v1`, `adr-write/v1` (for every write command), `adr-for/v1`, `adr-init/v1`, `adr-index/v1`, `adr-hooks/v1`, ledger's `ledger-findings/v1` for `verify`, or `ark-error/v1` (`{ "format": "ark-error/v1", "error": { "code", "message" } }`) when the command exits 2; a `commit-failed` error also has the write's `notes`. Every key is always present, with `null` where a value is unknown. A `numbering` object's `reason` is `"index"` when a shallow clone's numbers come from `index.md`. In a shallow clone with a committed index, `adr-write/v1`'s `decision.number` comes from the index in HEAD, which on a branch is the number the acceptance will get once the branch merges. Warnings and notes go to stderr.
122
+ With `--json`, stdout carries exactly one JSON document: `adr-list/v1` (with `since`, `null` without `--since`), `adr-show/v1`, `adr-search/v1`, `adr-write/v1` (for every write command), `adr-for/v1`, `adr-init/v1`, `adr-index/v1`, `adr-hooks/v1`, ledger's `ledger-findings/v1` for `verify`, or `ark-error/v1` (`{ "format": "ark-error/v1", "error": { "code", "message" } }`) when the command exits 2; a `commit-failed` error also has the write's `notes`. Every key is always present, with `null` where a value is unknown. A `numbering` object's `reason` is `"index"` when a shallow clone's numbers come from `index.md`. In a shallow clone with a committed index, `adr-write/v1`'s `decision.number` comes from the index in HEAD, which on a branch is the number the acceptance will get once the branch merges. Warnings and notes go to stderr.
107
123
 
108
124
  ## Config (`adr.toml`)
109
125
 
@@ -119,7 +135,7 @@ index = "none" # or "committed": adr index, fresh on every writ
119
135
  [policy]
120
136
  accept_requires_human = true # refuse acceptances by an agent
121
137
  auto_commit = false # commit writes without --commit
122
- mcp_can_decide = false # validated now, used in phase 3
138
+ mcp_can_decide = false # agents propose, humans decide; true adds adr_accept, adr_reject, adr_deprecate and adr_supersede to adr mcp
123
139
 
124
140
  [verify]
125
141
  fail_on = "error" # or "warning"
@@ -137,7 +153,9 @@ scope_follow_renames = "stage" # stage, warn or off: pre-commit's rename follow
137
153
  index = "check" # check, or stage to regenerate index.md in pre-commit
138
154
  ```
139
155
 
140
- verify also checks code against the log: `scope/glob-invalid` (error) for a stored glob that doesn't parse, `scope/glob-unmatched` (error) for a glob of a proposed or accepted decision that matches no tracked file, `scope/anchor-missing` (error) for an `adr:<id>` anchor naming no decision in the log (qualified anchors are checked in ark's step 4), `decision/governed-by-inactive` (a warning, or an error with `governed_by_inactive = "error"`) for a changed file governed by a superseded or deprecated decision, and `decision/scope-narrowed` (warning) when a new scope stops covering files that still exist. Deprecated decisions' globs no longer have to match files. With `index = "committed"`, `index/missing` and `index/stale` are errors, and `index/unchecked` warns in a shallow clone without a recorded index.
156
+ verify also checks code against the log: `scope/glob-invalid` (error) for a stored glob that doesn't parse, `scope/glob-unmatched` (error) for a glob of an accepted decision that matches no tracked file, `scope/anchor-missing` (error) for an `adr:<id>` anchor naming no decision in the log, `decision/governed-by-inactive` (a warning, or an error with `governed_by_inactive = "error"`) for a changed file governed by a superseded or deprecated decision, and `decision/scope-narrowed` (warning) when a new scope stops covering files that still exist. Deprecated decisions' globs no longer have to match files. With `index = "committed"`, `index/missing` and `index/stale` are errors, and `index/unchecked` warns in a shallow clone without a recorded index.
157
+
158
+ References into other repositories' decision logs (`platform:k3f9q8a1`, from `[[sources]]` entries with `kind = "adr"`) are checked against a local cache kept in the git directory. Plain `verify`, the hooks' pre-commit step and every read and write use only the cache and never the network: a referenced source that isn't cached gives one `sources/not-fetched` warning. `verify --fetch-sources` fetches each source first and exits 2 when a fetch fails; `adr sources fetch` refreshes the cache by hand, and `verify --json` records the commit each source resolved to. A missing target in a cached source is `decision/reference-missing`, and a source name that isn't configured `decision/unknown-source`. A ref may be a branch, a tag or a full commit; a tag or commit keeps CI reproducible. Fetching uses git's credentials: for a private source in CI, an `insteadOf` URL with a token from the CI secret store, or an SSH deploy key.
141
159
 
142
160
  `[commit] subject` is one line with `{title}` (what names the decision: its title with an ordinary capitalized first word lowercased (`Use` → `use`, so a single-capital proper noun such as `Aurora` loses that capital; `CLI`, `GraphQL` and `ARK_AGENT` stay), or its number or id), `{raw_title}` (the same with its case kept), `{action}`, `{id}`, `{display}` and `{command}`. It is checked when the config is read: at most one title placeholder, after the type and scope, and room within 72 characters for the title (20 characters) and, uncut, for the longest number-based name (`ADR-0001 to a decision in another log`); an invalid template exits 2. Whatever the template, the description's first letter is lowercased.
143
161
 
@@ -149,9 +167,41 @@ An agent using the CLI sets `ARK_AGENT=<agent-id>`, and `ARK_ON_BEHALF_OF=<email
149
167
 
150
168
  The git identity is git's author identity (`git var GIT_AUTHOR_IDENT` with `user.useConfigOnly`): `GIT_AUTHOR_NAME` and `GIT_AUTHOR_EMAIL` when set, else `user.name` and `user.email`; it is never guessed. Setting `GIT_AUTHOR_*` also changes the author of `--commit` commits, which is why agents should use `ARK_ON_BEHALF_OF` instead. `--commit` also needs a committer identity, and exits 2 before writing without one.
151
169
 
170
+ Agents with an MCP client use `adr mcp` instead (below), and `adr init --skill` gives them the skill: when to check the decisions, how to read them, and that they propose and a human accepts.
171
+
172
+ ## MCP server
173
+
174
+ `adr mcp` serves the decision log to agents over stdio, in the repository it starts in (`--root` works as for every command). Add it to your MCP client's server config:
175
+
176
+ ```json
177
+ {
178
+ "mcpServers": {
179
+ "adr": {
180
+ "command": "npx",
181
+ "args": ["-y", "@nikovirtala/adr", "mcp"],
182
+ "env": { "ARK_ON_BEHALF_OF": "you@example.com" }
183
+ }
184
+ }
185
+ }
186
+ ```
187
+
188
+ Set `ARK_ON_BEHALF_OF` in that `env`: stdio clients pass only a few environment variables (`HOME`, `PATH` and the like) to the server, so a value exported in your shell doesn't reach it. Writes are recorded as an agent named by the MCP client (`actor.agent`), on behalf of `ARK_ON_BEHALF_OF`, or of the git user, with a note. An invalid `ARK_ON_BEHALF_OF` makes `adr mcp` exit 2 before serving.
189
+
190
+ | Tools | Listed |
191
+ | --- | --- |
192
+ | `adr_search`, `adr_get`, `adr_list`, `adr_templates`, `adr_for_path` (reads) | always |
193
+ | `adr_propose`, `adr_update_draft`, `adr_note`, `adr_link`, `adr_scope`, `adr_withdraw` (writes) | always |
194
+ | `adr_accept`, `adr_reject`, `adr_deprecate`, `adr_supersede` | with `[policy] mcp_can_decide = true` |
195
+
196
+ - Every tool returns the JSON document its CLI command prints under `--json` (`adr-search/v1`, `adr-show/v1`, `adr-list/v1`, `adr-for/v1`, `adr-write/v1`, and `adr-templates/v1` for `adr_templates`) as `structuredContent`, with a readable text whose state headers come first and point at `adr://decision/<number>`. Errors are `isError` results with `ark-error/v1`; a write the log or the MCP policy refuses is a document with `ok: false` and the findings.
197
+ - Resources: `adr://index` (the index table) and `adr://decision/{id}`, one decision's state header and body, where `{id}` is the id, the number or `ADR-NNNN`. The prompt `adr_draft_from_discussion` (optional `title`, `template`, `supersedes`) walks an agent from a conversation to a proposal.
198
+ - `adr_propose` takes a `sections` map (section id to markdown); template lint findings come back as data, and `adr_update_draft` replaces sections of a draft in place, writing only if nobody changed the file meanwhile. With `auto_commit`, an incomplete draft is refused instead of committed.
199
+ - Without `mcp_can_decide`, an agent may update, scope and withdraw only proposals made on behalf of the same person, and never rescope an accepted or deprecated decision (`decision/mcp-cannot-decide`). `accept_requires_human` still refuses an agent's `adr_accept`.
200
+ - MCP writes stage their files and commit only with `[policy] auto_commit`; there is no commit input. Each call reads the log again, but the tool list is fixed at startup: restart `adr mcp` after changing `mcp_can_decide`.
201
+
152
202
  ## Library
153
203
 
154
- The CLI is a thin layer over the library, and phase 3's MCP server uses the same functions and returns the same JSON documents.
204
+ The CLI is a thin layer over the library, and the MCP server uses the same functions and returns the same JSON documents.
155
205
 
156
206
  ```ts
157
207
  import { listDecisions, openDecisionLog, readDecisions, showDecision, verifyDecisions } from "@nikovirtala/adr";
@@ -162,7 +212,7 @@ const { decisions } = listDecisions(read, { status: ["accepted"] });
162
212
  const findings = await verifyDecisions(log, { type: "full" });
163
213
  ```
164
214
 
165
- `initDecisionLog`, `proposeDecision`, `acceptDecision`, `rejectDecision`, `withdrawDecision`, `deprecateDecision`, `supersedeDecision`, `noteDecision`, `linkDecision`, `scopeDecision` and `followScopeRenames` write, `decisionsFor` answers `adr for`, `resolveDecision` turns an id or number into an id, and `stateHeader` gives the header `show` prints. `indexDecisionLog` and `renderDecisionIndex` regenerate or render the index, and `installDecisionHooks`, `uninstallDecisionHooks`, `printDecisionHooks`, `runPreCommitHook` and `addHookTrailers` are the hook commands.
215
+ `initDecisionLog`, `proposeDecision`, `acceptDecision`, `rejectDecision`, `withdrawDecision`, `deprecateDecision`, `supersedeDecision`, `noteDecision`, `linkDecision`, `scopeDecision` and `followScopeRenames` write, `decisionsFor` answers `adr for`, `resolveDecision` turns an id or number into an id, and `stateHeader` gives the header `show` prints. `searchDecisions` answers `adr search`, `listTemplates` lists the usable templates (`adr-templates/v1`), `updateDraft` replaces sections of a proposed draft, `sourcesNote` gives the local-only note, and `SKILL_MD` is the agent skill. `indexDecisionLog` and `renderDecisionIndex` regenerate or render the index, and `installDecisionHooks`, `uninstallDecisionHooks`, `printDecisionHooks`, `runPreCommitHook` and `addHookTrailers` are the hook commands.
166
216
 
167
217
  `@nikovirtala/adr/kind` exports only the decision kind (`adrKind`, made with ledger's `defineKind`) and its types, without any CLI code, for tools that fold decision logs themselves, such as issues linking to decisions:
168
218
 
@@ -172,6 +222,5 @@ import { adrKind } from "@nikovirtala/adr/kind";
172
222
 
173
223
  ## Not yet included
174
224
 
175
- - **Reference checks are local.** `verify` checks that `supersedes`, `superseded.by` and `linked.to` name decisions in the same log. Qualified references to other logs (`<source>:<id>`, written by `adr link`) and qualified anchors are skipped until ark's step 4.
176
- - **Phase 3:** an MCP server, a SKILL.md for agents, and search.
177
- - **ark's step 4, with issues:** cross-log reference checks at the pinned ref and listing across sources; until then `link` stores a qualified target unchecked.
225
+ - **Search limits.** `adr search` matches substrings without stemming (`orders` doesn't find `order`) and without phrases, and folds accents but not `ß` (`strasse` doesn't find `Straße`).
226
+ - **Qualified anchors.** `adr:<source>:<id>` anchors aren't checked against sources.
package/dist/cli.js CHANGED
@@ -1,10 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import { A as openDecisionLog, C as adrChecks, D as runDecisionIndex, N as resolveDecision, O as changedSince, S as withdrawDecision, _ as proposeDecision, a as initDecisionLog, c as installDecisionHooks, d as uninstallDecisionHooks, f as acceptDecision, g as noteDecision, h as linkDecision, j as readDecisions, k as numberingNote, l as printDecisionHooks, m as followScopeRenames, n as listDecisions, o as addHookTrailers, p as deprecateDecision, r as showDecision, t as decisionsFor, u as runPreCommitHook, v as rejectDecision, x as supersedeDecision, y as scopeDecision } from "./scope-CLqH-q1y.js";
3
- import { n as DECISION_STATUSES, t as adrKind } from "./kind-DjvA3dyA.js";
2
+ import { F as resolveDecision, M as openDecisionLog, N as readDecisions, O as runDecisionIndex, _ as withdrawDecision, b as readDecisionSources, c as followScopeRenames, d as proposeDecision, f as rejectDecision, h as supersedeDecision, i as showDecision, j as numberingNote, k as changedSince, l as linkDecision, n as decisionsFor, o as acceptDecision, p as scopeDecision, r as listDecisions, s as deprecateDecision, t as searchDecisions, u as noteDecision, x as readSourceDecisions, y as decisionSourceConfigs } from "./search-CTspg2pd.js";
3
+ import { n as DECISION_STATUSES, t as adrKind } from "./kind-C3DiBuUp.js";
4
+ import { a as installDecisionHooks, c as uninstallDecisionHooks, l as adrChecks, o as printDecisionHooks, r as addHookTrailers, s as runPreCommitHook, t as initDecisionLog, u as decisionVerifyInputs } from "./init-CaKKCINh.js";
4
5
  import { createRequire } from "node:module";
5
6
  import { UsageError, exitCode, findingsReport, formatText, renderStateHeader, resolveAttribution, stagedRenames, templateHistoryRef } from "@nikovirtala/ledger";
6
- import { resolve } from "node:path";
7
- import { COMMIT_OPTIONS, commitChoice, confirm, processIO, runCli, verifyCommand } from "@nikovirtala/ledger/cli";
7
+ import { realpath } from "node:fs/promises";
8
+ import { isAbsolute, relative, resolve, sep } from "node:path";
9
+ import { COMMIT_OPTIONS, commitChoice, confirm, processIO, runCli, sourcesCommand, verifyCommand } from "@nikovirtala/ledger/cli";
8
10
  import { spawn } from "node:child_process";
9
11
  // src/cli/open.ts
10
12
  /**
@@ -176,7 +178,8 @@ const VERBS = {
176
178
  deprecate: "deprecated",
177
179
  note: "noted",
178
180
  link: "linked",
179
- scope: "scoped"
181
+ scope: "scoped",
182
+ update: "updated"
180
183
  };
181
184
  /**
182
185
  * The text of a write command (design §5.6, §6.1). `subject` names what a refused command was
@@ -243,6 +246,9 @@ function writeText(doc, display, o) {
243
246
  recorded
244
247
  ].join("\n");
245
248
  }
249
+ case "update":
250
+ if (doc.written.length === 0) return `Draft of ${named(v.id, display)} unchanged`;
251
+ return [`Updated the draft of ${named(v.id, display)}: ${v.title}`, recorded].join("\n");
246
252
  }
247
253
  }
248
254
  /**
@@ -298,15 +304,39 @@ function forText(doc, display, keyword) {
298
304
  }
299
305
  return lines.join("\n");
300
306
  }
307
+ /**
308
+ * `adr search`: one padded row per result with its excerpt (or which field matched) under it, and
309
+ * an inactive result's warning; then the count.
310
+ */
311
+ function searchText(doc) {
312
+ const quoted = JSON.stringify(doc.query);
313
+ if (doc.results.length === 0) return `No ${doc.include_inactive ? "" : "active "}decisions match ${quoted}.`;
314
+ const rows = columns(doc.results.map((r) => [
315
+ r.decision.number === null ? r.decision.id : `${r.decision.display} (${r.decision.id})`,
316
+ r.decision.status,
317
+ r.decision.title
318
+ ])).split("\n");
319
+ const lines = [];
320
+ doc.results.forEach((r, i) => {
321
+ lines.push(rows[i] ?? "");
322
+ if (r.header.warning !== null) lines.push(` ${r.header.warning}`);
323
+ const where = r.matched.filter((f) => f === "id" || f === "title").join(" and ");
324
+ lines.push(r.excerpt === null ? ` (${where} match)` : ` ${r.excerpt}`);
325
+ });
326
+ const n = doc.total;
327
+ lines.push(`${n === 1 ? "1 decision matches" : `${n} decisions match`} ${quoted}.`);
328
+ return lines.join("\n");
329
+ }
301
330
  /** `adr init`: what was written and kept, then the next step; or that nothing was needed. */
302
331
  function initText(doc) {
303
332
  if (doc.written.length === 0) return `Already initialized: ${doc.root} (kept ${doc.kept.join(", ")})`;
333
+ const skill = doc.skill !== null && doc.written.includes(doc.skill);
304
334
  return [
305
- `Initialized ${doc.root}`,
335
+ doc.written.every((p) => p === doc.skill || p === "AGENTS.md") ? "Set up the adr agent skill" : `Initialized ${doc.root}`,
306
336
  ...doc.written.map((p) => ` ${p}`),
307
337
  ...doc.kept.map((p) => `Kept ${p}`),
308
338
  ...doc.commit === null ? [] : [`Committed ${short$1(doc.commit)}.`],
309
- "Next: adr new \"<title>\""
339
+ skill ? "Next: adr mcp, from your MCP client's config" : "Next: adr new \"<title>\""
310
340
  ].join("\n");
311
341
  }
312
342
  // src/cli/accept.ts
@@ -594,39 +624,68 @@ const indexCommand = {
594
624
  }
595
625
  };
596
626
  // src/cli/init.ts
597
- /** `adr init [--template <name>]… [--commit | --no-commit] [-m <message>]` (design §6.2). */
598
- const initCommand = {
599
- name: "init",
600
- summary: "set up a decision log: a config file and starter templates",
601
- usage: "init [--template <name>]… [--commit | --no-commit] [-m <message>]",
602
- options: {
603
- template: {
604
- type: "string",
605
- multiple: true
627
+ const DEFAULT_SKILL_DIR = ".claude/skills/adr";
628
+ const MAX_DIR = 1024;
629
+ /** `--skill-dir` as a repo-relative directory inside the work tree and outside `.git`. */
630
+ async function skillDir(root, cwd, given) {
631
+ const dir = given.trim();
632
+ const bad = () => new UsageError("--skill-dir must be a directory inside the repository");
633
+ if (dir === "" || dir.length > MAX_DIR || dir.includes("\0")) throw bad();
634
+ const base = await realpath(cwd).catch(() => cwd);
635
+ const rel = relative(root, resolve(base, dir));
636
+ if (rel === ".." || rel.startsWith(`..${sep}`) || isAbsolute(rel)) throw bad();
637
+ const segments = rel.split(sep).filter((s) => s !== "");
638
+ if (segments[0] === ".git") throw bad();
639
+ return segments.join("/");
640
+ }
641
+ /**
642
+ * `adr init [--template <name>]… [--skill [--skill-dir <path>]] [--commit | --no-commit]
643
+ * [-m <message>]` (design §6.2, phase 3 §9).
644
+ */
645
+ function initCommand(version) {
646
+ return {
647
+ name: "init",
648
+ summary: "set up a decision log: a config file and starter templates",
649
+ usage: "init [--template <name>]… [--skill [--skill-dir <path>]] [--commit | --no-commit] [-m <message>]",
650
+ options: {
651
+ template: {
652
+ type: "string",
653
+ multiple: true
654
+ },
655
+ skill: { type: "boolean" },
656
+ "skill-dir": { type: "string" },
657
+ ...COMMIT_OPTIONS
606
658
  },
607
- ...COMMIT_OPTIONS
608
- },
609
- positionals: {
610
- min: 0,
611
- max: 0,
612
- names: []
613
- },
614
- ref: "reject",
615
- async run({ io, flags, values }) {
616
- const templates = Array.isArray(values.template) ? values.template : void 0;
617
- const log = await openForCli(io, flags);
618
- const doc = await initDecisionLog(log, {
619
- ...templates === void 0 ? {} : { templates },
620
- ...commitChoice(values, { autoCommit: log.adr.autoCommit })
621
- });
622
- return {
623
- exit: 0,
624
- json: doc,
625
- text: initText(doc),
626
- notes: doc.notes
627
- };
628
- }
629
- };
659
+ positionals: {
660
+ min: 0,
661
+ max: 0,
662
+ names: []
663
+ },
664
+ ref: "reject",
665
+ async run({ io, flags, values }) {
666
+ const templates = Array.isArray(values.template) ? values.template : void 0;
667
+ const given = typeof values["skill-dir"] === "string" ? values["skill-dir"] : null;
668
+ if (given !== null && values.skill !== true) throw new UsageError("--skill-dir needs --skill");
669
+ const log = await openForCli(io, flags);
670
+ const root = log.git.root ?? io.cwd;
671
+ const dir = values.skill !== true ? null : given === null ? DEFAULT_SKILL_DIR : await skillDir(root, io.cwd, given);
672
+ const doc = await initDecisionLog(log, {
673
+ ...templates === void 0 ? {} : { templates },
674
+ ...dir === null ? {} : { skill: {
675
+ dir,
676
+ version
677
+ } },
678
+ ...commitChoice(values, { autoCommit: log.adr.autoCommit })
679
+ });
680
+ return {
681
+ exit: 0,
682
+ json: doc,
683
+ text: initText(doc),
684
+ notes: doc.notes
685
+ };
686
+ }
687
+ };
688
+ }
630
689
  // src/cli/link.ts
631
690
  /** `adr link <decision> <target> [--rel <rel>]` (design §6.7): a typed link, in any state. */
632
691
  const linkCommand = {
@@ -685,17 +744,21 @@ function sinceRev(values) {
685
744
  if (v.trim() === "" || v.startsWith("-")) throw new UsageError("--since must be a revision");
686
745
  return v;
687
746
  }
688
- /** `adr list [--status <status>]… [--since <rev>]` (design §5.6, 2b D7). */
747
+ /**
748
+ * `adr list [--status <status>]… [--since <rev>] [--source <name>]` (design §5.6, 2b D7):
749
+ * `--source` lists a `[[sources]]` entry's cached log instead of the local one.
750
+ */
689
751
  const listCommand = {
690
752
  name: "list",
691
753
  summary: "list decisions with their computed status",
692
- usage: "list [--status <status>]… [--since <rev>]",
754
+ usage: "list [--status <status>]… [--since <rev>] [--source <name>]",
693
755
  options: {
694
756
  status: {
695
757
  type: "string",
696
758
  multiple: true
697
759
  },
698
- since: { type: "string" }
760
+ since: { type: "string" },
761
+ source: { type: "string" }
699
762
  },
700
763
  positionals: {
701
764
  min: 0,
@@ -706,9 +769,11 @@ const listCommand = {
706
769
  async run({ io, flags, values }) {
707
770
  const status = statuses(values);
708
771
  const rev = sinceRev(values);
772
+ const source = typeof values.source === "string" ? values.source : null;
773
+ if (source !== null && rev !== null) throw new UsageError("--source can't be combined with --since");
709
774
  const log = await openForCli(io, flags);
710
775
  const since = rev === null ? null : await changedSince(log, rev);
711
- const read = await readDecisions(log);
776
+ const read = source === null ? await readDecisions(log) : await readSourceDecisions(log, source);
712
777
  const doc = listDecisions(read, {
713
778
  status,
714
779
  since
@@ -728,6 +793,42 @@ const listCommand = {
728
793
  };
729
794
  }
730
795
  };
796
+ // src/cli/mcp.ts
797
+ /**
798
+ * `adr mcp` (design §7.1): the MCP server over stdio. Loaded with a dynamic import, so no other
799
+ * command loads the MCP SDK.
800
+ */
801
+ function mcpCommand(version) {
802
+ return {
803
+ name: "mcp",
804
+ summary: "start the MCP server over stdio",
805
+ usage: "mcp",
806
+ options: {},
807
+ positionals: {
808
+ min: 0,
809
+ max: 0,
810
+ names: []
811
+ },
812
+ ref: "reject",
813
+ async run({ io, flags }) {
814
+ if (flags.json) throw new UsageError("adr mcp speaks JSON-RPC on stdout; it takes no --json");
815
+ if (io.interactive) io.stderr.write("adr: adr mcp speaks MCP on stdin and stdout; start it from an MCP client\n");
816
+ const { serveAdrMcp } = await import("./server-D3ySzyj6.js");
817
+ await serveAdrMcp({
818
+ cwd: io.cwd,
819
+ root: flags.root,
820
+ env: io.env,
821
+ version,
822
+ stderr: io.stderr
823
+ });
824
+ return {
825
+ exit: 0,
826
+ json: null,
827
+ text: ""
828
+ };
829
+ }
830
+ };
831
+ }
731
832
  // src/cli/editor.ts
732
833
  /**
733
834
  * The user's editor as an `edit` callback (design §5.7), or `null` when neither `VISUAL` nor
@@ -1066,6 +1167,45 @@ const scopeCommand = {
1066
1167
  };
1067
1168
  }
1068
1169
  };
1170
+ // src/cli/search.ts
1171
+ /**
1172
+ * `adr search <query>… [--all] [--source <name>]` (design §8.2): words are joined, and every one
1173
+ * must match. `--source` searches a `[[sources]]` entry's cached log instead of the local one.
1174
+ */
1175
+ const searchCommand = {
1176
+ name: "search",
1177
+ summary: "search decisions' ids, titles, bodies and notes",
1178
+ usage: "search <query>… [--all] [--source <name>]",
1179
+ options: {
1180
+ all: { type: "boolean" },
1181
+ source: { type: "string" }
1182
+ },
1183
+ positionals: {
1184
+ min: 1,
1185
+ max: 20,
1186
+ names: ["query"]
1187
+ },
1188
+ ref: "read",
1189
+ async run({ io, flags, values, positionals }) {
1190
+ const log = await openForCli(io, flags);
1191
+ const read = typeof values.source === "string" ? await readSourceDecisions(log, values.source) : await readDecisions(log);
1192
+ const doc = searchDecisions(read, {
1193
+ query: positionals.join(" "),
1194
+ includeInactive: values.all === true
1195
+ });
1196
+ const notes = [...notesWith(doc.notes, numberingNote(read, { unavailable: false }))];
1197
+ if (doc.inactive_omitted > 0) {
1198
+ const k = doc.inactive_omitted;
1199
+ notes.push(`${k === 1 ? "1 inactive decision also matches" : `${k} inactive decisions also match`}; add --all to see them`);
1200
+ }
1201
+ return {
1202
+ exit: 0,
1203
+ json: doc,
1204
+ text: searchText(doc),
1205
+ notes
1206
+ };
1207
+ }
1208
+ };
1069
1209
  // src/cli/show.ts
1070
1210
  /** `adr show <decision> [--history]` (design §5.6). */
1071
1211
  const showCommand = {
@@ -1185,17 +1325,34 @@ const withdrawCommand = {
1185
1325
  * ledger's shared `verify`: the log as the mode reads it (the index for `--staged`, else the
1186
1326
  * `--ref` tree or the work tree), every phase-1 check, and `[verify] fail_on`.
1187
1327
  */
1188
- const verify = verifyCommand({ async open({ io, flags, mode }) {
1328
+ const verify = verifyCommand({ async open({ io, flags, mode, fetchSources }) {
1189
1329
  const log = await openForCli(io, flags, { reader: mode.type === "staged" ? "index" : "worktree" });
1330
+ const sources = await readDecisionSources(log, { fetch: fetchSources ? "network" : "cache" });
1190
1331
  return {
1191
1332
  git: log.git,
1192
1333
  kind: adrKind,
1193
1334
  layout: log.layout,
1194
- checks: adrChecks(log, await templateHistoryRef(log.git, mode)),
1335
+ checks: adrChecks(log, await templateHistoryRef(log.git, mode), sources),
1195
1336
  failOn: log.adr.failOn,
1196
- notes: log.notes
1337
+ notes: [...log.notes, ...sources.notes],
1338
+ widenOn: decisionVerifyInputs(log),
1339
+ ...(log.config?.sources ?? []).length === 0 ? {} : { sources: sources.statuses }
1197
1340
  };
1198
1341
  } });
1342
+ /** ledger's shared `sources fetch`, over the `kind = "adr"` entries of `[[sources]]`. */
1343
+ const sources = sourcesCommand({
1344
+ format: "adr-sources/v1",
1345
+ tool: "adr",
1346
+ async open({ io, flags }) {
1347
+ const log = await openForCli(io, flags);
1348
+ return {
1349
+ git: log.git,
1350
+ ...decisionSourceConfigs(log),
1351
+ configPath: log.configPath,
1352
+ notes: log.notes
1353
+ };
1354
+ }
1355
+ });
1199
1356
  /** The `adr` tool: its commands, for ledger's `runCli`. */
1200
1357
  function adrCli(version) {
1201
1358
  return {
@@ -1203,7 +1360,7 @@ function adrCli(version) {
1203
1360
  version,
1204
1361
  summary: "Architecture decision records kept as event logs in git.",
1205
1362
  commands: [
1206
- initCommand,
1363
+ initCommand(version),
1207
1364
  newCommand,
1208
1365
  acceptCommand,
1209
1366
  rejectCommand,
@@ -1218,7 +1375,10 @@ function adrCli(version) {
1218
1375
  forCommand,
1219
1376
  listCommand,
1220
1377
  showCommand,
1221
- verify
1378
+ searchCommand,
1379
+ verify,
1380
+ sources,
1381
+ mcpCommand(version)
1222
1382
  ]
1223
1383
  };
1224
1384
  }