@zigrivers/scaffold 3.29.0 → 3.31.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 (86) hide show
  1. package/content/guides/AUTHORING.md +146 -0
  2. package/content/guides/cli/index.html +1855 -0
  3. package/content/guides/cli/index.md +206 -0
  4. package/content/guides/concepts/index.html +1970 -0
  5. package/content/guides/concepts/index.md +347 -0
  6. package/content/guides/dashboard/index.html +1913 -0
  7. package/content/guides/dashboard/index.md +264 -0
  8. package/content/guides/index.html +368 -15
  9. package/content/guides/install/.diagrams/diagram-0.svg +1 -0
  10. package/content/guides/install/.diagrams/manifest.json +3 -0
  11. package/content/guides/install/index.html +1653 -0
  12. package/content/guides/install/index.md +186 -0
  13. package/content/guides/knowledge/.diagrams/diagram-0.svg +1 -0
  14. package/content/guides/knowledge/.diagrams/manifest.json +3 -0
  15. package/content/guides/knowledge/index.html +1765 -0
  16. package/content/guides/knowledge/index.md +209 -0
  17. package/content/guides/knowledge-freshness/.diagrams/diagram-0.svg +1 -0
  18. package/content/guides/knowledge-freshness/.diagrams/manifest.json +3 -0
  19. package/content/guides/knowledge-freshness/index.html +2795 -0
  20. package/content/guides/knowledge-freshness/index.md +893 -0
  21. package/content/guides/mmr/index.html +407 -36
  22. package/content/guides/mmr/index.md +39 -16
  23. package/content/guides/multi-agent/.diagrams/diagram-0.svg +1 -0
  24. package/content/guides/multi-agent/.diagrams/manifest.json +3 -0
  25. package/content/guides/multi-agent/index.html +1715 -0
  26. package/content/guides/multi-agent/index.md +243 -0
  27. package/content/guides/observability/.diagrams/diagram-0.svg +1 -0
  28. package/content/guides/observability/.diagrams/diagram-1.svg +1 -0
  29. package/content/guides/observability/.diagrams/diagram-2.svg +1 -0
  30. package/content/guides/observability/.diagrams/diagram-3.svg +1 -0
  31. package/content/guides/observability/.diagrams/manifest.json +6 -0
  32. package/content/guides/observability/index.html +3257 -0
  33. package/content/guides/observability/index.md +1097 -0
  34. package/content/guides/pipeline/.diagrams/diagram-0.svg +1 -0
  35. package/content/guides/pipeline/.diagrams/diagram-1.svg +1 -0
  36. package/content/guides/pipeline/.diagrams/manifest.json +4 -0
  37. package/content/guides/pipeline/index.html +1973 -0
  38. package/content/guides/pipeline/index.md +387 -0
  39. package/content/guides/review-workflow/.diagrams/diagram-0.svg +1 -0
  40. package/content/guides/review-workflow/.diagrams/diagram-1.svg +1 -0
  41. package/content/guides/review-workflow/.diagrams/manifest.json +4 -0
  42. package/content/guides/review-workflow/index.html +1790 -0
  43. package/content/guides/review-workflow/index.md +248 -0
  44. package/dist/guides/build.d.ts +1 -1
  45. package/dist/guides/build.d.ts.map +1 -1
  46. package/dist/guides/build.js +21 -9
  47. package/dist/guides/build.js.map +1 -1
  48. package/dist/guides/build.test.js +47 -0
  49. package/dist/guides/build.test.js.map +1 -1
  50. package/dist/guides/chrome.d.ts.map +1 -1
  51. package/dist/guides/chrome.js +83 -12
  52. package/dist/guides/chrome.js.map +1 -1
  53. package/dist/guides/dashboard-theme.css +8 -0
  54. package/dist/guides/directives-cite.test.d.ts +2 -0
  55. package/dist/guides/directives-cite.test.d.ts.map +1 -0
  56. package/dist/guides/directives-cite.test.js +26 -0
  57. package/dist/guides/directives-cite.test.js.map +1 -0
  58. package/dist/guides/directives-tabs.test.js +47 -0
  59. package/dist/guides/directives-tabs.test.js.map +1 -1
  60. package/dist/guides/directives.d.ts +1 -0
  61. package/dist/guides/directives.d.ts.map +1 -1
  62. package/dist/guides/directives.js +38 -0
  63. package/dist/guides/directives.js.map +1 -1
  64. package/dist/guides/guides.css +268 -0
  65. package/dist/guides/index-page.d.ts.map +1 -1
  66. package/dist/guides/index-page.js +41 -8
  67. package/dist/guides/index-page.js.map +1 -1
  68. package/dist/guides/links.d.ts +14 -0
  69. package/dist/guides/links.d.ts.map +1 -0
  70. package/dist/guides/links.js +56 -0
  71. package/dist/guides/links.js.map +1 -0
  72. package/dist/guides/links.test.d.ts +2 -0
  73. package/dist/guides/links.test.d.ts.map +1 -0
  74. package/dist/guides/links.test.js +72 -0
  75. package/dist/guides/links.test.js.map +1 -0
  76. package/dist/guides/render.d.ts +1 -0
  77. package/dist/guides/render.d.ts.map +1 -1
  78. package/dist/guides/render.js +1 -1
  79. package/dist/guides/render.js.map +1 -1
  80. package/dist/guides/sanitize.d.ts.map +1 -1
  81. package/dist/guides/sanitize.js +5 -0
  82. package/dist/guides/sanitize.js.map +1 -1
  83. package/dist/guides/template.d.ts.map +1 -1
  84. package/dist/guides/template.js +7 -2
  85. package/dist/guides/template.js.map +1 -1
  86. package/package.json +2 -2
