@adrkit/core 0.1.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 (60) hide show
  1. package/README.md +22 -0
  2. package/dist/LICENSE +201 -0
  3. package/dist/NOTICE +11 -0
  4. package/dist/affects/catalog.d.ts +14 -0
  5. package/dist/affects/index.d.ts +30 -0
  6. package/dist/affects/inert.d.ts +8 -0
  7. package/dist/affects/matchers/package.d.ts +20 -0
  8. package/dist/affects/matchers/path.d.ts +5 -0
  9. package/dist/check/index.d.ts +46 -0
  10. package/dist/graph/build.d.ts +18 -0
  11. package/dist/import/classify.d.ts +13 -0
  12. package/dist/import/fingerprint.d.ts +2 -0
  13. package/dist/import/index.d.ts +32 -0
  14. package/dist/import/madr.d.ts +21 -0
  15. package/dist/import/merge.d.ts +21 -0
  16. package/dist/import/status.d.ts +11 -0
  17. package/dist/index.d.ts +13 -0
  18. package/dist/index.js +1768 -0
  19. package/dist/load/corpus.d.ts +20 -0
  20. package/dist/parse/frontmatter.d.ts +10 -0
  21. package/dist/scaffold/new.d.ts +26 -0
  22. package/dist/schema/adr.schema.d.ts +416 -0
  23. package/dist/schema/adr.schema.js +182 -0
  24. package/dist/schema/emit.cli.d.ts +1 -0
  25. package/dist/schema/emit.d.ts +6 -0
  26. package/dist/schema/emit.js +200 -0
  27. package/dist/schema/index.d.ts +2 -0
  28. package/dist/schema/index.js +220 -0
  29. package/dist/validate/contract.d.ts +9 -0
  30. package/dist/validate/corpus-invariants.d.ts +3 -0
  31. package/dist/validate/findings.d.ts +19 -0
  32. package/dist/validate/import-incomplete.d.ts +3 -0
  33. package/dist/validate/index.d.ts +13 -0
  34. package/package.json +76 -0
  35. package/src/affects/catalog.ts +17 -0
  36. package/src/affects/index.ts +240 -0
  37. package/src/affects/inert.ts +63 -0
  38. package/src/affects/matchers/package.ts +102 -0
  39. package/src/affects/matchers/path.ts +37 -0
  40. package/src/check/index.ts +121 -0
  41. package/src/graph/build.ts +94 -0
  42. package/src/import/classify.ts +53 -0
  43. package/src/import/fingerprint.ts +10 -0
  44. package/src/import/index.ts +240 -0
  45. package/src/import/madr.ts +117 -0
  46. package/src/import/merge.ts +321 -0
  47. package/src/import/status.ts +48 -0
  48. package/src/index.ts +13 -0
  49. package/src/load/corpus.ts +101 -0
  50. package/src/parse/frontmatter.ts +73 -0
  51. package/src/scaffold/new.ts +208 -0
  52. package/src/schema/adr.schema.ts +338 -0
  53. package/src/schema/emit.cli.ts +9 -0
  54. package/src/schema/emit.ts +55 -0
  55. package/src/schema/index.ts +2 -0
  56. package/src/validate/contract.ts +120 -0
  57. package/src/validate/corpus-invariants.ts +77 -0
  58. package/src/validate/findings.ts +51 -0
  59. package/src/validate/import-incomplete.ts +23 -0
  60. package/src/validate/index.ts +68 -0
