plumbbob 0.9.5 → 0.10.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 (142) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +87 -86
  3. package/dist/cli-core.js +8 -8
  4. package/dist/cli.js +1 -1
  5. package/dist/lib/agents.js +26 -26
  6. package/dist/lib/buildlog.js +11 -11
  7. package/dist/lib/buildlogsync.js +8 -8
  8. package/dist/lib/check.js +14 -14
  9. package/dist/lib/commitbody.js +72 -0
  10. package/dist/lib/commitmsg.js +7 -7
  11. package/dist/lib/git.js +44 -15
  12. package/dist/lib/intent.js +20 -19
  13. package/dist/lib/latch.js +16 -16
  14. package/dist/lib/orient.js +36 -17
  15. package/dist/lib/reentry.js +3 -3
  16. package/dist/lib/settings.js +16 -16
  17. package/dist/lib/sidecar.js +54 -54
  18. package/dist/lib/templates.js +1 -1
  19. package/dist/verbs/agent.js +25 -25
  20. package/dist/verbs/build.js +9 -9
  21. package/dist/verbs/check.js +6 -6
  22. package/dist/verbs/checkpoint.js +48 -47
  23. package/dist/verbs/doctor.js +27 -26
  24. package/dist/verbs/finish.js +27 -40
  25. package/dist/verbs/handoff.js +9 -8
  26. package/dist/verbs/init.js +9 -9
  27. package/dist/verbs/park.js +3 -3
  28. package/dist/verbs/recover.js +11 -11
  29. package/dist/verbs/revert.js +12 -12
  30. package/dist/verbs/spike.js +17 -17
  31. package/dist/verbs/start.js +49 -19
  32. package/dist/verbs/status.js +8 -8
  33. package/dist/verbs/turn.js +16 -16
  34. package/dist/verbs/use.js +4 -4
  35. package/node_modules/checkride/.claude-plugin/plugin.json +1 -1
  36. package/node_modules/checkride/CHANGELOG.md +401 -0
  37. package/node_modules/checkride/README.md +27 -9
  38. package/node_modules/checkride/dist/adapters.d.ts +12 -4
  39. package/node_modules/checkride/dist/adapters.d.ts.map +1 -1
  40. package/node_modules/checkride/dist/adapters.js +21 -1
  41. package/node_modules/checkride/dist/adapters.js.map +1 -1
  42. package/node_modules/checkride/dist/agent-setup/cursor.d.ts +9 -1
  43. package/node_modules/checkride/dist/agent-setup/cursor.d.ts.map +1 -1
  44. package/node_modules/checkride/dist/agent-setup/cursor.js +59 -1
  45. package/node_modules/checkride/dist/agent-setup/cursor.js.map +1 -1
  46. package/node_modules/checkride/dist/agent-setup/harness.d.ts +1 -1
  47. package/node_modules/checkride/dist/agent-setup/harness.d.ts.map +1 -1
  48. package/node_modules/checkride/dist/agent-setup/harness.js +10 -1
  49. package/node_modules/checkride/dist/agent-setup/harness.js.map +1 -1
  50. package/node_modules/checkride/dist/agent-setup/scripts.d.ts +23 -0
  51. package/node_modules/checkride/dist/agent-setup/scripts.d.ts.map +1 -1
  52. package/node_modules/checkride/dist/agent-setup/scripts.js +387 -82
  53. package/node_modules/checkride/dist/agent-setup/scripts.js.map +1 -1
  54. package/node_modules/checkride/dist/baseline/fallow.js +2 -2
  55. package/node_modules/checkride/dist/baseline/fingerprint.d.ts +14 -5
  56. package/node_modules/checkride/dist/baseline/fingerprint.d.ts.map +1 -1
  57. package/node_modules/checkride/dist/baseline/fingerprint.js +58 -5
  58. package/node_modules/checkride/dist/baseline/fingerprint.js.map +1 -1
  59. package/node_modules/checkride/dist/baseline/history.d.ts +98 -0
  60. package/node_modules/checkride/dist/baseline/history.d.ts.map +1 -0
  61. package/node_modules/checkride/dist/baseline/history.js +232 -0
  62. package/node_modules/checkride/dist/baseline/history.js.map +1 -0
  63. package/node_modules/checkride/dist/baseline/index.d.ts +4 -2
  64. package/node_modules/checkride/dist/baseline/index.d.ts.map +1 -1
  65. package/node_modules/checkride/dist/baseline/index.js +2 -1
  66. package/node_modules/checkride/dist/baseline/index.js.map +1 -1
  67. package/node_modules/checkride/dist/baseline/store.d.ts +30 -7
  68. package/node_modules/checkride/dist/baseline/store.d.ts.map +1 -1
  69. package/node_modules/checkride/dist/baseline/store.js +50 -16
  70. package/node_modules/checkride/dist/baseline/store.js.map +1 -1
  71. package/node_modules/checkride/dist/cli.d.ts +5 -1
  72. package/node_modules/checkride/dist/cli.d.ts.map +1 -1
  73. package/node_modules/checkride/dist/cli.js +98 -25
  74. package/node_modules/checkride/dist/cli.js.map +1 -1
  75. package/node_modules/checkride/dist/config.d.ts +33 -4
  76. package/node_modules/checkride/dist/config.d.ts.map +1 -1
  77. package/node_modules/checkride/dist/config.js +21 -6
  78. package/node_modules/checkride/dist/config.js.map +1 -1
  79. package/node_modules/checkride/dist/digest/digest.js +1 -1
  80. package/node_modules/checkride/dist/doctor.d.ts +2 -0
  81. package/node_modules/checkride/dist/doctor.d.ts.map +1 -1
  82. package/node_modules/checkride/dist/doctor.js +39 -1
  83. package/node_modules/checkride/dist/doctor.js.map +1 -1
  84. package/node_modules/checkride/dist/gate.d.ts +49 -4
  85. package/node_modules/checkride/dist/gate.d.ts.map +1 -1
  86. package/node_modules/checkride/dist/gate.js +143 -16
  87. package/node_modules/checkride/dist/gate.js.map +1 -1
  88. package/node_modules/checkride/dist/init.d.ts +8 -1
  89. package/node_modules/checkride/dist/init.d.ts.map +1 -1
  90. package/node_modules/checkride/dist/init.js +68 -7
  91. package/node_modules/checkride/dist/init.js.map +1 -1
  92. package/node_modules/checkride/dist/node-pin.d.ts +1 -1
  93. package/node_modules/checkride/dist/node-pin.js +1 -1
  94. package/node_modules/checkride/dist/orchestrator.d.ts +13 -0
  95. package/node_modules/checkride/dist/orchestrator.d.ts.map +1 -1
  96. package/node_modules/checkride/dist/orchestrator.js +118 -13
  97. package/node_modules/checkride/dist/orchestrator.js.map +1 -1
  98. package/node_modules/checkride/dist/pm/index.d.ts +1 -0
  99. package/node_modules/checkride/dist/pm/index.d.ts.map +1 -1
  100. package/node_modules/checkride/dist/pm/index.js.map +1 -1
  101. package/node_modules/checkride/dist/pm/launch.d.ts +23 -2
  102. package/node_modules/checkride/dist/pm/launch.d.ts.map +1 -1
  103. package/node_modules/checkride/dist/pm/launch.js +16 -0
  104. package/node_modules/checkride/dist/pm/launch.js.map +1 -1
  105. package/node_modules/checkride/dist/pm/translate.js +1 -1
  106. package/node_modules/checkride/dist/pm/translate.js.map +1 -1
  107. package/node_modules/checkride/dist/qa/mutation.d.ts +4 -4
  108. package/node_modules/checkride/dist/qa/mutation.js +4 -4
  109. package/node_modules/checkride/dist/recover.d.ts +48 -0
  110. package/node_modules/checkride/dist/recover.d.ts.map +1 -0
  111. package/node_modules/checkride/dist/recover.js +220 -0
  112. package/node_modules/checkride/dist/recover.js.map +1 -0
  113. package/node_modules/checkride/dist/smoke.d.ts +1 -1
  114. package/node_modules/checkride/dist/smoke.js +1 -1
  115. package/node_modules/checkride/dist/snippets.d.ts +1 -1
  116. package/node_modules/checkride/package.json +3 -2
  117. package/node_modules/checkride/schema/checkride.config.schema.json +9 -1
  118. package/node_modules/checkride/skills/check/SKILL.md +9 -1
  119. package/node_modules/checkride/templates/shared/styles/Repo/Drift.yml +41 -0
  120. package/node_modules/checkride/templates/shared/styles/Repo/Latin.yml +14 -0
  121. package/node_modules/checkride/templates/shared/styles/Repo/LyHyphen.yml +28 -0
  122. package/node_modules/checkride/templates/shared/styles/Repo/Minted.yml +33 -0
  123. package/node_modules/checkride/templates/shared/styles/Repo/ThereIs.yml +16 -0
  124. package/node_modules/checkride/templates/shared/styles/Repo/Weasel.yml +26 -0
  125. package/node_modules/checkride/templates/shared/vale.ini +34 -0
  126. package/package.json +10 -9
  127. package/skills/build/SKILL.md +69 -64
  128. package/skills/doctor/SKILL.md +11 -11
  129. package/skills/finish/SKILL.md +20 -19
  130. package/skills/harvest/SKILL.md +13 -12
  131. package/skills/park/SKILL.md +10 -10
  132. package/skills/plan/SKILL.md +63 -54
  133. package/skills/recover/SKILL.md +6 -6
  134. package/skills/refine/SKILL.md +18 -16
  135. package/skills/revert/SKILL.md +6 -6
  136. package/skills/spike/SKILL.md +9 -9
  137. package/skills/status/SKILL.md +5 -5
  138. package/skills/step/SKILL.md +17 -12
  139. package/skills/verify/SKILL.md +45 -40
  140. package/templates/build-log.md +7 -7
  141. package/templates/intent.md +49 -39
  142. package/templates/spike-report.md +10 -10
