@nikovirtala/adr 0.1.0 → 0.3.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 (40) hide show
  1. package/README.md +70 -9
  2. package/dist/cli.js +821 -61
  3. package/dist/cli.js.map +1 -1
  4. package/dist/index.js +3 -3
  5. package/dist/{kind-DqFhApu7.js → kind-DjvA3dyA.js} +10 -23
  6. package/dist/kind-DjvA3dyA.js.map +1 -0
  7. package/dist/kind.js +1 -1
  8. package/dist/scope-CLqH-q1y.js +2873 -0
  9. package/dist/scope-CLqH-q1y.js.map +1 -0
  10. package/dist/types/cli/accept.d.ts +2 -2
  11. package/dist/types/cli/deprecate.d.ts +3 -0
  12. package/dist/types/cli/for.d.ts +3 -0
  13. package/dist/types/cli/hooks.d.ts +6 -0
  14. package/dist/types/cli/index-command.d.ts +3 -0
  15. package/dist/types/cli/init.d.ts +3 -0
  16. package/dist/types/cli/link.d.ts +3 -0
  17. package/dist/types/cli/list.d.ts +1 -1
  18. package/dist/types/cli/new.d.ts +1 -1
  19. package/dist/types/cli/note.d.ts +3 -0
  20. package/dist/types/cli/open.d.ts +2 -2
  21. package/dist/types/cli/reject.d.ts +3 -0
  22. package/dist/types/cli/scope.d.ts +7 -0
  23. package/dist/types/cli/supersede.d.ts +1 -1
  24. package/dist/types/cli/text.d.ts +39 -3
  25. package/dist/types/cli/withdraw.d.ts +3 -0
  26. package/dist/types/commit-actions.d.ts +72 -0
  27. package/dist/types/config.d.ts +16 -2
  28. package/dist/types/hooks.d.ts +59 -0
  29. package/dist/types/index.d.ts +6 -2
  30. package/dist/types/init.d.ts +33 -0
  31. package/dist/types/log-index.d.ts +117 -0
  32. package/dist/types/log.d.ts +34 -1
  33. package/dist/types/scope.d.ts +51 -0
  34. package/dist/types/verify.d.ts +6 -4
  35. package/dist/types/views.d.ts +9 -3
  36. package/dist/types/write.d.ts +206 -26
  37. package/package.json +2 -2
  38. package/dist/kind-DqFhApu7.js.map +0 -1
  39. package/dist/write-C3IW5WrA.js +0 -1011
  40. package/dist/write-C3IW5WrA.js.map +0 -1
@@ -1,15 +1,17 @@
1
- import { type Actor, type EventEnvelope, type Finding, type Template, type TemplateSource, type Trailer } from "@nikovirtala/ledger";
1
+ import { type Actor, type EventEnvelope, type Finding, type SetOp, type Template, type TemplateSource, type Trailer, type TreeReader } from "@nikovirtala/ledger";
2
2
  import { type DecisionView } from "./kind.js";
3
3
  import { type DecisionLog, type DecisionsRead } from "./log.js";