@@ -0,0 +1,200 @@
1
+ // src/schema/adr.schema.ts
2
+ import { z } from "zod";
3
+ var SCHEMA_VERSION = "0.1.0";
4
+ var Identity = z.string().regex(/^(@[A-Za-z0-9-]+|team:[a-z0-9-]+|[^@\s]+@[^@\s]+\.[^@\s]+)$/, "Expected @handle, team:slug, or an email address");
5
+ var AdrRef = z.string().regex(/^(([a-z0-9][a-z0-9-]*):)?([0-9]{4,}|[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26})$/, "Expected an ADR id, optionally prefixed with a log name");
6
+ var IsoDate = z.string().date();
7
+ var IsoDateTime = z.string().datetime({ offset: true });
8
+ var Slug = z.string().regex(/^[a-z0-9][a-z0-9-]*$/);
9
+ var strictObject = (shape) => z.strictObject(shape);
10
+ var uniqueArray = (item) => z.array(item).refine((xs) => new Set(xs.map((x) => JSON.stringify(x))).size === xs.length, {
11
+ message: "Items must be unique"
12
+ }).meta({ uniqueItems: true });
13
+ var Status = z.enum([
14
+ "draft",
15
+ "proposed",
16
+ "accepted",
17
+ "rejected",
18
+ "superseded",
19
+ "deprecated"
20
+ ]);
21
+ var Scope = z.enum(["component", "domain", "org"]);
22
+ var Reversibility = z.enum(["two-way-door", "one-way-door", "unknown"]);
23
+ var BlastRadius = z.enum(["component", "team", "cross-team", "org"]);
24
+ var ReviewTier = z.enum(["auto", "async", "arb"]);
25
+ var Severity = z.enum(["error", "warn", "info"]);
26
+ var EscalationReason = z.enum([
27
+ "one-way-door",
28
+ "cost-threshold",
29
+ "security-surface",
30
+ "data-residency",
31
+ "regulatory",
32
+ "contradicts-accepted-adr",
33
+ "low-confidence",
34
+ "pass-disagreement",
35
+ "agent-authored-production",
36
+ "novel-no-precedent",
37
+ "human-requested"
38
+ ]);
39
+ var AffectsType = z.enum([
40
+ "path",
41
+ "entity",
42
+ "package",
43
+ "resource",
44
+ "api",
45
+ "data"
46
+ ]);
47
+ var AffectsMatcher = strictObject({
48
+ type: AffectsType,
49
+ pattern: z.string().min(1),
50
+ repo: z.string().optional(),
51
+ negate: z.boolean().default(false),
52
+ note: z.string().optional()
53
+ });
54
+ var Assertion = strictObject({
55
+ id: Slug,
56
+ description: z.string().optional(),
57
+ engine: z.enum(["rego", "jsonpath", "grep", "custom"]),
58
+ expression: z.string().optional(),
59
+ expressionFile: z.string().optional(),
60
+ input: z.enum(["source", "iac-plan", "sbom", "openapi", "catalog", "custom"]).default("source"),
61
+ severity: Severity
62
+ });
63
+ var Provenance = strictObject({
64
+ authoredBy: z.enum(["human", "agent", "agent-drafted"]).default("human"),
65
+ agent: strictObject({
66
+ name: z.string().optional(),
67
+ model: z.string().optional(),
68
+ harness: z.string().optional(),
69
+ runId: z.string().optional()
70
+ }).optional(),
71
+ ratifiedBy: Identity.optional(),
72
+ sourceArtifact: z.string().optional(),
73
+ importedFrom: strictObject({
74
+ sourceKind: z.enum(["madr", "agent-log", "plan-artifact", "other"]),
75
+ sourceRef: z.string(),
76
+ fingerprint: z.string(),
77
+ importedAt: IsoDateTime.optional()
78
+ }).optional()
79
+ });
80
+ var Objection = strictObject({
81
+ by: Identity,
82
+ summary: z.string().optional(),
83
+ resolved: z.boolean().default(false)
84
+ });
85
+ var Review = strictObject({
86
+ tier: ReviewTier.optional(),
87
+ tierReason: z.string().optional(),
88
+ queuedAt: IsoDateTime.optional(),
89
+ slaDays: z.number().int().min(0).optional(),
90
+ escalatedAt: IsoDateTime.optional(),
91
+ decidedAt: IsoDateTime.optional(),
92
+ quorum: z.number().int().min(1).optional(),
93
+ approvals: z.array(Identity).default([]),
94
+ objections: z.array(Objection).default([])
95
+ });
96
+ var DeterministicFinding = strictObject({
97
+ rule: z.string(),
98
+ severity: Severity,
99
+ message: z.string().optional(),
100
+ adr: AdrRef.optional()
101
+ });
102
+ var Evaluation = strictObject({
103
+ ranAt: IsoDateTime.optional(),
104
+ evaluatorVersion: z.string().optional(),
105
+ rubricVersion: z.string().optional(),
106
+ scores: z.record(z.string(), z.number().min(0).max(4)).optional(),
107
+ confidence: z.number().min(0).max(1).optional(),
108
+ escalate: z.boolean().optional(),
109
+ escalationReasons: z.array(EscalationReason).default([]),
110
+ deterministicFindings: z.array(DeterministicFinding).default([])
111
+ });
112
+ var ExternalRef = strictObject({
113
+ type: z.enum(["issue", "pr", "rfc", "incident", "doc", "meeting", "control", "other"]),
114
+ id: z.string().optional(),
115
+ url: z.string().url(),
116
+ label: z.string().optional()
117
+ });
118
+ var AdrFrontmatter = strictObject({
119
+ schemaVersion: z.string().regex(/^\d+\.\d+\.\d+$/).default(SCHEMA_VERSION),
120
+ id: z.string().regex(/^([0-9]{4,}|[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26})$/),
121
+ title: z.string().min(3).max(120),
122
+ status: Status,
123
+ date: IsoDate,
124
+ created: IsoDate.optional(),
125
+ deciders: z.array(Identity).default([]),
126
+ consulted: z.array(Identity).default([]),
127
+ informed: z.array(Identity).default([]),
128
+ tags: uniqueArray(Slug).default([]),
129
+ scope: Scope.default("component"),
130
+ domain: z.string().optional(),
131
+ reversibility: Reversibility.default("unknown"),
132
+ blastRadius: BlastRadius.default("component"),
133
+ supersedes: uniqueArray(AdrRef).default([]),
134
+ supersededBy: AdrRef.optional(),
135
+ relatesTo: uniqueArray(AdrRef).default([]),
136
+ conflictsWith: z.array(AdrRef).default([]),
137
+ affects: z.array(AffectsMatcher).default([]),
138
+ assertions: z.array(Assertion).default([]),
139
+ provenance: Provenance.optional(),
140
+ review: Review.optional(),
141
+ evaluation: Evaluation.optional(),
142
+ externalRefs: z.array(ExternalRef).default([]),
143
+ complianceControls: uniqueArray(z.string()).default([]),
144
+ reviewBy: IsoDate.optional()
145
+ }).refine((a) => a.status === "superseded" ? Boolean(a.supersededBy) : true, {
146
+ message: 'status "superseded" requires supersededBy',
147
+ path: ["supersededBy"]
148
+ }).refine((a) => a.supersededBy ? a.status === "superseded" : true, {
149
+ message: 'supersededBy is set but status is not "superseded"',
150
+ path: ["status"]
151
+ }).refine((a) => a.status !== "accepted" || a.deciders.length > 0 || Boolean(a.provenance?.importedFrom), {
152
+ message: "an accepted decision must name at least one decider, unless it was imported",
153
+ path: ["deciders"]
154
+ }).refine((a) => a.status !== "accepted" || a.provenance?.authoredBy !== "agent" || Boolean(a.provenance?.ratifiedBy), {
155
+ message: 'an agent-authored record cannot reach "accepted" without a named human ratifier',
156
+ path: ["provenance", "ratifiedBy"]
157
+ }).refine((a) => !(a.reversibility === "one-way-door" && a.review?.tier === "auto"), {
158
+ message: "one-way-door decisions may not take the auto-approve fast path",
159
+ path: ["review", "tier"]
160
+ });
161
+
162
+ // src/schema/emit.ts
163
+ import { z as z2 } from "zod";
164
+ var ADR_SCHEMA_ID = `https://adrkit.dev/schema/adr/v${SCHEMA_VERSION}/adr.schema.json`;
165
+ function sortJson(value) {
166
+ if (Array.isArray(value)) {
167
+ return value.map((item) => sortJson(item));
168
+ }
169
+ if (value && typeof value === "object") {
170
+ const input = value;
171
+ const output = {};
172
+ for (const key of Object.keys(input).sort()) {
173
+ output[key] = sortJson(input[key]);
174
+ }
175
+ return output;
176
+ }
177
+ if (value === null || typeof value === "boolean" || typeof value === "number" || typeof value === "string") {
178
+ return value;
179
+ }
180
+ throw new TypeError(`Cannot serialize JSON schema value of type ${typeof value}`);
181
+ }
182
+ function emitJsonSchema() {
183
+ const schema = z2.toJSONSchema(AdrFrontmatter, { io: "input" });
184
+ const withMetadata = {
185
+ ...schema,
186
+ $id: ADR_SCHEMA_ID,
187
+ title: "Architecture Decision Record",
188
+ description: "Typed frontmatter for a decision record. A superset of MADR: every MADR field is present or derivable, plus governance, routing, provenance, and enforcement metadata. The markdown body below the frontmatter carries the prose."
189
+ };
190
+ return sortJson(withMetadata);
191
+ }
192
+ function stringifyJsonSchema(schema = emitJsonSchema()) {
193
+ return `${JSON.stringify(schema, null, 2)}
194
+ `;
195
+ }
196
+ export {
197
+ stringifyJsonSchema,
198
+ emitJsonSchema,
199
+ ADR_SCHEMA_ID
200
+ };
@@ -0,0 +1,2 @@
1
+ export * from './adr.schema.js';
2
+ export * from './emit.js';
@@ -0,0 +1,220 @@
1
+ // src/schema/adr.schema.ts
2
+ import { z } from "zod";
3
+ var SCHEMA_VERSION = "0.1.0";
4
+ var Identity = z.string().regex(/^(@[A-Za-z0-9-]+|team:[a-z0-9-]+|[^@\s]+@[^@\s]+\.[^@\s]+)$/, "Expected @handle, team:slug, or an email address");
5
+ var AdrRef = z.string().regex(/^(([a-z0-9][a-z0-9-]*):)?([0-9]{4,}|[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26})$/, "Expected an ADR id, optionally prefixed with a log name");
6
+ var IsoDate = z.string().date();
7
+ var IsoDateTime = z.string().datetime({ offset: true });
8
+ var Slug = z.string().regex(/^[a-z0-9][a-z0-9-]*$/);
9
+ var strictObject = (shape) => z.strictObject(shape);
10
+ var uniqueArray = (item) => z.array(item).refine((xs) => new Set(xs.map((x) => JSON.stringify(x))).size === xs.length, {
11
+ message: "Items must be unique"
12
+ }).meta({ uniqueItems: true });
13
+ var Status = z.enum([
14
+ "draft",
15
+ "proposed",
16
+ "accepted",
17
+ "rejected",
18
+ "superseded",
19
+ "deprecated"
20
+ ]);
21
+ var Scope = z.enum(["component", "domain", "org"]);
22
+ var Reversibility = z.enum(["two-way-door", "one-way-door", "unknown"]);
23
+ var BlastRadius = z.enum(["component", "team", "cross-team", "org"]);
24
+ var ReviewTier = z.enum(["auto", "async", "arb"]);
25
+ var Severity = z.enum(["error", "warn", "info"]);
26
+ var EscalationReason = z.enum([
27
+ "one-way-door",
28
+ "cost-threshold",
29
+ "security-surface",
30
+ "data-residency",
31
+ "regulatory",
32
+ "contradicts-accepted-adr",
33
+ "low-confidence",
34
+ "pass-disagreement",
35
+ "agent-authored-production",
36
+ "novel-no-precedent",
37
+ "human-requested"
38
+ ]);
39
+ var AffectsType = z.enum([
40
+ "path",
41
+ "entity",
42
+ "package",
43
+ "resource",
44
+ "api",
45
+ "data"
46
+ ]);
47
+ var AffectsMatcher = strictObject({
48
+ type: AffectsType,
49
+ pattern: z.string().min(1),
50
+ repo: z.string().optional(),
51
+ negate: z.boolean().default(false),
52
+ note: z.string().optional()
53
+ });
54
+ var Assertion = strictObject({
55
+ id: Slug,
56
+ description: z.string().optional(),
57
+ engine: z.enum(["rego", "jsonpath", "grep", "custom"]),
58
+ expression: z.string().optional(),
59
+ expressionFile: z.string().optional(),
60
+ input: z.enum(["source", "iac-plan", "sbom", "openapi", "catalog", "custom"]).default("source"),
61
+ severity: Severity
62
+ });
63
+ var Provenance = strictObject({
64
+ authoredBy: z.enum(["human", "agent", "agent-drafted"]).default("human"),
65
+ agent: strictObject({
66
+ name: z.string().optional(),
67
+ model: z.string().optional(),
68
+ harness: z.string().optional(),
69
+ runId: z.string().optional()
70
+ }).optional(),
71
+ ratifiedBy: Identity.optional(),
72
+ sourceArtifact: z.string().optional(),
73
+ importedFrom: strictObject({
74
+ sourceKind: z.enum(["madr", "agent-log", "plan-artifact", "other"]),
75
+ sourceRef: z.string(),
76
+ fingerprint: z.string(),
77
+ importedAt: IsoDateTime.optional()
78
+ }).optional()
79
+ });
80
+ var Objection = strictObject({
81
+ by: Identity,
82
+ summary: z.string().optional(),
83
+ resolved: z.boolean().default(false)
84
+ });
85
+ var Review = strictObject({
86
+ tier: ReviewTier.optional(),
87
+ tierReason: z.string().optional(),
88
+ queuedAt: IsoDateTime.optional(),
89
+ slaDays: z.number().int().min(0).optional(),
90
+ escalatedAt: IsoDateTime.optional(),
91
+ decidedAt: IsoDateTime.optional(),
92
+ quorum: z.number().int().min(1).optional(),
93
+ approvals: z.array(Identity).default([]),
94
+ objections: z.array(Objection).default([])
95
+ });
96
+ var DeterministicFinding = strictObject({
97
+ rule: z.string(),
98
+ severity: Severity,
99
+ message: z.string().optional(),
100
+ adr: AdrRef.optional()
101
+ });
102
+ var Evaluation = strictObject({
103
+ ranAt: IsoDateTime.optional(),
104
+ evaluatorVersion: z.string().optional(),
105
+ rubricVersion: z.string().optional(),
106
+ scores: z.record(z.string(), z.number().min(0).max(4)).optional(),
107
+ confidence: z.number().min(0).max(1).optional(),
108
+ escalate: z.boolean().optional(),
109
+ escalationReasons: z.array(EscalationReason).default([]),
110
+ deterministicFindings: z.array(DeterministicFinding).default([])
111
+ });
112
+ var ExternalRef = strictObject({
113
+ type: z.enum(["issue", "pr", "rfc", "incident", "doc", "meeting", "control", "other"]),
114
+ id: z.string().optional(),
115
+ url: z.string().url(),
116
+ label: z.string().optional()
117
+ });
118
+ var AdrFrontmatter = strictObject({
119
+ schemaVersion: z.string().regex(/^\d+\.\d+\.\d+$/).default(SCHEMA_VERSION),
120
+ id: z.string().regex(/^([0-9]{4,}|[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26})$/),
121
+ title: z.string().min(3).max(120),
122
+ status: Status,
123
+ date: IsoDate,
124
+ created: IsoDate.optional(),
125
+ deciders: z.array(Identity).default([]),
126
+ consulted: z.array(Identity).default([]),
127
+ informed: z.array(Identity).default([]),
128
+ tags: uniqueArray(Slug).default([]),
129
+ scope: Scope.default("component"),
130
+ domain: z.string().optional(),
131
+ reversibility: Reversibility.default("unknown"),
132
+ blastRadius: BlastRadius.default("component"),
133
+ supersedes: uniqueArray(AdrRef).default([]),
134
+ supersededBy: AdrRef.optional(),
135
+ relatesTo: uniqueArray(AdrRef).default([]),
136
+ conflictsWith: z.array(AdrRef).default([]),
137
+ affects: z.array(AffectsMatcher).default([]),
138
+ assertions: z.array(Assertion).default([]),
139
+ provenance: Provenance.optional(),
140
+ review: Review.optional(),
141
+ evaluation: Evaluation.optional(),
142
+ externalRefs: z.array(ExternalRef).default([]),
143
+ complianceControls: uniqueArray(z.string()).default([]),
144
+ reviewBy: IsoDate.optional()
145
+ }).refine((a) => a.status === "superseded" ? Boolean(a.supersededBy) : true, {
146
+ message: 'status "superseded" requires supersededBy',
147
+ path: ["supersededBy"]
148
+ }).refine((a) => a.supersededBy ? a.status === "superseded" : true, {
149
+ message: 'supersededBy is set but status is not "superseded"',
150
+ path: ["status"]
151
+ }).refine((a) => a.status !== "accepted" || a.deciders.length > 0 || Boolean(a.provenance?.importedFrom), {
152
+ message: "an accepted decision must name at least one decider, unless it was imported",
153
+ path: ["deciders"]
154
+ }).refine((a) => a.status !== "accepted" || a.provenance?.authoredBy !== "agent" || Boolean(a.provenance?.ratifiedBy), {
155
+ message: 'an agent-authored record cannot reach "accepted" without a named human ratifier',
156
+ path: ["provenance", "ratifiedBy"]
157
+ }).refine((a) => !(a.reversibility === "one-way-door" && a.review?.tier === "auto"), {
158
+ message: "one-way-door decisions may not take the auto-approve fast path",
159
+ path: ["review", "tier"]
160
+ });
161
+
162
+ // src/schema/emit.ts
163
+ import { z as z2 } from "zod";
164
+ var ADR_SCHEMA_ID = `https://adrkit.dev/schema/adr/v${SCHEMA_VERSION}/adr.schema.json`;
165
+ function sortJson(value) {
166
+ if (Array.isArray(value)) {
167
+ return value.map((item) => sortJson(item));
168
+ }
169
+ if (value && typeof value === "object") {
170
+ const input = value;
171
+ const output = {};
172
+ for (const key of Object.keys(input).sort()) {
173
+ output[key] = sortJson(input[key]);
174
+ }
175
+ return output;
176
+ }
177
+ if (value === null || typeof value === "boolean" || typeof value === "number" || typeof value === "string") {
178
+ return value;
179
+ }
180
+ throw new TypeError(`Cannot serialize JSON schema value of type ${typeof value}`);
181
+ }
182
+ function emitJsonSchema() {
183
+ const schema = z2.toJSONSchema(AdrFrontmatter, { io: "input" });
184
+ const withMetadata = {
185
+ ...schema,
186
+ $id: ADR_SCHEMA_ID,
187
+ title: "Architecture Decision Record",
188
+ description: "Typed frontmatter for a decision record. A superset of MADR: every MADR field is present or derivable, plus governance, routing, provenance, and enforcement metadata. The markdown body below the frontmatter carries the prose."
189
+ };
190
+ return sortJson(withMetadata);
191
+ }
192
+ function stringifyJsonSchema(schema = emitJsonSchema()) {
193
+ return `${JSON.stringify(schema, null, 2)}
194
+ `;
195
+ }
196
+ export {
197
+ stringifyJsonSchema,
198
+ emitJsonSchema,
199
+ Status,
200
+ Severity,
201
+ Scope,
202
+ SCHEMA_VERSION,
203
+ ReviewTier,
204
+ Review,
205
+ Reversibility,
206
+ Provenance,
207
+ Objection,
208
+ Identity,
209
+ ExternalRef,
210
+ Evaluation,
211
+ EscalationReason,
212
+ DeterministicFinding,
213
+ BlastRadius,
214
+ Assertion,
215
+ AffectsType,
216
+ AffectsMatcher,
217
+ AdrRef,
218
+ AdrFrontmatter,
219
+ ADR_SCHEMA_ID
220
+ };
@@ -0,0 +1,9 @@
1
+ import { type Adr } from '../schema/adr.schema.js';
2
+ import type { ParsedAdrFile } from '../load/corpus.js';
3
+ import type { Finding } from './findings.js';
4
+ export interface ContractValidationResult {
5
+ record?: Adr;
6
+ findings: Finding[];
7
+ }
8
+ export declare function validateParsedAdr(parsed: ParsedAdrFile): ContractValidationResult;
9
+ export declare function validateAdrFrontmatter(data: unknown, path: string): ContractValidationResult;
@@ -0,0 +1,3 @@
1
+ import type { Adr } from '../schema/adr.schema.js';
2
+ import type { Finding } from './findings.js';
3
+ export declare function validateCorpusInvariants(records: readonly Adr[]): Finding[];
@@ -0,0 +1,19 @@
1
+ export declare const IMPORT_FINDING_RULES: readonly ["import-incomplete", "import-status-unrecognized", "import-not-madr"];
2
+ export type ImportFindingRule = (typeof IMPORT_FINDING_RULES)[number];
3
+ export type FindingSeverity = 'error' | 'warn' | 'info';
4
+ export interface Finding {
5
+ rule: string;
6
+ severity: FindingSeverity;
7
+ message: string;
8
+ path?: string;
9
+ id?: string;
10
+ field?: string;
11
+ pattern?: string;
12
+ }
13
+ export declare function sortFindings(findings: readonly Finding[]): Finding[];
14
+ export declare function countFindings(findings: readonly Finding[]): {
15
+ errors: number;
16
+ warnings: number;
17
+ infos: number;
18
+ };
19
+ export declare function exitCodeForFindings(findings: readonly Finding[]): 0 | 1;
@@ -0,0 +1,3 @@
1
+ import type { Adr } from '../schema/adr.schema.js';
2
+ import type { Finding } from './findings.js';
3
+ export declare function validateImportIncomplete(records: readonly Adr[]): Finding[];
@@ -0,0 +1,13 @@
1
+ import type { Adr } from '../schema/adr.schema.js';
2
+ import { type Finding } from './findings.js';
3
+ export interface LintCorpusOptions {
4
+ dir?: string;
5
+ paths?: string[];
6
+ cwd?: string;
7
+ }
8
+ export interface LintCorpusResult {
9
+ checked: number;
10
+ findings: Finding[];
11
+ records: Adr[];
12
+ }
13
+ export declare function lintCorpus(options?: LintCorpusOptions): Promise<LintCorpusResult>;
package/package.json ADDED
@@ -0,0 +1,76 @@
1
+ {
2
+ "name": "@adrkit/core",
3
+ "version": "0.1.0",
4
+ "description": "Pure ADR parsing, validation, migration, and affects resolution for adrkit.",
5
+ "type": "module",
6
+ "license": "Apache-2.0",
7
+ "homepage": "https://adrkit.dev",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/mbeacom/adrkit.git",
11
+ "directory": "packages/core"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/mbeacom/adrkit/issues"
15
+ },
16
+ "keywords": [
17
+ "adr",
18
+ "architecture-decision-records",
19
+ "governance"
20
+ ],
21
+ "engines": {
22
+ "node": ">=22"
23
+ },
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "exports": {
28
+ ".": {
29
+ "bun": "./src/index.ts",
30
+ "types": "./dist/index.d.ts",
31
+ "import": "./dist/index.js",
32
+ "default": "./dist/index.js"
33
+ },
34
+ "./schema": {
35
+ "bun": "./src/schema/index.ts",
36
+ "types": "./dist/schema/index.d.ts",
37
+ "import": "./dist/schema/index.js",
38
+ "default": "./dist/schema/index.js"
39
+ },
40
+ "./schema/adr.schema": {
41
+ "bun": "./src/schema/adr.schema.ts",
42
+ "types": "./dist/schema/adr.schema.d.ts",
43
+ "import": "./dist/schema/adr.schema.js",
44
+ "default": "./dist/schema/adr.schema.js"
45
+ },
46
+ "./schema/emit": {
47
+ "bun": "./src/schema/emit.ts",
48
+ "types": "./dist/schema/emit.d.ts",
49
+ "import": "./dist/schema/emit.js",
50
+ "default": "./dist/schema/emit.js"
51
+ }
52
+ },
53
+ "scripts": {
54
+ "build": "rm -rf dist && bun build ./src/index.ts ./src/schema/index.ts ./src/schema/adr.schema.ts ./src/schema/emit.ts --target=node --outdir=dist --packages=external && tsc --project tsconfig.build.json && bun ../../scripts/normalize-dts-imports.ts dist && cp ../../LICENSE ../../NOTICE dist/",
55
+ "lint": "bun run typecheck",
56
+ "prepack": "bun run build",
57
+ "schema:emit": "bun ./src/schema/emit.cli.ts",
58
+ "typecheck": "tsc --noEmit --customConditions bun --project ../../tsconfig.json"
59
+ },
60
+ "dependencies": {
61
+ "picomatch": "^4",
62
+ "semver": "^7",
63
+ "yaml": "latest",
64
+ "zod": "^4"
65
+ },
66
+ "devDependencies": {
67
+ "@types/bun": "latest",
68
+ "@types/picomatch": "^4",
69
+ "@types/semver": "^7"
70
+ },
71
+ "files": [
72
+ "dist",
73
+ "README.md",
74
+ "src"
75
+ ]
76
+ }
@@ -0,0 +1,17 @@
1
+ export type EntityId = string;
2
+
3
+ export interface CatalogSnapshotEntity {
4
+ id: EntityId;
5
+ refs?: readonly string[];
6
+ paths?: readonly string[];
7
+ }
8
+
9
+ export interface CatalogSnapshot {
10
+ entities: readonly CatalogSnapshotEntity[];
11
+ }
12
+
13
+ export interface CatalogPort {
14
+ resolveEntity(ref: string): readonly EntityId[];
15
+ entitiesForPaths(paths: readonly string[]): readonly EntityId[];
16
+ snapshot(): CatalogSnapshot;
17
+ }