spec-ctx 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,111 +1,160 @@
1
1
  # spec-ctx
2
2
 
3
- spec-ctx ticks an [OpenSpec](https://github.com/Fission-AI/OpenSpec) task only after its Verify command passes and hands the agent one task of spec text, a context ratio of 0.0518 (`docs/metrics/2026-10-25.md`).
3
+ Stable IDs for OpenSpec. Your coding agent loads only the spec one task needs, and knows what to do next.
4
4
 
5
- ```bash
6
- npx -y github:sonqh/spec-ctx#4490d188ad48 init --all
7
- npx -y github:sonqh/spec-ctx#4490d188ad48 task next
8
- npx -y github:sonqh/spec-ctx#4490d188ad48 task start add-mfa/1.3
9
- ```
5
+ For teams that run Claude Code, Codex, or Cursor on an OpenSpec project.
10
6
 
11
- ```text
12
- $ specctx task start add-mfa/1.3
13
- -- REQ-UA-004 | openspec/changes/add-mfa/specs/user-auth/spec.md:5 | active | requested
14
- ### Requirement: REQ-UA-004 Second factor
15
- The system SHALL ask for a TOTP code after a valid password.
16
-
17
- #### Scenario: SCN-UA-004-1 Valid code
18
- - **WHEN** the user enters the current TOTP code
19
- - **THEN** the system opens a session
20
-
21
- #### Scenario: SCN-UA-004-2 Expired code
22
- - **WHEN** the user enters a code older than 30 seconds
23
- - **THEN** the system rejects it
7
+ ## What OpenSpec is
8
+
9
+ [OpenSpec](https://github.com/Fission-AI/OpenSpec) is a folder named `openspec/` in your repo. It holds specs, the rules your software must follow, and changes. A change holds a proposal, a design, and a task list. A coding agent reads them and works down the list.
10
+
11
+ ## The problem
12
+
13
+ Three things go wrong.
14
+
15
+ - The agent reads the whole `openspec/` tree for every task. Most of it is not about the task. Tokens go to text the agent will not use.
16
+ - OpenSpec links a change to a spec by header text. A reword breaks the link, and the agent loses the thread between requirement, code, and test.
17
+ - A new session starts cold. The agent does not know which task is next, what it already did, or which questions are open.
18
+
19
+ ## What spec-ctx adds
20
+
21
+ | Without | With spec-ctx |
22
+ | --- | --- |
23
+ | The agent reads the whole `openspec/` tree. | The agent gets the bundle of one task: the requirements it cites, their scenarios, decisions, and neighbors. |
24
+ | Links go by header text. | Every requirement, scenario, decision, and task has an ID. Code and tests carry tags that name it. |
25
+ | Each session starts cold. | `status`, `task next`, and the generated handoff say where the work stands. |
26
+ | The agent ticks `[x]` by hand. | `[x]` appears only after the Verify command of the task exits 0. The run leaves an evidence file. |
27
+
28
+ A later edit can break a task that passed. `check --strict` names each task whose files changed after its Verify passed.
29
+
30
+ No LLM call. No daemon. The same files give the same output.
31
+
32
+ ## See it work
33
+
34
+ Six commands on a small project. Each clip is one command.
35
+
36
+ ### 1. Give every requirement an ID
37
+
38
+ OpenSpec names a requirement by its header text. A reword breaks every link to it. `adopt` gives each requirement and scenario an ID that stays. Run it once on a project that has specs. A new project gets IDs from `init --all`.
39
+
40
+ ![The adopt dry run lists each header and its new ID](docs/demo/clips/1-adopt.svg)
41
+
42
+ You see: the dry run prints each header and the ID it gets. Then `adopt` writes them.
43
+
44
+ ### 2. Where are we
45
+
46
+ `status` shows the open change, the task counts, and the next command to run.
47
+
48
+ ![One change with two tasks done and one open](docs/demo/clips/2-status.svg)
49
+
50
+ You see: one change, two tasks done, one open, and the hint.
51
+
52
+ ### 3. What is next
53
+
54
+ `task next` picks the first open task. It prints the requirement IDs the task cites and the Verify command, the shell command that proves the task is done.
55
+
56
+ ![Task add-mfa/1.3 with its requirement and Verify command](docs/demo/clips/3-next.svg)
57
+
58
+ You see: task `add-mfa/1.3`, its requirement, and `grep -q totp src/login.ts`.
59
+
60
+ ### 4. Only the spec this task needs
61
+
62
+ `task start` prints the requirement, its scenarios, the task line, and the test that covers it. Nothing else. The last line is the size of that bundle next to the size of all spec text.
63
+
64
+ ![The bundle of one task and its size footer](docs/demo/clips/4-start.svg)
65
+
66
+ You see: 711 characters, 3.6 percent of the tree. The agent reads this instead of the tree.
67
+
68
+ ### 5. Done means Verify passed
69
+
70
+ `task done` runs the Verify command. On exit 1 the box stays open. On exit 0 the box flips to `[x]` and an evidence file records the files that were checked. The agent cannot tick the box by hand.
71
+
72
+ ![A refused done, the edit, and a passing done](docs/demo/clips/5-done.svg)
73
+
74
+ You see: a red refusal, the edit, then a green done line.
75
+
76
+ ### 6. Hand off to the next session
77
+
78
+ `handoff write` puts the state in one file: the change, the done tasks, the current task, and the open questions. The next session starts from it.
79
+
80
+ ![The head of the handoff file](docs/demo/clips/6-handoff.svg)
81
+
82
+ You see: the head of `.ctx/handoff.md`.
83
+
84
+ The transcript of all six clips is in `docs/demo/loop.txt`. The clips run on a copy of `tests/fixtures/no-id-repo` plus the six capabilities in `docs/demo/specs/`. `bash docs/demo/record.sh` records them again.
85
+
86
+ ## Quickstart
87
+
88
+ ```bash
89
+ npx -y spec-ctx init --all # config, schema, and three agent skills
90
+ npx -y spec-ctx task next # the next task and the command that proves it
91
+ npx -y spec-ctx task start <task> # only the spec that this task needs
92
+ npx -y spec-ctx task done <task> # runs that command. A pass ticks the box.
24
93
  ```
25
94
 
26
- ## Why
95
+ A project with specs but no IDs needs `specctx adopt` first. See [Two paths](#two-paths).
27
96
 
28
- - Checkboxes lie. `task done` runs Verify and writes evidence, and 70 of 86 tasks hold it (evidence ratio 0.81).
29
- - Context overflows. A bundle holds 0.0518 of the spec text on average (27 tasks).
30
- - Evidence goes stale. The check caught 36 stale results in 59 reopens.
97
+ ## How it finds the context
31
98
 
32
- ## Demo
99
+ ```mermaid
100
+ graph LR
101
+ T["task add-mfa/1.3"] -->|cites| R["REQ-UA-004"]
102
+ R -->|scenario| S1["SCN-UA-004-1"]
103
+ R -->|scenario| S2["SCN-UA-004-2"]
104
+ R -->|"// REQ tag"| C["src/login.ts"]
105
+ R -->|"Covers:"| X["tests/login.test.ts"]
106
+ ```
33
107
 
34
- ![One task loop: status, task next, task start, an edit, task done, stats](docs/demo/loop.svg)
108
+ The ID is the stable key. A reword of a header does not change it. The index is the graph of IDs: tasks, requirements, scenarios, decisions, code tags, and test tags. `bundle` walks the edges to the configured depth inside a character budget. A decision record joins the graph through its `Refs:` line. The demo fixture has none, so the graph above shows no decision.
35
109
 
36
- <details>
37
- <summary>Transcript of the demo</summary>
110
+ `specctx related` prints each neighbor of an ID and the reason for the link. This is the output for the demo project after its last step:
38
111
 
39
112
  ```text
40
- $ specctx status
41
- index rebuilt
42
- add-mfa done 2 open 1
43
- uncovered active REQs in main: 5
44
- next: specctx task next
45
- $ specctx task next
46
- add-mfa/1.3 Add the TOTP prompt to the login form.
47
- reqs: REQ-UA-004
48
- verify: grep -q totp src/login.ts
49
- $ specctx task start add-mfa/1.3 | head -12
50
- -- REQ-UA-004 | openspec/changes/add-mfa/specs/user-auth/spec.md:5 | active | requested
51
- ### Requirement: REQ-UA-004 Second factor
52
- The system SHALL ask for a TOTP code after a valid password.
53
-
54
- #### Scenario: SCN-UA-004-1 Valid code
55
- - **WHEN** the user enters the current TOTP code
56
- - **THEN** the system opens a session
57
-
58
- #### Scenario: SCN-UA-004-2 Expired code
59
- - **WHEN** the user enters a code older than 30 seconds
60
- - **THEN** the system rejects it
61
-
62
- $ printf '// REQ-UA-004\nexport const prompt = "totp";\n' > src/login.ts
63
- $ specctx task done add-mfa/1.3
64
- index rebuilt
65
- done add-mfa/1.3. Evidence: .ctx/evidence/add-mfa/1.3.json
66
- $ specctx stats --change add-mfa
67
- index rebuilt
68
- change context_ratio evidence_ratio stale_catches cycle_time_median_s debt
69
- add-mfa 0.2950 (n=1) 1.00 (1/1) n/a 6 (n=1) 2
70
- total 0.2950 (n=1) 1.00 (1/1) n/a 6 (n=1) 13 (0 baselined + 13 new)
71
- gate_runs n/a
72
- gate_pass_rate n/a
73
- gate_failures_caught n/a
74
- context_ratio = bundle chars / chars of all specs. Lower is better.
113
+ $ specctx related REQ-UA-004
114
+ scn SCN-UA-004-1 active openspec/changes/add-mfa/specs/user-auth/spec.md:8 scenario of REQ-UA-004
115
+ scn SCN-UA-004-2 active openspec/changes/add-mfa/specs/user-auth/spec.md:12 scenario of REQ-UA-004
116
+ task add-mfa/1.3 done openspec/changes/add-mfa/tasks.md:7 task cites REQ-UA-004
117
+ code src/login.ts:1 active src/login.ts:1 implements REQ-UA-004
118
+ test tests/login.test.ts:1 active tests/login.test.ts:1 covers REQ-UA-004
75
119
  ```
76
120
 
77
- </details>
78
-
79
- The demo runs on a copy of `tests/fixtures/no-id-repo` after `specctx adopt`. `bash docs/demo/record.sh` records it again.
121
+ ## The life cycle for agents
80
122
 
81
- ## What it does
123
+ `init --all` installs three skills. Each one fires at a fixed point of the session.
82
124
 
83
- spec-ctx is a deterministic context engine and task workflow for OpenSpec projects. The CLI is `specctx`.
125
+ - `specctx-bootstrap` fires at the start of a session. It reads the status and the handoff and starts the task.
126
+ - `specctx-next` fires after a task closes. It picks the next task and loads its bundle.
127
+ - `specctx-done` fires when the work is complete. It runs Verify, closes the task, and writes the handoff.
84
128
 
85
- OpenSpec gives you a proposal, specs, a design, and tasks. spec-ctx adds what an AI agent needs to work on them without reading the whole tree:
129
+ The loop that the skills teach:
86
130
 
87
- - Stable IDs on every requirement, scenario, decision, and task.
88
- - An index that links each ID to code, tests, and other IDs.
89
- - `bundle`: the few kilobytes of spec that one task needs, with the file and line of each block.
90
- - `task next`, `task start`, `task done`: the checkbox changes only after the `Verify:` command of the task exits 0, and the evidence stays beside the tree.
91
- - A generated handoff, so the next session starts with one command.
131
+ ```bash
132
+ specctx init --all # config, schema, and the three skills
133
+ specctx status # active changes, current task, open questions
134
+ specctx task next # the next open task, its REQ IDs, and its Verify command
135
+ specctx task start <task> # the bundle of that task and its size
136
+ specctx task done <task> # run Verify, write evidence, set the checkbox
137
+ specctx check --strict # IDs, links, coverage, and evidence
138
+ specctx handoff write # .ctx/handoff.md for the next session
139
+ ```
92
140
 
93
- No LLM call. No daemon. The same files give the same bytes.
141
+ The rule: the agent never opens `openspec/specs/` by hand. It uses `task start` or `bundle`. The skills are in [`skills/`](skills/). Install them alone with `npx skills add sonqh/spec-ctx` or `specctx init --skills`.
94
142
 
95
143
  ## Install
96
144
 
97
145
  spec-ctx needs Node 22. Run it in a project after `openspec init`.
98
146
 
99
147
  ```bash
100
- npx -y github:sonqh/spec-ctx#4490d188ad48 init --all # from git, works today
101
- npx spec-ctx init --all # from npm, after the 0.1.0 publish
148
+ npx -y spec-ctx init --all # from npm
149
+ npm install -g spec-ctx # puts specctx on your path
150
+ npx -y github:sonqh/spec-ctx#<sha> init --all # from git, for an unreleased commit
102
151
  ```
103
152
 
104
153
  The git form builds the package on install with Node only. Pin a commit SHA. A branch name such as `main` also works, but it moves.
105
154
 
106
155
  The command writes `spec-ctx.toml`, installs the `spec-driven-ids` schema into `openspec/schemas/`, adds its rules to `openspec/config.yaml`, and installs three skills into `.claude/skills/` and `.agents/skills/`.
107
156
 
108
- The examples below use `specctx`. With `npx`, write the `npx` form in its place. After the publish, `npm install -g spec-ctx` puts `specctx` on your path. Each GitHub release also carries a single binary for Linux and macOS.
157
+ The examples below use `specctx`. With `npx`, write `npx -y spec-ctx` in its place. Each GitHub release also carries a single binary for Linux and macOS.
109
158
 
110
159
  ## Two paths
111
160
 
@@ -132,24 +181,12 @@ specctx gate --strict
132
181
  - `adopt` derives a capability code from each folder name, for example `UA` for `user-auth`. It writes the codes into `spec-ctx.toml`. Rename a code there before the IDs spread.
133
182
  - `adopt` runs `check` before and after the write. A finding that the write added undoes every file. A second run prints `nothing to adopt`.
134
183
  - `task backfill` writes manual evidence for every ticked task that has none.
135
- - `baseline write` records the debt of the day in `.ctx/baseline.json`: untested requirements and scenarios, tasks without evidence, and legacy tasks without a citation or a Verify code span. `check` hides that debt and prints `baselined: <n>`. New debt still shows.
184
+ - `baseline write` records the debt of the day in `.ctx/baseline.json`. The debt has five kinds. Untested requirements and scenarios. Tasks without evidence. Legacy tasks without a citation or a Verify code span. Delta headers that match no main requirement. Hard lint findings per file and rule on the gate globs. `check` hides that debt and prints `baselined: <n>`. `gate` fails the lint step only when a count rises. New debt still shows.
185
+ - `[gate] markdown` in `spec-ctx.toml` names the markdown globs that `gate` lints. Narrow it when a folder is not yours to fix.
136
186
  - Legacy tasks stay in the baseline until an agent adds `[REQ-...]` citations and a `Verify:` code span. `specctx baseline prune` then drops them. No command adds a single entry.
137
187
 
138
188
  Both paths have an end to end test: `tests/paths/fresh.sh` and `tests/paths/existing.sh`.
139
189
 
140
- ## The loop
141
-
142
- ```bash
143
- specctx status # active changes, current task, open questions
144
- specctx task next # the next open task, its REQ IDs, and its Verify command
145
- specctx task start 001/1.1 # the spec bundle for that task
146
- specctx task done 001/1.1 # run Verify, write evidence, set the checkbox
147
- specctx check --strict # IDs, links, coverage, and evidence
148
- specctx handoff write # .ctx/handoff.md for the next session
149
- ```
150
-
151
- The skills `specctx-bootstrap`, `specctx-next`, and `specctx-done` teach an agent this loop. Install them alone with `npx skills add sonqh/spec-ctx` or `specctx init --skills`.
152
-
153
190
  ## Commands
154
191
 
155
192
  | Command | Use |
@@ -233,9 +270,26 @@ The action runs `specctx gate`: `check --strict`, both markdown linters, `opensp
233
270
 
234
271
  ## Status
235
272
 
236
- - Archived: 001 engine port, 002 IDs and tasks, 004 adopt existing, 005 metrics, 006 polish, 007 README and demo, 008 first run UX.
237
- - Open: 003 distribution. Only the npm publish of `0.1.0` waits.
238
- - Until the publish, install from git with `npx -y github:sonqh/spec-ctx#4490d188ad48`. The npm forms `npx spec-ctx` and `npm install -g spec-ctx` work after it.
273
+ - Published: `spec-ctx@0.1.2` on npm, with tags `v0.1.2` and `v0` and binaries on the GitHub release.
274
+ - Archived: 001 to 017. No change is open. See `CHANGELOG.md` for each release.
275
+ - A version bump on `main` publishes the next release. See `docs/CONTRIBUTING.md`.
276
+ - Upstream: the ID scheme is proposed as a comment on [OpenSpec#1967](https://github.com/Fission-AI/OpenSpec/issues/1967#issuecomment-6414314730). The schema bundle is submitted to the community table in [OpenSpec#2157](https://github.com/Fission-AI/OpenSpec/issues/2157). No pull request until a maintainer asks.
277
+
278
+ ## Measured
279
+
280
+ `specctx stats --write` measures this repository after each change. The newest file is `docs/metrics/2026-10-27.md`. Its total row:
281
+
282
+ | change | context_ratio | evidence_ratio | stale_catches | cycle_time_median_s | debt |
283
+ | --- | --- | --- | --- | --- | --- |
284
+ | total | 0.0435 (n=52) | 0.87 (106/122) | 36 (of 68 reopens) | 70 (n=52) | 0 (0 baselined + 0 new) |
285
+
286
+ - `context_ratio`: the size of one task bundle divided by the size of all spec text. Lower is better.
287
+ - `evidence_ratio`: done tasks with a passed Verify command, divided by all done tasks. The rest have a manual note. Higher is better.
288
+ - `stale_catches`: reopened tasks that `check --strict` flagged as stale, out of all reopened tasks. A higher share means the check found the drift before a person did.
289
+ - `cycle_time_median_s`: the median number of seconds from `task start` to `task done`. Lower is faster.
290
+ - `debt`: findings that the baseline hides plus new findings. Zero is the goal.
291
+
292
+ The value in brackets is the count of inputs. A value without inputs reads n/a.
239
293
 
240
294
  ## Contribute
241
295
 
@@ -1,14 +1,14 @@
1
1
  // Generated by scripts/gen-assets.mjs from schemas/spec-driven-ids/ and skills/. Do not edit.
2
2
  // REQ-SCH-001 REQ-SKL-002
3
3
  export const ASSETS = {
4
- "schemas/spec-driven-ids/README.md": "IyBzcGVjLWRyaXZlbi1pZHMKCkEgZm9yayBvZiB0aGUgT3BlblNwZWMgYHNwZWMtZHJpdmVuYCBzY2hlbWEuIEl0IGFkZHMgc3RhYmxlIElEcyBmcm9tIHNwZWMtY3R4IHRvIGV2ZXJ5IGFydGlmYWN0LgoKLSBUaGUgc3BlYyB0ZW1wbGF0ZSBzdGFydHMgZWFjaCByZXF1aXJlbWVudCB3aXRoIGBSRVEtPENBUD4tTk5OYCBhbmQgZWFjaCBzY2VuYXJpbyB3aXRoIGBTQ04tPENBUD4tTk5OLTxuPmAuCi0gVGhlIGluc3RydWN0aW9ucyB0ZWxsIHRoZSBhZ2VudCB0byBnZXQgSURzIGZyb20gYHNwZWNjdHggaWQgbmV3YCBhbmQgdG8gbGluayBJRHMgd2l0aCBgUmVmczpgIGxpbmVzLgotIFRoZSB0YXNrcyB0ZW1wbGF0ZSBjaXRlcyBSRVEgSURzIGFuZCBwdXRzIHRoZSBgVmVyaWZ5OmAgY29tbWFuZCBpbiBhIGNvZGUgc3Bhbiwgc28gYHNwZWNjdHggdGFzayBkb25lYCBjYW4gcnVuIGl0LgotIGBjb25maWctZnJhZ21lbnQueWFtbGAgaG9sZHMgdGhlIGBydWxlc2AgYW5kIGBvcGVyYXRpb25zYCB0aGF0IGBzcGVjY3R4IGluaXQgLS1zY2hlbWFgIGFkZHMgdG8gYG9wZW5zcGVjL2NvbmZpZy55YW1sYC4KCkZvcmtlZCBmcm9tIE9wZW5TcGVjIDEuMTQuMyB3aXRoIGBvcGVuc3BlYyBzY2hlbWEgZm9yayBzcGVjLWRyaXZlbiBzcGVjLWRyaXZlbi1pZHNgLiBDSSB2YWxpZGF0ZXMgaXQgYWdhaW5zdCB0aGF0IHZlcnNpb24uCgojIyBJbnN0YWxsCgpgYGBiYXNoCm5weCBzcGVjLWN0eCBpbml0IC0tc2NoZW1hCmBgYAoKVGhlIGNvbW1hbmQgY29waWVzIHRoaXMgZm9sZGVyIHRvIGBvcGVuc3BlYy9zY2hlbWFzL3NwZWMtZHJpdmVuLWlkcy9gIGFuZCBzZXRzIGBzY2hlbWE6IHNwZWMtZHJpdmVuLWlkc2AgaW4gYG9wZW5zcGVjL2NvbmZpZy55YW1sYC4K",
5
- "schemas/spec-driven-ids/config-fragment.yaml": "IyBzcGVjLWN0eCBmcmFnbWVudCBmb3Igb3BlbnNwZWMvY29uZmlnLnlhbWwuIHNwZWNjdHggaW5pdCAtLXNjaGVtYSBhZGRzIGVhY2ggdG9wLWxldmVsIGtleQojIHRoYXQgdGhlIHByb2plY3QgY29uZmlnIGRvZXMgbm90IGhhdmUgeWV0LiBJdCBuZXZlciBjaGFuZ2VzIGEga2V5IHRoYXQgZXhpc3RzLgpydWxlczoKICBzcGVjczoKICAgIC0gRXZlcnkgcmVxdWlyZW1lbnQgaGVhZGVyIHN0YXJ0cyB3aXRoIGl0cyBJRCwgZS5nLiAiIyMjIFJlcXVpcmVtZW50OiBSRVEtQUJDLTAwMSBOYW1lIi4gR2V0IHRoZSBJRCBmcm9tIGBzcGVjY3R4IGlkIG5ldyBSRVEgQUJDYC4KICAgIC0gRXZlcnkgc2NlbmFyaW8gaGVhZGVyIHN0YXJ0cyB3aXRoIGl0cyBJRCwgZS5nLiAiIyMjIyBTY2VuYXJpbzogU0NOLUFCQy0wMDEtMSBOYW1lIi4KICAgIC0gQSByZXF1aXJlbWVudCBtYXkgZW5kIHdpdGggYSBsaW5lICJSZWZzOiBSRVEtQUJDLTAwMiwgQURSLTAwMSIgdG8gbGluayByZWxhdGVkIElEcy4KICAgIC0gUmVxdWlyZW1lbnQgdGV4dCBzdGF5cyB1bmRlciA1MDAgY2hhcmFjdGVycy4gTW92ZSBkZXRhaWwgaW50byBzY2VuYXJpb3MuCiAgZGVzaWduOgogICAgLSBFYWNoIGRlY2lzaW9uIGlzIG9uZSBidWxsZXQgdW5kZXIgIiMjIERlY2lzaW9ucyIuIEFkZCBuZXcgZGVjaXNpb25zIGF0IHRoZSBlbmQuCiAgdGFza3M6CiAgICAtIEV2ZXJ5IHRhc2sgY2l0ZXMgYXQgbGVhc3Qgb25lIFJFUSBJRCBpbiBzcXVhcmUgYnJhY2tldHMsIGUuZy4gIltSRVEtQUJDLTAwMV0iLgogICAgLSBFdmVyeSB0YXNrIHN0YXRlcyBpdHMgdmVyaWZpY2F0aW9uIGFzIGEgY29tbWFuZCBpbiBhIGNvZGUgc3BhbiBhZnRlciAiVmVyaWZ5OiIuCgpvcGVyYXRpb25zOgogIGFwcGx5OgogICAgZ3VpZGFuY2U6CiAgICAgIC0gU3RhcnQgZWFjaCB0YXNrIHdpdGggYHNwZWNjdHggdGFzayBzdGFydCA8aWQ+YCBhbmQgcmVhZCB0aGUgYnVuZGxlIGl0IHByaW50cyBiZWZvcmUgeW91IHJlYWQgc3BlY3MuCiAgICAgIC0gVGFnIGNvZGUgd2l0aCB0aGUgUkVRIElEIGl0IGltcGxlbWVudHMgKGEgY29tbWVudCBgLy8gUkVRLUFCQy0wMDFgKS4gVGFnIHRlc3RzIHdpdGggYC8vIENvdmVyczogUkVRLUFCQy0wMDFgLgogICAgICAtIENsb3NlIGVhY2ggdGFzayB3aXRoIGBzcGVjY3R4IHRhc2sgZG9uZSA8aWQ+YC4gTmV2ZXIgdGljayBhIGNoZWNrYm94IGJ5IGhhbmQuCiAgICAgIC0gUnVuIGBzcGVjY3R4IGNoZWNrIC0tc3RyaWN0YCBhZnRlciBlYWNoIHRhc2sgZ3JvdXAuCiAgYXJjaGl2ZToKICAgIGd1aWRhbmNlOgogICAgICAtIFJ1biBgc3BlY2N0eCBjaGVjayAtLXN0cmljdGAgYW5kIGBvcGVuc3BlYyB2YWxpZGF0ZSAtLWFsbCAtLXN0cmljdGAuIEJvdGggbXVzdCBwYXNzIGJlZm9yZSBhcmNoaXZlLgogICAgICAtIFJ1biBgb3BlbnNwZWMgdmFsaWRhdGUgLS1hbGwgLS1zdHJpY3RgIGFnYWluIGFmdGVyIGFyY2hpdmUgYW5kIGJlZm9yZSBwdXNoLgo=",
4
+ "schemas/spec-driven-ids/README.md": "IyBzcGVjLWRyaXZlbi1pZHMKCkEgZm9yayBvZiB0aGUgT3BlblNwZWMgYHNwZWMtZHJpdmVuYCBzY2hlbWEuIEl0IGFkZHMgc3RhYmxlIElEcyBmcm9tIHNwZWMtY3R4IHRvIGV2ZXJ5IGFydGlmYWN0LgoKLSBUaGUgc3BlYyB0ZW1wbGF0ZSBzdGFydHMgZWFjaCByZXF1aXJlbWVudCB3aXRoIGBSRVEtPENBUD4tTk5OYCBhbmQgZWFjaCBzY2VuYXJpbyB3aXRoIGBTQ04tPENBUD4tTk5OLTxuPmAuCi0gVGhlIGluc3RydWN0aW9ucyB0ZWxsIHRoZSBhZ2VudCB0byBnZXQgSURzIGZyb20gYHNwZWNjdHggaWQgbmV3YCBhbmQgdG8gbGluayBJRHMgd2l0aCBgUmVmczpgIGxpbmVzLgotIFRoZSB0YXNrcyB0ZW1wbGF0ZSBjaXRlcyBSRVEgSURzIGFuZCBwdXRzIHRoZSBgVmVyaWZ5OmAgY29tbWFuZCBpbiBhIGNvZGUgc3Bhbiwgc28gYHNwZWNjdHggdGFzayBkb25lYCBjYW4gcnVuIGl0LgotIGBjb25maWctZnJhZ21lbnQueWFtbGAgaG9sZHMgdGhlIGBydWxlc2AgYW5kIGBvcGVyYXRpb25zYCBmb3IgYG9wZW5zcGVjL2NvbmZpZy55YW1sYC4KCiMjIEluc3RhbGwgYnkgY29weQoKLSBDbG9uZSB0aGUgcmVwb3NpdG9yeTogYGdpdCBjbG9uZSBodHRwczovL2dpdGh1Yi5jb20vc29ucWgvc3BlYy1jdHhgLgotIENvcHkgYHNjaGVtYXMvc3BlYy1kcml2ZW4taWRzYCB0byBgb3BlbnNwZWMvc2NoZW1hcy9zcGVjLWRyaXZlbi1pZHNgIGluIHlvdXIgcHJvamVjdC4KLSBTZXQgYHNjaGVtYTogc3BlYy1kcml2ZW4taWRzYCBpbiBgb3BlbnNwZWMvY29uZmlnLnlhbWxgLgotIE1lcmdlIGBjb25maWctZnJhZ21lbnQueWFtbGAgaW50byBgb3BlbnNwZWMvY29uZmlnLnlhbWxgIGJ5IGhhbmQuIEFkZCBpdHMgYHJ1bGVzYCBhbmQgYG9wZXJhdGlvbnNgIGtleXMuIEtlZXAgZXZlcnkgaXRlbSBxdW90ZWQuCi0gUnVuIGBvcGVuc3BlYyBzY2hlbWEgdmFsaWRhdGUgc3BlYy1kcml2ZW4taWRzYC4KCiMjIEluc3RhbGwgd2l0aCBpbml0IC0tc2NoZW1hCgpgYGBiYXNoCm5weCAteSBzcGVjLWN0eCBpbml0IC0tc2NoZW1hCmBgYAoKLSBUaGUgY29tbWFuZCBjb3BpZXMgdGhpcyBmb2xkZXIgdG8gYG9wZW5zcGVjL3NjaGVtYXMvc3BlYy1kcml2ZW4taWRzL2AuCi0gSXQgc2V0cyBgc2NoZW1hOiBzcGVjLWRyaXZlbi1pZHNgIGluIGBvcGVuc3BlYy9jb25maWcueWFtbGAuCi0gSXQgYWRkcyB0aGUgYHJ1bGVzYCBhbmQgYG9wZXJhdGlvbnNgIGtleXMgdGhhdCB0aGUgY29uZmlnIGRvZXMgbm90IGhhdmUgeWV0LiBJdCBsZWF2ZXMgb3RoZXIga2V5cyBhcyB0aGV5IGFyZS4KLSBJdCBxdW90ZXMgYSBsaXN0IGl0ZW0gdGhhdCBZQU1MIHdvdWxkIHJlYWQgYXMgYSBtYXBwaW5nLgoKIyMgVmVyc2lvbgoKRm9ya2VkIGZyb20gT3BlblNwZWMgMS4xNC4zIHdpdGggYG9wZW5zcGVjIHNjaGVtYSBmb3JrIHNwZWMtZHJpdmVuIHNwZWMtZHJpdmVuLWlkc2AuIENJIHZhbGlkYXRlcyBpdCBhZ2FpbnN0IHRoYXQgdmVyc2lvbi4K",
5
+ "schemas/spec-driven-ids/config-fragment.yaml": "IyBzcGVjLWN0eCBmcmFnbWVudCBmb3Igb3BlbnNwZWMvY29uZmlnLnlhbWwuIHNwZWNjdHggaW5pdCAtLXNjaGVtYSBhZGRzIGVhY2ggdG9wLWxldmVsIGtleQojIHRoYXQgdGhlIHByb2plY3QgY29uZmlnIGRvZXMgbm90IGhhdmUgeWV0LiBJdCBuZXZlciBjaGFuZ2VzIGEga2V5IHRoYXQgZXhpc3RzLgpydWxlczoKICBzcGVjczoKICAgIC0gJ0V2ZXJ5IHJlcXVpcmVtZW50IGhlYWRlciBzdGFydHMgd2l0aCBpdHMgSUQsIGUuZy4gIiMjIyBSZXF1aXJlbWVudDogUkVRLUFCQy0wMDEgTmFtZSIuIEdldCB0aGUgSUQgZnJvbSBgc3BlY2N0eCBpZCBuZXcgUkVRIEFCQ2AuJwogICAgLSAnRXZlcnkgc2NlbmFyaW8gaGVhZGVyIHN0YXJ0cyB3aXRoIGl0cyBJRCwgZS5nLiAiIyMjIyBTY2VuYXJpbzogU0NOLUFCQy0wMDEtMSBOYW1lIi4nCiAgICAtICdBIHJlcXVpcmVtZW50IG1heSBlbmQgd2l0aCBhIGxpbmUgIlJlZnM6IFJFUS1BQkMtMDAyLCBBRFItMDAxIiB0byBsaW5rIHJlbGF0ZWQgSURzLicKICAgIC0gJ1JlcXVpcmVtZW50IHRleHQgc3RheXMgdW5kZXIgNTAwIGNoYXJhY3RlcnMuIE1vdmUgZGV0YWlsIGludG8gc2NlbmFyaW9zLicKICBkZXNpZ246CiAgICAtICdFYWNoIGRlY2lzaW9uIGlzIG9uZSBidWxsZXQgdW5kZXIgIiMjIERlY2lzaW9ucyIuIEFkZCBuZXcgZGVjaXNpb25zIGF0IHRoZSBlbmQuJwogIHRhc2tzOgogICAgLSAnRXZlcnkgdGFzayBjaXRlcyBhdCBsZWFzdCBvbmUgUkVRIElEIGluIHNxdWFyZSBicmFja2V0cywgZS5nLiAiW1JFUS1BQkMtMDAxXSIuJwogICAgLSAnRXZlcnkgdGFzayBzdGF0ZXMgaXRzIHZlcmlmaWNhdGlvbiBhcyBhIGNvbW1hbmQgaW4gYSBjb2RlIHNwYW4gYWZ0ZXIgIlZlcmlmeToiLicKCm9wZXJhdGlvbnM6CiAgYXBwbHk6CiAgICBndWlkYW5jZToKICAgICAgLSAnU3RhcnQgZWFjaCB0YXNrIHdpdGggYHNwZWNjdHggdGFzayBzdGFydCA8aWQ+YCBhbmQgcmVhZCB0aGUgYnVuZGxlIGl0IHByaW50cyBiZWZvcmUgeW91IHJlYWQgc3BlY3MuJwogICAgICAtICdUYWcgY29kZSB3aXRoIHRoZSBSRVEgSUQgaXQgaW1wbGVtZW50cyAoYSBjb21tZW50IGAvLyBSRVEtQUJDLTAwMWApLiBUYWcgdGVzdHMgd2l0aCBgLy8gQ292ZXJzOiBSRVEtQUJDLTAwMWAuJwogICAgICAtICdDbG9zZSBlYWNoIHRhc2sgd2l0aCBgc3BlY2N0eCB0YXNrIGRvbmUgPGlkPmAuIE5ldmVyIHRpY2sgYSBjaGVja2JveCBieSBoYW5kLicKICAgICAgLSAnUnVuIGBzcGVjY3R4IGNoZWNrIC0tc3RyaWN0YCBhZnRlciBlYWNoIHRhc2sgZ3JvdXAuJwogIGFyY2hpdmU6CiAgICBndWlkYW5jZToKICAgICAgLSAnUnVuIGBzcGVjY3R4IGNoZWNrIC0tc3RyaWN0YCBhbmQgYG9wZW5zcGVjIHZhbGlkYXRlIC0tYWxsIC0tc3RyaWN0YC4gQm90aCBtdXN0IHBhc3MgYmVmb3JlIGFyY2hpdmUuJwogICAgICAtICdSdW4gYG9wZW5zcGVjIHZhbGlkYXRlIC0tYWxsIC0tc3RyaWN0YCBhZ2FpbiBhZnRlciBhcmNoaXZlIGFuZCBiZWZvcmUgcHVzaC4nCg==",
6
6
  "schemas/spec-driven-ids/schema.yaml": "bmFtZTogc3BlYy1kcml2ZW4taWRzCnZlcnNpb246IDEKZGVzY3JpcHRpb246IE9wZW5TcGVjIHNwZWMtZHJpdmVuIHdvcmtmbG93IHdpdGggc3RhYmxlIElEcyBmcm9tIHNwZWMtY3R4IC0gcHJvcG9zYWwg4oaSIHNwZWNzIOKGkiBkZXNpZ24g4oaSIHRhc2tzCmFydGlmYWN0czoKICAtIGlkOiBwcm9wb3NhbAogICAgZ2VuZXJhdGVzOiBwcm9wb3NhbC5tZAogICAgZGVzY3JpcHRpb246IEluaXRpYWwgcHJvcG9zYWwgZG9jdW1lbnQgb3V0bGluaW5nIHRoZSBjaGFuZ2UKICAgIHRlbXBsYXRlOiBwcm9wb3NhbC5tZAogICAgaW5zdHJ1Y3Rpb246IHwKICAgICAgQ3JlYXRlIHRoZSBwcm9wb3NhbCBkb2N1bWVudCB0aGF0IGVzdGFibGlzaGVzIFdIWSB0aGlzIGNoYW5nZSBpcyBuZWVkZWQuCgogICAgICBTZWN0aW9uczoKICAgICAgLSAqKldoeSoqOiAxLTIgc2VudGVuY2VzIG9uIHRoZSBwcm9ibGVtIG9yIG9wcG9ydHVuaXR5LiBXaGF0IHByb2JsZW0gZG9lcyB0aGlzIHNvbHZlPyBXaHkgbm93PwogICAgICAtICoqV2hhdCBDaGFuZ2VzKio6IEJ1bGxldCBsaXN0IG9mIGNoYW5nZXMuIEJlIHNwZWNpZmljIGFib3V0IG5ldyBjYXBhYmlsaXRpZXMsIG1vZGlmaWNhdGlvbnMsIG9yIHJlbW92YWxzLiBNYXJrIGJyZWFraW5nIGNoYW5nZXMgd2l0aCAqKkJSRUFLSU5HKiouCiAgICAgIC0gKipDYXBhYmlsaXRpZXMqKjogSWRlbnRpZnkgd2hpY2ggc3BlY3Mgd2lsbCBiZSBjcmVhdGVkIG9yIG1vZGlmaWVkOgogICAgICAgIC0gKipOZXcgQ2FwYWJpbGl0aWVzKio6IExpc3QgY2FwYWJpbGl0aWVzIGJlaW5nIGludHJvZHVjZWQuIEVhY2ggYmVjb21lcyBhIG5ldyBgc3BlY3MvPGNhcGFiaWxpdHktcGF0aD4vc3BlYy5tZGAuIE5hbWUgZWFjaCBjYXBhYmlsaXR5IGZvciBhIGR1cmFibGUgc3lzdGVtIGJlaGF2aW9yIChmb3IgZXhhbXBsZSwgYHVzZXItYXV0aGApLCBub3QgdGhlIHdvcmsgaW4gdGhpcyBjaGFuZ2UgKGZvciBleGFtcGxlLCBgYWRkLWxvZ2luLWVuZHBvaW50YCkuIENob29zZSBhIGNvaGVzaXZlIGJvdW5kYXJ5IHRoYXQgY2FuIG93biByZWxhdGVkIHJlcXVpcmVtZW50cyBhcyB0aGUgc3lzdGVtIGV2b2x2ZXM7IGF2b2lkIGJyb2FkIGNhdGNoLWFsbCBjYXBhYmlsaXRpZXMuIFVzZSBrZWJhYi1jYXNlIGZvciBwYXRoIHNlZ21lbnRzIHlvdSBpbnRyb2R1Y2UgKGUuZy4sIGB1c2VyLWF1dGhgIG9yIGBpZGVudGl0eS91c2VyLWF1dGhgKSBhbmQgZm9sbG93IHRoZSBwcm9qZWN0J3MgZXhpc3Rpbmcgc3BlYyBvcmdhbml6YXRpb24uCiAgICAgICAgLSAqKk1vZGlmaWVkIENhcGFiaWxpdGllcyoqOiBMaXN0IGV4aXN0aW5nIGNhcGFiaWxpdGllcyB3aG9zZSBSRVFVSVJFTUVOVFMgYXJlIGNoYW5naW5nLiBPbmx5IGluY2x1ZGUgaWYgc3BlYy1sZXZlbCBiZWhhdmlvciBjaGFuZ2VzIChub3QganVzdCBpbXBsZW1lbnRhdGlvbiBkZXRhaWxzKS4gRWFjaCBuZWVkcyBhIGRlbHRhIHNwZWMgZmlsZS4gVXNlIHRoZSBleGFjdCBleGlzdGluZyBwYXRoIHVuZGVyIGBvcGVuc3BlYy9zcGVjcy9gLiBMZWF2ZSBlbXB0eSBpZiBubyByZXF1aXJlbWVudCBjaGFuZ2VzLgogICAgICAtICoqSW1wYWN0Kio6IEFmZmVjdGVkIGNvZGUsIEFQSXMsIGRlcGVuZGVuY2llcywgb3Igc3lzdGVtcy4KCiAgICAgIElNUE9SVEFOVDogVGhlIENhcGFiaWxpdGllcyBzZWN0aW9uIGlzIGNyaXRpY2FsLiBJdCBjcmVhdGVzIHRoZSBjb250cmFjdCBiZXR3ZWVuCiAgICAgIHByb3Bvc2FsIGFuZCBzcGVjcyBwaGFzZXMuIFJlc2VhcmNoIGV4aXN0aW5nIHNwZWNzIGJlZm9yZSBmaWxsaW5nIHRoaXMgaW46CiAgICAgIHJ1biBgb3BlbnNwZWMgbGlzdCAtLXNwZWNzYCBmb3IgdGhlIHByb2plY3QncyBjYXBhYmlsaXR5IGludmVudG9yeSwgdGhlbgogICAgICBgb3BlbnNwZWMgc2hvdyAiPHNwZWMtaWQ+IiAtLXR5cGUgc3BlYyAtLWpzb24gLS1uby1zY2VuYXJpb3NgIGZvciBhbnkgdGhhdAogICAgICBsb29rIHJlbGF0ZWQgLSB0aGF0IHJldHVybnMgYSBjYXBhYmlsaXR5J3MgcHVycG9zZSBhbmQgcmVxdWlyZW1lbnQgdGV4dHMKICAgICAgd2l0aG91dCBwdWxsaW5nIHdob2xlIHNwZWMgZmlsZXMgaW50byBjb250ZXh0LiBBcHBlbmQgYC0tc3RvcmUgIjxpZD4iYCB0bwogICAgICBib3RoIGNvbW1hbmRzIG9ubHkgZm9yIGEgcmVnaXN0ZXJlZCBzdGFuZGFsb25lIHN0b3JlLCBhbmQga2VlcCBgLS10eXBlCiAgICAgIHNwZWNgOiBhIGNoYW5nZSBhbmQgYSBzcGVjIHNoYXJpbmcgYSBuYW1lIGlzIG90aGVyd2lzZSBhbiBhbWJpZ3VvdXMtaXRlbQogICAgICBlcnJvci4gYG9wZW5zcGVjIGxpc3RgIHdpdGhvdXQgYC0tc3BlY3NgIGxpc3RzIGluLWZsaWdodCBjaGFuZ2VzLCBub3QKICAgICAgc3BlY3MgLSBpdCBuZXZlciBzaG93cyB3aGF0IHRoZSBwcm9qZWN0IGFscmVhZHkgY292ZXJzLiBSZXVzZSBhbiBleGlzdGluZwogICAgICBjYXBhYmlsaXR5J3MgZXhhY3QgcGF0aCBpbnN0ZWFkIG9mIGludHJvZHVjaW5nIGEgbmVhci1kdXBsaWNhdGUgbmFtZS4KICAgICAgVGhlIGZpbHRlcmVkIHJlYWQgaXMgb25seSBhbiBvdmVydmlldy4gQmVmb3JlIGRlY2lkaW5nIHdoYXQgaXMgYWxyZWFkeQogICAgICBjb3ZlcmVkIG9yIHdoYXQgc2hvdWxkIGNoYW5nZSwgcmVhZCBlYWNoIHJlbGV2YW50IHNwZWMgaW4gZnVsbCwgaW5jbHVkaW5nCiAgICAgIHNjZW5hcmlvcywgd2l0aCBgb3BlbnNwZWMgc2hvdyAiPHNwZWMtaWQ+IiAtLXR5cGUgc3BlY2AgKHNhbWUgYC0tc3RvcmVgIHJ1bGUpLgogICAgICBFYWNoIGNhcGFiaWxpdHkgbGlzdGVkIGhlcmUgd2lsbCBuZWVkIGEgY29ycmVzcG9uZGluZyBzcGVjIGZpbGUuCgogICAgICBFdmVyeSBjaGFuZ2UgbXVzdCBlaXRoZXIgZGVjbGFyZSBhdCBsZWFzdCBvbmUgY2FwYWJpbGl0eSAobmV3IG9yCiAgICAgIG1vZGlmaWVkKSBvciBleHBsaWNpdGx5IG9wdCBvdXQgb2Ygc3BlY3M6IGBvcGVuc3BlYyB2YWxpZGF0ZWAgcmVqZWN0cyBhCiAgICAgIGNoYW5nZSB3aXRoIHplcm8gZGVsdGFzIHVubGVzcyB0aGUgY2hhbmdlJ3MgYC5vcGVuc3BlYy55YW1sYCBzZXRzCiAgICAgIGBza2lwX3NwZWNzOiB0cnVlYC4gVXNlIGBza2lwX3NwZWNzOiB0cnVlYCBvbmx5IHdoZW4gbm8gc3BlYy1sZXZlbAogICAgICBiZWhhdmlvciBjaGFuZ2VzIChwdXJlIHJlZmFjdG9yLCB0b29saW5nLCBkb2NzKSAtIHNwZWNzIGRlc2NyaWJlCiAgICAgIGJlaGF2aW9yLCBzbyBpZiBiZWhhdmlvciBkb2VzIG5vdCBjaGFuZ2UsIG5vIHNwZWMgc2hvdWxkIGNoYW5nZSBlaXRoZXIuCiAgICAgIERvIG5vdCBpbnZlbnQgYSByZXF1aXJlbWVudCBqdXN0IHRvIHNhdGlzZnkgdmFsaWRhdGlvbi4KCiAgICAgIEtlZXAgaXQgY29uY2lzZSAoMS0yIHBhZ2VzKS4gRm9jdXMgb24gdGhlICJ3aHkiIG5vdCB0aGUgImhvdyIgLQogICAgICBpbXBsZW1lbnRhdGlvbiBkZXRhaWxzIGJlbG9uZyBpbiBkZXNpZ24ubWQuCgogICAgICBUaGlzIGlzIHRoZSBmb3VuZGF0aW9uIC0gc3BlY3MsIGRlc2lnbiwgYW5kIHRhc2tzIGFsbCBidWlsZCBvbiB0aGlzLgogICAgcmVxdWlyZXM6IFtdCgogIC0gaWQ6IHNwZWNzCiAgICBnZW5lcmF0ZXM6ICJzcGVjcy8qKi8qLm1kIgogICAgZGVzY3JpcHRpb246IERldGFpbGVkIHNwZWNpZmljYXRpb25zIGZvciB0aGUgY2hhbmdlCiAgICB0ZW1wbGF0ZTogc3BlYy5tZAogICAgaW5zdHJ1Y3Rpb246IHwKICAgICAgQ3JlYXRlIHNwZWNpZmljYXRpb24gZmlsZXMgdGhhdCBkZWZpbmUgV0hBVCB0aGUgc3lzdGVtIHNob3VsZCBkby4KCiAgICAgIEEgc3BlYyBpcyBhIGJlaGF2aW9yIGNvbnRyYWN0LCBub3QgYW4gaW1wbGVtZW50YXRpb24gcGxhbi4KCiAgICAgIEdvb2Qgc3BlYyBjb250ZW50OgogICAgICAtIE9ic2VydmFibGUgYmVoYXZpb3IgdXNlcnMgb3IgZG93bnN0cmVhbSBzeXN0ZW1zIHJlbHkgb24KICAgICAgLSBJbnB1dHMsIG91dHB1dHMsIGFuZCBlcnJvciBjb25kaXRpb25zCiAgICAgIC0gRXh0ZXJuYWwgY29uc3RyYWludHMgKHNlY3VyaXR5LCBwcml2YWN5LCByZWxpYWJpbGl0eSwgY29tcGF0aWJpbGl0eSkKICAgICAgLSBTY2VuYXJpb3MgdGhhdCBjYW4gYmUgdGVzdGVkIG9yIGV4cGxpY2l0bHkgdmFsaWRhdGVkCgogICAgICBBdm9pZCBpbiBzcGVjczoKICAgICAgLSBJbnRlcm5hbCBjbGFzcy9mdW5jdGlvbiBuYW1lcwogICAgICAtIExpYnJhcnkgb3IgZnJhbWV3b3JrIGNob2ljZXMKICAgICAgLSBTdGVwLWJ5LXN0ZXAgaW1wbGVtZW50YXRpb24gZGV0YWlscwogICAgICAtIERldGFpbGVkIGV4ZWN1dGlvbiBwbGFucyAodGhvc2UgYmVsb25nIGluIGRlc2lnbi5tZCBvciB0YXNrcy5tZCkKCiAgICAgIFF1aWNrIHRlc3Q6IGlmIHRoZSBpbXBsZW1lbnRhdGlvbiBjYW4gY2hhbmdlIHdpdGhvdXQgY2hhbmdpbmcgZXh0ZXJuYWxseQogICAgICB2aXNpYmxlIGJlaGF2aW9yLCBpdCBsaWtlbHkgZG9lcyBub3QgYmVsb25nIGluIHRoZSBzcGVjLgoKICAgICAgQ3JlYXRlIG9uZSBzcGVjIGZpbGUgcGVyIGNhcGFiaWxpdHkgbGlzdGVkIGluIHRoZSBwcm9wb3NhbCdzIENhcGFiaWxpdGllcyBzZWN0aW9uLgogICAgICBgPGNhcGFiaWxpdHktcGF0aD5gIGlzIHRoZSBzcGVjIGRpcmVjdG9yeSByZWxhdGl2ZSB0byBgc3BlY3MvYCAoZm9yIGV4YW1wbGUsCiAgICAgIGB1c2VyLWF1dGhgIG9yIGBpZGVudGl0eS91c2VyLWF1dGhgKS4gUHJlc2VydmUgdGhlIGZ1bGwgcGF0aDoKICAgICAgLSBOZXcgY2FwYWJpbGl0aWVzOiB1c2UgdGhlIGV4YWN0IHBhdGggZnJvbSB0aGUgcHJvcG9zYWwgYXQgYHNwZWNzLzxjYXBhYmlsaXR5LXBhdGg+L3NwZWMubWRgLiBBbnkgcGF0aCBzZWdtZW50IG5ld2x5IGludHJvZHVjZWQgaW4gdGhlIHByb3Bvc2FsIG11c3QgYmUga2ViYWItY2FzZS4gRm9sbG93IHRoZSBwcm9qZWN0J3MgZXhpc3Rpbmcgb3JnYW5pemF0aW9uOyBkbyBub3QgYWRkIGEgbmV3IGRvbWFpbiBsZXZlbCB3aGVuIHRoZSBwcm9qZWN0IHVzZXMgYSBmbGF0IGxheW91dC4KICAgICAgLSBNb2RpZmllZCBjYXBhYmlsaXRpZXM6IHVzZSB0aGUgZXhhY3QgZXhpc3RpbmcgcGF0aCBmcm9tIGBvcGVuc3BlYy9zcGVjcy88Y2FwYWJpbGl0eS1wYXRoPi9gIHdoZW4gY3JlYXRpbmcgdGhlIGRlbHRhIGF0IGBzcGVjcy88Y2FwYWJpbGl0eS1wYXRoPi9zcGVjLm1kYC4gUnVuIGBvcGVuc3BlYyBsaXN0IC0tc3BlY3NgIHRvIGNvbmZpcm0gdGhhdCBwYXRoIGJlZm9yZSB3cml0aW5nIHRoZSBkZWx0YSwgYXBwZW5kaW5nIGAtLXN0b3JlICI8aWQ+ImAgb25seSBmb3IgYSByZWdpc3RlcmVkIHN0YW5kYWxvbmUgc3RvcmUgLSBhIG1pc3R5cGVkIG9yIGludmVudGVkIHBhdGggdGFyZ2V0cyBhIGNhcGFiaWxpdHkgdGhhdCBkb2VzIG5vdCBleGlzdCByYXRoZXIgdGhhbiB0aGUgb25lIHlvdSBtZWFudC4gRG8gbm90IG1vdmUgb3IgcmVuYW1lIHRoZSBjYXBhYmlsaXR5LgoKICAgICAgV3JpdGUgdGhlIHNwZWMgZmlsZXMgb25lIGF0IGEgdGltZSwgc28gdGhlIHVzZXIgc2VlcyBwcm9ncmVzcyBhbmQgYW4KICAgICAgaW50ZXJydXB0ZWQgcnVuIGtlZXBzIHRoZSBmaWxlcyBpdCBhbHJlYWR5IHdyb3RlOgogICAgICAtIEJlZm9yZSB3cml0aW5nIGFueXRoaW5nLCBjb21wYXJlIHRoZSBjYXBhYmlsaXRpZXMgdGhlIHByb3Bvc2FsIGxpc3RzCiAgICAgICAgd2l0aCB0aGUgYHNwZWNzLzxjYXBhYmlsaXR5LXBhdGg+L3NwZWMubWRgIGZpbGVzIHRoYXQgYWxyZWFkeSBleGlzdCwKICAgICAgICBhbmQgc3RhcnQgd2l0aCB0aGUgZmlyc3QgY2FwYWJpbGl0eSB0aGF0IGhhcyBubyBmaWxlLiBEbyBub3QgcmV3cml0ZQogICAgICAgIGFuIGV4aXN0aW5nIGZpbGUgdW5sZXNzIHRoZSB1c2VyIGFza3MgeW91IHRvLgogICAgICAtIEJlZm9yZSBlYWNoIGZpbGUsIHNheSBpbiBvbmUgbGluZSB3aGljaCBjYXBhYmlsaXR5IHlvdSBhcmUgd3JpdGluZy4KICAgICAgLSBXcml0ZSBlYWNoIGZpbGUgYXMgc29vbiBhcyB5b3UgaGF2ZSBkcmFmdGVkIGl0LiBEbyBub3QgcGxhbiBldmVyeSBmaWxlCiAgICAgICAgYmVmb3JlIHdyaXRpbmcgdGhlIGZpcnN0LgogICAgICAtIFN0b3Agd2hlbiBldmVyeSBjYXBhYmlsaXR5IHRoZSBwcm9wb3NhbCBsaXN0cyBoYXMgaXRzIGZpbGUuCgogICAgICBUaGVyZSBtdXN0IGJlIGF0IGxlYXN0IG9uZSBzcGVjIGZpbGUgdW5sZXNzIHRoZSBjaGFuZ2UncyBgLm9wZW5zcGVjLnlhbWxgCiAgICAgIHNldHMgYHNraXBfc3BlY3M6IHRydWVgIChubyBzcGVjLWxldmVsIGJlaGF2aW9yIGNoYW5nZSkgLSBgb3BlbnNwZWMgdmFsaWRhdGVgCiAgICAgIHJlamVjdHMgYSB6ZXJvLWRlbHRhIGNoYW5nZSB3aXRob3V0IHRoYXQgbWFya2VyLiBJZiB0aGUgcHJvcG9zYWwgbGlzdHMgbm8KICAgICAgY2FwYWJpbGl0aWVzIGFuZCBgc2tpcF9zcGVjc2AgaXMgbm90IHNldCwgcmV2aXNpdCB0aGUgcHJvcG9zYWwgZmlyc3QuCgogICAgICBEZWx0YSBvcGVyYXRpb25zICh1c2UgIyMgaGVhZGVycyk6CiAgICAgIC0gKipBRERFRCBSZXF1aXJlbWVudHMqKjogTmV3IGNhcGFiaWxpdGllcwogICAgICAtICoqTU9ESUZJRUQgUmVxdWlyZW1lbnRzKio6IENoYW5nZWQgYmVoYXZpb3IgLSBNVVNUIGluY2x1ZGUgZnVsbCB1cGRhdGVkIGNvbnRlbnQKICAgICAgLSAqKlJFTU9WRUQgUmVxdWlyZW1lbnRzKio6IERlcHJlY2F0ZWQgZmVhdHVyZXMgLSBNVVNUIGluY2x1ZGUgKipSZWFzb24qKiBhbmQgKipNaWdyYXRpb24qKgogICAgICAtICoqUkVOQU1FRCBSZXF1aXJlbWVudHMqKjogTmFtZSBjaGFuZ2VzIG9ubHkgLSB1c2UgRlJPTTovVE86IGZvcm1hdAoKICAgICAgRm9ybWF0IHJlcXVpcmVtZW50czoKICAgICAgLSBFYWNoIHJlcXVpcmVtZW50OiBgIyMjIFJlcXVpcmVtZW50OiA8bmFtZT5gIGZvbGxvd2VkIGJ5IGRlc2NyaXB0aW9uCiAgICAgIC0gVXNlIFNIQUxML01VU1QgZm9yIG5vcm1hdGl2ZSByZXF1aXJlbWVudHMgKGF2b2lkIHNob3VsZC9tYXkpCiAgICAgIC0gRWFjaCBzY2VuYXJpbzogYCMjIyMgU2NlbmFyaW86IDxuYW1lPmAgd2l0aCBXSEVOL1RIRU4gZm9ybWF0CiAgICAgIC0gKipDUklUSUNBTCoqOiBTY2VuYXJpb3MgTVVTVCB1c2UgZXhhY3RseSA0IGhhc2h0YWdzIChgIyMjI2ApLiBVc2luZyAzIGhhc2h0YWdzIG9yIGJ1bGxldHMgd2lsbCBmYWlsIHNpbGVudGx5LgogICAgICAtIEV2ZXJ5IHJlcXVpcmVtZW50IE1VU1QgaGF2ZSBhdCBsZWFzdCBvbmUgc2NlbmFyaW8uCiAgICAgIC0gS2VlcCBlYWNoIHJlcXVpcmVtZW50J3MgZGVzY3JpcHRpb24gKHRoZSB0ZXh0IGJldHdlZW4gYCMjIyBSZXF1aXJlbWVudDpgIGFuZCBpdHMgZmlyc3Qgc2NlbmFyaW8pIHRvIDUwMCBjaGFyYWN0ZXJzIG9yIGZld2VyLiBgb3BlbnNwZWMgdmFsaWRhdGVgIGZsYWdzIGxvbmdlciBkZXNjcmlwdGlvbnMgaW4gQURERUQgcmVxdWlyZW1lbnRzIGFuZCBpbiB0aGUgbWFpbiBzcGVjLiBUaGlzIGlzIGEgd2FybmluZzogbm9ybWFsIHZhbGlkYXRpb24gc3RpbGwgcGFzc2VzLCBidXQgYG9wZW5zcGVjIHZhbGlkYXRlIC0tc3RyaWN0YCBmYWlscyBvbiBpdC4gV2hlbiB3cml0aW5nIGEgbmV3IHJlcXVpcmVtZW50LCBzdGF0ZSBvbmUgYmVoYXZpb3IgcGVyIHJlcXVpcmVtZW50OiBtb3ZlIGV4YW1wbGVzIGFuZCBlZGdlIGNhc2VzIGludG8gc2NlbmFyaW9zLCBhbmQgc3BsaXQgYSByZXF1aXJlbWVudCB0aGF0IGNvdmVycyBzZXZlcmFsIGJlaGF2aW9ycyBpbnRvIHNlcGFyYXRlIGAjIyMgUmVxdWlyZW1lbnQ6YCBibG9ja3MsIGVhY2ggd2l0aCBpdHMgb3duIHNjZW5hcmlvcy4gVW5kZXIgTU9ESUZJRUQsIGtlZXAgdGhlIGV4aXN0aW5nIHJlcXVpcmVtZW50IGJsb2NrIHdob2xlOyBuZXZlciBzcGxpdCwgdHJpbSBvciByZXdyaXRlIGV4aXN0aW5nIHRleHQganVzdCB0byBtZWV0IHRoZSBsZW5ndGguIFNwbGl0IGFuIGV4aXN0aW5nIGxvbmcgcmVxdWlyZW1lbnQgb25seSB3aGVuIHRoZSB1c2VyIGFza3MgZm9yIGl0LCBpbiBhIGNoYW5nZSBtYWRlIGZvciB0aGF0IHB1cnBvc2U6IHVuZGVyIE1PRElGSUVELCBrZWVwIGl0cyBoZWFkZXIgYW5kIGV2ZXJ5IHNjZW5hcmlvIGFuZCBjdXQgaXRzIGRlc2NyaXB0aW9uIGRvd24gdG8gb25lIGJlaGF2aW9yIHdpdGhvdXQgY2hhbmdpbmcgaXRzIG1lYW5pbmcsIHRoZW4gYWRkIGVhY2ggYmVoYXZpb3IgeW91IHJlbW92ZWQgYXMgaXRzIG93biBBRERFRCByZXF1aXJlbWVudCB3aXRoIGl0cyBvd24gc2NlbmFyaW9zLgoKICAgICAgTmV3IGNhcGFiaWxpdGllcyBvbmx5OiB0aGUgZGVsdGEgc3BlYydzIGZpcnN0IHNlY3Rpb24gaXMgYCMjIFB1cnBvc2VgIC0KICAgICAgb25lIG9yIHR3byBzZW50ZW5jZXMgKDUwKyBjaGFyYWN0ZXJzLCBvciBgb3BlbnNwZWMgdmFsaWRhdGUgLS1zdHJpY3RgCiAgICAgIHJlcG9ydHMgaXQgYXMgdG9vIGJyaWVmKSBkZXNjcmliaW5nIHdoYXQgdGhlIGNhcGFiaWxpdHkgaXMgZm9yLiBBcmNoaXZlCiAgICAgIGNvcGllcyBpdCBpbnRvIHRoZSBtYWluIHNwZWMgaXQgY3JlYXRlczsgd2l0aG91dCBpdCB0aGUgbmV3IG1haW4gc3BlYyBpcwogICAgICBsZWZ0IHdpdGggYSBgVEJEIC4uLiBVcGRhdGUgUHVycG9zZSBhZnRlciBhcmNoaXZlYCBwbGFjZWhvbGRlciB0byBmaWxsIGluCiAgICAgIGJ5IGhhbmQuIERvIE5PVCBhZGQgYCMjIFB1cnBvc2VgIHRvIGEgZGVsdGEgZm9yIGFuIGV4aXN0aW5nIGNhcGFiaWxpdHkgLQogICAgICB0aGF0IHNwZWMgYWxyZWFkeSBoYXMgb25lIGFuZCB0aGUgZGVsdGEncyBpcyBpZ25vcmVkLiBUbyBjaGFuZ2UgYW4KICAgICAgZXhpc3RpbmcgY2FwYWJpbGl0eSdzIFB1cnBvc2UgLSBpbmNsdWRpbmcgYSBsZWZ0b3ZlciBgVEJEYCBwbGFjZWhvbGRlciAtCiAgICAgIGVkaXQgYDxwbGFubmluZ0hvbWUucm9vdD4vb3BlbnNwZWMvc3BlY3MvPGNhcGFiaWxpdHktcGF0aD4vc3BlYy5tZGAKICAgICAgZGlyZWN0bHkuIGBwbGFubmluZ0hvbWUucm9vdGAgY29tZXMgZnJvbSB0aGUgYG9wZW5zcGVjIGluc3RydWN0aW9ucyAuLi4KICAgICAgLS1qc29uYCByZXNwb25zZS4gQWx3YXlzIHVzZSBpdCByYXRoZXIgdGhhbiBhIHJlcG8tcmVsYXRpdmUgcGF0aDogaXQKICAgICAgcmVzb2x2ZXMgdG8gdGhlIHN0b3JlIHdoZW5ldmVyIHRoZSBjaGFuZ2UgbGl2ZXMgaW4gb25lIC0gd2hldGhlciB0aGF0CiAgICAgIGNhbWUgZnJvbSBgLS1zdG9yZWAsIGEgcHJvamVjdCBgc3RvcmU6YCBwb2ludGVyLCBvciBhIGdsb2JhbCBkZWZhdWx0CiAgICAgIHN0b3JlIC0gYW5kIHRvIHRoZSBjdXJyZW50IHJlcG9zaXRvcnkgb3RoZXJ3aXNlLiBEbyBub3QgdHJ5IHRvIHdvcmsgb3V0CiAgICAgIHdoaWNoIGNhc2UgYXBwbGllczsgdGhlIGZpZWxkIGFscmVhZHkgaGFzLgoKICAgICAgTU9ESUZJRUQgcmVxdWlyZW1lbnRzIHdvcmtmbG93OgogICAgICAxLiBMb2NhdGUgdGhlIGV4aXN0aW5nIHJlcXVpcmVtZW50IGluIGA8cGxhbm5pbmdIb21lLnJvb3Q+L29wZW5zcGVjL3NwZWNzLzxjYXBhYmlsaXR5LXBhdGg+L3NwZWMubWRgICh0aGUgc2FtZSBzdG9yZS1hd2FyZSByb290IGFzIGFib3ZlKQogICAgICAyLiBDb3B5IHRoZSBFTlRJUkUgcmVxdWlyZW1lbnQgYmxvY2sgKGZyb20gYCMjIyBSZXF1aXJlbWVudDpgIHRocm91Z2ggYWxsIHNjZW5hcmlvcykKICAgICAgMy4gUGFzdGUgdW5kZXIgYCMjIE1PRElGSUVEIFJlcXVpcmVtZW50c2AgYW5kIGVkaXQgdG8gcmVmbGVjdCBuZXcgYmVoYXZpb3IKICAgICAgNC4gRW5zdXJlIGhlYWRlciB0ZXh0IG1hdGNoZXMgZXhhY3RseSAod2hpdGVzcGFjZS1pbnNlbnNpdGl2ZSkKCiAgICAgIENvbW1vbiBwaXRmYWxsOiBVc2luZyBNT0RJRklFRCB3aXRoIHBhcnRpYWwgY29udGVudCBsb3NlcyBkZXRhaWwgYXQgYXJjaGl2ZSB0aW1lLgogICAgICBJZiBhZGRpbmcgbmV3IGNvbmNlcm5zIHdpdGhvdXQgY2hhbmdpbmcgZXhpc3RpbmcgYmVoYXZpb3IsIHVzZSBBRERFRCBpbnN0ZWFkLgoKICAgICAgRXhhbXBsZSAoYSBuZXcgY2FwYWJpbGl0eSwgc28gaXRzIGZpcnN0IHNlY3Rpb24gaXMgYCMjIFB1cnBvc2VgKToKICAgICAgYGBgCiAgICAgICMgU3BlYyBEZWx0YQoKICAgICAgIyMgUHVycG9zZQoKICAgICAgTGV0cyB1c2VycyB0YWtlIHRoZWlyIGRhdGEgb3V0IG9mIHRoZSBwcm9kdWN0IGluIGEgcG9ydGFibGUgZm9ybWF0LgoKICAgICAgIyMgQURERUQgUmVxdWlyZW1lbnRzCgogICAgICAjIyMgUmVxdWlyZW1lbnQ6IFVzZXIgY2FuIGV4cG9ydCBkYXRhCiAgICAgIFRoZSBzeXN0ZW0gU0hBTEwgYWxsb3cgdXNlcnMgdG8gZXhwb3J0IHRoZWlyIGRhdGEgaW4gQ1NWIGZvcm1hdC4KCiAgICAgICMjIyMgU2NlbmFyaW86IFN1Y2Nlc3NmdWwgZXhwb3J0CiAgICAgIC0gKipXSEVOKiogdXNlciBjbGlja3MgIkV4cG9ydCIgYnV0dG9uCiAgICAgIC0gKipUSEVOKiogc3lzdGVtIGRvd25sb2FkcyBhIENTViBmaWxlIHdpdGggYWxsIHVzZXIgZGF0YQoKICAgICAgIyMgUkVNT1ZFRCBSZXF1aXJlbWVudHMKCiAgICAgICMjIyBSZXF1aXJlbWVudDogTGVnYWN5IGV4cG9ydAogICAgICAqKlJlYXNvbioqOiBSZXBsYWNlZCBieSBuZXcgZXhwb3J0IHN5c3RlbQogICAgICAqKk1pZ3JhdGlvbioqOiBVc2UgbmV3IGV4cG9ydCBlbmRwb2ludCBhdCAvYXBpL3YyL2V4cG9ydAogICAgICBgYGAKCgogICAgICBTdGFibGUgSURzIChzcGVjLWN0eCk6CiAgICAgIC0gRXZlcnkgcmVxdWlyZW1lbnQgaGVhZGVyIHN0YXJ0cyB3aXRoIGFuIElEOiBgIyMjIFJlcXVpcmVtZW50OiBSRVEtPENBUD4tTk5OIDxuYW1lPmAuCiAgICAgICAgR2V0IGEgbmV3IElEIGZyb20gYHNwZWNjdHggaWQgbmV3IFJFUSA8Q0FQPmAuIE5ldmVyIGNvdW50IG51bWJlcnMgYnkgaGFuZC4KICAgICAgICBgPENBUD5gIGlzIGEgY2FwYWJpbGl0eSBjb2RlIGZyb20gYFtpZHNdIGNhcHNgIGluIGBzcGVjLWN0eC50b21sYC4KICAgICAgLSBFdmVyeSBzY2VuYXJpbyBoZWFkZXIgc3RhcnRzIHdpdGggYW4gSUQ6IGAjIyMjIFNjZW5hcmlvOiBTQ04tPENBUD4tTk5OLTxuPiA8bmFtZT5gLgogICAgICAgIEdldCBpdCBmcm9tIGBzcGVjY3R4IGlkIG5ldyBTQ04gPENBUD4gLS1mb3IgUkVRLTxDQVA+LU5OTmAuCiAgICAgIC0gVW5kZXIgTU9ESUZJRUQsIFJFTU9WRUQsIG9yIFJFTkFNRUQsIGtlZXAgdGhlIGV4aXN0aW5nIElELiBBbiBJRCBuZXZlciBjaGFuZ2VzLgogICAgICAtIExpbmsgcmVsYXRlZCBJRHMgd2l0aCBvbmUgbGluZSBgUmVmczogSUQsIElEYCBhZnRlciB0aGUgcmVxdWlyZW1lbnQgdGV4dC4KICAgICAgLSBSZXBsYWNlIGV2ZXJ5IHBsYWNlaG9sZGVyIG9mIHRoZSB0ZW1wbGF0ZS4gYHNwZWNjdHggY2hlY2tgIHJlcG9ydHMgYSBoZWFkZXIgd2l0aAogICAgICAgIG5vIElEIGFzIGBtaXNzaW5nLWlkYC4KCiAgICAgIFNwZWNzIHNob3VsZCBiZSB0ZXN0YWJsZSAtIGVhY2ggc2NlbmFyaW8gaXMgYSBwb3RlbnRpYWwgdGVzdCBjYXNlLgogICAgcmVxdWlyZXM6CiAgICAgIC0gcHJvcG9zYWwKCiAgLSBpZDogZGVzaWduCiAgICBnZW5lcmF0ZXM6IGRlc2lnbi5tZAogICAgZGVzY3JpcHRpb246IFRlY2huaWNhbCBkZXNpZ24gZG9jdW1lbnQgd2l0aCBpbXBsZW1lbnRhdGlvbiBkZXRhaWxzCiAgICB0ZW1wbGF0ZTogZGVzaWduLm1kCiAgICBpbnN0cnVjdGlvbjogfAogICAgICBDcmVhdGUgdGhlIGRlc2lnbiBkb2N1bWVudCB0aGF0IGV4cGxhaW5zIEhPVyB0byBpbXBsZW1lbnQgdGhlIGNoYW5nZS4KCiAgICAgIFdoZW4gdG8gaW5jbHVkZSBkZXNpZ24ubWQgKGNyZWF0ZSBvbmx5IGlmIGFueSBhcHBseSk6CiAgICAgIC0gQ3Jvc3MtY3V0dGluZyBjaGFuZ2UgKG11bHRpcGxlIHNlcnZpY2VzL21vZHVsZXMpIG9yIG5ldyBhcmNoaXRlY3R1cmFsIHBhdHRlcm4KICAgICAgLSBOZXcgZXh0ZXJuYWwgZGVwZW5kZW5jeSBvciBzaWduaWZpY2FudCBkYXRhIG1vZGVsIGNoYW5nZXMKICAgICAgLSBTZWN1cml0eSwgcGVyZm9ybWFuY2UsIG9yIG1pZ3JhdGlvbiBjb21wbGV4aXR5CiAgICAgIC0gQW1iaWd1aXR5IHRoYXQgYmVuZWZpdHMgZnJvbSB0ZWNobmljYWwgZGVjaXNpb25zIGJlZm9yZSBjb2RpbmcKCiAgICAgIFNlY3Rpb25zOgogICAgICAtICoqQ29udGV4dCoqOiBPbmx5IHRoZSBjdXJyZW50IHN0YXRlIGFuZCBjb25zdHJhaW50cyBuZWVkZWQgdG8gZXhwbGFpbiB0aGUgYXBwcm9hY2guIFJlZmVyZW5jZSB0aGUgcHJvcG9zYWwgZm9yIG1vdGl2YXRpb24gaW5zdGVhZCBvZiByZXN0YXRpbmcgaXQgKGUuZy4sICJTZWUgcHJvcG9zYWwubWQgLSBXaHkiKS4KICAgICAgLSAqKkdvYWxzIC8gTm9uLUdvYWxzKio6IFdoYXQgdGhpcyBkZXNpZ24gYWNoaWV2ZXMgYW5kIGV4cGxpY2l0bHkgZXhjbHVkZXMuIERvbid0IHJlc3RhdGUgdGhlIHByb3Bvc2FsJ3Mgc2NvcGUgLSBhZGQgb25seSBkZXNpZ24tbGV2ZWwgYm91bmRhcmllcy4KICAgICAgLSAqKkRlY2lzaW9ucyoqOiBLZXkgdGVjaG5pY2FsIGNob2ljZXMgd2l0aCByYXRpb25hbGUgKHdoeSBYIG92ZXIgWT8pLiBJbmNsdWRlIGFsdGVybmF0aXZlcyBjb25zaWRlcmVkIGZvciBlYWNoIGRlY2lzaW9uLgogICAgICAtICoqUmlza3MgLyBUcmFkZS1vZmZzKio6IEtub3duIGxpbWl0YXRpb25zLCB0aGluZ3MgdGhhdCBjb3VsZCBnbyB3cm9uZy4gRm9ybWF0OiBbUmlza10g4oaSIE1pdGlnYXRpb24KICAgICAgLSAqKk1pZ3JhdGlvbiBQbGFuKio6IFN0ZXBzIHRvIGRlcGxveSwgcm9sbGJhY2sgc3RyYXRlZ3kgKGlmIGFwcGxpY2FibGUpCiAgICAgIC0gKipPcGVuIFF1ZXN0aW9ucyoqOiBVbmtub3ducyB0aGF0IGNhbiBzYWZlbHkgYmUgYW5zd2VyZWQgbGF0ZXIgd2l0aG91dAogICAgICAgIGNoYW5naW5nIHRoZSBzcGVjcywgdGhlIGFwcHJvYWNoLCBvciB0aGUgdGFzayBicmVha2Rvd24uIE9taXQgaWYgbm9uZS4KCiAgICAgIE9wZW4gcXVlc3Rpb25zIGFyZSBmb3IgZ2VudWluZWx5IGRlZmVycmFibGUgdW5rbm93bnMsIG5vdCBkZWNpc2lvbnMgeW91CiAgICAgIHNraXBwZWQuIElmIGEgcXVlc3Rpb24gd291bGQgY2hhbmdlIHRoZSBzcGVjcywgdGhlIGNob3NlbiBhcHByb2FjaCwgb3IKICAgICAgdGhlIHRhc2sgYnJlYWtkb3duLCByZXNvbHZlIGl0IG5vdyAtIGFzayB0aGUgdXNlciBpbnN0ZWFkIG9mIGd1ZXNzaW5nLgoKICAgICAgRm9jdXMgb24gYXJjaGl0ZWN0dXJlIGFuZCBhcHByb2FjaCwgbm90IGxpbmUtYnktbGluZSBpbXBsZW1lbnRhdGlvbi4KICAgICAgVGhlIHByb3Bvc2FsIGNvdmVycyB3aHkgYW5kIHdoYXQ7IGRlc2lnbiBjb3ZlcnMgaG93LiBSZWZlcmVuY2UgdGhlCiAgICAgIHByb3Bvc2FsIGZvciBtb3RpdmF0aW9uIGFuZCwgb25jZSB3cml0dGVuLCB0aGUgc3BlY3MgZm9yIHJlcXVpcmVtZW50cyAtCiAgICAgIGlmIGEgc2VjdGlvbiB3b3VsZCBvbmx5IHJlc3RhdGUgdGhlbSwgcG9pbnQgdG8gdGhlbSBpbnN0ZWFkLgoKCiAgICAgIFN0YWJsZSBJRHMgKHNwZWMtY3R4KToKICAgICAgLSBFYWNoIGJ1bGxldCB1bmRlciBgIyMgRGVjaXNpb25zYCBpcyBvbmUgZGVjaXNpb24uIEl0cyBJRCBpcyBgPGNoYW5nZSBudW1iZXI+L0Q8bj5gCiAgICAgICAgYnkgcG9zaXRpb24sIHNvIGFkZCBuZXcgZGVjaXNpb25zIGF0IHRoZSBlbmQgYW5kIG5ldmVyIHJlb3JkZXIgdGhlbS4KICAgICAgLSBFbmQgYSBkZWNpc2lvbiB3aXRoIGBSZWZzOiBgIGFuZCB0aGUgUkVRIG9yIEFEUiBJRHMgaXQgc2VydmVzLiBUaGVuIGBzcGVjY3R4IGJ1bmRsZWAKICAgICAgICBwcmludHMgdGhlIGRlY2lzaW9uIHdpdGggdGhvc2UgcmVxdWlyZW1lbnRzLgoKICAgICAgR29vZCBkZXNpZ24gZG9jcyBleHBsYWluIHRoZSAid2h5IiBiZWhpbmQgdGVjaG5pY2FsIGRlY2lzaW9ucy4KICAgIHJlcXVpcmVzOgogICAgICAtIHByb3Bvc2FsCgogIC0gaWQ6IHRhc2tzCiAgICBnZW5lcmF0ZXM6IHRhc2tzLm1kCiAgICBkZXNjcmlwdGlvbjogSW1wbGVtZW50YXRpb24gY2hlY2tsaXN0IHdpdGggdHJhY2thYmxlIHRhc2tzCiAgICB0ZW1wbGF0ZTogdGFza3MubWQKICAgIGluc3RydWN0aW9uOiB8CiAgICAgIENyZWF0ZSB0aGUgdGFzayBsaXN0IHRoYXQgYnJlYWtzIGRvd24gdGhlIGltcGxlbWVudGF0aW9uIHdvcmsuCgogICAgICBCZWZvcmUgd3JpdGluZyB0YXNrcywgY2hlY2sgZGVzaWduLm1kIGZvciBPcGVuIFF1ZXN0aW9ucy4gSWYgYW55IG9mIHRoZW0KICAgICAgd291bGQgY2hhbmdlIHdoYXQgZ2V0cyBidWlsdCwgcmVzb2x2ZSB0aGVtIHdpdGggdGhlIHVzZXIgZmlyc3QgLSBkbyBub3QKICAgICAgYmFrZSBhbiB1bnN0YXRlZCBhc3N1bXB0aW9uIGludG8gdGhlIHRhc2sgbGlzdC4KCiAgICAgICoqSU1QT1JUQU5UOiBGb2xsb3cgdGhlIHRlbXBsYXRlIGJlbG93IGZvciB0cmFja2VkIHRhc2tzLioqIFRoZSBhcHBseSBwaGFzZSBwYXJzZXMKICAgICAgY2hlY2tib3ggZm9ybWF0IHRvIHRyYWNrIHByb2dyZXNzLiBBIGJveCBob2xkaW5nIG9ubHkgYHhgIGNvdW50cyBhcyBkb25lLAogICAgICB1cHBlciBvciBsb3dlciBjYXNlIGFuZCB3aXRoIGFueSBzcGFjaW5nLCBzbyBgLSBbIHhdYCBpcyBkb25lIHRvby4gRXZlcnkKICAgICAgb3RoZXIgbWFya2VyLCBpbmNsdWRpbmcgYC0gW35dYCwgYC0gWy1dYCBhbmQgYW4gZW1wdHkgYC0gW11gLCByZWFkcyBhcwogICAgICB1bmZpbmlzaGVkLiBBIGxpbmUgd2l0aCBubyBjaGVja2JveCBpcyBub3QgdHJhY2tlZCBhdCBhbGwuCgogICAgICBHdWlkZWxpbmVzOgogICAgICAtIEdyb3VwIHJlbGF0ZWQgdHJhY2tlZCB0YXNrcyB1bmRlciAjIyBudW1iZXJlZCBoZWFkaW5ncwogICAgICAtIEVhY2ggdHJhY2tlZCB0YXNrIE1VU1QgYmUgYSBjaGVja2JveDogYC0gWyBdIFguWSBUYXNrIGRlc2NyaXB0aW9uYAogICAgICAtIFRhc2tzIHNob3VsZCBiZSBzbWFsbCBlbm91Z2ggdG8gY29tcGxldGUgaW4gb25lIHNlc3Npb24KICAgICAgLSBPcmRlciB0YXNrcyBieSBkZXBlbmRlbmN5ICh3aGF0IG11c3QgYmUgZG9uZSBmaXJzdD8pCiAgICAgIC0gVHJhY2sgaW1wbGVtZW50YXRpb24gYW5kIHZlcmlmaWNhdGlvbiB3b3JrIHRoYXQgY2FuIGJlIGNvbXBsZXRlZCBiZWZvcmUKICAgICAgICBhcmNoaXZlLiBJZiB0aGUgcmVxdWVzdGVkIHdvcmtmbG93IGluY2x1ZGVzIGFyY2hpdmUgb3Igd29yayB0aGF0IHJlcXVpcmVzCiAgICAgICAgdGhpcyBjaGFuZ2UgdG8gYmUgYXJjaGl2ZWQsIHByZXNlcnZlIHRob3NlIHN0ZXBzIGFzIHBsYWluIGJ1bGxldHMgaW4gYW4KICAgICAgICBvcHRpb25hbCBgIyMgV29ya2Zsb3cgZm9sbG93LXVwYCBzZWN0aW9uIGF0IHRoZSBlbmQgb2YgdGFza3MubWQuIFRoZXNlCiAgICAgICAgYnVsbGV0cyBhcmUgcmVmZXJlbmNlIGluZm9ybWF0aW9uIG91dHNpZGUgdHJhY2tlZCB0YXNrIHByb2dyZXNzLgogICAgICAtIEVhY2ggdGFzayBNVVNUIHN0YXRlIGhvdyB0byB2ZXJpZnkgY29tcGxldGlvbiAoYSB0ZXN0LCBjb21tYW5kLAogICAgICAgIG9ic2VydmFibGUgYmVoYXZpb3IsIG9yIGRlbGl2ZXJlZCBhcnRpZmFjdCkuIFB1dCB0aGUgdmVyaWZpY2F0aW9uIGluCiAgICAgICAgdGhhdCB0YXNrJ3MgY2hlY2tib3ggZGVzY3JpcHRpb24uIFVzZSBhIHNlcGFyYXRlIHZlcmlmaWNhdGlvbiB0YXNrIG9ubHkKICAgICAgICB3aGVuIGl0IGNoZWNrcyBicm9hZGVyIGludGVncmF0aW9uIG9yIHN5c3RlbSBiZWhhdmlvciB0aGF0IHNwYW5zCiAgICAgICAgbXVsdGlwbGUgaW1wbGVtZW50YXRpb24gdGFza3MuCiAgICAgIC0gRWFjaCB0YXNrIGdyb3VwIE1VU1QgbGFuZCB0aGUgdGVzdHMgYW5kIGRvY3VtZW50YXRpb24gaXRzIG93biB3b3JrCiAgICAgICAgY2FsbHMgZm9yLiBEbyBOT1QgY29sbGVjdCB0ZXN0aW5nIG9yIGRvY3VtZW50YXRpb24gaW50byBhIGZpbmFsIGdyb3VwIC0KICAgICAgICB3aGVuIGEgbGF0ZSBncm91cCBmaXJzdCBleGVyY2lzZXMgd29yayBmcm9tIGFuIGVhcmx5IG9uZSwgdGhlIGZhaWx1cmVzCiAgICAgICAgY2FzY2FkZSBiYWNrIHRocm91Z2ggZXZlcnkgZ3JvdXAgaW4gYmV0d2VlbiBhbmQgZm9yY2UgcmV3b3JrLiBBIGdyb3VwCiAgICAgICAgd2hvc2Ugd29yayBjYWxscyBmb3IgbmVpdGhlciwgc3VjaCBhcyBzY2FmZm9sZGluZyBvciBkZXBlbmRlbmN5IHNldHVwLAogICAgICAgIGNhcnJpZXMgbmVpdGhlci4gQSBmaW5hbCBncm91cCBpcyBmb3IgaW50ZWdyYXRpb24gY2hlY2tzIG9ubHksIG5vdCBmb3IKICAgICAgICB0aGUgdGVzdHMgYW5kIGRvY3MgYW4gZWFybGllciBncm91cCBvd2VkLgoKICAgICAgRXhhbXBsZToKICAgICAgYGBgCiAgICAgICMgVGFza3MKCiAgICAgICMjIDEuIFNldHVwCgogICAgICAtIFsgXSAxLjEgQ3JlYXRlIG5ldyBtb2R1bGUgc3RydWN0dXJlIGFuZCB2ZXJpZnkgZXhwZWN0ZWQgZmlsZXMgYXJlIHByZXNlbnQKICAgICAgLSBbIF0gMS4yIEFkZCBkZXBlbmRlbmNpZXMgdG8gcGFja2FnZS5qc29uIGFuZCB2ZXJpZnkgcGFja2FnZSBpbnN0YWxsYXRpb24gc3VjY2VlZHMKCiAgICAgICMjIDIuIENvcmUgSW1wbGVtZW50YXRpb24KCiAgICAgIC0gWyBdIDIuMSBJbXBsZW1lbnQgZGF0YSBleHBvcnQgZnVuY3Rpb24gYW5kIHZlcmlmeSB0aGUgZXhwb3J0IHRlc3QgcGFzc2VzCiAgICAgIC0gWyBdIDIuMiBBZGQgQ1NWIGZvcm1hdHRpbmcgdXRpbGl0aWVzIGFuZCB2ZXJpZnkgdW5pdCB0ZXN0cyBjb3ZlciBxdW90aW5nIGFuZCBkZWxpbWl0ZXJzCiAgICAgIC0gWyBdIDIuMyBEb2N1bWVudCB0aGUgZXhwb3J0IEFQSSBpbiBkb2NzL2V4cG9ydC5tZCBhbmQgdmVyaWZ5IHRoZSBkb2N1bWVudGVkIGNvbW1hbmQgcnVucyBhcyB3cml0dGVuCiAgICAgIGBgYAoKICAgICAgV2hlbiBhcHBsaWNhYmxlLCBhcHBlbmQgd29ya2Zsb3cgZm9sbG93LXVwIGFzIHBsYWluIGJ1bGxldHMsIGZvciBleGFtcGxlOgogICAgICBgYGAKICAgICAgIyMgV29ya2Zsb3cgZm9sbG93LXVwCgogICAgICAtIEFyY2hpdmUgdGhlIGNoYW5nZSBhZnRlciB0aGUgcHJvamVjdCdzIHJldmlldyByZXF1aXJlbWVudHMgYXJlIHNhdGlzZmllZC4KICAgICAgLSBWZXJpZnkgdGhlIGFyY2hpdmVkIHJlc3VsdC4KICAgICAgYGBgCgoKICAgICAgU3RhYmxlIElEcyBhbmQgVmVyaWZ5IChzcGVjLWN0eCk6CiAgICAgIC0gRXZlcnkgdGFzayBjaXRlcyBhdCBsZWFzdCBvbmUgcmVxdWlyZW1lbnQgaW4gc3F1YXJlIGJyYWNrZXRzOiBgW1JFUS08Q0FQPi1OTk5dYC4KICAgICAgLSBFdmVyeSB0YXNrIGVuZHMgd2l0aCBgVmVyaWZ5OmAgYW5kIHRoZSBjb21tYW5kIGluIGEgY29kZSBzcGFuLCBmb3IgZXhhbXBsZQogICAgICAgIGBgVmVyaWZ5OiBgbnBtIHRlc3QgLS0gdGVzdHMvZXhwb3J0LnRlc3QudHNgIGBgLiBUd28gc3BhbnMgcnVuIGpvaW5lZCB3aXRoIGAmJmAuCiAgICAgIC0gVXNlIHByb3NlIGFmdGVyIGBWZXJpZnk6YCBvbmx5IHdoZW4gbm8gY29tbWFuZCBjYW4gY2hlY2sgdGhlIHdvcmsuIFRoZW4KICAgICAgICBgc3BlY2N0eCB0YXNrIGRvbmUgPGlkPiAtLW1hbnVhbCAiPG5vdGU+ImAgcmVjb3JkcyBpdC4KICAgICAgLSBDbG9zZSBhIHRhc2sgb25seSB3aXRoIGBzcGVjY3R4IHRhc2sgZG9uZSA8aWQ+YC4gSXQgcnVucyB0aGUgY29tbWFuZCwgd3JpdGVzCiAgICAgICAgZXZpZGVuY2UgdW5kZXIgYC5jdHgvZXZpZGVuY2UvYCwgYW5kIHNldHMgdGhlIGNoZWNrYm94LgoKICAgICAgUmVmZXJlbmNlIHNwZWNzIGZvciB3aGF0IG5lZWRzIHRvIGJlIGJ1aWx0LCBkZXNpZ24gZm9yIGhvdyB0byBidWlsZCBpdC4KICAgIHJlcXVpcmVzOgogICAgICAtIHNwZWNzCiAgICAgIC0gZGVzaWduCgphcHBseToKICByZXF1aXJlczogWyB0YXNrcyBdCiAgdHJhY2tzOiB0YXNrcy5tZAogIGluc3RydWN0aW9uOiB8CiAgICBSZWFkIGNvbnRleHQgZmlsZXMsIHdvcmsgdGhyb3VnaCBwZW5kaW5nIHRhc2tzLCBtYXJrIGNvbXBsZXRlIGFzIHlvdSBnby4KICAgIFBhdXNlIGlmIHlvdSBoaXQgYmxvY2tlcnMgb3IgbmVlZCBjbGFyaWZpY2F0aW9uLgo=",
7
7
  "schemas/spec-driven-ids/templates/design.md": "IyBEZXNpZ24KCiMjIENvbnRleHQKCjwhLS0gVGhlIGN1cnJlbnQgc3RhdGUgYW5kIHRoZSBjb25zdHJhaW50cyB0aGF0IHNoYXBlIHRoZSBhcHByb2FjaC4gVGhlIHByb3Bvc2FsIGhvbGRzIHRoZSBtb3RpdmF0aW9uLiAtLT4KCiMjIEdvYWxzIC8gTm9uLUdvYWxzCgoqKkdvYWxzOioqCjwhLS0gV2hhdCB0aGlzIGRlc2lnbiBnaXZlcyAtLT4KCioqTm9uLUdvYWxzOioqCjwhLS0gV2hhdCBzdGF5cyBvdXQgb2Ygc2NvcGUgLS0+CgojIyBEZWNpc2lvbnMKCjwhLS0gT25lIGJ1bGxldCBwZXIgZGVjaXNpb24uIFRoZSBJRCBvZiBhIGRlY2lzaW9uIGlzIDxjaGFuZ2UgbnVtYmVyPi9EPG4+IGJ5IHBvc2l0aW9uLiBBZGQgbmV3IG9uZXMgYXQgdGhlIGVuZC4gLS0+Ci0gPCEtLSBUaGUgZGVjaXNpb24sIHRoZSBhbHRlcm5hdGl2ZSwgYW5kIHdoeS4gLS0+IFJlZnM6IDwhLS0gUkVRLTxDQVA+LU5OTiwgQURSLU5OTiAtLT4KCiMjIFJpc2tzIC8gVHJhZGUtb2ZmcwoKPCEtLSBLbm93biByaXNrcyBhbmQgdGhlIG1pdGlnYXRpb24gZm9yIGVhY2ggLS0+Cg==",
8
8
  "schemas/spec-driven-ids/templates/proposal.md": "IyBQcm9wb3NhbAoKIyMgV2h5Cgo8IS0tIEV4cGxhaW4gdGhlIG1vdGl2YXRpb24gZm9yIHRoaXMgY2hhbmdlLiBXaGF0IHByb2JsZW0gZG9lcyB0aGlzIHNvbHZlPyBXaHkgbm93PyAtLT4KCiMjIFdoYXQgQ2hhbmdlcwoKPCEtLSBEZXNjcmliZSB3aGF0IHdpbGwgY2hhbmdlLiBCZSBzcGVjaWZpYyBhYm91dCBuZXcgY2FwYWJpbGl0aWVzLCBtb2RpZmljYXRpb25zLCBvciByZW1vdmFscy4gLS0+CgojIyBDYXBhYmlsaXRpZXMKCiMjIyBOZXcgQ2FwYWJpbGl0aWVzCjwhLS0gQ2FwYWJpbGl0aWVzIGJlaW5nIGludHJvZHVjZWQuIE5hbWUgZWFjaCBjYXBhYmlsaXR5IGZvciBhIGNvaGVzaXZlIHN5c3RlbQogICAgIGJlaGF2aW9yIHRoYXQgY2FuIG93biByZWxhdGVkIHJlcXVpcmVtZW50cyBhcyB0aGUgc3lzdGVtIGV2b2x2ZXMuIERvIG5vdCBuYW1lCiAgICAgaW1wbGVtZW50YXRpb24gdGFza3Mgb3IgcHJvcG9zYWwgc2VjdGlvbnMuIEF2b2lkIGJyb2FkIGNhdGNoLWFsbCBuYW1lcy4gVXNlCiAgICAga2ViYWItY2FzZSBmb3IgcGF0aCBzZWdtZW50cyB5b3UgaW50cm9kdWNlIChlLmcuLCB1c2VyLWF1dGggb3IgaWRlbnRpdHkvdXNlci1hdXRoKQogICAgIHRoYXQgZm9sbG93IHRoZSBwcm9qZWN0J3MgZXhpc3Rpbmcgc3BlYyBvcmdhbml6YXRpb24uIEVhY2ggY3JlYXRlcwogICAgIHNwZWNzLzxjYXBhYmlsaXR5LXBhdGg+L3NwZWMubWQuIC0tPgotIGA8Y2FwYWJpbGl0eS1wYXRoPmA6IDxicmllZiBkZXNjcmlwdGlvbiBvZiB3aGF0IHRoaXMgY2FwYWJpbGl0eSBjb3ZlcnM+CgojIyMgTW9kaWZpZWQgQ2FwYWJpbGl0aWVzCjwhLS0gRXhpc3RpbmcgY2FwYWJpbGl0aWVzIHdob3NlIFJFUVVJUkVNRU5UUyBhcmUgY2hhbmdpbmcgKG5vdCBqdXN0IGltcGxlbWVudGF0aW9uKS4KICAgICBPbmx5IGxpc3QgaGVyZSBpZiBzcGVjLWxldmVsIGJlaGF2aW9yIGNoYW5nZXMuIEVhY2ggbmVlZHMgYSBkZWx0YSBzcGVjIGZpbGUuCiAgICAgVXNlIHRoZSBleGFjdCBleGlzdGluZyBwYXRoIHVuZGVyIG9wZW5zcGVjL3NwZWNzLy4gTGVhdmUgZW1wdHkgaWYgbm8gcmVxdWlyZW1lbnQKICAgICBjaGFuZ2VzLiBBIGNoYW5nZSB3aXRoIG5vIGNhcGFiaWxpdGllcyBhdCBhbGwgKHB1cmUgcmVmYWN0b3IsIHRvb2xpbmcsIGRvY3MpCiAgICAgbXVzdCBzZXQgYHNraXBfc3BlY3M6IHRydWVgIGluIGl0cyAub3BlbnNwZWMueWFtbCAtIG9wZW5zcGVjIHZhbGlkYXRlIHJlamVjdHMKICAgICBhIHplcm8tZGVsdGEgY2hhbmdlIHdpdGhvdXQgdGhhdCBtYXJrZXIuIERvIG5vdCBpbnZlbnQgYSByZXF1aXJlbWVudCBqdXN0IHRvCiAgICAgc2F0aXNmeSB2YWxpZGF0aW9uLiAtLT4KLSBgPGV4aXN0aW5nLWNhcGFiaWxpdHktcGF0aD5gOiA8d2hhdCByZXF1aXJlbWVudCBpcyBjaGFuZ2luZz4KCiMjIEltcGFjdAoKPCEtLSBBZmZlY3RlZCBjb2RlLCBBUElzLCBkZXBlbmRlbmNpZXMsIHN5c3RlbXMgLS0+Cg==",
9
9
  "schemas/spec-driven-ids/templates/spec.md": "IyBTcGVjIERlbHRhCgojIyBQdXJwb3NlCjwhLS0gTmV3IGNhcGFiaWxpdHkgb25seS4gV3JpdGUgb25lIG9yIHR3byBzZW50ZW5jZXMgb2YgNTAgY2hhcmFjdGVycyBvciBtb3JlLiBEZWxldGUgdGhpcyBzZWN0aW9uIGZvciBhbiBleGlzdGluZyBjYXBhYmlsaXR5LiAtLT4KCiMjIEFEREVEIFJlcXVpcmVtZW50cwoKIyMjIFJlcXVpcmVtZW50OiBSRVEtPENBUD4tTk5OIDwhLS0gcmVxdWlyZW1lbnQgbmFtZSAtLT4KPCEtLSBSZXF1aXJlbWVudCB0ZXh0LiBSZXBsYWNlIFJFUS08Q0FQPi1OTk4gd2l0aCB0aGUgb3V0cHV0IG9mIGBzcGVjY3R4IGlkIG5ldyBSRVEgPENBUD5gLiAtLT4KClJlZnM6IDwhLS0gcmVsYXRlZCBJRHMgc3VjaCBhcyBBRFItMDAxLiBEZWxldGUgdGhpcyBsaW5lIHdoZW4gdGhlcmUgYXJlIG5vbmUuIC0tPgoKIyMjIyBTY2VuYXJpbzogU0NOLTxDQVA+LU5OTi0xIDwhLS0gc2NlbmFyaW8gbmFtZS4gR2V0IHRoZSBJRCBmcm9tIGBzcGVjY3R4IGlkIG5ldyBTQ04gPENBUD4gLS1mb3IgUkVRLTxDQVA+LU5OTmAuIC0tPgotICoqV0hFTioqIDwhLS0gY29uZGl0aW9uIC0tPgotICoqVEhFTioqIDwhLS0gZXhwZWN0ZWQgb3V0Y29tZSAtLT4K",
10
10
  "schemas/spec-driven-ids/templates/tasks.md": "IyBUYXNrcwoKIyMgMS4gPCEtLSBUYXNrIGdyb3VwIG5hbWUgLS0+CgotIFsgXSAxLjEgPCEtLSBUYXNrIGRlc2NyaXB0aW9uIC0tPiBbUkVRLTxDQVA+LU5OTl0gVmVyaWZ5OiBgPCEtLSBjb21tYW5kIC0tPmAKLSBbIF0gMS4yIDwhLS0gVGFzayBkZXNjcmlwdGlvbiAtLT4gW1JFUS08Q0FQPi1OTk5dIFZlcmlmeTogYDwhLS0gY29tbWFuZCAtLT5gCgojIyAyLiA8IS0tIFRhc2sgZ3JvdXAgbmFtZSAtLT4KCi0gWyBdIDIuMSA8IS0tIFRhc2sgZGVzY3JpcHRpb24gLS0+IFtSRVEtPENBUD4tTk5OXSBWZXJpZnk6IGA8IS0tIGNvbW1hbmQgLS0+YAo=",
11
11
  "skills/specctx-bootstrap/SKILL.md": "LS0tCm5hbWU6IHNwZWNjdHgtYm9vdHN0cmFwCmRlc2NyaXB0aW9uOiBTdGFydCBhIHNlc3Npb24gaW4gYW4gT3BlblNwZWMgcHJvamVjdCB0aGF0IHVzZXMgc3BlYy1jdHguIFVzZSBhdCB0aGUgc3RhcnQgb2YgZXZlcnkgc2Vzc2lvbiwgYW5kIG9uICJzdGFydCIsICJib290c3RyYXAiLCBvciAid2hhdCBzaG91bGQgSSB3b3JrIG9uIi4gTG9hZHMgb25seSB0aGUgc3BlYyB0ZXh0IHRoYXQgdGhlIG5leHQgdGFzayBuZWVkcy4KLS0tCgojIHNwZWNjdHgtYm9vdHN0cmFwCgpMb2FkIHRoZSBtaW5pbXVtIGNvbnRleHQgZm9yIG9uZSB0YXNrLiBSdW4gYHNwZWNjdHhgIGFzIGBucHggc3BlYy1jdHhgIHdoZW4gaXQgaXMgbm90IGluc3RhbGxlZC4KCiMjIFN0ZXBzCgoxLiBSdW4gYHNwZWNjdHggc3RhdHVzYC4gSXQgcmVidWlsZHMgYSBzdGFsZSBpbmRleCBmaXJzdC4gTm90ZSB0aGUgYWN0aXZlIGNoYW5nZSwgdGhlIGN1cnJlbnQgdGFzaywgYW5kIHRoZSBjb3VudCBvZiBvcGVuIHF1ZXN0aW9ucy4gVGhlIGxhc3QgbGluZSBgbmV4dDogPHN0ZXA+YCBuYW1lcyB0aGUgbmV4dCBzdGVwLiBFeGl0IDIgd2l0aCBgbm90IGFuIE9wZW5TcGVjIHByb2plY3RgIG1lYW5zIHRoZSBmb2xkZXIgaGFzIG5vIGBvcGVuc3BlYy9gLiBUZWxsIHRoZSB1c2VyIHRvIHJ1biBgbnB4IC15IEBmaXNzaW9uLWFpL29wZW5zcGVjQGxhdGVzdCBpbml0YCBhbmQgc3RvcC4KMi4gUmVhZCBgLmN0eC9oYW5kb2ZmLm1kYCBpZiBpdCBleGlzdHMuIE5vdGUgYGN1cnJlbnRgLCBgcmVvcGVuZWRgLCBhbmQgYG9wZW5fcXVlc3Rpb25zYC4KMy4gSWYgYHN0YXR1c2AgcHJpbnRzIGBubyBhY3RpdmUgY2hhbmdlYCwgc2hvdyB0aGUgb3BlbiBxdWVzdGlvbnMgdG8gdGhlIHVzZXIuIEFzayB3aGljaCBjaGFuZ2UgdG8gc3RhcnQuIFN0b3AgaGVyZS4KNC4gUGljayB0aGUgdGFzay4gVXNlIGBjdXJyZW50YCBmcm9tIHRoZSBoYW5kb2ZmLCB0aGVuIHRoZSB1c2VyJ3MgbWVzc2FnZSwgdGhlbiB0aGUgb3V0cHV0IG9mIGBzcGVjY3R4IHRhc2sgbmV4dGAuCjUuIFJ1biBgc3BlY2N0eCB0YXNrIHN0YXJ0IDx0YXNrPmAuIEl0IHByaW50cyB0aGUgYnVuZGxlIGZvciB0aGUgUkVRIElEcyBvZiB0aGUgdGFzayBhbmQgc2V0cyB0aGUgY3VycmVudCB0YXNrLgo2LiBSZWFkIHRoZSBidW5kbGUuIEVhY2ggYmxvY2sgc3RhcnRzIHdpdGggYC0tIDxpZD4gfCA8ZmlsZT46PGxpbmU+IHwgPHN0YXR1cz4gfCA8cmVhc29uPmAuIEEgYG1vZGlmaWVkYCBibG9jayBpcyB0aGUgcGVuZGluZyB0ZXh0IG9mIGFuIGFjdGl2ZSBjaGFuZ2UuIFRydXN0IGl0IG92ZXIgdGhlIG1haW4gc3BlYy4KNy4gSWYgdGhlIGJ1bmRsZSBlbmRzIHdpdGggYHRydW5jYXRlZDogTiBlbnRyaWVzIG9taXR0ZWQ6IDxpZHM+YCwgcnVuIGBzcGVjY3R4IGJ1bmRsZSA8aWQ+YCBmb3IgZWFjaCBJRCB0aGF0IHRoZSB0YXNrIG5lZWRzLgo4LiBTYXkgaW4gb25lIGxpbmUgd2hpY2ggdGFzayB5b3UgYXJlIG9uIGFuZCB3aGljaCBJRHMgeW91IGxvYWRlZC4gVGhlbiBzdGFydCB0aGUgd29yay4KCiMjIFJ1bGVzCgotIERvIG5vdCBvcGVuIGBvcGVuc3BlYy9zcGVjcy9gIG9yIGBvcGVuc3BlYy9jaGFuZ2VzLyovc3BlY3MvYCBieSBoYW5kLiBVc2UgYHNwZWNjdHggYnVuZGxlYCBvciBgc3BlY2N0eCB0YXNrIHN0YXJ0YC4KLSBSZWFkIGF0IG1vc3QgMTAsMDAwIGNoYXJhY3RlcnMgb2Ygc3BlYyB0ZXh0IGJlZm9yZSB0aGUgZmlyc3QgY29kZSBlZGl0LgotIFRhZyBjb2RlIHdpdGggYC8vIFJFUS1BQkMtMDAxYCBhbmQgdGVzdHMgd2l0aCBgLy8gQ292ZXJzOiBSRVEtQUJDLTAwMWAuCi0gR2V0IGEgbmV3IElEIGZyb20gYHNwZWNjdHggaWQgbmV3IFJFUSA8Q0FQPmAuIE5ldmVyIGNvdW50IG51bWJlcnMgYnkgaGFuZC4KLSBDbG9zZSB0aGUgdGFzayB3aXRoIHRoZSBgc3BlY2N0eC1kb25lYCBza2lsbC4K",
12
- "skills/specctx-done/SKILL.md": "LS0tCm5hbWU6IHNwZWNjdHgtZG9uZQpkZXNjcmlwdGlvbjogQ2xvc2UgYSB0YXNrIGluIGFuIE9wZW5TcGVjIHByb2plY3QgdGhhdCB1c2VzIHNwZWMtY3R4LiBSdW5zIHRoZSBWZXJpZnkgY29tbWFuZCwgd3JpdGVzIGV2aWRlbmNlLCBzZXRzIHRoZSBjaGVja2JveCwgd3JpdGVzIHRoZSBoYW5kb2ZmLCBhbmQgc2hvd3MgdGhlIG1ldHJpY3MuIFVzZSB3aGVuIHRoZSB3b3JrIG9mIGEgdGFzayBpcyBjb21wbGV0ZSwgb3Igb24gImRvbmUiLCAiY2xvc2UgdGhlIHRhc2siLCBhbmQgImVuZCB0aGUgc2Vzc2lvbiIuCi0tLQoKIyBzcGVjY3R4LWRvbmUKCkNsb3NlIHRoZSBjdXJyZW50IHRhc2sgd2l0aCBldmlkZW5jZS4gUnVuIGBzcGVjY3R4YCBhcyBgbnB4IHNwZWMtY3R4YCB3aGVuIGl0IGlzIG5vdCBpbnN0YWxsZWQuCgojIyBTdGVwcwoKMS4gUnVuIGBzcGVjY3R4IHRhc2sgZG9uZSA8dGFzaz5gLiBJdCBydW5zIHRoZSBgVmVyaWZ5OmAgY29tbWFuZCBvZiB0aGUgdGFzayBpbiB0aGUgcHJvamVjdCByb290LgoyLiBPbiBleGl0IDAgaXQgd3JpdGVzIGAuY3R4L2V2aWRlbmNlLzxjaGFuZ2U+Lzx0YXNrPi5qc29uYCBhbmQgc2V0cyBgW3hdYCBvbiB0aGUgdGFzayBsaW5lLiBOb3RoaW5nIGVsc2UgaW4gYHRhc2tzLm1kYCBjaGFuZ2VzLgozLiBPbiBhIGZhaWx1cmUgaXQgcHJpbnRzIHRoZSBsYXN0IDIwIGxpbmVzIG9mIG91dHB1dCBhbmQgZXhpdHMgMS4gVGhlIHRhc2sgc3RheXMgb3Blbi4gRml4IHRoZSBjYXVzZSBhbmQgcnVuIHN0ZXAgMSBhZ2Fpbi4KNC4gSWYgdGhlIHRhc2sgaGFzIHByb3NlIGFmdGVyIGBWZXJpZnk6YCBhbmQgbm8gY29tbWFuZCwgcnVuIGBzcGVjY3R4IHRhc2sgZG9uZSA8dGFzaz4gLS1tYW51YWwgIjx3aGF0IHlvdSBjaGVja2VkPiJgLgo1LiBBZnRlciB0aGUgbGFzdCB0YXNrIG9mIGEgZ3JvdXAsIHJ1biBgc3BlY2N0eCBjaGVjayAtLXN0cmljdGAuIEZpeCBldmVyeSBmaW5kaW5nIGJlZm9yZSB0aGUgbmV4dCBncm91cC4KNi4gUnVuIGBzcGVjY3R4IGhhbmRvZmYgd3JpdGVgLiBJdCB3cml0ZXMgYC5jdHgvaGFuZG9mZi5tZGAgZnJvbSB0aGUgaW5kZXgsIHRoZSBldmlkZW5jZSwgYW5kIHRoZSBvcGVuIHF1ZXN0aW9ucy4KNy4gUnVuIGBzcGVjY3R4IHN0YXRzIC0tY2hhbmdlIDxjaGFuZ2U+YC4gUmVwb3J0IHRoZSBmaXZlIG1ldHJpY3Mgb2YgdGhlIGNoYW5nZSBpbiBvbmUgbGluZSBlYWNoLgo4LiBDb21taXQgdGhlIHdvcmsgdG9nZXRoZXIgd2l0aCBgLmN0eC9gLiBMZWF2ZSBgLmN0eC9pbmRleC5qc29uYCBvdXQgb2YgZ2l0LgoKIyMgUnVsZXMKCi0gTmV2ZXIgdGljayBhIGNoZWNrYm94IGJ5IGhhbmQuIGBjaGVjayAtLXN0cmljdGAgcmVwb3J0cyBhIHRpY2tlZCB0YXNrIHdpdGggbm8gZXZpZGVuY2UgYXMgYGRvbmUtd2l0aG91dC1ldmlkZW5jZWAuCi0gSWYgYSBzcGVjIGNoYW5nZWQgYWZ0ZXIgeW91IGNsb3NlZCBhIHRhc2ssIHJ1biBgc3BlY2N0eCB0YXNrIHJlb3BlbiA8dGFzaz4gIjxyZWFzb24+ImAuCi0gVG8gbGVhdmUgYSBxdWVzdGlvbiBmb3IgdGhlIG5leHQgc2Vzc2lvbiwgcnVuIGBzcGVjY3R4IGhhbmRvZmYgYXNrICI8cXVlc3Rpb24+ImAgYmVmb3JlIHN0ZXAgNi4K",
12
+ "skills/specctx-done/SKILL.md": "LS0tCm5hbWU6IHNwZWNjdHgtZG9uZQpkZXNjcmlwdGlvbjogQ2xvc2UgYSB0YXNrIGluIGFuIE9wZW5TcGVjIHByb2plY3QgdGhhdCB1c2VzIHNwZWMtY3R4LiBSdW5zIHRoZSBWZXJpZnkgY29tbWFuZCwgd3JpdGVzIGV2aWRlbmNlLCBzZXRzIHRoZSBjaGVja2JveCwgd3JpdGVzIHRoZSBoYW5kb2ZmLCBhbmQgc2hvd3MgdGhlIG1ldHJpY3MuIFVzZSB3aGVuIHRoZSB3b3JrIG9mIGEgdGFzayBpcyBjb21wbGV0ZSwgb3Igb24gImRvbmUiLCAiY2xvc2UgdGhlIHRhc2siLCBhbmQgImVuZCB0aGUgc2Vzc2lvbiIuCi0tLQoKIyBzcGVjY3R4LWRvbmUKCkNsb3NlIHRoZSBjdXJyZW50IHRhc2sgd2l0aCBldmlkZW5jZS4gUnVuIGBzcGVjY3R4YCBhcyBgbnB4IHNwZWMtY3R4YCB3aGVuIGl0IGlzIG5vdCBpbnN0YWxsZWQuCgojIyBTdGVwcwoKMS4gUnVuIGBzcGVjY3R4IHRhc2sgZG9uZSA8dGFzaz5gLiBJdCBydW5zIHRoZSBgVmVyaWZ5OmAgY29tbWFuZCBvZiB0aGUgdGFzayBpbiB0aGUgcHJvamVjdCByb290LgoyLiBPbiBleGl0IDAgaXQgd3JpdGVzIGAuY3R4L2V2aWRlbmNlLzxjaGFuZ2U+Lzx0YXNrPi5qc29uYCBhbmQgc2V0cyBgW3hdYCBvbiB0aGUgdGFzayBsaW5lLiBOb3RoaW5nIGVsc2UgaW4gYHRhc2tzLm1kYCBjaGFuZ2VzLgozLiBPbiBhIGZhaWx1cmUgaXQgcHJpbnRzIHRoZSBsYXN0IDIwIGxpbmVzIG9mIG91dHB1dCBhbmQgdGhlbiB0aGUgbGluZSBgVmVyaWZ5IGZhaWxlZCAoZXhpdCA8bj4pLiBUaGUgdGFzayBzdGF5cyBvcGVuLmAgSXQgZXhpdHMgMS4gRml4IHRoZSBjYXVzZSBhbmQgcnVuIHN0ZXAgMSBhZ2Fpbi4KNC4gSWYgdGhlIHRhc2sgaGFzIHByb3NlIGFmdGVyIGBWZXJpZnk6YCBhbmQgbm8gY29tbWFuZCwgcnVuIGBzcGVjY3R4IHRhc2sgZG9uZSA8dGFzaz4gLS1tYW51YWwgIjx3aGF0IHlvdSBjaGVja2VkPiJgLgo1LiBBZnRlciB0aGUgbGFzdCB0YXNrIG9mIGEgZ3JvdXAsIHJ1biBgc3BlY2N0eCBjaGVjayAtLXN0cmljdGAuIEZpeCBldmVyeSBmaW5kaW5nIGJlZm9yZSB0aGUgbmV4dCBncm91cC4KNi4gUnVuIGBzcGVjY3R4IGhhbmRvZmYgd3JpdGVgLiBJdCB3cml0ZXMgYC5jdHgvaGFuZG9mZi5tZGAgZnJvbSB0aGUgaW5kZXgsIHRoZSBldmlkZW5jZSwgYW5kIHRoZSBvcGVuIHF1ZXN0aW9ucy4KNy4gUnVuIGBzcGVjY3R4IHN0YXRzIC0tY2hhbmdlIDxjaGFuZ2U+YC4gUmVwb3J0IHRoZSBmaXZlIG1ldHJpY3Mgb2YgdGhlIGNoYW5nZSBpbiBvbmUgbGluZSBlYWNoLgo4LiBDb21taXQgdGhlIHdvcmsgdG9nZXRoZXIgd2l0aCBgLmN0eC9gLiBMZWF2ZSBgLmN0eC9pbmRleC5qc29uYCBvdXQgb2YgZ2l0LgoKIyMgUnVsZXMKCi0gTmV2ZXIgdGljayBhIGNoZWNrYm94IGJ5IGhhbmQuIGBjaGVjayAtLXN0cmljdGAgcmVwb3J0cyBhIHRpY2tlZCB0YXNrIHdpdGggbm8gZXZpZGVuY2UgYXMgYGRvbmUtd2l0aG91dC1ldmlkZW5jZWAuCi0gSWYgYSBzcGVjIGNoYW5nZWQgYWZ0ZXIgeW91IGNsb3NlZCBhIHRhc2ssIHJ1biBgc3BlY2N0eCB0YXNrIHJlb3BlbiA8dGFzaz4gIjxyZWFzb24+ImAuCi0gVG8gbGVhdmUgYSBxdWVzdGlvbiBmb3IgdGhlIG5leHQgc2Vzc2lvbiwgcnVuIGBzcGVjY3R4IGhhbmRvZmYgYXNrICI8cXVlc3Rpb24+ImAgYmVmb3JlIHN0ZXAgNi4K",
13
13
  "skills/specctx-next/SKILL.md": "LS0tCm5hbWU6IHNwZWNjdHgtbmV4dApkZXNjcmlwdGlvbjogUGljayBhbmQgc3RhcnQgdGhlIG5leHQgdGFzayBpbiB0aGUgbWlkZGxlIG9mIGEgc2Vzc2lvbiBpbiBhbiBPcGVuU3BlYyBwcm9qZWN0IHRoYXQgdXNlcyBzcGVjLWN0eC4gVXNlIGFmdGVyIHlvdSBjbG9zZSBhIHRhc2ssIG9yIG9uICJuZXh0IHRhc2siIGFuZCAid2hhdCBpcyBuZXh0Ii4KLS0tCgojIHNwZWNjdHgtbmV4dAoKTW92ZSB0byB0aGUgbmV4dCBvcGVuIHRhc2suIFJ1biBgc3BlY2N0eGAgYXMgYG5weCBzcGVjLWN0eGAgd2hlbiBpdCBpcyBub3QgaW5zdGFsbGVkLgoKIyMgU3RlcHMKCjEuIFJ1biBgc3BlY2N0eCB0YXNrIG5leHRgLiBJdCBwcmludHMgdGhlIHRhc2sgSUQgYW5kIHRleHQsIHRoZW4gYHJlcXM6YCBhbmQgYHZlcmlmeTpgLgoyLiBJZiBpdCBwcmludHMgYG5vIG9wZW4gdGFzay4gRXZlcnkgdGFzayBpbiB0aGUgYWN0aXZlIGNoYW5nZXMgaXMgZG9uZS4gTmV4dDogYXJjaGl2ZSA8Y2hhbmdlPi5gLCBldmVyeSB0YXNrIG9mIHRoZSBhY3RpdmUgY2hhbmdlcyBoYXMgaXRzIGNoZWNrYm94IHNldC4gUnVuIGBzcGVjY3R4IHN0YXR1c2AuIEl0cyBsYXN0IGxpbmUgaXMgYG5leHQ6IGFyY2hpdmUgPGNoYW5nZT5gLiBUZWxsIHRoZSB1c2VyIHRoYXQgdGhlIGNoYW5nZSBpcyByZWFkeSBmb3IgYHNwZWNjdHggY2hlY2sgLS1zdHJpY3RgIGFuZCBhcmNoaXZlLiBTdG9wIGhlcmUuCjMuIFJ1biBgc3BlY2N0eCB0YXNrIHN0YXJ0IDx0YXNrPmAuIEl0IHByaW50cyB0aGUgYnVuZGxlIGZvciB0aGUgUkVRIElEcyBvZiB0aGUgdGFzayBhbmQgc2V0cyB0aGUgY3VycmVudCB0YXNrIGluIGAuY3R4L2N1cnJlbnQuanNvbmAuCjQuIFJlYWQgdGhlIGJ1bmRsZS4gUmVxdWVzdCBhbiBvbWl0dGVkIElEIHdpdGggYHNwZWNjdHggYnVuZGxlIDxpZD5gIG9ubHkgd2hlbiB0aGUgdGFzayBuZWVkcyBpdC4KNS4gUnVuIGBzcGVjY3R4IHRhc2sgdmVyaWZ5IDx0YXNrPmAgb25jZSBiZWZvcmUgdGhlIHdvcmsuIEl0IHJ1bnMgdGhlIGBWZXJpZnk6YCBjb21tYW5kIGFuZCB3cml0ZXMgbm90aGluZy4gQSBmYWlsdXJlIG5vdyBzaG93cyB3aGF0IHRoZSB3b3JrIG11c3QgZml4Lgo2LiBTYXkgaW4gb25lIGxpbmUgd2hpY2ggdGFzayB5b3UgYXJlIG9uLiBUaGVuIHN0YXJ0IHRoZSB3b3JrLgoKIyMgUnVsZXMKCi0gVGFrZSB0aGUgdGFza3MgaW4gdGhlIG9yZGVyIHRoYXQgYHNwZWNjdHggdGFzayBuZXh0YCBnaXZlcy4gRWFybGllciB0YXNrcyBpbiBhIGdyb3VwIGNvbWUgZmlyc3QuCi0gQSBxdWVzdGlvbiB0aGF0IGJsb2NrcyB5b3UgZ29lcyB0byBgc3BlY2N0eCBoYW5kb2ZmIGFzayAiPHF1ZXN0aW9uPiJgLiBUaGVuIGNvbnRpbnVlIHdpdGggd2hhdCB5b3UgY2FuIGRvLgotIENsb3NlIHRoZSB0YXNrIHdpdGggdGhlIGBzcGVjY3R4LWRvbmVgIHNraWxsLgo=",
14
14
  };
@@ -1,10 +1,12 @@
1
1
  // REQ-ADOPT-005 REQ-CHK-002 the baseline ratchet in .ctx/baseline.json: sorted "rule id" pairs.
2
2
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
3
  import { join } from "node:path";
4
+ import { lintLine, parseLintLine } from "../lint/counts.js";
4
5
  import { cmpStr } from "../util/pystr.js";
5
6
  export const BASELINE_PATH = ".ctx/baseline.json";
6
- export const BASELINE_RULES = ["uncovered", "scenario-untested", "done-without-evidence", "manual-evidence", "task-without-req", "task-without-verify"];
7
- const key = (rule, id) => `${rule} ${id}`;
7
+ export const BASELINE_RULES = ["uncovered", "scenario-untested", "done-without-evidence", "manual-evidence", "task-without-req", "task-without-verify", "missing-id"];
8
+ /** REQ-ADOPT-005 a missing-id finding has no ID. Its key carries the file and the header title. */
9
+ const key = (f) => (f.rule === "missing-id" ? `${f.rule} ${f.file} ${f.id}` : `${f.rule} ${f.id}`);
8
10
  /** A warning line reads "manual-evidence <task>". */
9
11
  const warningKey = (w) => w;
10
12
  export function readBaseline(root) {
@@ -24,24 +26,48 @@ function save(root, entries) {
24
26
  }
25
27
  /** The current debt that the baseline may hold: strict findings and warnings of the listed rules. */
26
28
  export function debt(findings, warnings) {
27
- const out = findings.filter((f) => BASELINE_RULES.includes(f.rule)).map((f) => key(f.rule, f.id));
29
+ const out = findings.filter((f) => BASELINE_RULES.includes(f.rule)).map((f) => key(f));
28
30
  for (const w of warnings)
29
31
  if (BASELINE_RULES.includes(w.split(" ")[0]))
30
32
  out.push(warningKey(w));
31
33
  return out;
32
34
  }
33
- export function writeBaseline(root, findings, warnings) {
34
- return save(root, debt(findings, warnings));
35
+ /** REQ-ADOPT-007 one `lint <file> <rule> <count>` line per key with hard lint findings. */
36
+ export function lintDebt(counts) {
37
+ return [...counts].filter(([, n]) => n > 0).map(([k, n]) => lintLine(k, n));
38
+ }
39
+ export function writeBaseline(root, findings, warnings, lint = new Map()) {
40
+ return save(root, [...debt(findings, warnings), ...lintDebt(lint)]);
35
41
  }
36
42
  /** Drop entries that no longer fire. Returns the number dropped. */
37
- export function pruneBaseline(root, findings, warnings) {
43
+ export function pruneBaseline(root, findings, warnings, lint = new Map()) {
38
44
  const cur = readBaseline(root);
39
45
  if (!cur)
40
46
  return 0;
41
47
  const live = new Set(debt(findings, warnings));
42
- const kept = [...cur].filter((e) => live.has(e));
48
+ const kept = [];
49
+ let pruned = 0;
50
+ for (const e of cur) {
51
+ const l = parseLintLine(e);
52
+ if (l) {
53
+ // REQ-ADOPT-007 a lint line drops at zero and lowers when the count fell
54
+ const now = lint.get(l.key) ?? 0;
55
+ if (now === 0)
56
+ pruned++;
57
+ else if (now < l.count) {
58
+ pruned++;
59
+ kept.push(lintLine(l.key, now));
60
+ }
61
+ else
62
+ kept.push(e);
63
+ }
64
+ else if (live.has(e))
65
+ kept.push(e);
66
+ else
67
+ pruned++;
68
+ }
43
69
  save(root, kept);
44
- return cur.size - kept.length;
70
+ return pruned;
45
71
  }
46
72
  /** REQ-CHK-002 a finding or warning in the baseline leaves the output and counts as baselined. */
47
73
  export function applyBaseline(root, findings, warnings) {
@@ -50,7 +76,7 @@ export function applyBaseline(root, findings, warnings) {
50
76
  return { findings, warnings, baselined: 0 };
51
77
  let n = 0;
52
78
  const f2 = findings.filter((f) => {
53
- const hit = base.has(key(f.rule, f.id));
79
+ const hit = base.has(key(f));
54
80
  if (hit)
55
81
  n++;
56
82
  return !hit;
@@ -0,0 +1,23 @@
1
+ // REQ-CLI-008 color on a TTY. Without color the bytes equal the plain output.
2
+ const CODES = { ok: "\x1b[32m", fail: "\x1b[31m", dim: "\x1b[2m" };
3
+ const RESET = "\x1b[0m";
4
+ /**
5
+ * Color is on when `FORCE_COLOR` is set, or when stdout is a TTY and `TERM` is not `dumb`.
6
+ * `NO_COLOR` wins over both. An empty value counts as unset. `FORCE_COLOR=0` counts as unset.
7
+ */
8
+ export function colorOn(tty, env = process.env) {
9
+ if (env.NO_COLOR)
10
+ return false;
11
+ const force = env.FORCE_COLOR;
12
+ if (force && force !== "0" && force !== "false")
13
+ return true;
14
+ return tty && env.TERM !== "dumb";
15
+ }
16
+ /** Wrap one line of text in the code of its kind. A trailing newline stays outside the codes. */
17
+ export function paint(kind, text, tty) {
18
+ if (!colorOn(tty === true))
19
+ return text;
20
+ const nl = text.endsWith("\n") ? "\n" : "";
21
+ const body = nl ? text.slice(0, -1) : text;
22
+ return `${CODES[kind]}${body}${RESET}${nl}`;
23
+ }