4
- /** `adr new|accept|supersede --json` (design §5.5). */
4
+ /** `adr <write command> --json` (design §5.5, §6.1). */
5
5
  export interface WriteResultJson {
6
6
  readonly format: "adr-write/v1";
7
- readonly command: "new" | "accept" | "supersede";
7
+ readonly command: "new" | "accept" | "supersede" | "reject" | "withdraw" | "deprecate" | "note" | "link" | "scope";
8
8
  readonly ok: boolean;
9
9
  /**
10
10
  * The decision after the write; before it when `ok` is false (`null` for a refused `new`).
11
11
  * After a commit it is read again from the log, so an acceptance committed on the main ref
12
- * carries its number; otherwise `number` is `null` until the acceptance lands on main.
12
+ * carries its number; otherwise `number` is `null` until the acceptance lands on main. In a
13
+ * shallow clone with a committed index, the number comes from HEAD's `index.md`, which on a
14
+ * branch is the number the decision will get once the branch merges.
13
15
  */
14
16
  readonly decision: DecisionView | null;
15
17
  /** Each decision superseded by this write, after it (read again after a commit, like `decision`). */
@@ -19,9 +21,26 @@ export interface WriteResultJson {
19
21
  readonly commit: string | null;
20
22
  /** Refusal findings when `ok` is false; the draft's template lint for `new` (informational). */
21
23
  readonly findings: readonly Finding[];
22
- /** How the log was located (`ToolLog.notes`). */
24
+ /**
25
+ * How the log was located (`ToolLog.notes`), then the caller's notes (attribution), then the
26
+ * write's own (a shortened commit subject, …).
27
+ */
23
28
  readonly notes: readonly string[];
24
29
  }
30
+ /** What every write function takes besides its input (design §6.1). */
31
+ export interface WriteOptions {
32
+ /** Commit the write; default `[policy] auto_commit`. */
33
+ readonly commit?: boolean;
34
+ /** The commit message to use instead of the `[commit] subject` one; used only when committing. */
35
+ readonly message?: string | null;
36
+ /** Notes to report before the write's own, such as the attribution notes. */
37
+ readonly notes?: readonly string[];
38
+ /**
39
+ * With `[log] index = "committed"`: `"refresh"` (the default) keeps `<root>/index.md` fresh;
40
+ * `"skip"` leaves it alone (the pre-commit hook's rename following, design 2b D8).
41
+ */
42
+ readonly index?: "refresh" | "skip";
43
+ }
25
44
  export interface ProposeInput {
26
45
  readonly title: string;
27
46
  /** Default `[log] default_template`. */
@@ -64,15 +83,32 @@ export interface WritePlan {
64
83
  readonly rendered: Uint8Array;
65
84
  readonly template: Template;
66
85
  } | null;
67
- /** The D6 commit message. */
68
- readonly message: string;
86
+ /** What the commit message is made of; `write()` renders it with `[commit] subject`. */
87
+ readonly commit: CommitParts | null;
69
88
  /** One `ADR`/`ADR-Event` pair per plan event, in write order. */
70
89
  readonly trailers: readonly Trailer[];
71
90
  /** Views after the write, computed on `overlayTree(read.tree, files)`. */
72
- readonly decision: DecisionView;
91
+ readonly decision: DecisionView | null;
73
92
  readonly affected: readonly DecisionView[];
74
93
  /** Informational (new: the draft's template lint). */
75
94
  readonly findings: readonly Finding[];
95
+ /** The write's own notes for the result (an already existing link, …). */
96
+ readonly notes?: readonly string[];
97
+ }
98
+ /** The parts of a commit message (design §4.3): the template's variables and the body. */
99
+ export interface CommitParts {
100
+ /** `{action}`, the verb phrase, e.g. `propose to` or `set the scope of`. */
101
+ readonly action: string;
102
+ /**
103
+ * The text after `{action}`, which `{title}` and `{raw_title}` come from: the decision's title
104
+ * as recorded for propose, accept, reject and withdraw, else its display (`ADR-0006`, or
105
+ * `ADR-0006 with ADR-0007` for supersede).
106
+ */
107
+ readonly title: string;
108
+ readonly id: string;
109
+ readonly display: string;
110
+ /** Body paragraphs, each wrapped at 72. */
111
+ readonly body: readonly string[];
76
112
  }
77
113
  export type PlanResult = {
78
114
  readonly ok: true;
@@ -82,13 +118,42 @@ export type PlanResult = {
82
118
  readonly decision: DecisionView | null;
83
119
  readonly findings: readonly Finding[];
84
120
  };
85
- /** Plans `adr new`: a rendered body, a materialized template if needed, and `proposed`. */
86
- export declare function planPropose(read: DecisionsRead, input: ProposeInput, c: PlanContext): Promise<PlanResult>;
121
+ /**
122
+ * Plans `adr new`: a rendered body, a materialized template if needed, and `proposed`. With
123
+ * `refuseIncomplete` (a commit with no editor to fill the draft in, design §7.2), a draft that
124
+ * fails the template lint is refused with those findings before any file is planned.
125
+ */
126
+ export declare function planPropose(read: DecisionsRead, input: ProposeInput, c: PlanContext, o?: {
127
+ readonly refuseIncomplete?: boolean;
128
+ }): Promise<PlanResult>;
87
129
  /** Plans `adr accept`: `accepted` with the body hash, and `superseded` on each declared target. */
88
130
  export declare function planAccept(read: DecisionsRead, input: {
89
131
  readonly id: string;
90
132
  readonly actor: Actor;
91
- }, c: PlanContext): Promise<PlanResult>;
133
+ }, c: PlanContext, o?: {
134
+ readonly copyGlobs?: readonly string[];
135
+ }): Promise<PlanResult>;
136
+ /** The scope an `accept` can copy from the decisions it supersedes (design §6.10). */
137
+ export interface ScopeOffer {
138
+ /** The decision being accepted. */
139
+ readonly id: string;
140
+ /** The superseded decisions with globs the accepted one lacks, sorted by id. */
141
+ readonly sources: readonly string[];
142
+ /** Their displays (`ADR-0002`, or the id), in `sources` order. */
143
+ readonly displays: readonly string[];
144
+ /** The globs to add: the union of their scopes minus the accepted decision's own, sorted. */
145
+ readonly globs: readonly string[];
146
+ }
147
+ /**
148
+ * Whether `accept` copies the superseded decisions' scope: always, never, never but with a note
149
+ * naming the `adr scope` command that would (the default), or as a function decides.
150
+ */
151
+ export type CopyScope = "copy" | "skip" | "suggest" | ((offer: ScopeOffer) => Promise<boolean>);
152
+ /**
153
+ * What accepting `id` could copy: the declared targets it will supersede (accepted or
154
+ * deprecated, as `planAccept` selects them) and the globs of theirs it doesn't have yet.
155
+ */
156
+ export declare function scopeToCopy(read: DecisionsRead, id: string): ScopeOffer;
92
157
  /** Plans `adr supersede <id> --by <by>`: one `superseded` event on `id`. */