@@ -13,9 +13,9 @@
13
13
  * an adapter whose output isn't a stable diagnostic set simply has no extractor
14
14
  * and returns `null` — baseline is unsupported for that slot, decided
15
15
  * per-adapter against real fixtures, not from an up-front list. Extractors
16
- * ship for the blessed lint/struct/spell adapters (oxlint, ast-grep, cspell) and
17
- * for fallow's three analyses (dead-code, dupes, health — see `./fallow.ts`,
18
- * which also owns fallow's gating verdict).
16
+ * ship for the blessed lint/struct/spell/prose adapters (oxlint, ast-grep,
17
+ * cspell, vale) and for fallow's three analyses (dead-code, dupes, health — see
18
+ * `./fallow.ts`, which also owns fallow's gating verdict).
19
19
  */
20
20
  /** A stable, order-independent set of diagnostic keys for one adapter's output. */
21
21
  export type Fingerprint = ReadonlySet<string>;
@@ -25,15 +25,24 @@ export type Fingerprint = ReadonlySet<string>;
25
25
  * alternate tool that shares a slot with a supported default (biome/eslint for
26
26
  * `lint`, knip for `dead`) opts out until it grows its own extractor. A
27
27
  * supported adapter with zero findings returns an empty set, never `null` —
28
- * "supported but clean" and "unsupported" are distinct, and masking and the
28
+ * "supported but clean" and "not observed" are distinct, and masking and the
29
29
  * ratchet depend on the difference.