@@ -0,0 +1,248 @@
1
+ ---
2
+ title: The Code-Review Workflow
3
+ topic: review-workflow
4
+ description: When and how to run multi-model review — entry points, input modes, verdicts, the round limit, and degraded mode
5
+ category: workflows
6
+ order: 30
7
+ ---
8
+
9
+ ## What this guide covers
10
+
11
+ This is the **workflow** around multi-model review: *when* to review, *which*
12
+ entry point to reach for, *which* input mode matches your target, how to read
13
+ the verdict, and how the fix loop is bounded. It does **not** re-explain the
14
+ review engine itself — channels, reconciliation, the `finding_key`, the verdict
15
+ algorithm, and `.mmr.yaml` all live in the [MMR reference](../mmr/index.md).
16
+ Read that guide for "what is a channel"; read this one for "I have a change, now
17
+ what do I run."
18
+
19
+ :::callout{type=tip}
20
+ **Two layers.** `mmr review` is the engine. `scaffold run review-pr` and
21
+ `review-code` are *workflow wrappers* on top — they pick the input mode, add the
22
+ Superpowers code-reviewer agent channel via `mmr reconcile`, handle auth
23
+ recovery, and bound the fix loop. `post-implementation-review` is a separate,
24
+ release-time full-codebase review with its own flow (see Step 1). This guide is
25
+ about driving those entry points; the engine details are in
26
+ [the MMR reference](../mmr/index.md).
27
+ :::
28
+
29
+ ## Step 1 — Pick the entry point
30
+
31
+ Two of these are wrappers over `mmr review` — `review-pr` and `review-code` —
32
+ sharing the same engine and verdict semantics, differing in *scope* and *what
33
+ they synthesize*. `post-implementation-review` is **not** a `mmr review` wrapper:
34
+ it's an independent release-time review of the whole codebase that runs its own
35
+ channel flow and writes its own report under `docs/reviews/`, with MMR
36
+ reconciliation only as an optional add-on. Consult its own doc for specifics.
37
+
38
+ ```mermaid
39
+ flowchart TD
40
+ Q{What are you reviewing?} --> A[An open PR]
41
+ Q --> B[Local changes
42
+ before commit/push]
43
+ Q --> C[The whole codebase
44
+ after all tasks land]
45
+ A --> AR["scaffold run review-pr
46
+ (mmr review --pr N)"]
47
+ B --> BR["scaffold run review-code
48
+ (synthesized delivery candidate)"]
49
+ C --> CR["scaffold run post-implementation-review
50
+ (two-phase: systemic + per-story)"]
51
+ ```
52
+
53
+ | Entry point | Target | Notes |
54
+ | --- | --- | --- |
55
+ | `scaffold run review-pr` | One PR (`--pr N`, auto-detected from the branch) | **MMR wrapper.** Adds auth checks, the Superpowers agent channel, the per-finding round bookkeeping, an opt-in Beads bridge over a bare `mmr review`. |
56
+ | `scaffold run review-code` | Local pre-push: committed branch diff + staged + unstaged, as one synthesized "delivery candidate" | **MMR wrapper.** Adds the same agent channel + round bounding, plus file & standards context for the file-blind CLIs. **Untracked files are not covered.** |
57
+ | `scaffold run post-implementation-review` | The full implemented codebase against stories + standards | **Independent, not an MMR wrapper.** A release-time review (systemic sweep + per-story functional review via parallel agents) with its own report under `docs/reviews/`; MMR injection is optional. Consult its own doc. |
58
+
59
+ :::callout{type=note}
60
+ **The mandatory one.** After `gh pr create`, running `review-pr` is mandatory
61
+ before moving to the next task (a PostToolUse hook reminds you).
62
+ `review-code` is the recommended preflight before a push but isn't gated.
63
+ `post-implementation-review` is a release-time sweep, not a per-change gate.
64
+ :::
65
+
66
+ ### When no wrapper fits
67
+
68
+ The wrappers are conveniences, not gates on the engine. For any target a wrapper
69
+ doesn't cover — a branch range, an existing patch file, a single doc — call
70
+ `mmr review` directly with the matching input flag. The
71
+ [MMR reference](../mmr/index.md) lists every flag; the next step is the workflow
72
+ view of the same choice.
73
+
74
+ ## Step 2 — Choose the input mode
75
+
76
+ `mmr review` resolves a diff from exactly one input source. Pick the one that
77
+ describes your target. The `--diff -` (stdin) form is the universal escape hatch:
78
+ anything you can express as a unified diff, you can pipe in.
79
+
80
+ ```mermaid
81
+ flowchart TD
82
+ S{Where is the change?} --> PR[On a GitHub PR]
83
+ S --> ST[Staged in the index]
84
+ S --> BR[A branch, vs a base]
85
+ S --> DC[Local working tree:
86
+ committed + staged + unstaged]
87
+ S --> UF[A brand-new file
88
+ git doesn't track yet]
89
+ PR --> PRc["mmr review --pr N"]
90
+ ST --> STc["mmr review --staged"]
91
+ BR --> BRc["mmr review --base main --head BRANCH"]
92
+ DC --> DCc["git diff MERGE_BASE | mmr review --diff -
93
+ (this is what review-code synthesizes)"]
94
+ UF --> UFc["(diff -u /dev/null FILE || true) | mmr review --diff -"]
95
+ ```
96
+
97
+ | Target | Command | Notes |
98
+ | --- | --- | --- |
99
+ | A PR | `mmr review --pr 123` | Fetches the diff via `gh pr diff`. This is `review-pr`'s mode. |
100
+ | Staged changes | `mmr review --staged` | Just the index (`git diff --cached`) — the pre-commit slice. |
101
+ | A branch range | `mmr review --base main --head "$BRANCH"` | Committed work only; no staged/unstaged. |
102
+ | Full delivery candidate | `git diff "$MERGE_BASE" \| mmr review --diff -` | Committed branch diff + staged + unstaged in one patch. `review-code` synthesizes this for you. |
103
+ | A single tracked file's pending edits | `git diff HEAD -- path/file.ts \| mmr review --diff -` | Fails with "no diff content" if the file has no local changes — use the next row. |
104
+ | A brand-new / untracked file | `(diff -u /dev/null path/file.ts \|\| true) \| mmr review --diff -` | Synthesizes an "all-added" diff from current contents. |
105
+ | An existing patch | `mmr review --diff path/changes.patch` | Reads diff-format content directly. |
106
+
107
+ :::callout{type=danger}
108
+ **Untracked files are silently skipped — this is the trap.** `review-code`
109
+ reviews the committed branch diff plus staged and unstaged changes *to tracked
110
+ files*. A brand-new file you've never `git add`-ed is **not** in any of those
111
+ diffs, so it sails through review with zero findings — not because it's clean,
112
+ but because no channel ever saw it. To review a new file, pipe it in explicitly:
113
+ `(diff -u /dev/null path/to/new-file.ts || true) | mmr review --diff -`. The
114
+ `|| true` guard is required: `diff` exits non-zero whenever files differ, which
115
+ would otherwise kill the pipeline under `set -o pipefail`. The wrappers cannot
116
+ guess which untracked files you meant to include
117
+ :cite[content/tools/review-code.md:37].
118
+ :::
119
+
120
+ The `--diff` flag expects **diff-format content** — a path to a `.patch`/`.diff`
121
+ file, or `-` for stdin. It does not accept raw document text; wrap the target in
122
+ a diff first.
123
+
124
+ ## Step 3 — Read the verdict, then act
125
+
126
+ Every review collapses to exactly one of four verdicts. The verdict, not the raw
127
+ findings, is what decides whether you proceed. The
128
+ [MMR reference](../mmr/index.md) defines the gate, the severity tiers, and the
129
+ exact derivation algorithm; this table is the *action* you take for each outcome.
130
+
131
+ | Verdict | Exit | Do |
132
+ | --- | --- | --- |
133
+ | `pass` | 0 | **Proceed** — merge / push / next task. |
134
+ | `degraded-pass` | 0 | **Proceed**, noting reduced coverage. The max achievable verdict once any channel was compensated. |
135
+ | `blocked` | 2 | **Stop.** Fix the blocking findings (Step 4), then re-review. Do not merge. |
136
+ | `needs-user-decision` | 3 | **Stop and surface to the user.** Automated iteration can't resolve this. |
137
+
138
+ A review is `blocked` when any unacknowledged finding sits at or above the fix
139
+ threshold (:sev[P2]{level=p2} by default; override per-run with
140
+ `--fix-threshold`). See the [MMR reference](../mmr/index.md) for how the verdict
141
+ is derived from gate result + channel health.
142
+
143
+ :::callout{type=warning}
144
+ **Proceed only on `pass` or `degraded-pass`.** On `blocked` or
145
+ `needs-user-decision`, never merge automatically — surface the verdict and the
146
+ remaining findings to the user. The wrappers enforce this: a `blocked` /
147
+ `needs-user-decision` outcome takes the "Stop path" and does **not** print the
148
+ ready-for-merge message :cite[content/tools/review-pr.md:610].
149
+ :::
150
+
151
+ ## Step 4 — Fix the blocking findings (bounded)
152
+
153
+ When the verdict is `blocked`, the loop is: fix the findings at or above the
154
+ threshold → re-review → repeat. The guard rail is that this loop is **bounded
155
+ per finding**, so a finding the model can't actually fix doesn't trap you in an
156
+ infinite cycle.
157
+
158
+ ### The 3-round-per-finding limit
159
+
160
+ The limit is **3 attempts per finding**, not 3 rounds total. Each round that
161
+ surfaces *genuinely new* findings is healthy iteration — keep going. The loop
162
+ stops only when one specific finding has been attempted three times without
163
+ resolution.
164
+
165
+ A "finding" here is its **stable identity**, not its wording, so a re-worded
166
+ report of the same defect still counts against the same finding. (The
167
+ [MMR reference](../mmr/index.md) covers how that identity is computed.) Co-equal
168
+ stop conditions:
169
+
170
+ - A finding's identity reaches 3 recorded attempts.
171
+ - The same underlying defect recurs across 3 rounds even if the reviewer's
172
+ wording produces a new identity each time.
173
+ - Channels genuinely contradict each other (→ `needs-user-decision`).
174
+ - The user explicitly asks to stop.
175
+
176
+ When you stop, **do not merge**. Document each unresolved finding (severity,
177
+ location, attempt count) and hand the decision to the user
178
+ :cite[content/tools/review-pr.md:610].
179
+
180
+ ### Where the bookkeeping lives today
181
+
182
+ The engine ships **native** multi-round sessions — `mmr review --session <id>
183
+ --round N --max-rounds M` :cite[packages/mmr/src/commands/review.ts:289] — and a
184
+ stable, line-number-independent `finding_key`
185
+ :cite[packages/mmr/src/core/stable-id.ts:115]. (See the
186
+ [MMR reference](../mmr/index.md) for how that key collapses the same issue at
187
+ different severities.)
188
+
189
+ The scaffold **wrappers** have not yet migrated to native sessions. Until they
190
+ do, `review-pr` and `review-code` enforce the 3-strike rule with their own
191
+ bookkeeping: a per-session attempts file at
192
+ `.scaffold/review-attempts/<session-id>.json`. Each fix round computes a hash
193
+ over the same four identity components, increments that finding's counter, and
194
+ the `_review_at_strike_limit` helper blocks once it hits 3
195
+ :cite[content/tools/review-pr.md:468]. The wrapper hash deliberately mirrors the
196
+ engine's `finding_key` components, so the eventual swap to
197
+ `mmr review --session` is a clean migration rather than a re-think.
198
+
199
+ :::callout{type=note}
200
+ **Practical takeaway.** You drive the fix loop through the wrapper; the attempts
201
+ file under `.scaffold/review-attempts/` is the current source of truth for the
202
+ strike count. For a very noisy loop you may narrow the gate for one run with
203
+ `--fix-threshold P1` — but don't permanently lower the project default (P2).
204
+ :::
205
+
206
+ ## Step 5 — Handle degraded mode
207
+
208
+ A review never silently runs with fewer reviewers. A channel is *degraded* when
209
+ its binary isn't installed, auth fails, it times out, or it errors out. The
210
+ workflow's response is to **compensate and tell you how to recover**, then cap
211
+ the verdict at `degraded-pass`. The mechanics — how compensation runs and the
212
+ per-channel auth checks — live in the [MMR reference](../mmr/index.md); below is
213
+ what it means for *your* workflow.
214
+
215
+ - **Compensating pass.** For each degraded *external* channel, MMR runs a
216
+ compensating pass focused on that channel's strength area and records the
217
+ source as `compensating-<channel>` :cite[packages/mmr/src/core/compensator.ts:162].
218
+ The compensator defaults to `claude -p` unless `defaults.compensator.channel`
219
+ overrides it :cite[packages/mmr/src/core/compensator.ts:74]. These findings
220
+ are single-source, low confidence. With the default compensator, a missing
221
+ Claude CLI has no compensator of its own. (The bracket labels like
222
+ `[compensating: Grok-equivalent]` you'll see are the *manual fallback* summary
223
+ wording, distinct from the engine's `compensating-<channel>` source name.)
224
+ - **Auth recovery is never silent.** The workflow surfaces the exact recovery
225
+ command for the failed channel; the channel's `recovery` string drives this
226
+ :cite[packages/mmr/src/core/auth.ts:65]. See the
227
+ [MMR reference](../mmr/index.md) for the per-channel auth-check + recovery
228
+ table.
229
+
230
+ :::callout{type=warning}
231
+ **Foreground only.** When the `mmr` CLI is unavailable and a wrapper falls back
232
+ to invoking Codex / Gemini / Claude / Grok directly, run them as **foreground**
233
+ Bash calls — never with `run_in_background`, `&`, or `nohup`. Background
234
+ execution produces empty output, which the parser then reads as a degraded
235
+ channel :cite[content/tools/review-code.md:265].
236
+ :::
237
+
238
+ Once any channel was compensated, the best possible verdict is
239
+ `degraded-pass` — full `pass` requires all channels to have completed for real.
240
+
241
+ ## See also
242
+
243
+ - [MMR reference](../mmr/index.md){mode=advisory} — channels, reconciliation,
244
+ the `finding_key`, verdict internals, and `.mmr.yaml`.
245
+ - The wrapper meta-prompts themselves:
246
+ :cite[content/tools/review-pr.md:15]{mode=advisory},
247
+ :cite[content/tools/review-code.md:16]{mode=advisory}, and
248
+ :cite[content/tools/post-implementation-review.md:16]{mode=advisory}.
@@ -1,5 +1,5 @@
1
1
  import type { LintResult } from './lint.js';
2
- export declare function loadThemeCss(): string;
2
+ export declare function loadGuideStyles(): string;
3
3
  export interface BuildGuideArgs {
4
4
  guideDir: string;
5
5
  css: string;
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/guides/build.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAE3C,wBAAgB,YAAY,IAAI,MAAM,CAQrC;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAA;IAChB,GAAG,EAAE,MAAM,CAAA;IACX,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;CACpD;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC,CAoBpF;AAED,wBAAsB,cAAc,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQxE"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/guides/build.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAG3C,wBAAgB,eAAe,IAAI,MAAM,CAexC;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAA;IAChB,GAAG,EAAE,MAAM,CAAA;IACX,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;CACpD;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC,CAwBpF;AAED,wBAAsB,cAAc,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQxE"}
@@ -3,17 +3,25 @@ import path from 'node:path';
3
3
  import { atomicWriteFile, getPackageRoot, getPackageGuidesDir } from '../utils/fs.js';
4
4
  import { buildGuidesIndex, extractGuideFrontmatter } from './loader.js';
5
5
  import { renderGuideBody } from './render.js';
6
- import { remarkCallout, remarkTabs, remarkFilterTable, remarkChart, remarkSev } from './directives.js';
6
+ import { remarkCallout, remarkTabs, remarkFilterTable, remarkChart, remarkSev, remarkCite } from './directives.js';
7
7
  import { remarkMermaid, pruneDiagrams } from './mermaid.js';
8
8
  import { wrapInChrome } from './template.js';
9
9
  import { renderIndexPage } from './index-page.js';
10
10
  import { lintGuide } from './lint.js';
11
- export function loadThemeCss() {
12
- const p = path.join(getPackageRoot(), 'dist', 'guides', 'dashboard-theme.css');
13
- if (!fs.existsSync(p)) {
14
- throw new Error(`Missing ${p} run \`npm run build\` (the build copies lib/dashboard-theme.css into dist/guides/).`);
15
- }
16
- return fs.readFileSync(p, 'utf8');
11
+ import { findBrokenRelativeLinks } from './links.js';
12
+ export function loadGuideStyles() {
13
+ // The guide stylesheet is the design tokens (dashboard-theme.css) followed by
14
+ // the guide-specific layout + component styles (guides.css). Both are inlined
15
+ // into each guide's <style> so the output stays self-contained.
16
+ const dir = path.join(getPackageRoot(), 'dist', 'guides');
17
+ const parts = ['dashboard-theme.css', 'guides.css'].map((name) => {
18
+ const p = path.join(dir, name);
19
+ if (!fs.existsSync(p)) {
20
+ throw new Error(`Missing ${p} — run \`npm run build\` (the build copies lib/${name} into dist/guides/).`);
21
+ }
22
+ return fs.readFileSync(p, 'utf8');
23
+ });
24
+ return parts.join('\n');
17
25
  }
18
26
  export async function buildGuide(args) {
19
27
  const md = fs.readFileSync(path.join(args.guideDir, 'index.md'), 'utf8');
@@ -23,13 +31,17 @@ export async function buildGuide(args) {
23
31
  }
24
32
  for (const w of lint.warnings)
25
33
  process.stderr.write(`warning: ${w}\n`);
34
+ const brokenLinks = findBrokenRelativeLinks(md, args.guideDir);
35
+ if (brokenLinks.length) {
36
+ throw new Error(`guide has broken relative link(s):\n ${brokenLinks.join('\n ')}`);
37
+ }
26
38
  const fm = extractGuideFrontmatter(md);
27
39
  if (!fm)
28
40
  throw new Error(`invalid or missing frontmatter in ${path.join(args.guideDir, 'index.md')}`);
29
41
  const diagramIds = [];
30
42
  const { body, headings } = await renderGuideBody(md, {
31
43
  plugins: [
32
- remarkCallout, remarkTabs, remarkFilterTable, remarkChart, remarkSev,
44
+ remarkCallout, remarkTabs, remarkFilterTable, remarkChart, remarkSev, remarkCite,
33
45
  remarkMermaid({ guideDir: args.guideDir, render: args.mermaidRender, collect: diagramIds }),
34
46
  ],
35
47
  });
@@ -39,7 +51,7 @@ export async function buildGuide(args) {
39
51
  return { lint };
40
52
  }
41
53
  export async function buildAllGuides(projectRoot) {
42
- const css = loadThemeCss();
54
+ const css = loadGuideStyles();
43
55
  const guidesDir = getPackageGuidesDir(projectRoot);
44
56
  const index = buildGuidesIndex(guidesDir);
45
57
  for (const entry of index.values()) {
@@ -1 +1 @@
1
- {"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/guides/build.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/guides/build.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAA;AACrF,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAA;AACvE,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,iBAAiB,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAClH,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAErC,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAA;AAEpD,MAAM,UAAU,eAAe;IAC7B,8EAA8E;IAC9E,8EAA8E;IAC9E,gEAAgE;IAChE,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAA;IACzD,MAAM,KAAK,GAAG,CAAC,qBAAqB,EAAE,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QAC/D,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;QAC9B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CACb,WAAW,CAAC,kDAAkD,IAAI,sBAAsB,CACzF,CAAA;QACH,CAAC;QACD,OAAO,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAA;IACnC,CAAC,CAAC,CAAA;IACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACzB,CAAC;AAQD,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAoB;IACnD,MAAM,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,CAAA;IACxE,MAAM,IAAI,GAAG,SAAS,CAAC,EAAE,CAAC,CAAA;IAC1B,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,yBAAyB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;IACtE,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ;QAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAA;IACtE,MAAM,WAAW,GAAG,uBAAuB,CAAC,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAA;IAC9D,IAAI,WAAW,CAAC,MAAM,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,yCAAyC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;IACtF,CAAC;IACD,MAAM,EAAE,GAAG,uBAAuB,CAAC,EAAE,CAAC,CAAA;IACtC,IAAI,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,CAAC,CAAA;IACrG,MAAM,UAAU,GAAa,EAAE,CAAA;IAC/B,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,MAAM,eAAe,CAAC,EAAE,EAAE;QACnD,OAAO,EAAE;YACP,aAAa,EAAE,UAAU,EAAE,iBAAiB,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU;YAChF,aAAa,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;SAC5F;KACF,CAAC,CAAA;IACF,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;IACxC,MAAM,IAAI,GAAG,YAAY,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAA;IAC7E,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,EAAE,IAAI,CAAC,CAAA;IAC7D,OAAO,EAAE,IAAI,EAAE,CAAA;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,WAAoB;IACvD,MAAM,GAAG,GAAG,eAAe,EAAE,CAAA;IAC7B,MAAM,SAAS,GAAG,mBAAmB,CAAC,WAAW,CAAC,CAAA;IAClD,MAAM,KAAK,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAA;IACzC,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;QACnC,MAAM,UAAU,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAA;IAChD,CAAC;IACD,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,EAAE,eAAe,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAA;AAChG,CAAC"}
@@ -44,6 +44,14 @@ describe('buildGuide', () => {
44
44
  await expect(buildGuide({ guideDir: dir, css: CSS, mermaidRender: async () => '' }))
45
45
  .rejects.toThrow(/text-equivalent/i);
46
46
  });
47
+ it('throws when a relative link target does not resolve', async () => {
48
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'gb-'));
49
+ const dir = path.join(root, 'mmr');
50
+ fs.mkdirSync(dir, { recursive: true });
51
+ fs.writeFileSync(path.join(dir, 'index.md'), GUIDE_MD + '\nSee [concepts](../concepts/index.md).\n');
52
+ await expect(buildGuide({ guideDir: dir, css: CSS, mermaidRender: async () => '' }))
53
+ .rejects.toThrow(/broken relative link/i);
54
+ });
47
55
  });
48
56
  describe('renderIndexPage', () => {
49
57
  it('lists guides by order with links', () => {
@@ -58,6 +66,45 @@ describe('renderIndexPage', () => {
58
66
  expect(html).toContain('MMR');
59
67
  expect(html).toContain('review');
60
68
  });
69
+ it('groups guides into ordered category card sections', () => {
70
+ const html = renderIndexPage([
71
+ /* eslint-disable @typescript-eslint/no-explicit-any */
72
+ ({ topic: 'cli', frontmatter: {
73
+ title: 'CLI', topic: 'cli', description: 'commands', category: 'reference', order: 20,
74
+ } }),
75
+ ({ topic: 'pipeline', frontmatter: {
76
+ title: 'Pipeline', topic: 'pipeline', description: 'the pipeline', category: 'concepts', order: 10,
77
+ } }),
78
+ /* eslint-enable @typescript-eslint/no-explicit-any */
79
+ ], CSS);
80
+ // category section headings (ids derived by catId) + labels
81
+ expect(html).toContain('id="cat-concepts"');
82
+ expect(html).toContain('id="cat-reference"');
83
+ expect(html).toContain('>Concepts<');
84
+ expect(html).toContain('>Reference<');
85
+ // card markup, not a bare list
86
+ expect(html).toContain('class="guide-card" href="pipeline/index.html"');
87
+ expect(html).toContain('class="guide-card-title"');
88
+ // CATEGORY_ORDER puts concepts before reference regardless of input order
89
+ expect(html.indexOf('cat-concepts')).toBeLessThan(html.indexOf('cat-reference'));
90
+ });
91
+ it('appends unknown categories after the known ones with a capitalized label', () => {
92
+ const html = renderIndexPage([
93
+ /* eslint-disable @typescript-eslint/no-explicit-any */
94
+ ({ topic: 'odd', frontmatter: {
95
+ title: 'Odd', topic: 'odd', description: 'misc', category: 'experimental', order: 5,
96
+ } }),
97
+ ({ topic: 'cli', frontmatter: {
98
+ title: 'CLI', topic: 'cli', description: 'commands', category: 'reference', order: 20,
99
+ } }),
100
+ /* eslint-enable @typescript-eslint/no-explicit-any */
101
+ ], CSS);
102
+ // Unknown 'experimental' category gets a capitalized label and an id…
103
+ expect(html).toContain('id="cat-experimental"');
104
+ expect(html).toContain('>Experimental<');
105
+ // …and sorts AFTER the known 'reference' category despite a lower order
106
+ expect(html.indexOf('cat-reference')).toBeLessThan(html.indexOf('cat-experimental'));
107
+ });
61
108
  it('escapes < and & in frontmatter fields', () => {
62
109
  const html = renderIndexPage([
63
110
  /* eslint-disable @typescript-eslint/no-explicit-any */
@@ -1 +1 @@
1
- {"version":3,"file":"build.test.js","sourceRoot":"","sources":["../../src/guides/build.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"build.test.js","sourceRoot":"","sources":["../../src/guides/build.test.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"chrome.d.ts","sourceRoot":"","sources":["../../src/guides/chrome.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,EAAE,MAGqD,CAAA;AAEjF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,SAAS,EAAE,MA4FlB,CAAA"}
1
+ {"version":3,"file":"chrome.d.ts","sourceRoot":"","sources":["../../src/guides/chrome.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,EAAE,MAGqD,CAAA;AAEjF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,SAAS,EAAE,MAmKlB,CAAA"}
@@ -39,12 +39,69 @@ export const CHROME_JS = /* js */ `(function(){
39
39
  });
40
40
  });
41
41
 
42
- // ─── Mobile nav ──────────────────────────────────────────────────────────
42
+ // ─── Mobile nav (drawer + backdrop; aria-expanded + Escape-to-close) ──────
43
+ function setNav(open) {
44
+ var rail = document.querySelector('.rail');
45
+ if (rail) rail.classList.toggle('open', open);
46
+ var toggle = document.querySelector('.nav-toggle');
47
+ if (toggle) toggle.setAttribute('aria-expanded', open ? 'true' : 'false');
48
+ // Modal-drawer focus containment: while open, make the page content inert
49
+ // (out of tab order + a11y tree) and move focus into the drawer; on close,
50
+ // restore content and return focus to the toggle.
51
+ var main = document.querySelector('.content');
52
+ if (main) main.inert = open;
53
+ if (open) {
54
+ var first = rail && rail.querySelector('a, button, [tabindex]:not([tabindex="-1"])');
55
+ if (first) first.focus();
56
+ else if (rail) { rail.setAttribute('tabindex', '-1'); rail.focus(); }
57
+ } else if (toggle) {
58
+ toggle.focus();
59
+ }
60
+ }
61
+ // If the viewport grows past the mobile breakpoint while the drawer is open,
62
+ // the rail becomes the desktop sidebar and the toggle hides — clear the open
63
+ // state so .content doesn't stay inert with no way to close it.
64
+ if (window.matchMedia) {
65
+ var mq = window.matchMedia('(max-width: 860px)');
66
+ var onMq = function() {
67
+ if (mq.matches) return;
68
+ var rail = document.querySelector('.rail');
69
+ if (rail) rail.classList.remove('open');
70
+ var toggle = document.querySelector('.nav-toggle');
71
+ if (toggle) toggle.setAttribute('aria-expanded', 'false');
72
+ var main = document.querySelector('.content');
73
+ if (main) main.inert = false;
74
+ };
75
+ if (mq.addEventListener) mq.addEventListener('change', onMq);
76
+ else if (mq.addListener) mq.addListener(onMq);
77
+ }
43
78
  document.querySelectorAll('[data-action="nav"]').forEach(function(btn) {
44
79
  btn.addEventListener('click', function() {
45
80
  var rail = document.querySelector('.rail');
46
- if (rail) rail.classList.toggle('open');
81
+ setNav(!(rail && rail.classList.contains('open')));
82
+ });
83
+ });
84
+ // Selecting a TOC link closes the drawer (so the now-active content isn't
85
+ // left inert behind the panel) before the anchor navigation scrolls.
86
+ var drawerRail = document.querySelector('.rail');
87
+ if (drawerRail) {
88
+ drawerRail.querySelectorAll('a').forEach(function(a) {
89
+ a.addEventListener('click', function() {
90
+ if (drawerRail.classList.contains('open')) setNav(false);
91
+ });
47
92
  });
93
+ }
94
+ document.addEventListener('keydown', function(e) {
95
+ var rail = document.querySelector('.rail');
96
+ if (!rail || !rail.classList.contains('open')) return;
97
+ if (e.key === 'Escape') { setNav(false); return; } // setNav restores focus to the toggle
98
+ // Trap Tab within the open drawer (modal pattern).
99
+ if (e.key !== 'Tab') return;
100
+ var f = rail.querySelectorAll('a[href], button, [tabindex]:not([tabindex="-1"])');
101
+ if (!f.length) return;
102
+ var first = f[0], last = f[f.length - 1];
103
+ if (e.shiftKey && document.activeElement === first) { e.preventDefault(); last.focus(); }
104
+ else if (!e.shiftKey && document.activeElement === last) { e.preventDefault(); first.focus(); }
48
105
  });
49
106
 
50
107
  // ─── Copy buttons ─────────────────────────────────────────────────────────
@@ -71,17 +128,31 @@ export const CHROME_JS = /* js */ `(function(){
71
128
  wrapper.insertBefore(btn, pre);
72
129
  });
73
130
 
74
- // ─── Tabs ─────────────────────────────────────────────────────────────────
131
+ // ─── Tabs (ARIA pattern: aria-selected + roving tabindex + arrow keys) ────
132
+ function activateTab(group, btn, focus) {
133
+ var idx = btn.getAttribute('data-tab');
134
+ group.querySelectorAll('.tab-btn').forEach(function(b) {
135
+ var on = b === btn;
136
+ b.classList.toggle('active', on);
137
+ b.setAttribute('aria-selected', on ? 'true' : 'false');
138
+ b.setAttribute('tabindex', on ? '0' : '-1');
139
+ });
140
+ group.querySelectorAll('.tabpane').forEach(function(pane) {
141
+ pane.classList.toggle('active', pane.getAttribute('data-tab') === idx);
142
+ });
143
+ if (focus) btn.focus();
144
+ }
75
145
  document.querySelectorAll('.tabs').forEach(function(group) {
76
- group.querySelectorAll('.tab-btn').forEach(function(btn) {
77
- btn.addEventListener('click', function() {
78
- var idx = btn.getAttribute('data-tab');
79
- group.querySelectorAll('.tab-btn').forEach(function(b) {
80
- b.classList.toggle('active', b === btn);
81
- });
82
- group.querySelectorAll('.tabpane').forEach(function(pane) {
83
- pane.classList.toggle('active', pane.getAttribute('data-tab') === idx);
84
- });
146
+ var btns = [].slice.call(group.querySelectorAll('.tab-btn'));
147
+ btns.forEach(function(btn, i) {
148
+ btn.addEventListener('click', function() { activateTab(group, btn, false); });
149
+ btn.addEventListener('keydown', function(e) {
150
+ var ni = -1;
151
+ if (e.key === 'ArrowRight' || e.key === 'ArrowDown') ni = (i + 1) % btns.length;
152
+ else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') ni = (i - 1 + btns.length) % btns.length;
153
+ else if (e.key === 'Home') ni = 0;
154
+ else if (e.key === 'End') ni = btns.length - 1;
155
+ if (ni >= 0) { e.preventDefault(); activateTab(group, btns[ni], true); }
85
156
  });
86
157
  });
87
158
  });
@@ -1 +1 @@
1
- {"version":3,"file":"chrome.js","sourceRoot":"","sources":["../../src/guides/chrome.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,aAAa,GACxB,8DAA8D;IAC9D,4FAA4F;IAC5F,+EAA+E,CAAA;AAEjF;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,SAAS,GAAW,QAAQ,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MA4FpC,CAAA"}
1
+ {"version":3,"file":"chrome.js","sourceRoot":"","sources":["../../src/guides/chrome.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,aAAa,GACxB,8DAA8D;IAC9D,4FAA4F;IAC5F,+EAA+E,CAAA;AAEjF;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,SAAS,GAAW,QAAQ,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAmKpC,CAAA"}
@@ -41,9 +41,13 @@
41
41
  --yellow: #d97706;
42
42
  --yellow-bg: #fffbeb;
43
43
  --yellow-border:#fde68a;
44
+ --red: #dc2626;
45
+ --red-bg: #fef2f2;
46
+ --red-border: #fecaca;
44
47
  --gray: #9ca3af;
45
48
  --gray-bg: #f3f4f6;
46
49
  --gray-border: #e5e7eb;
50
+ --scrim: rgba(15, 17, 23, 0.45);
47
51
 
48
52
  /* Semantic: Next Banner */
49
53
  --next-bg: #eef2ff;
@@ -126,9 +130,13 @@
126
130
  --yellow: #fbbf24;
127
131
  --yellow-bg: rgba(120, 53, 15, 0.25);
128
132
  --yellow-border:rgba(251, 191, 36, 0.20);
133
+ --red: #f87171;
134
+ --red-bg: rgba(127, 29, 29, 0.25);
135
+ --red-border: rgba(248, 113, 113, 0.22);
129
136
  --gray: #6b7294;
130
137
  --gray-bg: #252940;
131
138
  --gray-border: #363c58;
139
+ --scrim: rgba(0, 0, 0, 0.6);
132
140
 
133
141
  /* Semantic: Next Banner */
134
142
  --next-bg: rgba(30, 27, 75, 0.50);
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=directives-cite.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directives-cite.test.d.ts","sourceRoot":"","sources":["../../src/guides/directives-cite.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,26 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { renderGuideBody } from './render.js';
3
+ import { remarkCite } from './directives.js';
4
+ describe('remarkCite', () => {
5
+ it('renders a blocking citation as an fp span the citation checker matches', async () => {
6
+ const { body } = await renderGuideBody('See :cite[src/foo.ts:42] for details.\n', {
7
+ plugins: [remarkCite],
8
+ });
9
+ expect(body).toContain('class="fp"');
10
+ expect(body).toContain('data-path="src/foo.ts:42"');
11
+ expect(body).toContain('>src/foo.ts:42<');
12
+ });
13
+ it('preserves a line range in data-path', async () => {
14
+ const { body } = await renderGuideBody(':cite[src/bar.ts:10-20]\n', { plugins: [remarkCite] });
15
+ expect(body).toContain('data-path="src/bar.ts:10-20"');
16
+ });
17
+ it('renders an advisory citation without the fp class so the gate does not block on it', async () => {
18
+ const { body } = await renderGuideBody(':cite[docs/x.md:3]{mode=advisory}\n', {
19
+ plugins: [remarkCite],
20
+ });
21
+ expect(body).toContain('class="cite-advisory"');
22
+ expect(body).toContain('data-path="docs/x.md:3"');
23
+ expect(body).not.toContain('class="fp"');
24
+ });
25
+ });
26
+ //# sourceMappingURL=directives-cite.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directives-cite.test.js","sourceRoot":"","sources":["../../src/guides/directives-cite.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAE5C,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,EAAE,CAAC,wEAAwE,EAAE,KAAK,IAAI,EAAE;QACtF,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,eAAe,CAAC,yCAAyC,EAAE;YAChF,OAAO,EAAE,CAAC,UAAU,CAAC;SACtB,CAAC,CAAA;QACF,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAA;QACpC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,2BAA2B,CAAC,CAAA;QACnD,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAA;IAC3C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACnD,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,eAAe,CAAC,2BAA2B,EAAE,EAAE,OAAO,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA;QAC9F,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,8BAA8B,CAAC,CAAA;IACxD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oFAAoF,EAAE,KAAK,IAAI,EAAE;QAClG,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,eAAe,CAAC,qCAAqC,EAAE;YAC5E,OAAO,EAAE,CAAC,UAAU,CAAC;SACtB,CAAC,CAAA;QACF,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,uBAAuB,CAAC,CAAA;QAC/C,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,yBAAyB,CAAC,CAAA;QACjD,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,YAAY,CAAC,CAAA;IAC1C,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}