@nikovirtala/adr 0.4.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.
- package/README.md +15 -9
- package/dist/cli.js +47 -16
- package/dist/cli.js.map +1 -1
- package/dist/index.js +5 -5
- package/dist/{init-YgW7g9Fx.js → init-CaKKCINh.js} +79 -16
- package/dist/init-CaKKCINh.js.map +1 -0
- package/dist/{kind-DjvA3dyA.js → kind-C3DiBuUp.js} +44 -11
- package/dist/kind-C3DiBuUp.js.map +1 -0
- package/dist/kind.js +1 -1
- package/dist/{list-Dt4KGxvj.js → list-CJi9vZqJ.js} +3 -3
- package/dist/{list-Dt4KGxvj.js.map → list-CJi9vZqJ.js.map} +1 -1
- package/dist/{search-CwIPlNGd.js → search-CTspg2pd.js} +290 -88
- package/dist/search-CTspg2pd.js.map +1 -0
- package/dist/{server-CXCO5zfp.js → server-D3ySzyj6.js} +20 -8
- package/dist/server-D3ySzyj6.js.map +1 -0
- package/dist/types/cli/list.d.ts +4 -1
- package/dist/types/cli/search.d.ts +4 -1
- package/dist/types/commit-actions.d.ts +21 -1
- package/dist/types/hooks.d.ts +3 -2
- package/dist/types/index.d.ts +2 -1
- package/dist/types/kind/rules.d.ts +23 -2
- package/dist/types/kind.d.ts +1 -1
- package/dist/types/log-index.d.ts +0 -18
- package/dist/types/log.d.ts +6 -3
- package/dist/types/search.d.ts +2 -0
- package/dist/types/sources.d.ts +35 -0
- package/dist/types/verify.d.ts +20 -4
- package/dist/types/views.d.ts +2 -0
- package/dist/types/write.d.ts +37 -4
- package/package.json +2 -2
- package/dist/init-YgW7g9Fx.js.map +0 -1
- package/dist/kind-DjvA3dyA.js.map +0 -1
- package/dist/search-CwIPlNGd.js.map +0 -1
- package/dist/server-CXCO5zfp.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
|
|
|
@@ -77,6 +77,11 @@ adr search dynamodb --all
|
|
|
77
77
|
adr verify
|
|
78
78
|
adr verify --base origin/main --format github
|
|
79
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
|
|
80
85
|
|
|
81
86
|
# The generated index (with [log] index = "committed"): regenerate it, or check that it is current.
|
|
82
87
|
adr index
|
|
@@ -93,16 +98,16 @@ adr mcp
|
|
|
93
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.
|
|
94
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.
|
|
95
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.
|
|
96
|
-
- `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
|
|
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.
|
|
97
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.
|
|
98
|
-
- 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
|
|
99
|
-
- `--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
|
|
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.
|
|
100
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.
|
|
101
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.
|
|
102
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.
|
|
103
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.
|
|
104
|
-
- `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
|
|
105
|
-
- `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
|
|
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>`.
|
|
106
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).
|
|
107
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.`
|
|
108
113
|
|
|
@@ -148,7 +153,9 @@ scope_follow_renames = "stage" # stage, warn or off: pre-commit's rename follow
|
|
|
148
153
|
index = "check" # check, or stage to regenerate index.md in pre-commit
|
|
149
154
|
```
|
|
150
155
|
|
|
151
|
-
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
|
|
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.
|
|
152
159
|
|
|
153
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.
|
|
154
161
|
|
|
@@ -215,6 +222,5 @@ import { adrKind } from "@nikovirtala/adr/kind";
|
|
|
215
222
|
|
|
216
223
|
## Not yet included
|
|
217
224
|
|
|
218
|
-
- **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.
|
|
219
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`).
|
|
220
|
-
- **
|
|
226
|
+
- **Qualified anchors.** `adr:<source>:<id>` anchors aren't checked against sources.
|
package/dist/cli.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import { n as DECISION_STATUSES, t as adrKind } from "./kind-
|
|
4
|
-
import { a as installDecisionHooks, c as uninstallDecisionHooks, l as adrChecks, o as printDecisionHooks, r as addHookTrailers, s as runPreCommitHook, t as initDecisionLog } from "./init-
|
|
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";
|
|
5
5
|
import { createRequire } from "node:module";
|
|
6
6
|
import { UsageError, exitCode, findingsReport, formatText, renderStateHeader, resolveAttribution, stagedRenames, templateHistoryRef } from "@nikovirtala/ledger";
|
|
7
7
|
import { realpath } from "node:fs/promises";
|
|
8
8
|
import { isAbsolute, relative, resolve, sep } from "node:path";
|
|
9
|
-
import { COMMIT_OPTIONS, commitChoice, confirm, processIO, runCli, verifyCommand } from "@nikovirtala/ledger/cli";
|
|
9
|
+
import { COMMIT_OPTIONS, commitChoice, confirm, processIO, runCli, sourcesCommand, verifyCommand } from "@nikovirtala/ledger/cli";
|
|
10
10
|
import { spawn } from "node:child_process";
|
|
11
11
|
// src/cli/open.ts
|
|
12
12
|
/**
|
|
@@ -744,17 +744,21 @@ function sinceRev(values) {
|
|
|
744
744
|
if (v.trim() === "" || v.startsWith("-")) throw new UsageError("--since must be a revision");
|
|
745
745
|
return v;
|
|
746
746
|
}
|
|
747
|
-
/**
|
|
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
|
+
*/
|
|
748
751
|
const listCommand = {
|
|
749
752
|
name: "list",
|
|
750
753
|
summary: "list decisions with their computed status",
|
|
751
|
-
usage: "list [--status <status>]… [--since <rev>]",
|
|
754
|
+
usage: "list [--status <status>]… [--since <rev>] [--source <name>]",
|
|
752
755
|
options: {
|
|
753
756
|
status: {
|
|
754
757
|
type: "string",
|
|
755
758
|
multiple: true
|
|
756
759
|
},
|
|
757
|
-
since: { type: "string" }
|
|
760
|
+
since: { type: "string" },
|
|
761
|
+
source: { type: "string" }
|
|
758
762
|
},
|
|
759
763
|
positionals: {
|
|
760
764
|
min: 0,
|
|
@@ -765,9 +769,11 @@ const listCommand = {
|
|
|
765
769
|
async run({ io, flags, values }) {
|
|
766
770
|
const status = statuses(values);
|
|
767
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");
|
|
768
774
|
const log = await openForCli(io, flags);
|
|
769
775
|
const since = rev === null ? null : await changedSince(log, rev);
|
|
770
|
-
const read = await readDecisions(log);
|
|
776
|
+
const read = source === null ? await readDecisions(log) : await readSourceDecisions(log, source);
|
|
771
777
|
const doc = listDecisions(read, {
|
|
772
778
|
status,
|
|
773
779
|
since
|
|
@@ -807,7 +813,7 @@ function mcpCommand(version) {
|
|
|
807
813
|
async run({ io, flags }) {
|
|
808
814
|
if (flags.json) throw new UsageError("adr mcp speaks JSON-RPC on stdout; it takes no --json");
|
|
809
815
|
if (io.interactive) io.stderr.write("adr: adr mcp speaks MCP on stdin and stdout; start it from an MCP client\n");
|
|
810
|
-
const { serveAdrMcp } = await import("./server-
|
|
816
|
+
const { serveAdrMcp } = await import("./server-D3ySzyj6.js");
|
|
811
817
|
await serveAdrMcp({
|
|
812
818
|
cwd: io.cwd,
|
|
813
819
|
root: flags.root,
|
|
@@ -1162,12 +1168,18 @@ const scopeCommand = {
|
|
|
1162
1168
|
}
|
|
1163
1169
|
};
|
|
1164
1170
|
// src/cli/search.ts
|
|
1165
|
-
/**
|
|
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
|
+
*/
|
|
1166
1175
|
const searchCommand = {
|
|
1167
1176
|
name: "search",
|
|
1168
1177
|
summary: "search decisions' ids, titles, bodies and notes",
|
|
1169
|
-
usage: "search <query>… [--all]",
|
|
1170
|
-
options: {
|
|
1178
|
+
usage: "search <query>… [--all] [--source <name>]",
|
|
1179
|
+
options: {
|
|
1180
|
+
all: { type: "boolean" },
|
|
1181
|
+
source: { type: "string" }
|
|
1182
|
+
},
|
|
1171
1183
|
positionals: {
|
|
1172
1184
|
min: 1,
|
|
1173
1185
|
max: 20,
|
|
@@ -1175,7 +1187,8 @@ const searchCommand = {
|
|
|
1175
1187
|
},
|
|
1176
1188
|
ref: "read",
|
|
1177
1189
|
async run({ io, flags, values, positionals }) {
|
|
1178
|
-
const
|
|
1190
|
+
const log = await openForCli(io, flags);
|
|
1191
|
+
const read = typeof values.source === "string" ? await readSourceDecisions(log, values.source) : await readDecisions(log);
|
|
1179
1192
|
const doc = searchDecisions(read, {
|
|
1180
1193
|
query: positionals.join(" "),
|
|
1181
1194
|
includeInactive: values.all === true
|
|
@@ -1312,17 +1325,34 @@ const withdrawCommand = {
|
|
|
1312
1325
|
* ledger's shared `verify`: the log as the mode reads it (the index for `--staged`, else the
|
|
1313
1326
|
* `--ref` tree or the work tree), every phase-1 check, and `[verify] fail_on`.
|
|
1314
1327
|
*/
|
|
1315
|
-
const verify = verifyCommand({ async open({ io, flags, mode }) {
|
|
1328
|
+
const verify = verifyCommand({ async open({ io, flags, mode, fetchSources }) {
|
|
1316
1329
|
const log = await openForCli(io, flags, { reader: mode.type === "staged" ? "index" : "worktree" });
|
|
1330
|
+
const sources = await readDecisionSources(log, { fetch: fetchSources ? "network" : "cache" });
|
|
1317
1331
|
return {
|
|
1318
1332
|
git: log.git,
|
|
1319
1333
|
kind: adrKind,
|
|
1320
1334
|
layout: log.layout,
|
|
1321
|
-
checks: adrChecks(log, await templateHistoryRef(log.git, mode)),
|
|
1335
|
+
checks: adrChecks(log, await templateHistoryRef(log.git, mode), sources),
|
|
1322
1336
|
failOn: log.adr.failOn,
|
|
1323
|
-
notes: log.notes
|
|
1337
|
+
notes: [...log.notes, ...sources.notes],
|
|
1338
|
+
widenOn: decisionVerifyInputs(log),
|
|
1339
|
+
...(log.config?.sources ?? []).length === 0 ? {} : { sources: sources.statuses }
|
|
1324
1340
|
};
|
|
1325
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
|
+
});
|
|
1326
1356
|
/** The `adr` tool: its commands, for ledger's `runCli`. */
|
|
1327
1357
|
function adrCli(version) {
|
|
1328
1358
|
return {
|
|
@@ -1347,6 +1377,7 @@ function adrCli(version) {
|
|
|
1347
1377
|
showCommand,
|
|
1348
1378
|
searchCommand,
|
|
1349
1379
|
verify,
|
|
1380
|
+
sources,
|
|
1350
1381
|
mcpCommand(version)
|
|
1351
1382
|
]
|
|
1352
1383
|
};
|