30
+ *
31
+ * `null` therefore has two readings, and callers treat them the same way: no
32
+ * extractor for this adapter (decided by name, before any output), or an
33
+ * extractor that read its output and could not trust it — vale's runtime-error
34
+ * report being the one case a format can say that about (see
35
+ * {@link extractVale}). Either way the run contributes nothing to the baseline
36
+ * and prunes nothing from it.
30
37
  */
31
38
  export declare function fingerprint(adapter: string, raw: string): Fingerprint | null;
32
39
  /**
33
40
  * Whether an adapter can be fingerprinted (has an extractor), decided by name
34
41
  * without needing its output. `init --baseline` uses this to tell which failing
35
42
  * slots the baseline can grandfather from those that must still fall back to a
36
- * `false` disable.
43
+ * `false` disable. It answers for the adapter, not for a particular run: a
44
+ * fingerprintable adapter can still yield `null` on output it can't trust, in
45
+ * which case that run simply grandfathers nothing.
37
46
  */
38
47
  export declare function isFingerprintable(adapter: string): boolean;
39
48
  //# sourceMappingURL=fingerprint.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../../src/baseline/fingerprint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAMH,mFAAmF;AACnF,MAAM,MAAM,WAAW,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;AAqF9C;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAG5E;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE1D"}
1
+ {"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../../src/baseline/fingerprint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAMH,mFAAmF;AACnF,MAAM,MAAM,WAAW,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;AAyI9C;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAG5E;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE1D"}
@@ -13,9 +13,9 @@
13
13
  * an adapter whose output isn't a stable diagnostic set simply has no extractor
14
14
  * and returns `null` — baseline is unsupported for that slot, decided
15
15
  * per-adapter against real fixtures, not from an up-front list. Extractors
16
- * ship for the blessed lint/struct/spell adapters (oxlint, ast-grep, cspell) and
17
- * for fallow's three analyses (dead-code, dupes, health — see `./fallow.ts`,
18
- * which also owns fallow's gating verdict).
16
+ * ship for the blessed lint/struct/spell/prose adapters (oxlint, ast-grep,
17
+ * cspell, vale) and for fallow's three analyses (dead-code, dupes, health — see
18
+ * `./fallow.ts`, which also owns fallow's gating verdict).
19
19
  */
20
20
  import { isRecord } from '../json.js';
21
21
  import { parseToolJson } from '../tool-json.js';
@@ -86,11 +86,55 @@ const extractCspell = (raw) => {
86
86
  }
87
87
  return keys;
88
88
  };
89
+ /**
90
+ * Whether a parsed vale payload is an *alert report* — the `{ "<path>": [alert,
91
+ * …] }` shape a lint run emits — rather than one of the flat runtime-error
92
+ * objects (`{ Code: "E100" | "E201", Text, Path, Line, Span }`) it emits instead
93
+ * when the config won't load. Every value of an alert report is an array of
94
+ * alerts; an error report's are scalars, so the two never look alike. A clean
95
+ * run's `{}` passes vacuously, which is the point: "clean" must stay
96
+ * distinguishable from "broken".
97
+ */
98
+ function isValeAlertReport(payload) {
99
+ return (isRecord(payload) && Object.values(payload).every((alerts) => Array.isArray(alerts) && alerts.every(isRecord)));
100
+ }
101
+ /**
102
+ * vale `--output=JSON`: `{ "<path>": [{ Check, Message, Severity }] }`.
103
+ *
104
+ * Only error-severity alerts are keyed. Vale's exit code — the `prose` slot's
105
+ * whole verdict — is 1 iff an error-severity alert exists, so a warning can
106
+ * never fail a check; fingerprinting one would hand an advisory alert gating
107
+ * power in a baselined repo (a new warning key blocks masking on an otherwise
108
+ * grandfathered red run) and churn the ratchet with keys no verdict can use.
109
+ *
110
+ * Returns `null` — never the empty set — for anything that is not an alert
111
+ * report. A runtime error (`E100` no config, `E201` bad config) is a flat object
112
+ * that an alert-shaped reader would happily see as zero findings, and one such
113
+ * run would prune every grandfathered prose key out of the baseline on the next
114
+ * ratchet. `null` means "not observed", which leaves the baseline standing.
115
+ */
116
+ const extractVale = (raw) => {
117
+ const payload = parseJson(raw);
118
+ if (!isValeAlertReport(payload))
119
+ return null;
120
+ const keys = new Set();
121
+ for (const [file, alerts] of Object.entries(payload)) {
122
+ for (const a of alerts) {
123
+ if (str(a['Severity']) !== 'error')
124
+ continue;
125
+ const message = str(a['Message']);
126
+ if (file && message)
127
+ keys.add(key(file, str(a['Check']), message));
128
+ }
129
+ }
130
+ return keys;
131
+ };
89
132
  /** Extractors keyed by adapter name (not slot); everything else sits out. */