93
158
  export declare function planSupersede(read: DecisionsRead, input: {
94
159
  readonly id: string;
@@ -107,6 +172,63 @@ export declare function planEvent(read: DecisionsRead, input: {
107
172
  readonly reason?: string | null;
108
173
  readonly actor: Actor;
109
174
  }, c: PlanContext): Promise<PlanResult>;
175
+ /** Input of the lifecycle exits: the decision and the envelope's `reason`. */
176
+ export interface ReasonInput {
177
+ readonly id: string;
178
+ readonly reason?: string | null;
179
+ readonly actor: Actor;
180
+ }
181
+ /** Plans `adr reject`: `rejected` with its required reason, while proposed. */
182
+ export declare function planReject(read: DecisionsRead, input: ReasonInput, c: PlanContext): Promise<PlanResult>;
183
+ /** Plans `adr withdraw`: `withdrawn`, with a reason when given, while proposed. */
184
+ export declare function planWithdraw(read: DecisionsRead, input: ReasonInput, c: PlanContext): Promise<PlanResult>;
185
+ /** Plans `adr deprecate`: `deprecated` with its required reason, while accepted. */
186
+ export declare function planDeprecate(read: DecisionsRead, input: ReasonInput, c: PlanContext): Promise<PlanResult>;
187
+ /** Plans `adr note`: `noted` with the text as given, in every state. */
188
+ export declare function planNote(read: DecisionsRead, input: {
189
+ readonly id: string;
190
+ readonly text: string;
191
+ readonly actor: Actor;
192
+ }, c: PlanContext): Promise<PlanResult>;
193
+ export interface LinkInput {
194
+ readonly id: string;
195
+ /** A local id or number, or `<source>:<id>` naming a configured `[[sources]]` entry. */
196
+ readonly to: string;
197
+ /** Default `relates-to`. */
198
+ readonly rel?: string;
199
+ readonly actor: Actor;
200
+ }
201
+ /**
202
+ * Plans `adr link` (design §6.7): `linked` in every state. A qualified target must name one of
203
+ * `o.sources` (the log's `[[sources]]` names); it isn't looked up in the other log. A link that
204
+ * already exists plans nothing, with a note.
205
+ */
206
+ export declare function planLink(read: DecisionsRead, input: LinkInput, c: PlanContext, o?: {
207
+ readonly sources?: readonly string[];
208
+ }): Promise<PlanResult>;
209
+ export interface ScopeInput {
210
+ readonly id: string;
211
+ /** Replace (`set`, `[]` clears), or `add` and `remove` globs (design §3.2). */
212
+ readonly op: SetOp;
213
+ readonly actor: Actor;
214
+ /** How the caller names `set`, `add`, `remove` and `clear` in messages; default the field names. */
215
+ readonly names?: {
216
+ readonly set: string;
217
+ readonly add: string;
218
+ readonly remove: string;
219
+ readonly clear?: string;
220
+ };
221
+ }
222
+ /**
223
+ * Plans `adr scope` with a set operation (design §6.8): one `scoped` event with the whole new set
224
+ * while proposed, accepted or deprecated, or nothing when the set doesn't change. Invalid globs,
225
+ * conflicting operations and more than 200 globs are `UsageError`s. Notes name removed globs that
226
+ * weren't there, added ones that were, resulting globs matching none of `o.tracked` (when given)
227
+ * and a narrowed accepted scope.
228
+ */
229
+ export declare function planScope(read: DecisionsRead, input: ScopeInput, c: PlanContext, o?: {
230
+ readonly tracked?: readonly string[];
231
+ }): Promise<PlanResult>;
110
232
  /** What the editor step decided (§5.4 step 4a). */
111
233
  export interface AfterStage {
112
234
  /** Draft lint findings to report instead of `plan.findings`; `null` keeps `plan.findings`. */
@@ -114,19 +236,34 @@ export interface AfterStage {
114
236
  /** `false` skips the commit: the files stay written and staged, and `commit` is `null`. */
115
237
  readonly commit: boolean;
116
238
  }
239
+ /** What `applyPlan` did. */
240
+ export interface AppliedPlan {
241
+ /** Repo-relative paths written: the plan's files, then `<root>/index.md` when it was written. */
242
+ readonly written: string[];
243
+ readonly commit: string | null;
244
+ readonly findings: readonly Finding[];
245
+ /** Notes about the index ("not updated", "may be stale"); `[]` when none. */
246
+ readonly notes: readonly string[];
247
+ }
117
248
  /**
118
- * Applies a plan (§5.4): refuses a commit whose scope has unstaged or needed untracked paths,
119
- * writes the files (removing them again if a write fails), stages them, runs `afterStage`, and
120
- * commits `plan.stage` plus the involved subjects' already-staged files with exact trailers.
249
+ * What the recovery hint says about rerunning a write command after `git commit` failed (design
250
+ * 2b D5): the batch is already in the log, so a rerun is refused, writes nothing or duplicates it.
121
251
  */
252
+ export declare const WRITE_RERUN = "Don't run the command again: the log already holds the change, so a rerun would be refused, do nothing, or write it a second time.";
122
253
  export declare function applyPlan(log: DecisionLog, plan: WritePlan, o: {
123
254
  readonly commit: boolean;
255
+ /** The commit message, without trailers; required when committing. */
256
+ readonly message?: string;
257
+ /** `message` is the user's own: append the trailers to its own trailer block, if it ends in one. */
258
+ readonly mergeTrailers?: boolean;
124
259
  readonly afterStage?: () => Promise<AfterStage>;
125
- }): Promise<{
126
- written: string[];
127
- commit: string | null;
128
- findings: readonly Finding[];
129
- }>;
260
+ /**
261
+ * Renders the log's index for `tree`, which builds on `history` (HEAD, the new commit, or
262
+ * null on an unborn HEAD); `null` when the numbers can't be projected. Given only when the log
263
+ * keeps a committed index (design 2b D2, §4.5).
264
+ */
265
+ readonly index?: (tree: TreeReader, history: string | null) => Promise<string | null>;
266
+ }): Promise<AppliedPlan>;
130
267
  /**
131
268
  * The clock, the randomness and `applyPlan` the write functions use. Only tests pass their own
132
269
  * (for example an `apply` that fails once); the default is the real ones.
@@ -144,21 +281,25 @@ export interface WriteDeps {
144
281
  * body path. It resolves to `null` when the editor exited 0, else to a note for the user (spawn
145
282
  * error, exit status). `onNote` receives the notes about a skipped commit or a removed body,
146
283
  * without the "not committed: " prefix the CLI adds when a commit was requested.
284
+ *
285
+ * A draft with unfilled sections is never committed (design §7.2): without `edit` a commit is
286
+ * refused (`ok: false`, nothing written); after `edit` the commit is skipped with a note.
147
287
  */
148
- export declare function proposeDecision(log: DecisionLog, input: ProposeInput, o?: {
149
- readonly commit?: boolean;
288
+ export declare function proposeDecision(log: DecisionLog, input: ProposeInput, o?: WriteOptions & {
150
289
  readonly edit?: (absBodyPath: string) => Promise<string | null>;
151
290
  readonly onNote?: (note: string) => void;
152
291
  }, deps?: WriteDeps): Promise<WriteResultJson>;
153
292
  /**
154
293
  * `adr accept`: lints the draft, hashes the body, writes `accepted` and a `superseded` event on
155
- * each declared target, stages them with the body, and commits with `commit`.
294
+ * each declared target, stages them with the body, and commits with `commit`. When the targets
295
+ * have globs the decision lacks, `copyScope` decides whether a `scoped` event copies them
296
+ * (default `"suggest"`: no copy, and a note with the `adr scope` command that would).
156
297
  */
157
298
  export declare function acceptDecision(log: DecisionLog, input: {
158
299
  readonly id: string;
159
300
  readonly actor: Actor;
160
- }, o?: {
161
- readonly commit?: boolean;
301
+ }, o?: WriteOptions & {
302
+ readonly copyScope?: CopyScope;
162
303
  }, deps?: WriteDeps): Promise<WriteResultJson>;
163
304
  /** `adr supersede <id> --by <by>`: writes `superseded`, stages it, and commits with `commit`. */
164
305
  export declare function supersedeDecision(log: DecisionLog, input: {
@@ -166,6 +307,45 @@ export declare function supersedeDecision(log: DecisionLog, input: {
166
307
  readonly by: string;
167
308
  readonly reason?: string | null;
168
309
  readonly actor: Actor;
169
- }, o?: {
170
- readonly commit?: boolean;
310
+ }, o?: WriteOptions, deps?: WriteDeps): Promise<WriteResultJson>;
311
+ /**
312
+ * `adr reject <id> --reason <text>`: writes `rejected`, stages it, and commits with `commit`. The
313
+ * kind requires the reason; without one the write is refused (findings, nothing written).
314
+ */
315
+ export declare function rejectDecision(log: DecisionLog, input: ReasonInput, o?: WriteOptions, deps?: WriteDeps): Promise<WriteResultJson>;
316
+ /** `adr withdraw <id> [--reason <text>]`: writes `withdrawn`, stages it, and commits with `commit`. */
317
+ export declare function withdrawDecision(log: DecisionLog, input: ReasonInput, o?: WriteOptions, deps?: WriteDeps): Promise<WriteResultJson>;
318
+ /**
319
+ * `adr deprecate <id> --reason <text>`: writes `deprecated`, stages it, and commits with `commit`.
320
+ * The kind requires the reason, as for `rejectDecision`.
321
+ */
322
+ export declare function deprecateDecision(log: DecisionLog, input: ReasonInput, o?: WriteOptions, deps?: WriteDeps): Promise<WriteResultJson>;
323
+ /** `adr note <id> <text>`: writes `noted`, stages it, and commits with `commit`. */
324
+ export declare function noteDecision(log: DecisionLog, input: {
325
+ readonly id: string;
326
+ readonly text: string;
327
+ readonly actor: Actor;
328
+ }, o?: WriteOptions, deps?: WriteDeps): Promise<WriteResultJson>;
329
+ /**
330
+ * `adr link <id> <target> [--rel <rel>]`: writes `linked`, stages it, and commits with `commit`.
331
+ * Qualified targets name the log's `[[sources]]`; a link that exists already writes nothing.
332
+ */
333
+ export declare function linkDecision(log: DecisionLog, input: LinkInput, o?: WriteOptions, deps?: WriteDeps): Promise<WriteResultJson>;
334
+ /**
335
+ * `adr scope <id> --set|--add|--remove …`: writes one `scoped` event with the new set, stages it,
336
+ * and commits with `commit`. An unchanged set writes nothing.
337
+ */
338
+ export declare function scopeDecision(log: DecisionLog, input: ScopeInput, o?: WriteOptions, deps?: WriteDeps): Promise<WriteResultJson>;
339
+ /**
340
+ * `adr scope [<decision>] --follow-renames` (design §6.8): rewrites the scope globs of the given
341
+ * decision, or of every decision, after the renames staged against `HEAD`, and stages one
342
+ * `scoped` event per changed decision. It never commits, whatever `[policy] auto_commit` says
343
+ * (the events belong in the commit with the renames), so `o.commit: true` and a message are
344
+ * `InvalidArgumentError`s. `dryRun` plans the same events and notes without writing anything.
345
+ */
346
+ export declare function followScopeRenames(log: DecisionLog, input: {
347
+ readonly id?: string;
348
+ readonly actor: Actor;
349
+ }, o?: WriteOptions & {
350
+ readonly dryRun?: boolean;
171
351
  }, deps?: WriteDeps): Promise<WriteResultJson>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nikovirtala/adr",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "Architecture decision records kept as event logs in git: frozen bodies, computed status and supersession chains. CLI and library.",
5
5
  "keywords": [
6
6
  "adr",
@@ -45,7 +45,7 @@
45
45
  "provenance": true
46
46
  },
47
47
  "dependencies": {
48
- "@nikovirtala/ledger": "^0.3.0"
48
+ "@nikovirtala/ledger": "^0.5.0"
49
49
  },
50
50
  "scripts": {
51
51
  "build": "tsdown",
@@ -1 +0,0 @@
1
- {"version":3,"file":"kind-DqFhApu7.js","names":[],"sources":["../src/kind/project.ts","../src/kind/reduce.ts","../src/kind/rules.ts","../src/kind/schemas.ts","../src/kind.ts"],"sourcesContent":["import type { FoldedSubject, ProjectContext } from \"@nikovirtala/ledger\";\nimport type { DecisionState } from \"./reduce.js\";\nimport type { DecisionEvents, DecisionStatus } from \"./schemas.js\";\n\n/** One decision as the CLI, the library and MCP show it (01:173–192, plus the added fields). */\nexport interface DecisionView {\n readonly id: string;\n readonly number: number | null;\n /** `ADR-0007`, or the id when unnumbered. */\n readonly display: string;\n readonly title: string;\n readonly status: DecisionStatus;\n readonly superseded_by: string | null;\n /** Ids whose applied `superseded.by` is this id, sorted. */\n readonly supersedes: readonly string[];\n /** The proposal's intent (01:164). */\n readonly declared_supersedes: readonly string[];\n /** Head of the `superseded_by` chain; `null` only on a cycle. */\n readonly effective: string | null;\n /** `[id, …, effective]`, following `superseded_by` forward. */\n readonly chain: readonly string[];\n readonly template: { readonly name: string; readonly version: number };\n readonly body_path: string | null;\n /** Recorded at acceptance. */\n readonly body_sha256: string | null;\n /** `null` until accepted; whether the current body hash equals the recorded one. */\n readonly body_intact: boolean | null;\n readonly links: readonly { readonly to: string; readonly rel: string }[];\n readonly applies_to: readonly string[];\n readonly notes: number;\n readonly proposed_at: string;\n readonly decided_at: string | null;\n readonly status_at: string;\n /** `proposed 2026-03-12`: state-changing events, in fold order. */\n readonly history: readonly string[];\n}\n\ntype Subject = FoldedSubject<DecisionStatus, DecisionState, DecisionEvents>;\ntype Context = ProjectContext<DecisionStatus, DecisionState, DecisionEvents>;\n\nconst NUMBER = /^(?:adr-?)?0*([1-9][0-9]{0,8})$/i;\n\n/** `ADR-0007`: at least 4 digits, growing past 9999. */\nexport function formatDecisionNumber(n: number): string {\n return `ADR-${String(n).padStart(4, \"0\")}`;\n}\n\n/** `7`, `0007`, `ADR-7`, `adr-0007` → 7; `null` for anything else. */\nexport function parseDecisionNumber(s: string): number | null {\n const m = NUMBER.exec(s.trim());\n return m === null ? null : Number(m[1]);\n}\n\n/**\n * Follows `superseded_by` from `id`. A visited set stops on a cycle (`effective: null`); a\n * reference to a subject that isn't folded ends the chain there.\n */\nfunction chainOf(id: string, ctx: Context): { chain: string[]; effective: string | null } {\n const chain = [id];\n let cur = id;\n for (;;) {\n const next = ctx.log.subjects.get(cur)?.state?.supersededBy ?? null;\n if (next === null) return { chain, effective: cur };\n if (chain.includes(next)) return { chain, effective: null };\n chain.push(next);\n cur = next;\n }\n}\n\n/** Pure: the view of one folded decision. */\nexport function project(subject: Subject, ctx: Context): DecisionView {\n const { id } = subject;\n const s = subject.state;\n if (s === null || subject.status === null) {\n throw new Error(`decision ${id} is not folded`);\n }\n const supersedes = [...ctx.log.subjects.values()]\n .filter((o) => o.id !== id && o.state?.supersededBy === id)\n .map((o) => o.id)\n .sort();\n const { chain, effective } = chainOf(id, ctx);\n const current = ctx.bodySha256(id);\n return {\n id,\n number: ctx.number(id),\n display: ctx.display(id),\n title: s.title,\n status: subject.status,\n superseded_by: s.supersededBy,\n supersedes,\n declared_supersedes: s.declaredSupersedes,\n effective,\n chain,\n template: s.template,\n body_path: subject.loaded.body?.path ?? subject.loaded.bodyPaths[0] ?? null,\n body_sha256: s.bodySha256,\n body_intact: s.bodySha256 === null ? null : current === s.bodySha256,\n links: s.links,\n applies_to: s.appliesTo,\n notes: s.notes,\n proposed_at: s.proposedAt,\n decided_at: s.decidedAt,\n status_at: s.statusAt,\n history: s.history.map((h) => `${h.type} ${h.at.slice(0, 10)}`),\n };\n}\n","import type { Actor, FoldEvent } from \"@nikovirtala/ledger\";\nimport type { DecisionEvents } from \"./schemas.js\";\n\n/** A decision's own state, maintained by `reduce` over its applied events. */\nexport interface DecisionState {\n readonly title: string;\n readonly template: { readonly name: string; readonly version: number };\n readonly declaredSupersedes: readonly string[];\n /** From the applied `accepted` event. */\n readonly bodySha256: string | null;\n readonly acceptedBy: Actor | null;\n readonly supersededBy: string | null;\n /** In fold order, duplicates kept once. */\n readonly links: readonly { readonly to: string; readonly rel: string }[];\n /** The latest `scoped` set (latest wins). */\n readonly appliesTo: readonly string[];\n readonly notes: number;\n /** State-changing events only, in fold order. */\n readonly history: readonly { readonly type: string; readonly at: string }[];\n readonly proposedAt: string;\n /** `at` of `accepted`, `rejected` or `withdrawn`. */\n readonly decidedAt: string | null;\n /** `at` of the latest state-changing event. */\n readonly statusAt: string;\n}\n\nconst EMPTY: DecisionState = {\n title: \"\",\n template: { name: \"\", version: 0 },\n declaredSupersedes: [],\n bodySha256: null,\n acceptedBy: null,\n supersededBy: null,\n links: [],\n appliesTo: [],\n notes: 0,\n history: [],\n proposedAt: \"\",\n decidedAt: null,\n statusAt: \"\",\n};\n\n/** Pure: the state after one applied event. The fold only passes events the machine allows. */\nexport function reduce(state: DecisionState | null, e: FoldEvent<DecisionEvents>): DecisionState {\n const s = state ?? EMPTY;\n const changed = (extra: Partial<DecisionState> = {}): DecisionState => ({\n ...s,\n ...extra,\n history: [...s.history, { type: e.type, at: e.at }],\n statusAt: e.at,\n });\n switch (e.type) {\n case \"proposed\":\n return changed({\n title: e.data.title,\n template: { name: e.data.template, version: e.data.template_version },\n declaredSupersedes: [...(e.data.supersedes ?? [])],\n proposedAt: e.at,\n });\n case \"accepted\":\n return changed({ bodySha256: e.data.body_sha256, acceptedBy: e.actor, decidedAt: e.at });\n case \"rejected\":\n case \"withdrawn\":\n return changed({ decidedAt: e.at });\n case \"deprecated\":\n return changed();\n case \"superseded\":\n return changed({ supersededBy: e.data.by });\n case \"noted\":\n return { ...s, notes: s.notes + 1 };\n case \"linked\": {\n const { to, rel } = e.data;\n const known = s.links.some((l) => l.to === to && l.rel === rel);\n return known ? s : { ...s, links: [...s.links, { to, rel }] };\n }\n case \"scoped\":\n return { ...s, appliesTo: [...e.data.set] };\n }\n}\n","import type { FoldedLog, FoldedSubject, KindFinding } from \"@nikovirtala/ledger\";\nimport type { DecisionState } from \"./reduce.js\";\nimport type { DecisionEvents, DecisionStatus } from \"./schemas.js\";\n\n/** Options of the decision kind's `invariants` and `relate`. */\nexport interface AdrOptions {\n /** Default `true`: an agent may propose, but only a human may accept (01:98). */\n readonly acceptRequiresHuman: boolean;\n}\n\ntype Subject = FoldedSubject<DecisionStatus, DecisionState, DecisionEvents>;\ntype Log = FoldedLog<DecisionStatus, DecisionState, DecisionEvents>;\n\n/** `decision/agent-accepted`: an applied `accepted` event written by an agent under the human policy. */\nexport function invariants(subject: Subject, options: AdrOptions): readonly KindFinding[] {\n if (!options.acceptRequiresHuman) return [];\n return subject.applied.flatMap(({ event }) =>\n event.type === \"accepted\" && event.actor.kind === \"agent\"\n ? [\n {\n severity: \"error\" as const,\n rule: \"decision/agent-accepted\",\n message: `accepted by agent ${event.actor.name}; accept_requires_human needs a human`,\n subject: subject.id,\n event: event.id,\n },\n ]\n : [],\n );\n}\n\n/**\n * Qualified ids (`<source>:<id>`) name decisions in other logs. Phase 1 checks local references\n * only and skips qualified ones, which only hand-written events can hold; CI checks them at the\n * pinned ref in phase 2 (design §E).\n */\nconst isQualified = (ref: string) => ref.includes(\":\");\n\n/**\n * Cross-subject rules: `decision/reference-missing` for a local `supersedes`, `superseded.by` or\n * `linked.to` naming no subject in the log; `decision/superseded-by-unaccepted` when the target of\n * an applied `superseded.by` has no applied `accepted` event in this tree; and\n * `decision/supersession-cycle`, once per cycle on its smallest id.\n */\nexport function relate(log: Log): readonly KindFinding[] {\n const out: KindFinding[] = [];\n const isAccepted = (id: string) =>\n log.subjects.get(id)?.applied.some((a) => a.event.type === \"accepted\") ?? false;\n const missing = (subject: string, event: string, ref: string, what: string) => {\n if (isQualified(ref) || log.subjects.has(ref)) return false;\n out.push({\n severity: \"error\",\n rule: \"decision/reference-missing\",\n message: `${what} ${ref}, which is not in the log`,\n subject,\n event,\n related: [ref],\n });\n return true;\n };\n\n for (const [id, s] of log.subjects) {\n for (const { event } of s.applied) {\n switch (event.type) {\n case \"proposed\":\n for (const ref of event.data.supersedes ?? []) missing(id, event.id, ref, \"supersedes\");\n break;\n case \"superseded\": {\n const by = event.data.by;\n if (missing(id, event.id, by, \"superseded by\") || isQualified(by)) break;\n if (!isAccepted(by)) {\n out.push({\n severity: \"error\",\n rule: \"decision/superseded-by-unaccepted\",\n message: `superseded by ${by}, which is not accepted`,\n subject: id,\n event: event.id,\n related: [by],\n });\n }\n break;\n }\n case \"linked\":\n missing(id, event.id, event.data.to, \"links to\");\n break;\n default:\n break;\n }\n }\n }\n\n const next = (id: string) => log.subjects.get(id)?.state?.supersededBy ?? null;\n const reported = new Set<string>();\n for (const start of log.subjects.keys()) {\n const path: string[] = [];\n let cur: string | null = start;\n while (cur !== null && !path.includes(cur)) {\n path.push(cur);\n cur = next(cur);\n }\n if (cur === null) continue;\n const cycle = path.slice(path.indexOf(cur));\n const smallest = [...cycle].sort()[0];\n if (smallest === undefined || reported.has(smallest)) continue;\n reported.add(smallest);\n const from = cycle.indexOf(smallest);\n const ordered = [...cycle.slice(from), ...cycle.slice(0, from), smallest];\n const event = log.subjects.get(smallest)?.applied.find((a) => a.event.type === \"superseded\")\n ?.event.id;\n out.push({\n severity: \"error\",\n rule: \"decision/supersession-cycle\",\n message: `supersession cycle: ${ordered.join(\" → \")}`,\n subject: smallest,\n ...(event === undefined ? {} : { event }),\n related: [...cycle].sort(),\n });\n }\n return out;\n}\n","import { eventType } from \"@nikovirtala/ledger\";\n\n/** A decision's computed status. */\nexport type DecisionStatus =\n | \"proposed\"\n | \"accepted\"\n | \"rejected\"\n | \"withdrawn\"\n | \"deprecated\"\n | \"superseded\";\n\n/** Every status, in lifecycle order. */\nexport const DECISION_STATUSES: readonly DecisionStatus[] = Object.freeze([\n \"proposed\",\n \"accepted\",\n \"rejected\",\n \"withdrawn\",\n \"deprecated\",\n \"superseded\",\n]);\n\n/** A local subject id, or a qualified `<source>:<id>` one. */\nexport const REF = \"^(?:[a-z][a-z0-9-]*:)?[0-9a-hjkmnp-tv-z]{8}$\";\n\nconst ref = { type: \"string\", pattern: REF } as const;\nconst SINGLE_LINE = \"^[^\\\\r\\\\n]*$\";\n\n/** How a `linked` decision relates to its target. */\nexport type LinkRel = \"relates-to\" | \"refines\" | \"depends-on\";\n\n/** The decision kind's event types (01:128–136): data schemas, allowed states and targets. */\nexport const decisionEvents = {\n proposed: eventType<{\n title: string;\n template: string;\n template_version: number;\n supersedes?: string[];\n }>()({\n data: {\n type: \"object\",\n required: [\"title\", \"template\", \"template_version\"],\n properties: {\n title: { type: \"string\", minLength: 1, maxLength: 200, pattern: SINGLE_LINE },\n template: { type: \"string\", pattern: \"^[a-z][a-z0-9-]*$\" },\n template_version: { type: \"integer\", minimum: 1 },\n supersedes: { type: \"array\", items: ref, uniqueItems: true, maxItems: 20 },\n },\n },\n allowedIn: [],\n to: \"proposed\",\n }),\n accepted: eventType<{ body_sha256: string }>()({\n data: {\n type: \"object\",\n required: [\"body_sha256\"],\n properties: { body_sha256: { type: \"string\", pattern: \"^[0-9a-f]{64}$\" } },\n },\n allowedIn: [\"proposed\"],\n to: \"accepted\",\n }),\n rejected: eventType()({\n data: { type: \"object\" },\n allowedIn: [\"proposed\"],\n to: \"rejected\",\n reason: \"required\",\n }),\n withdrawn: eventType()({ data: { type: \"object\" }, allowedIn: [\"proposed\"], to: \"withdrawn\" }),\n deprecated: eventType()({\n data: { type: \"object\" },\n allowedIn: [\"accepted\"],\n to: \"deprecated\",\n reason: \"required\",\n }),\n superseded: eventType<{ by: string }>()({\n data: { type: \"object\", required: [\"by\"], properties: { by: ref } },\n allowedIn: [\"accepted\", \"deprecated\"],\n to: \"superseded\",\n }),\n noted: eventType<{ text: string }>()({\n data: {\n type: \"object\",\n required: [\"text\"],\n properties: { text: { type: \"string\", minLength: 1 } },\n },\n allowedIn: \"any\",\n to: null,\n }),\n linked: eventType<{ to: string; rel: LinkRel }>()({\n data: {\n type: \"object\",\n required: [\"to\", \"rel\"],\n properties: { to: ref, rel: { enum: [\"relates-to\", \"refines\", \"depends-on\"] } },\n },\n allowedIn: \"any\",\n to: null,\n }),\n scoped: eventType<{ set: string[] }>()({\n data: {\n type: \"object\",\n required: [\"set\"],\n properties: {\n set: {\n type: \"array\",\n items: { type: \"string\", minLength: 1, maxLength: 500 },\n uniqueItems: true,\n maxItems: 200,\n },\n },\n },\n allowedIn: [\"proposed\", \"accepted\", \"deprecated\"],\n to: null,\n }),\n} as const;\n\nexport type DecisionEvents = typeof decisionEvents;\n","import { defineKind, type Kind } from \"@nikovirtala/ledger\";\nimport {\n type DecisionView,\n formatDecisionNumber,\n parseDecisionNumber,\n project,\n} from \"./kind/project.js\";\nimport { type DecisionState, reduce } from \"./kind/reduce.js\";\nimport { type AdrOptions, invariants, relate } from \"./kind/rules.js\";\nimport { type DecisionEvents, type DecisionStatus, decisionEvents } from \"./kind/schemas.js\";\n\nexport type { DecisionView } from \"./kind/project.js\";\nexport { formatDecisionNumber, parseDecisionNumber } from \"./kind/project.js\";\nexport type { DecisionState } from \"./kind/reduce.js\";\nexport type { AdrOptions } from \"./kind/rules.js\";\nexport {\n DECISION_STATUSES,\n type DecisionEvents,\n type DecisionStatus,\n type LinkRel,\n REF,\n} from \"./kind/schemas.js\";\n\n/**\n * The decision kind (01:128–194), as imported by other tools through `@nikovirtala/adr/kind`.\n *\n * Decisions are proposed, then accepted (which freezes the body and earns a number on main),\n * rejected or withdrawn; accepted ones can be deprecated or superseded. This module imports only\n * `@nikovirtala/ledger` and `./kind/*`, so importing the kind never loads CLI or MCP code.\n */\nexport const adrKind: Kind<\n DecisionStatus,\n DecisionEvents,\n DecisionState,\n DecisionView,\n AdrOptions\n> = defineKind<DecisionStatus, DecisionEvents, DecisionState, DecisionView, AdrOptions>({\n name: \"decision\",\n schema: \"decision/v1\",\n states: [\"proposed\", \"accepted\", \"rejected\", \"withdrawn\", \"deprecated\", \"superseded\"],\n events: decisionEvents,\n initial: \"proposed\",\n reduce,\n invariants,\n relate,\n project,\n body: { freezeOn: \"accepted\" },\n layout: { bodies: \"decisions\", events: \"events\" },\n defaultRoot: \"docs/adr\",\n sourceName: \"adr\",\n numbering: { on: \"accepted\", format: formatDecisionNumber, parse: parseDecisionNumber },\n templates: {\n dir: \"templates\",\n nameField: \"template\",\n versionField: \"template_version\",\n lintIn: [\"proposed\"],\n lintOn: \"accepted\",\n requireSections: [\"scope\"],\n },\n scope: { event: \"scoped\", activeIn: [\"proposed\", \"accepted\", \"deprecated\"] },\n options: Object.freeze({ acceptRequiresHuman: true }),\n});\n"],"mappings":"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"}