90
133
  const EXTRACTORS = {
91
134
  oxlint: extractOxlint,
92
135
  'ast-grep': extractAstGrep,
93
136
  cspell: extractCspell,
137
+ vale: extractVale,
94
138
  // One `fallow` adapter fills all three fallow slots (dead/dupes/health); its
95
139
  // extractor dispatches on the report's `kind`, so a single registration serves
96
140
  // every slot. See `./fallow.ts`.
@@ -102,8 +146,15 @@ const EXTRACTORS = {
102
146
  * alternate tool that shares a slot with a supported default (biome/eslint for
103
147
  * `lint`, knip for `dead`) opts out until it grows its own extractor. A
104
148
  * supported adapter with zero findings returns an empty set, never `null` —
105
- * "supported but clean" and "unsupported" are distinct, and masking and the
149
+ * "supported but clean" and "not observed" are distinct, and masking and the
106
150
  * ratchet depend on the difference.
151
+ *
152
+ * `null` therefore has two readings, and callers treat them the same way: no
153
+ * extractor for this adapter (decided by name, before any output), or an
154
+ * extractor that read its output and could not trust it — vale's runtime-error
155
+ * report being the one case a format can say that about (see
156
+ * {@link extractVale}). Either way the run contributes nothing to the baseline
157
+ * and prunes nothing from it.
107
158
  */
108
159
  export function fingerprint(adapter, raw) {
109
160
  const extractor = EXTRACTORS[adapter];
@@ -113,7 +164,9 @@ export function fingerprint(adapter, raw) {
113
164
  * Whether an adapter can be fingerprinted (has an extractor), decided by name
114
165
  * without needing its output. `init --baseline` uses this to tell which failing
115
166
  * slots the baseline can grandfather from those that must still fall back to a
116
- * `false` disable.
167
+ * `false` disable. It answers for the adapter, not for a particular run: a
168
+ * fingerprintable adapter can still yield `null` on output it can't trust, in
169
+ * which case that run simply grandfathers nothing.
117
170
  */
118
171
  export function isFingerprintable(adapter) {
119
172
  return EXTRACTORS[adapter] !== undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../../src/baseline/fingerprint.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../../src/baseline/fingerprint.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Git plumbing for baseline recovery: reconstruct recent committed states of
3
+ * `checkride.baseline.json` so a clobbered file (a botched merge, an agent
4
+ * resolving a conflict by deleting the "problem" lines) can be restored without
5
+ * manual archaeology. Everything here is read-only toward git — recovery writes
6
+ * the file through `writeBaseline`, never `git checkout`, so a restore lands as
7
+ * an ordinary reviewable working-tree edit.
8
+ *
9
+ * `git log --follow` is deliberately not used: the baseline's name and location
10
+ * are constants ({@link BASELINE_FILE}), so history beyond a rename boundary
11
+ * would describe a different file — and a repo that renamed the baseline is not
12
+ * running stock checkride anyway.
13
+ */
14
+ import type { Baseline } from './store.js';
15
+ /** Why a git invocation failed, classified for user-facing messages. */
16
+ export type GitFailure = 'missing' | 'not-a-repo' | 'timeout' | 'failed';
17
+ export type GitResult = {
18
+ ok: true;
19
+ stdout: string;
20
+ } | {
21
+ ok: false;
22
+ error: GitFailure;
23
+ detail: string;
24
+ };
25
+ /** Runs `git <args>`; injectable so history logic is testable without a repo. */
26
+ export type GitRunner = (args: readonly string[]) => Promise<GitResult>;
27
+ /** Commits of file history walked when `--depth` is not given. */
28
+ export declare const DEFAULT_DEPTH = 25;
29
+ /** The real runner: `git` under `cwd`, with a timeout so recovery can't hang. */
30
+ export declare function realGit(cwd: string, timeoutMs?: number): GitRunner;
31
+ /** The user-facing error for a failed git invocation; `runCli` renders it as exit 2. */
32
+ export declare function gitFailureError(result: {
33
+ error: GitFailure;
34
+ detail: string;
35
+ }): Error;
36
+ /** One commit that touched the baseline file. */
37
+ export type BaselineRevision = {
38
+ sha: string;
39
+ shortSha: string;
40
+ date: string;
41
+ author: string;
42
+ subject: string;
43
+ };
44
+ export type Candidate = {
45
+ kind: 'snapshot';
46
+ rev: BaselineRevision;
47
+ baseline: Baseline;
48
+ } | {
49
+ kind: 'union';
50
+ baseline: Baseline;
51
+ folded: number;
52
+ };
53
+ export type HistoryScan = {
54
+ /** Union first (when it adds anything), then distinct snapshots newest-first. */
55
+ candidates: Candidate[];
56
+ /** Commits whose snapshot was actually examined (≤ the log's length). */
57
+ walked: number;
58
+ /** Short shas whose blob was unreadable or unparseable — skipped, never fatal. */
59
+ skipped: string[];
60
+ /** A shallow clone's log is truncated; said in the report, never an error. */
61
+ shallow: boolean;
62
+ };
63
+ /** Whether the working-tree baseline carries uncommitted changes. */
64
+ export declare function baselineDirty(git: GitRunner): Promise<boolean>;
65
+ export declare function collectCandidates(git: GitRunner, current: Baseline | null, depth: number): Promise<HistoryScan>;
66
+ /** Per-slot key union of every part, canonical (sorted slots and keys). */
67
+ export declare function unionBaselines(parts: readonly Baseline[]): Baseline;
68
+ /** What the red-run probe found: `matched` of `total` new keys were grandfathered at `shortSha`. */
69
+ export type HistoricalHint = {
70
+ matched: number;
71
+ total: number;
72
+ shortSha: string;
73
+ };
74
+ /**
75
+ * The red-run detection probe: were these "new" findings grandfathered in a
76
+ * recent committed baseline? The difference between "a wall of new debt" and
77
+ * "a merge dropped baseline entries" is a diagnosis the run output alone
78
+ * cannot make. Strictly best-effort: the whole probe races a
79
+ * {@link HINT_BUDGET_MS} budget, its git children carry the same short
80
+ * timeout, and any failure — git absent, not a repository, shallow miss,
81
+ * mangled blobs — resolves to `null`, never a thrown error or a slow run.
82
+ */
83
+ export declare function historicalHint(cwd: string, newKeys: readonly string[], git?: GitRunner, budgetMs?: number): Promise<HistoricalHint | null>;
84
+ /** What applying `to` over `from` changes, per slot: keys gained and keys lost. */
85
+ export type BaselineDelta = {
86
+ restored: Record<string, string[]>;
87
+ absent: Record<string, string[]>;
88
+ restoredCount: number;
89
+ absentCount: number;
90
+ };
91
+ /**
92
+ * `restored` is what an apply adds; `absent` is what only an `--exact` apply
93
+ * would drop (the default union write never removes a key, so its `absent` side
94
+ * is empty by construction — the renderer still shows it so `--exact`'s cost is
95
+ * visible before it is paid).
96
+ */
97
+ export declare function diffBaselines(from: Baseline | null, to: Baseline): BaselineDelta;
98
+ //# sourceMappingURL=history.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../../src/baseline/history.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,232 @@
1
+ /**
2
+ * Git plumbing for baseline recovery: reconstruct recent committed states of
3
+ * `checkride.baseline.json` so a clobbered file (a botched merge, an agent
4
+ * resolving a conflict by deleting the "problem" lines) can be restored without
5
+ * manual archaeology. Everything here is read-only toward git — recovery writes
6
+ * the file through `writeBaseline`, never `git checkout`, so a restore lands as
7
+ * an ordinary reviewable working-tree edit.
8
+ *
9
+ * `git log --follow` is deliberately not used: the baseline's name and location
10
+ * are constants ({@link BASELINE_FILE}), so history beyond a rename boundary
11
+ * would describe a different file — and a repo that renamed the baseline is not
12
+ * running stock checkride anyway.
13
+ */
14
+ import { execFile } from 'node:child_process';
15
+ import { promisify } from 'node:util';
16
+ import { BASELINE_FILE, BASELINE_SCHEMA_VERSION, baselinesEqual, parseBaseline } from './store.js';
17
+ const execFileP = promisify(execFile);
18
+ const GIT_TIMEOUT_MS = 10_000;
19
+ /** A monorepo baseline can be large; a `git show` must not be truncated mid-blob. */
20
+ const GIT_MAX_BUFFER = 64 * 1024 * 1024;
21
+ /** At most this many distinct snapshots are presented — a small set to choose from. */
22
+ const MAX_SNAPSHOTS = 5;
23
+ /** Commits of file history walked when `--depth` is not given. */
24
+ export const DEFAULT_DEPTH = 25;
25
+ /** The `code`/`killed`/`stderr` shape of a rejected `execFile`, checked not cast. */
26
+ function rejection(err) {
27
+ if (typeof err !== 'object' || err === null)
28
+ return {};
29
+ const out = {};
30
+ if ('code' in err && typeof err.code === 'string')
31
+ out.code = err.code;
32
+ if ('killed' in err && typeof err.killed === 'boolean')
33
+ out.killed = err.killed;
34
+ if ('stderr' in err && typeof err.stderr === 'string')
35
+ out.stderr = err.stderr;
36
+ return out;
37
+ }
38
+ /** The real runner: `git` under `cwd`, with a timeout so recovery can't hang. */
39
+ export function realGit(cwd, timeoutMs = GIT_TIMEOUT_MS) {
40
+ return async (args) => {
41
+ try {
42
+ const { stdout } = await execFileP('git', [...args], { cwd, timeout: timeoutMs, maxBuffer: GIT_MAX_BUFFER });
43
+ return { ok: true, stdout };
44
+ }
45
+ catch (err) {
46
+ const e = rejection(err);
47
+ if (e.code === 'ENOENT')
48
+ return { ok: false, error: 'missing', detail: 'git not found on PATH' };
49
+ if (e.killed === true)
50
+ return { ok: false, error: 'timeout', detail: `git ${args[0]} timed out (>${GIT_TIMEOUT_MS / 1000}s)` };
51
+ const stderr = (e.stderr ?? '').trim();
52
+ if (stderr.includes('not a git repository'))
53
+ return { ok: false, error: 'not-a-repo', detail: stderr };
54
+ return { ok: false, error: 'failed', detail: stderr.length > 0 ? stderr : `git ${args[0]} failed` };
55
+ }
56
+ };
57
+ }
58
+ /** The user-facing error for a failed git invocation; `runCli` renders it as exit 2. */
59
+ export function gitFailureError(result) {
60
+ if (result.error === 'missing')
61
+ return new Error('recover: git is required but was not found on PATH');
62
+ if (result.error === 'not-a-repo')
63
+ return new Error('recover: not inside a git repository');
64
+ return new Error(`recover: ${result.detail}`);
65
+ }
66
+ /**
67
+ * Field/record separators keep `git log` parsing exact: a subject line may
68
+ * contain anything printable, but never the unit or record separator bytes.
69
+ */
70
+ const LOG_FORMAT = '%H%x1f%h%x1f%cI%x1f%an%x1f%s%x1e';
71
+ function parseLog(stdout) {
72
+ return stdout
73
+ .split('\x1e')
74
+ .map((record) => record.replace(/^\n/, ''))
75
+ .filter((record) => record.length > 0)
76
+ .map((record) => {
77
+ const [sha = '', shortSha = '', date = '', author = '', subject = ''] = record.split('\x1f');
78
+ return { sha, shortSha, date, author, subject };
79
+ })
80
+ .filter((rev) => rev.sha.length > 0);
81
+ }
82
+ /**
83
+ * Where the baseline lives relative to the *git* root — in a monorepo the
84
+ * checkride root is often a subdirectory, and `git show <sha>:<path>` resolves
85
+ * `<path>` from the repository root, not from cwd.
86
+ */
87
+ async function locate(git) {
88
+ const result = await git(['rev-parse', '--show-toplevel', '--show-prefix', '--is-shallow-repository']);
89
+ if (!result.ok)
90
+ throw gitFailureError(result);
91
+ const [, prefix = '', shallowWord = ''] = result.stdout.split('\n');
92
+ return { path: `${prefix}${BASELINE_FILE}`, shallow: shallowWord.trim() === 'true' };
93
+ }
94
+ /** Whether the working-tree baseline carries uncommitted changes. */
95
+ export async function baselineDirty(git) {
96
+ const result = await git(['status', '--porcelain', '--', BASELINE_FILE]);
97
+ if (!result.ok)
98
+ throw gitFailureError(result);
99
+ return result.stdout.trim().length > 0;
100
+ }
101
+ /** Is this state worth presenting — different from current and from everything kept? */
102
+ function isNewState(baseline, current, kept) {
103
+ if (current !== null && baselinesEqual(baseline, current))
104
+ return false;
105
+ return !kept.some((s) => baselinesEqual(s.baseline, baseline));
106
+ }
107
+ async function walkSnapshots(git, path, revisions, current) {
108
+ const walk = { snapshots: [], parsed: [], skipped: [], walked: 0 };
109
+ for (const rev of revisions) {
110
+ if (walk.snapshots.length >= MAX_SNAPSHOTS)
111
+ break;
112
+ walk.walked += 1;
113
+ // oxlint-disable-next-line no-await-in-loop -- sequential on purpose: the early-stop above only saves `git show` calls if they run one at a time.
114
+ const show = await git(['show', `${rev.sha}:${path}`]);
115
+ const baseline = show.ok ? parseBaseline(show.stdout) : null;
116
+ if (baseline === null) {
117
+ walk.skipped.push(rev.shortSha);
118
+ continue;
119
+ }
120
+ walk.parsed.push(baseline);
121
+ if (isNewState(baseline, current, walk.snapshots))
122
+ walk.snapshots.push({ kind: 'snapshot', rev, baseline });
123
+ }
124
+ return walk;
125
+ }
126
+ export async function collectCandidates(git, current, depth) {
127
+ const located = await locate(git);
128
+ const log = await git(['log', '-n', String(depth), `--format=${LOG_FORMAT}`, '--', located.path]);
129
+ if (!log.ok)
130
+ throw gitFailureError(log);
131
+ const walk = await walkSnapshots(git, located.path, parseLog(log.stdout), current);
132
+ const union = unionBaselines(current === null ? walk.parsed : [current, ...walk.parsed]);
133
+ const unionAddsAnything = current === null ? walk.parsed.length > 0 : !baselinesEqual(union, current);
134
+ const candidates = [
135
+ ...(unionAddsAnything ? [{ kind: 'union', baseline: union, folded: walk.parsed.length }] : []),
136
+ ...walk.snapshots,
137
+ ];
138
+ return { candidates, walked: walk.walked, skipped: walk.skipped, shallow: located.shallow };
139
+ }
140
+ /** Per-slot key union of every part, canonical (sorted slots and keys). */
141
+ export function unionBaselines(parts) {
142
+ const merged = new Map();
143
+ for (const part of parts) {
144
+ for (const [slot, keys] of Object.entries(part.slots)) {
145
+ const set = merged.get(slot) ?? new Set();
146
+ for (const key of keys)
147
+ set.add(key);
148
+ merged.set(slot, set);
149
+ }
150
+ }
151
+ const slots = {};
152
+ for (const slot of [...merged.keys()].toSorted())
153
+ slots[slot] = [...(merged.get(slot) ?? [])].toSorted();
154
+ return { schema_version: BASELINE_SCHEMA_VERSION, slots };
155
+ }
156
+ /** The probe's whole budget — a hint must never make a red run noticeably slower. */
157
+ const HINT_BUDGET_MS = 750;
158
+ const HINT_LOG_DEPTH = 5;
159
+ const HINT_SNAPSHOTS = 3;
160
+ /** Resolves `null` when the budget expires; unref'd so it never holds the process open. */
161
+ function budget(ms) {
162
+ return new Promise((resolve) => {
163
+ setTimeout(() => resolve(null), ms).unref();
164
+ });
165
+ }
166
+ async function probeHistory(git, newKeys) {
167
+ const located = await locate(git);
168
+ const log = await git(['log', '-n', String(HINT_LOG_DEPTH), `--format=${LOG_FORMAT}`, '--', located.path]);
169
+ if (!log.ok)
170
+ return null;
171
+ const keys = new Set(newKeys);
172
+ for (const rev of parseLog(log.stdout).slice(0, HINT_SNAPSHOTS)) {
173
+ // oxlint-disable-next-line no-await-in-loop -- at most three probes, and the newest match wins — later shows are only paid for when earlier ones miss.
174
+ const show = await git(['show', `${rev.sha}:${located.path}`]);
175
+ const baseline = show.ok ? parseBaseline(show.stdout) : null;
176
+ if (baseline === null)
177
+ continue;
178
+ const grandfathered = new Set(Object.values(baseline.slots).flat());
179
+ const matched = [...keys].filter((k) => grandfathered.has(k)).length;
180
+ if (matched > 0)
181
+ return { matched, total: newKeys.length, shortSha: rev.shortSha };
182
+ }
183
+ return null;
184
+ }
185
+ /**
186
+ * The red-run detection probe: were these "new" findings grandfathered in a
187
+ * recent committed baseline? The difference between "a wall of new debt" and
188
+ * "a merge dropped baseline entries" is a diagnosis the run output alone
189
+ * cannot make. Strictly best-effort: the whole probe races a
190
+ * {@link HINT_BUDGET_MS} budget, its git children carry the same short
191
+ * timeout, and any failure — git absent, not a repository, shallow miss,
192
+ * mangled blobs — resolves to `null`, never a thrown error or a slow run.
193
+ */
194
+ export async function historicalHint(cwd, newKeys, git, budgetMs = HINT_BUDGET_MS) {
195
+ if (newKeys.length === 0)
196
+ return null;
197
+ try {
198
+ return await Promise.race([probeHistory(git ?? realGit(cwd, budgetMs), newKeys), budget(budgetMs)]);
199
+ }
200
+ catch {
201
+ return null;
202
+ }
203
+ }
204
+ /**
205
+ * `restored` is what an apply adds; `absent` is what only an `--exact` apply
206
+ * would drop (the default union write never removes a key, so its `absent` side
207
+ * is empty by construction — the renderer still shows it so `--exact`'s cost is
208
+ * visible before it is paid).
209
+ */
210
+ export function diffBaselines(from, to) {
211
+ const restored = {};
212
+ const absent = {};
213
+ let restoredCount = 0;
214
+ let absentCount = 0;
215
+ const slots = new Set([...Object.keys(from?.slots ?? {}), ...Object.keys(to.slots)]);
216
+ for (const slot of [...slots].toSorted()) {
217
+ const fromKeys = new Set(from?.slots[slot] ?? []);
218
+ const toKeys = new Set(to.slots[slot] ?? []);
219
+ const gained = [...toKeys].filter((k) => !fromKeys.has(k)).toSorted();
220
+ const lost = [...fromKeys].filter((k) => !toKeys.has(k)).toSorted();
221
+ if (gained.length > 0) {
222
+ restored[slot] = gained;
223
+ restoredCount += gained.length;
224
+ }
225
+ if (lost.length > 0) {
226
+ absent[slot] = lost;
227
+ absentCount += lost.length;
228
+ }
229
+ }
230
+ return { restored, absent, restoredCount, absentCount };
231
+ }
232
+ //# sourceMappingURL=history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.js","sourceRoot":"","sources":["../../src/baseline/history.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,8 @@
7
7
  export type { Fingerprint } from './fingerprint.js';
8
8
  export { fingerprint, isFingerprintable } from './fingerprint.js';
9
9
  export { fallowVerdict } from './fallow.js';
10
- export type { Baseline } from './store.js';
11
- export { applyBaseline, BASELINE_FILE, BASELINE_SCHEMA_VERSION, baselinesEqual, countBaselineKeys, loadBaseline, ratchet, writeBaseline, } from './store.js';
10
+ export type { BaselineDelta, Candidate, GitResult, GitRunner, HistoryScan } from './history.js';
11
+ export { baselineDirty, collectCandidates, DEFAULT_DEPTH, diffBaselines, gitFailureError, historicalHint, realGit, unionBaselines, } from './history.js';
12
+ export type { Baseline, BaselineRead } from './store.js';
13
+ export { applyBaseline, BASELINE_FILE, BASELINE_SCHEMA_VERSION, baselinesEqual, countBaselineKeys, loadBaseline, parseBaseline, ratchet, readBaselineStatus, writeBaseline, } from './store.js';
12
14
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/baseline/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EACL,aAAa,EACb,aAAa,EACb,uBAAuB,EACvB,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,OAAO,EACP,aAAa,GACd,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/baseline/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChG,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,eAAe,EACf,cAAc,EACd,OAAO,EACP,cAAc,GACf,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACzD,OAAO,EACL,aAAa,EACb,aAAa,EACb,uBAAuB,EACvB,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,aAAa,EACb,OAAO,EACP,kBAAkB,EAClB,aAAa,GACd,MAAM,YAAY,CAAC"}
@@ -6,5 +6,6 @@
6
6
  */
7
7
  export { fingerprint, isFingerprintable } from './fingerprint.js';
8
8
  export { fallowVerdict } from './fallow.js';
9
- export { applyBaseline, BASELINE_FILE, BASELINE_SCHEMA_VERSION, baselinesEqual, countBaselineKeys, loadBaseline, ratchet, writeBaseline, } from './store.js';
9
+ export { baselineDirty, collectCandidates, DEFAULT_DEPTH, diffBaselines, gitFailureError, historicalHint, realGit, unionBaselines, } from './history.js';
10
+ export { applyBaseline, BASELINE_FILE, BASELINE_SCHEMA_VERSION, baselinesEqual, countBaselineKeys, loadBaseline, parseBaseline, ratchet, readBaselineStatus, writeBaseline, } from './store.js';
10
11
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/baseline/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EACL,aAAa,EACb,aAAa,EACb,uBAAuB,EACvB,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,OAAO,EACP,aAAa,GACd,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/baseline/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,eAAe,EACf,cAAc,EACd,OAAO,EACP,cAAc,GACf,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,aAAa,EACb,aAAa,EACb,uBAAuB,EACvB,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,aAAa,EACb,OAAO,EACP,kBAAkB,EAClB,aAAa,GACd,MAAM,YAAY,CAAC"}
@@ -29,12 +29,13 @@ export type BaselineAdjustment = {
29
29
  newKeys: string[];
30
30
  };
31
31
  /**
32
- * Read `checkride.baseline.json` from `cwd`; `null` when absent or unusable. The
33
- * baseline is a committed file a run reads on every invocation, so a malformed
34
- * one is coerced into a clean shape (or dropped) rather than thrown — a corrupt
35
- * baseline must never break `checkride`.
32
+ * Parse baseline file content; `null` when unusable. The baseline is a
33
+ * committed file a run reads on every invocation, so a malformed one is coerced
34
+ * into a clean shape (or dropped) rather than thrown — a corrupt baseline must
35
+ * never break `checkride`. Takes raw text rather than a path so historical
36
+ * copies (a `git show` blob during recovery) parse under the same tolerance.
36
37
  *
37
- * A file from a *newer* schema is dropped rather than read optimistically. The
38
+ * Content from a *newer* schema is dropped rather than read optimistically. The
38
39
  * fields it does not have yet are the ones that would say which findings are
39
40
  * masked and why, so guessing means either masking findings it never
40
41
  * grandfathered or claiming ones it did. Dropping it fails closed: the run
@@ -42,8 +43,30 @@ export type BaselineAdjustment = {
42
43
  * intended, never a green that was not earned. Same direction as
43
44
  * {@link applyBaseline}'s refusal to mask an unparseable run.
44
45
  */
46
+ export declare function parseBaseline(raw: string): Baseline | null;
47
+ /** How reading `checkride.baseline.json` went — see {@link readBaselineStatus}. */
48
+ export type BaselineRead = {
49
+ baseline: Baseline | null;
50
+ state: 'absent' | 'ok' | 'unparseable';
51
+ };
52
+ /**
53
+ * Read the baseline and say *why* it is missing when it is. Absent and
54
+ * unparseable both mask nothing, but they mean different things to the person
55
+ * staring at the resulting red: absent is a repo that never adopted a baseline,
56
+ * unparseable is a file somebody (often a merge) mangled — the run warns about
57
+ * the second so the damage is diagnosed at the moment it bites, not archaeology
58
+ * later.
59
+ */
60
+ export declare function readBaselineStatus(cwd: string): BaselineRead;
61
+ /** Read `checkride.baseline.json` from `cwd`; `null` when absent or unusable. */
45
62
  export declare function loadBaseline(cwd: string): Baseline | null;
46
- /** Serialize and write the baseline to `cwd` (pretty-printed, trailing newline, atomic). */
63
+ /**
64
+ * Serialize and write the baseline to `cwd` (canonical, pretty-printed,
65
+ * trailing newline, atomic). Written canonical — sorted slots, sorted keys — so
66
+ * the committed file diffs deterministically: two branches that grandfather the
67
+ * same debt produce byte-identical files instead of a spurious merge conflict
68
+ * over insertion order.
69
+ */
47
70
  export declare function writeBaseline(cwd: string, baseline: Baseline): Promise<void>;
48
71
  /**
49
72
  * Mask one slot's current fingerprint with its grandfathered keys. Masking is
@@ -58,7 +81,7 @@ export declare function writeBaseline(cwd: string, baseline: Baseline): Promise<
58
81
  */
59
82
  export declare function applyBaseline(current: Fingerprint, baselinedKeys: readonly string[], rawOk: boolean): BaselineAdjustment;
60
83
  /**
61
- * Ratchet the baseline against a fully-observed run: for every slot observed this
84
+ * Ratchet the baseline against a fully observed run: for every slot observed this
62
85
  * run, keep only the grandfathered keys still present (a fixed diagnostic is
63
86
  * dropped); a slot absent from `observed` — disabled, without an extractor, or
64
87
  * not run — is preserved untouched. The result never grows: genuinely new findings
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/baseline/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,oFAAoF;AACpF,eAAO,MAAM,aAAa,4BAA4B,CAAC;AAEvD,8EAA8E;AAC9E,eAAO,MAAM,uBAAuB,IAAI,CAAC;AAEzC,+EAA+E;AAC/E,MAAM,MAAM,QAAQ,GAAG;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACjC,CAAC;AAEF,8EAA8E;AAC9E,MAAM,MAAM,kBAAkB,GAAG;IAC/B,iFAAiF;IACjF,EAAE,EAAE,OAAO,CAAC;IACZ,oFAAoF;IACpF,SAAS,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAgBzD;AAED,4FAA4F;AAC5F,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAElF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,WAAW,EACpB,aAAa,EAAE,SAAS,MAAM,EAAE,EAChC,KAAK,EAAE,OAAO,GACb,kBAAkB,CAUpB;AAED;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,QAAQ,CAOhG;AAED,yDAAyD;AACzD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAE5D;AASD,sFAAsF;AACtF,wBAAgB,cAAc,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAEhE"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/baseline/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,oFAAoF;AACpF,eAAO,MAAM,aAAa,4BAA4B,CAAC;AAEvD,8EAA8E;AAC9E,eAAO,MAAM,uBAAuB,IAAI,CAAC;AAEzC,+EAA+E;AAC/E,MAAM,MAAM,QAAQ,GAAG;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACjC,CAAC;AAEF,8EAA8E;AAC9E,MAAM,MAAM,kBAAkB,GAAG;IAC/B,iFAAiF;IACjF,EAAE,EAAE,OAAO,CAAC;IACZ,oFAAoF;IACpF,SAAS,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAc1D;AAED,mFAAmF;AACnF,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC1B,KAAK,EAAE,QAAQ,GAAG,IAAI,GAAG,aAAa,CAAC;CACxC,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,CAW5D;AAED,iFAAiF;AACjF,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAEzD;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAElF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,WAAW,EACpB,aAAa,EAAE,SAAS,MAAM,EAAE,EAChC,KAAK,EAAE,OAAO,GACb,kBAAkB,CAUpB;AAED;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,QAAQ,CAOhG;AAED,yDAAyD;AACzD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAE5D;AAcD,sFAAsF;AACtF,wBAAgB,cAAc,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAEhE"}