spec-ctx 0.1.1 → 0.2.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.
package/README.md CHANGED
@@ -75,7 +75,7 @@ You see: a red refusal, the edit, then a green done line.
75
75
 
76
76
  ### 6. Hand off to the next session
77
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.
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. The questions live in `.ctx/questions.json`. `handoff ask` adds one and `handoff resolve <n>` answers it.
79
79
 
80
80
  ![The head of the handoff file](docs/demo/clips/6-handoff.svg)
81
81
 
@@ -86,7 +86,7 @@ The transcript of all six clips is in `docs/demo/loop.txt`. The clips run on a c
86
86
  ## Quickstart
87
87
 
88
88
  ```bash
89
- npx -y spec-ctx init --all # config, schema, and three agent skills
89
+ npx -y spec-ctx init --all # config, ID templates, rules, and the agent skill
90
90
  npx -y spec-ctx task next # the next task and the command that proves it
91
91
  npx -y spec-ctx task start <task> # only the spec that this task needs
92
92
  npx -y spec-ctx task done <task> # runs that command. A pass ticks the box.
@@ -120,25 +120,25 @@ test tests/login.test.ts:1 active tests/login.test.ts:1 covers REQ-UA-004
120
120
 
121
121
  ## The life cycle for agents
122
122
 
123
- `init --all` installs three skills. Each one fires at a fixed point of the session.
123
+ `init --all` installs one skill, `specctx-run`. The user types one prompt, such as "build this" or "continue". The skill loops until the change reaches the archive or a human must decide.
124
124
 
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.
125
+ - It runs `specctx next --json`. The engine reads the files on disk and prints one action: `plan`, `cite`, `start`, `work`, `fix`, `repair`, `gate`, `archive`, `ask`, or `stop`.
126
+ - It acts on the action with the exact commands, runs `specctx handoff write`, and repeats.
127
+ - It stops twice for a human by default: at the plan, and before archive. A Verify command that fails three times writes a question and stops too.
128
+ - `specctx-bootstrap`, `specctx-next`, and `specctx-done` stay for one release as aliases. Each one says: run `specctx-run`.
128
129
 
129
- The loop that the skills teach:
130
+ The commands the skill runs for one task:
130
131
 
131
132
  ```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
133
+ specctx init --all # config, ID templates, rules, and the skill
134
+ specctx next --json # the next action, its task, and its command
135
135
  specctx task start <task> # the bundle of that task and its size
136
136
  specctx task done <task> # run Verify, write evidence, set the checkbox
137
- specctx check --strict # IDs, links, coverage, and evidence
137
+ specctx gate --strict # check, baseline, linters, openspec validate, length
138
138
  specctx handoff write # .ctx/handoff.md for the next session
139
139
  ```
140
140
 
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`.
141
+ The rule: the agent never opens `openspec/specs/` by hand. It uses `task start` or `bundle`. It never ticks a checkbox and never runs `/opsx:apply`. The skill is in [`skills/`](skills/). Install it alone with `npx skills add sonqh/spec-ctx` or `specctx init --skills`.
142
142
 
143
143
  ## Install
144
144
 
@@ -152,27 +152,30 @@ npx -y github:sonqh/spec-ctx#<sha> init --all # from git, for an unreleas
152
152
 
153
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.
154
154
 
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/`.
155
+ The command writes `spec-ctx.toml`, copies the templates with ID placeholders to `openspec/templates/spec-driven-ids/`, adds the spec-ctx `rules` and `operations` to `openspec/config.yaml`, and installs the `specctx-run` skill and its three aliases into `.claude/skills/` and `.agents/skills/`. The project keeps the stock `schema: spec-driven`. Upstream OpenSpec injects the rules into every artifact instruction. It pins the OpenSpec version it finds in `[gate] openspec`. It adds four lines to `.gitignore`: `.ctx/index.json`, `adopt-report.md`, `.ctx/current.json`, and `.ctx/gate-log.jsonl`. The rest of `.ctx/` is meant for git, `questions.json` included.
156
156
 
157
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.
158
158
 
159
159
  ## Two paths
160
160
 
161
+ [`docs/getting-started.md`](docs/getting-started.md) walks the fresh path on upstream OpenSpec with real output, for a developer who knows OpenSpec.
162
+
161
163
  ### Fresh project
162
164
 
163
165
  ```bash
164
- npx -y @fission-ai/openspec@latest init
166
+ npx -y @fission-ai/openspec@latest init --tools <tool>
165
167
  npx spec-ctx init --all
166
168
  specctx gate --strict
167
169
  ```
168
170
 
171
+ `--tools <tool>` names your agent, such as `claude`, and skips the interactive picker. `--no-animation` keeps logs clean. `init --all` merges the ID rules into an existing `rules` key of `openspec/config.yaml` item by item and prints `merged openspec/config.yaml rules (<n> added)`.
172
+
169
173
  ### Existing OpenSpec project
170
174
 
171
175
  ```bash
172
176
  npx spec-ctx init --all
173
177
  specctx adopt --dry-run # the ID that each header gets. Writes nothing.
174
178
  specctx adopt # writes the IDs into main specs and active deltas
175
- specctx task backfill --manual "adopted"
176
179
  specctx baseline write
177
180
  specctx gate --strict
178
181
  ```
@@ -180,11 +183,12 @@ specctx gate --strict
180
183
  - `adopt` gives an ID to every requirement and scenario header without one, in `openspec/specs/` and in the deltas of active changes. A delta header gets the main ID by its text or through its RENAMED line. A delta header that matches neither keeps its text and goes into `adopt-report.md`.
181
184
  - `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.
182
185
  - `adopt` runs `check` before and after the write. A finding that the write added undoes every file. A second run prints `nothing to adopt`.
183
- - `task backfill` writes manual evidence for every ticked task that has none.
184
- - `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.
186
+ - `baseline write` records the debt of the day in `.ctx/baseline.json`. The debt has five kinds. Ticked 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.
187
+ - `gate` compares `.ctx/baseline.json` with the copy at the merge base of `HEAD` and `[gate] base`, default `origin/main`. A new entry fails the `baseline` step. Commit a grown baseline with a subject that starts with `baseline:` to pass once. In CI, check out with `fetch-depth: 0`, so the merge base exists. Without git or a merge base the step prints `skipped`.
188
+ - `[gate] markdown` in `spec-ctx.toml` names the markdown globs that `gate` lints. `init` writes `[]`, so the gate lints nothing until you opt in. The comment in the file names the globs this repository uses.
185
189
  - 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.
186
190
 
187
- Both paths have an end to end test: `tests/paths/fresh.sh` and `tests/paths/existing.sh`.
191
+ Both paths have an end to end test on upstream OpenSpec: `tests/paths/fresh.sh` and `tests/paths/existing.sh`. `tests/paths/rules-only.sh` shows that the merged `rules` reach the stock `spec-driven` schema.
188
192
 
189
193
  ## Commands
190
194
 
@@ -192,18 +196,18 @@ Both paths have an end to end test: `tests/paths/fresh.sh` and `tests/paths/exis
192
196
  | --- | --- |
193
197
  | `build` | Write `.ctx/index.json`. Every other command rebuilds a stale index first. |
194
198
  | `status` | Active changes with task counts, the current task, and open questions. |
199
+ | `next` | The next action of the loop from the files on disk: `plan`, `cite`, `start`, `work`, `fix`, `repair`, `gate`, `archive`, `ask`, or `stop`. `--json` prints one object. Flag: `--change`. |
195
200
  | `query <term...>` | Entries that hold every term. Flags: `--kind`, `--change`, `--limit`, `--all`. |
196
201
  | `related <ID>` | Linked entries with the reason for each link. Flags: `--depth`, `--all`. |
197
202
  | `bundle <ID...>` | Spec text of the IDs, their scenarios, decisions, and neighbors. Flags: `--budget`, `--depth`, `--all`. |
198
- | `check` | ID and link integrity. `--strict` adds test coverage and evidence. |
203
+ | `check` | ID and link integrity. `--strict` adds test coverage and evidence. `retitle-needs-renamed` names a retitled delta header that needs a RENAMED pair before `openspec archive`. |
199
204
  | `id new`, `id retire` | Allocate and retire IDs. |
200
205
  | `task next`, `start`, `verify`, `done`, `reopen` | The task state machine. |
201
- | `handoff write`, `ask`, `resolve` | The session handoff and its open questions. |
202
- | `init` | Config file, schema bundle, and skills. Flags: `--schema`, `--skills`, `--all`, `--force`. |
206
+ | `handoff write`, `ask`, `resolve` | The session handoff and its open questions in `.ctx/questions.json`. |
207
+ | `init` | Config file, ID templates and rules, and skills. Flags: `--schema`, `--skills`, `--all`, `--force`. |
203
208
  | `adopt` | IDs for a project without them. `--dry-run` writes nothing. |
204
209
  | `baseline write`, `prune` | The debt ratchet in `.ctx/baseline.json`. |
205
- | `task backfill` | Manual evidence for ticked tasks without it. |
206
- | `gate` | `check`, both markdown linters, `openspec validate`, and the 500 character length check on active deltas. |
210
+ | `gate` | `check`, the baseline against the merge base, both markdown linters, `openspec validate`, and the 500 character length check on active deltas. |
207
211
  | `lint tells`, `lint ste` | The two markdown linters. Flags: `--baseline`, `--disable`, `--json`, `--selftest`. |
208
212
  | `help <command>` | The page of one command. `specctx <command> --help` prints the same page. |
209
213
 
@@ -225,6 +229,7 @@ ignore = [] # globs that the scan skips
225
229
  [ids]
226
230
  caps = [] # capability codes. Empty means any code is valid.
227
231
  task_pattern = '\d+\.\d+' # the task number in a tasks.md checkbox
232
+ brackets = false # true: adopt and id new write [REQ-UA-001]. The scan reads both forms.
228
233
 
229
234
  [ids.paths]
230
235
  UA = "user-auth" # capability path of each code. adopt writes the derived ones.
@@ -235,13 +240,23 @@ depth = 1
235
240
 
236
241
  [verify]
237
242
  timeout_s = 600
243
+
244
+ [gate]
245
+ markdown = [] # globs that gate lints. Empty means no lint. This repo opts in.
246
+ openspec = "npx -y @fission-ai/openspec@1.15.0" # the command that runs OpenSpec. init pins the version it found.
247
+ base = "origin/main" # the ref whose merge base holds the baseline that gate compares with
248
+
249
+ [loop]
250
+ max_attempts = 3 # Verify failures on one task before task done writes a question
251
+ archive = "ask" # "ask" stops before archive for a human. "auto" lets the loop archive.
238
252
  ```
239
253
 
240
- One environment variable changes the engine:
254
+ Two environment variables change the engine:
241
255
 
242
256
  | Variable | Effect |
243
257
  | --- | --- |
244
- | `SPECCTX_OPENSPEC` | The command that `gate` runs for `openspec validate`. The default is `npx -y @fission-ai/openspec@latest`. Tests and offline machines set it. |
258
+ | `SPECCTX_OPENSPEC` | The command that `gate` runs for `openspec validate` and `next` runs for `openspec status`. It overrides `[gate] openspec` for one run. At `init` time it is written into the file as it is, and no version detection runs. Tests and offline machines set it. |
259
+ | `SPECCTX_BASELINE_SUBJECT` | The commit subject that the `baseline` step of `gate` tests for `baseline:`. It replaces the subject of `HEAD`. Tests set it. |
245
260
 
246
261
  ## Markdown linters
247
262
 
@@ -269,18 +284,18 @@ The action runs `specctx gate`: `check --strict`, both markdown linters, `opensp
269
284
 
270
285
  ## Status
271
286
 
272
- - Published: `spec-ctx@0.1.1` on npm, with tags `v0.1.1` and `v0` and binaries on the GitHub release.
273
- - Archived: 001 to 013. No change is open. See `CHANGELOG.md` for each release.
287
+ - Published: `spec-ctx@0.2.0` on npm, with tags `v0.2.0` and `v0` and binaries on the GitHub release.
288
+ - Archived: 001 to 025, and 027. No change is open. See `CHANGELOG.md` for each release.
274
289
  - A version bump on `main` publishes the next release. See `docs/CONTRIBUTING.md`.
275
290
  - 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.
276
291
 
277
292
  ## Measured
278
293
 
279
- `specctx stats --write` measures this repository after each change. The newest file is `docs/metrics/2026-10-26.md`. Its total row:
294
+ `specctx stats --write` measures this repository after each change. The newest file is `docs/metrics/2026-10-29.md`. Its total row:
280
295
 
281
296
  | change | context_ratio | evidence_ratio | stale_catches | cycle_time_median_s | debt |
282
297
  | --- | --- | --- | --- | --- | --- |
283
- | total | 0.0469 (n=41) | 0.85 (88/104) | 36 (of 62 reopens) | 60 (n=41) | 0 (0 baselined + 0 new) |
298
+ | total | 0.0327 (n=76) | 0.90 (143/159) | 36 (of 81 reopens) | 98 (n=76) | 0 (0 baselined + 0 new) |
284
299
 
285
300
  - `context_ratio`: the size of one task bundle divided by the size of all spec text. Lower is better.
286
301
  - `evidence_ratio`: done tasks with a passed Verify command, divided by all done tasks. The rest have a manual note. Higher is better.
@@ -8,6 +8,9 @@ const REQ_HDR = /^### Requirement:[ \t]*(.*)$/s;
8
8
  const SCN_HDR = /^#### Scenario:[ \t]*(.*)$/s;
9
9
  const HAS_REQ = /^REQ-([A-Z]{2,6})-(\d{3})(?:[ \t]|$)/;
10
10
  const HAS_SCN = /^SCN-([A-Z]{2,6})-(\d{3})-(\d+)(?:[ \t]|$)/;
11
+ // REQ-ADOPT-010 an ID in square brackets, the form of OpenSpec PR #1979 (027/D3)
12
+ const BR_REQ = /^\[(REQ-[A-Z]{2,6}-\d{3})\](?:[ \t]|$)/;
13
+ const BR_SCN = /^\[(SCN-[A-Z]{2,6}-\d{3}-\d+)\](?:[ \t]|$)/;
11
14
  const RENAME = /^- (FROM|TO):[ \t]*`### Requirement:[ \t]*(.*)`[ \t]*$/s;
12
15
  function listSpecs(root, base) {
13
16
  const out = [];
@@ -26,12 +29,15 @@ function listSpecs(root, base) {
26
29
  walk(join(root, base), base);
27
30
  return out;
28
31
  }
29
- function splitId(text, re) {
32
+ /** REQ-ADOPT-010 the ID at the start of a header text, bare or in square brackets, and the name after it. */
33
+ function splitId(text, re, br) {
30
34
  const m = re.exec(text);
31
- if (!m)
32
- return { id: null, name: text.trim() };
33
- const id = m[0].trim();
34
- return { id, name: text.slice(m[0].length).trim() };
35
+ if (m)
36
+ return { id: m[0].trim(), name: text.slice(m[0].length).trim(), bracketed: false };
37
+ const b = br.exec(text);
38
+ if (b)
39
+ return { id: b[1], name: text.slice(b[0].length).trim(), bracketed: true };
40
+ return { id: null, name: text.trim(), bracketed: false };
35
41
  }
36
42
  function parse(root, rel, cap) {
37
43
  const lines = splitLines(readFileSync(join(root, rel)).toString("utf8"));
@@ -53,21 +59,21 @@ function parse(root, rel, cap) {
53
59
  }
54
60
  let m = REQ_HDR.exec(line);
55
61
  if (m) {
56
- const { id, name } = splitId(m[1], HAS_REQ);
57
- req = { kind: "req", line: i + 1, raw: line, name, id, section };
62
+ const { id, name, bracketed } = splitId(m[1], HAS_REQ, BR_REQ);
63
+ req = { kind: "req", line: i + 1, raw: line, name, id, bracketed, section };
58
64
  blocks.push(req);
59
65
  return;
60
66
  }
61
67
  m = SCN_HDR.exec(line);
62
68
  if (m) {
63
- const { id, name } = splitId(m[1], HAS_SCN);
64
- blocks.push({ kind: "scn", line: i + 1, raw: line, name, id, req, section });
69
+ const { id, name, bracketed } = splitId(m[1], HAS_SCN, BR_SCN);
70
+ blocks.push({ kind: "scn", line: i + 1, raw: line, name, id, bracketed, req, section });
65
71
  return;
66
72
  }
67
73
  m = RENAME.exec(line);
68
74
  if (m && section === "RENAMED") {
69
- const { id, name } = splitId(m[2], HAS_REQ);
70
- const item = { line: i + 1, name, id, raw: line };
75
+ const { id, name, bracketed } = splitId(m[2], HAS_REQ, BR_REQ);
76
+ const item = { line: i + 1, name, id, bracketed, raw: line };
71
77
  if (m[1] === "FROM")
72
78
  from = item;
73
79
  else if (from) {
@@ -189,11 +195,15 @@ export function planAdopt(root, cfg) {
189
195
  };
190
196
  const edits = [];
191
197
  const unmatched = [];
192
- const reqHeader = (id, name) => `### Requirement: ${id} ${name}`;
193
- const scnHeader = (id, name) => `#### Scenario: ${id} ${name}`;
198
+ // REQ-ADOPT-010 the configured form of a new ID: bare, or in square brackets (027/D3)
199
+ const form = (id, br = cfg.ids.brackets) => (br ? `[${id}]` : id);
200
+ const reqHeader = (id, name, br) => `### Requirement: ${form(id, br)} ${name}`;
201
+ const scnHeader = (id, name) => `#### Scenario: ${form(id)} ${name}`;
194
202
  // main spec: requirement id by name, and scenario id by requirement and name
195
203
  const mainReq = new Map();
196
204
  const mainScn = new Map();
205
+ // the form of each main header after adopt: its own form when it had an ID, else the configured form
206
+ const mainBr = new Map();
197
207
  for (const f of mainFiles) {
198
208
  const code = codeFor.get(f.cap);
199
209
  const seen = new Set();
@@ -210,6 +220,7 @@ export function planAdopt(root, cfg) {
210
220
  if (!b.id)
211
221
  edits.push({ file: f.rel, line: b.line, old: b.raw, new: reqHeader(id, b.name) });
212
222
  mainReq.set(`${f.cap}\u0000${b.name}`, id);
223
+ mainBr.set(`${f.cap}\u0000${b.name}`, b.id ? b.bracketed : cfg.ids.brackets);
213
224
  b.id = id;
214
225
  }
215
226
  else if (b.req?.id) {
@@ -232,8 +243,9 @@ export function planAdopt(root, cfg) {
232
243
  continue;
233
244
  }
234
245
  renamedTo.set(r.to.name, id);
246
+ // REQ-ADOPT-010 the FROM line names the main header, so it takes the form of that header (027/D3)
235
247
  if (!r.from.id)
236
- edits.push({ file: f.rel, line: r.from.line, old: r.from.raw, new: `- FROM: \`${reqHeader(id, r.from.name)}\`` });
248
+ edits.push({ file: f.rel, line: r.from.line, old: r.from.raw, new: `- FROM: \`${reqHeader(id, r.from.name, mainBr.get(`${f.cap}\u0000${r.from.name}`))}\`` });
237
249
  if (!r.to.id)
238
250
  edits.push({ file: f.rel, line: r.to.line, old: r.to.raw, new: `- TO: \`${reqHeader(id, r.to.name)}\`` });
239
251
  }
@@ -1,14 +1,14 @@
1
1
  // Generated by scripts/gen-assets.mjs from schemas/spec-driven-ids/ and skills/. Do not edit.
2
- // REQ-SCH-001 REQ-SKL-002
2
+ // REQ-SCH-003 REQ-SKL-002
3
3
  export const ASSETS = {
4
- "schemas/spec-driven-ids/README.md": "IyBzcGVjLWRyaXZlbi1pZHMKCkEgZm9yayBvZiB0aGUgT3BlblNwZWMgYHNwZWMtZHJpdmVuYCBzY2hlbWEuIEl0IGFkZHMgc3RhYmxlIElEcyBmcm9tIHNwZWMtY3R4IHRvIGV2ZXJ5IGFydGlmYWN0LgoKLSBUaGUgc3BlYyB0ZW1wbGF0ZSBzdGFydHMgZWFjaCByZXF1aXJlbWVudCB3aXRoIGBSRVEtPENBUD4tTk5OYCBhbmQgZWFjaCBzY2VuYXJpbyB3aXRoIGBTQ04tPENBUD4tTk5OLTxuPmAuCi0gVGhlIGluc3RydWN0aW9ucyB0ZWxsIHRoZSBhZ2VudCB0byBnZXQgSURzIGZyb20gYHNwZWNjdHggaWQgbmV3YCBhbmQgdG8gbGluayBJRHMgd2l0aCBgUmVmczpgIGxpbmVzLgotIFRoZSB0YXNrcyB0ZW1wbGF0ZSBjaXRlcyBSRVEgSURzIGFuZCBwdXRzIHRoZSBgVmVyaWZ5OmAgY29tbWFuZCBpbiBhIGNvZGUgc3Bhbiwgc28gYHNwZWNjdHggdGFzayBkb25lYCBjYW4gcnVuIGl0LgotIGBjb25maWctZnJhZ21lbnQueWFtbGAgaG9sZHMgdGhlIGBydWxlc2AgYW5kIGBvcGVyYXRpb25zYCBmb3IgYG9wZW5zcGVjL2NvbmZpZy55YW1sYC4KCiMjIEluc3RhbGwgYnkgY29weQoKLSBDbG9uZSB0aGUgcmVwb3NpdG9yeTogYGdpdCBjbG9uZSBodHRwczovL2dpdGh1Yi5jb20vc29ucWgvc3BlYy1jdHhgLgotIENvcHkgYHNjaGVtYXMvc3BlYy1kcml2ZW4taWRzYCB0byBgb3BlbnNwZWMvc2NoZW1hcy9zcGVjLWRyaXZlbi1pZHNgIGluIHlvdXIgcHJvamVjdC4KLSBTZXQgYHNjaGVtYTogc3BlYy1kcml2ZW4taWRzYCBpbiBgb3BlbnNwZWMvY29uZmlnLnlhbWxgLgotIE1lcmdlIGBjb25maWctZnJhZ21lbnQueWFtbGAgaW50byBgb3BlbnNwZWMvY29uZmlnLnlhbWxgIGJ5IGhhbmQuIEFkZCBpdHMgYHJ1bGVzYCBhbmQgYG9wZXJhdGlvbnNgIGtleXMuIEtlZXAgZXZlcnkgaXRlbSBxdW90ZWQuCi0gUnVuIGBvcGVuc3BlYyBzY2hlbWEgdmFsaWRhdGUgc3BlYy1kcml2ZW4taWRzYC4KCiMjIEluc3RhbGwgd2l0aCBpbml0IC0tc2NoZW1hCgpgYGBiYXNoCm5weCAteSBzcGVjLWN0eCBpbml0IC0tc2NoZW1hCmBgYAoKLSBUaGUgY29tbWFuZCBjb3BpZXMgdGhpcyBmb2xkZXIgdG8gYG9wZW5zcGVjL3NjaGVtYXMvc3BlYy1kcml2ZW4taWRzL2AuCi0gSXQgc2V0cyBgc2NoZW1hOiBzcGVjLWRyaXZlbi1pZHNgIGluIGBvcGVuc3BlYy9jb25maWcueWFtbGAuCi0gSXQgYWRkcyB0aGUgYHJ1bGVzYCBhbmQgYG9wZXJhdGlvbnNgIGtleXMgdGhhdCB0aGUgY29uZmlnIGRvZXMgbm90IGhhdmUgeWV0LiBJdCBsZWF2ZXMgb3RoZXIga2V5cyBhcyB0aGV5IGFyZS4KLSBJdCBxdW90ZXMgYSBsaXN0IGl0ZW0gdGhhdCBZQU1MIHdvdWxkIHJlYWQgYXMgYSBtYXBwaW5nLgoKIyMgVmVyc2lvbgoKRm9ya2VkIGZyb20gT3BlblNwZWMgMS4xNC4zIHdpdGggYG9wZW5zcGVjIHNjaGVtYSBmb3JrIHNwZWMtZHJpdmVuIHNwZWMtZHJpdmVuLWlkc2AuIENJIHZhbGlkYXRlcyBpdCBhZ2FpbnN0IHRoYXQgdmVyc2lvbi4K",
5
- "schemas/spec-driven-ids/config-fragment.yaml": "IyBzcGVjLWN0eCBmcmFnbWVudCBmb3Igb3BlbnNwZWMvY29uZmlnLnlhbWwuIHNwZWNjdHggaW5pdCAtLXNjaGVtYSBhZGRzIGVhY2ggdG9wLWxldmVsIGtleQojIHRoYXQgdGhlIHByb2plY3QgY29uZmlnIGRvZXMgbm90IGhhdmUgeWV0LiBJdCBuZXZlciBjaGFuZ2VzIGEga2V5IHRoYXQgZXhpc3RzLgpydWxlczoKICBzcGVjczoKICAgIC0gJ0V2ZXJ5IHJlcXVpcmVtZW50IGhlYWRlciBzdGFydHMgd2l0aCBpdHMgSUQsIGUuZy4gIiMjIyBSZXF1aXJlbWVudDogUkVRLUFCQy0wMDEgTmFtZSIuIEdldCB0aGUgSUQgZnJvbSBgc3BlY2N0eCBpZCBuZXcgUkVRIEFCQ2AuJwogICAgLSAnRXZlcnkgc2NlbmFyaW8gaGVhZGVyIHN0YXJ0cyB3aXRoIGl0cyBJRCwgZS5nLiAiIyMjIyBTY2VuYXJpbzogU0NOLUFCQy0wMDEtMSBOYW1lIi4nCiAgICAtICdBIHJlcXVpcmVtZW50IG1heSBlbmQgd2l0aCBhIGxpbmUgIlJlZnM6IFJFUS1BQkMtMDAyLCBBRFItMDAxIiB0byBsaW5rIHJlbGF0ZWQgSURzLicKICAgIC0gJ1JlcXVpcmVtZW50IHRleHQgc3RheXMgdW5kZXIgNTAwIGNoYXJhY3RlcnMuIE1vdmUgZGV0YWlsIGludG8gc2NlbmFyaW9zLicKICBkZXNpZ246CiAgICAtICdFYWNoIGRlY2lzaW9uIGlzIG9uZSBidWxsZXQgdW5kZXIgIiMjIERlY2lzaW9ucyIuIEFkZCBuZXcgZGVjaXNpb25zIGF0IHRoZSBlbmQuJwogIHRhc2tzOgogICAgLSAnRXZlcnkgdGFzayBjaXRlcyBhdCBsZWFzdCBvbmUgUkVRIElEIGluIHNxdWFyZSBicmFja2V0cywgZS5nLiAiW1JFUS1BQkMtMDAxXSIuJwogICAgLSAnRXZlcnkgdGFzayBzdGF0ZXMgaXRzIHZlcmlmaWNhdGlvbiBhcyBhIGNvbW1hbmQgaW4gYSBjb2RlIHNwYW4gYWZ0ZXIgIlZlcmlmeToiLicKCm9wZXJhdGlvbnM6CiAgYXBwbHk6CiAgICBndWlkYW5jZToKICAgICAgLSAnU3RhcnQgZWFjaCB0YXNrIHdpdGggYHNwZWNjdHggdGFzayBzdGFydCA8aWQ+YCBhbmQgcmVhZCB0aGUgYnVuZGxlIGl0IHByaW50cyBiZWZvcmUgeW91IHJlYWQgc3BlY3MuJwogICAgICAtICdUYWcgY29kZSB3aXRoIHRoZSBSRVEgSUQgaXQgaW1wbGVtZW50cyAoYSBjb21tZW50IGAvLyBSRVEtQUJDLTAwMWApLiBUYWcgdGVzdHMgd2l0aCBgLy8gQ292ZXJzOiBSRVEtQUJDLTAwMWAuJwogICAgICAtICdDbG9zZSBlYWNoIHRhc2sgd2l0aCBgc3BlY2N0eCB0YXNrIGRvbmUgPGlkPmAuIE5ldmVyIHRpY2sgYSBjaGVja2JveCBieSBoYW5kLicKICAgICAgLSAnUnVuIGBzcGVjY3R4IGNoZWNrIC0tc3RyaWN0YCBhZnRlciBlYWNoIHRhc2sgZ3JvdXAuJwogIGFyY2hpdmU6CiAgICBndWlkYW5jZToKICAgICAgLSAnUnVuIGBzcGVjY3R4IGNoZWNrIC0tc3RyaWN0YCBhbmQgYG9wZW5zcGVjIHZhbGlkYXRlIC0tYWxsIC0tc3RyaWN0YC4gQm90aCBtdXN0IHBhc3MgYmVmb3JlIGFyY2hpdmUuJwogICAgICAtICdSdW4gYG9wZW5zcGVjIHZhbGlkYXRlIC0tYWxsIC0tc3RyaWN0YCBhZ2FpbiBhZnRlciBhcmNoaXZlIGFuZCBiZWZvcmUgcHVzaC4nCg==",
6
- "schemas/spec-driven-ids/schema.yaml": "bmFtZTogc3BlYy1kcml2ZW4taWRzCnZlcnNpb246IDEKZGVzY3JpcHRpb246IE9wZW5TcGVjIHNwZWMtZHJpdmVuIHdvcmtmbG93IHdpdGggc3RhYmxlIElEcyBmcm9tIHNwZWMtY3R4IC0gcHJvcG9zYWwg4oaSIHNwZWNzIOKGkiBkZXNpZ24g4oaSIHRhc2tzCmFydGlmYWN0czoKICAtIGlkOiBwcm9wb3NhbAogICAgZ2VuZXJhdGVzOiBwcm9wb3NhbC5tZAogICAgZGVzY3JpcHRpb246IEluaXRpYWwgcHJvcG9zYWwgZG9jdW1lbnQgb3V0bGluaW5nIHRoZSBjaGFuZ2UKICAgIHRlbXBsYXRlOiBwcm9wb3NhbC5tZAogICAgaW5zdHJ1Y3Rpb246IHwKICAgICAgQ3JlYXRlIHRoZSBwcm9wb3NhbCBkb2N1bWVudCB0aGF0IGVzdGFibGlzaGVzIFdIWSB0aGlzIGNoYW5nZSBpcyBuZWVkZWQuCgogICAgICBTZWN0aW9uczoKICAgICAgLSAqKldoeSoqOiAxLTIgc2VudGVuY2VzIG9uIHRoZSBwcm9ibGVtIG9yIG9wcG9ydHVuaXR5LiBXaGF0IHByb2JsZW0gZG9lcyB0aGlzIHNvbHZlPyBXaHkgbm93PwogICAgICAtICoqV2hhdCBDaGFuZ2VzKio6IEJ1bGxldCBsaXN0IG9mIGNoYW5nZXMuIEJlIHNwZWNpZmljIGFib3V0IG5ldyBjYXBhYmlsaXRpZXMsIG1vZGlmaWNhdGlvbnMsIG9yIHJlbW92YWxzLiBNYXJrIGJyZWFraW5nIGNoYW5nZXMgd2l0aCAqKkJSRUFLSU5HKiouCiAgICAgIC0gKipDYXBhYmlsaXRpZXMqKjogSWRlbnRpZnkgd2hpY2ggc3BlY3Mgd2lsbCBiZSBjcmVhdGVkIG9yIG1vZGlmaWVkOgogICAgICAgIC0gKipOZXcgQ2FwYWJpbGl0aWVzKio6IExpc3QgY2FwYWJpbGl0aWVzIGJlaW5nIGludHJvZHVjZWQuIEVhY2ggYmVjb21lcyBhIG5ldyBgc3BlY3MvPGNhcGFiaWxpdHktcGF0aD4vc3BlYy5tZGAuIE5hbWUgZWFjaCBjYXBhYmlsaXR5IGZvciBhIGR1cmFibGUgc3lzdGVtIGJlaGF2aW9yIChmb3IgZXhhbXBsZSwgYHVzZXItYXV0aGApLCBub3QgdGhlIHdvcmsgaW4gdGhpcyBjaGFuZ2UgKGZvciBleGFtcGxlLCBgYWRkLWxvZ2luLWVuZHBvaW50YCkuIENob29zZSBhIGNvaGVzaXZlIGJvdW5kYXJ5IHRoYXQgY2FuIG93biByZWxhdGVkIHJlcXVpcmVtZW50cyBhcyB0aGUgc3lzdGVtIGV2b2x2ZXM7IGF2b2lkIGJyb2FkIGNhdGNoLWFsbCBjYXBhYmlsaXRpZXMuIFVzZSBrZWJhYi1jYXNlIGZvciBwYXRoIHNlZ21lbnRzIHlvdSBpbnRyb2R1Y2UgKGUuZy4sIGB1c2VyLWF1dGhgIG9yIGBpZGVudGl0eS91c2VyLWF1dGhgKSBhbmQgZm9sbG93IHRoZSBwcm9qZWN0J3MgZXhpc3Rpbmcgc3BlYyBvcmdhbml6YXRpb24uCiAgICAgICAgLSAqKk1vZGlmaWVkIENhcGFiaWxpdGllcyoqOiBMaXN0IGV4aXN0aW5nIGNhcGFiaWxpdGllcyB3aG9zZSBSRVFVSVJFTUVOVFMgYXJlIGNoYW5naW5nLiBPbmx5IGluY2x1ZGUgaWYgc3BlYy1sZXZlbCBiZWhhdmlvciBjaGFuZ2VzIChub3QganVzdCBpbXBsZW1lbnRhdGlvbiBkZXRhaWxzKS4gRWFjaCBuZWVkcyBhIGRlbHRhIHNwZWMgZmlsZS4gVXNlIHRoZSBleGFjdCBleGlzdGluZyBwYXRoIHVuZGVyIGBvcGVuc3BlYy9zcGVjcy9gLiBMZWF2ZSBlbXB0eSBpZiBubyByZXF1aXJlbWVudCBjaGFuZ2VzLgogICAgICAtICoqSW1wYWN0Kio6IEFmZmVjdGVkIGNvZGUsIEFQSXMsIGRlcGVuZGVuY2llcywgb3Igc3lzdGVtcy4KCiAgICAgIElNUE9SVEFOVDogVGhlIENhcGFiaWxpdGllcyBzZWN0aW9uIGlzIGNyaXRpY2FsLiBJdCBjcmVhdGVzIHRoZSBjb250cmFjdCBiZXR3ZWVuCiAgICAgIHByb3Bvc2FsIGFuZCBzcGVjcyBwaGFzZXMuIFJlc2VhcmNoIGV4aXN0aW5nIHNwZWNzIGJlZm9yZSBmaWxsaW5nIHRoaXMgaW46CiAgICAgIHJ1biBgb3BlbnNwZWMgbGlzdCAtLXNwZWNzYCBmb3IgdGhlIHByb2plY3QncyBjYXBhYmlsaXR5IGludmVudG9yeSwgdGhlbgogICAgICBgb3BlbnNwZWMgc2hvdyAiPHNwZWMtaWQ+IiAtLXR5cGUgc3BlYyAtLWpzb24gLS1uby1zY2VuYXJpb3NgIGZvciBhbnkgdGhhdAogICAgICBsb29rIHJlbGF0ZWQgLSB0aGF0IHJldHVybnMgYSBjYXBhYmlsaXR5J3MgcHVycG9zZSBhbmQgcmVxdWlyZW1lbnQgdGV4dHMKICAgICAgd2l0aG91dCBwdWxsaW5nIHdob2xlIHNwZWMgZmlsZXMgaW50byBjb250ZXh0LiBBcHBlbmQgYC0tc3RvcmUgIjxpZD4iYCB0bwogICAgICBib3RoIGNvbW1hbmRzIG9ubHkgZm9yIGEgcmVnaXN0ZXJlZCBzdGFuZGFsb25lIHN0b3JlLCBhbmQga2VlcCBgLS10eXBlCiAgICAgIHNwZWNgOiBhIGNoYW5nZSBhbmQgYSBzcGVjIHNoYXJpbmcgYSBuYW1lIGlzIG90aGVyd2lzZSBhbiBhbWJpZ3VvdXMtaXRlbQogICAgICBlcnJvci4gYG9wZW5zcGVjIGxpc3RgIHdpdGhvdXQgYC0tc3BlY3NgIGxpc3RzIGluLWZsaWdodCBjaGFuZ2VzLCBub3QKICAgICAgc3BlY3MgLSBpdCBuZXZlciBzaG93cyB3aGF0IHRoZSBwcm9qZWN0IGFscmVhZHkgY292ZXJzLiBSZXVzZSBhbiBleGlzdGluZwogICAgICBjYXBhYmlsaXR5J3MgZXhhY3QgcGF0aCBpbnN0ZWFkIG9mIGludHJvZHVjaW5nIGEgbmVhci1kdXBsaWNhdGUgbmFtZS4KICAgICAgVGhlIGZpbHRlcmVkIHJlYWQgaXMgb25seSBhbiBvdmVydmlldy4gQmVmb3JlIGRlY2lkaW5nIHdoYXQgaXMgYWxyZWFkeQogICAgICBjb3ZlcmVkIG9yIHdoYXQgc2hvdWxkIGNoYW5nZSwgcmVhZCBlYWNoIHJlbGV2YW50IHNwZWMgaW4gZnVsbCwgaW5jbHVkaW5nCiAgICAgIHNjZW5hcmlvcywgd2l0aCBgb3BlbnNwZWMgc2hvdyAiPHNwZWMtaWQ+IiAtLXR5cGUgc3BlY2AgKHNhbWUgYC0tc3RvcmVgIHJ1bGUpLgogICAgICBFYWNoIGNhcGFiaWxpdHkgbGlzdGVkIGhlcmUgd2lsbCBuZWVkIGEgY29ycmVzcG9uZGluZyBzcGVjIGZpbGUuCgogICAgICBFdmVyeSBjaGFuZ2UgbXVzdCBlaXRoZXIgZGVjbGFyZSBhdCBsZWFzdCBvbmUgY2FwYWJpbGl0eSAobmV3IG9yCiAgICAgIG1vZGlmaWVkKSBvciBleHBsaWNpdGx5IG9wdCBvdXQgb2Ygc3BlY3M6IGBvcGVuc3BlYyB2YWxpZGF0ZWAgcmVqZWN0cyBhCiAgICAgIGNoYW5nZSB3aXRoIHplcm8gZGVsdGFzIHVubGVzcyB0aGUgY2hhbmdlJ3MgYC5vcGVuc3BlYy55YW1sYCBzZXRzCiAgICAgIGBza2lwX3NwZWNzOiB0cnVlYC4gVXNlIGBza2lwX3NwZWNzOiB0cnVlYCBvbmx5IHdoZW4gbm8gc3BlYy1sZXZlbAogICAgICBiZWhhdmlvciBjaGFuZ2VzIChwdXJlIHJlZmFjdG9yLCB0b29saW5nLCBkb2NzKSAtIHNwZWNzIGRlc2NyaWJlCiAgICAgIGJlaGF2aW9yLCBzbyBpZiBiZWhhdmlvciBkb2VzIG5vdCBjaGFuZ2UsIG5vIHNwZWMgc2hvdWxkIGNoYW5nZSBlaXRoZXIuCiAgICAgIERvIG5vdCBpbnZlbnQgYSByZXF1aXJlbWVudCBqdXN0IHRvIHNhdGlzZnkgdmFsaWRhdGlvbi4KCiAgICAgIEtlZXAgaXQgY29uY2lzZSAoMS0yIHBhZ2VzKS4gRm9jdXMgb24gdGhlICJ3aHkiIG5vdCB0aGUgImhvdyIgLQogICAgICBpbXBsZW1lbnRhdGlvbiBkZXRhaWxzIGJlbG9uZyBpbiBkZXNpZ24ubWQuCgogICAgICBUaGlzIGlzIHRoZSBmb3VuZGF0aW9uIC0gc3BlY3MsIGRlc2lnbiwgYW5kIHRhc2tzIGFsbCBidWlsZCBvbiB0aGlzLgogICAgcmVxdWlyZXM6IFtdCgogIC0gaWQ6IHNwZWNzCiAgICBnZW5lcmF0ZXM6ICJzcGVjcy8qKi8qLm1kIgogICAgZGVzY3JpcHRpb246IERldGFpbGVkIHNwZWNpZmljYXRpb25zIGZvciB0aGUgY2hhbmdlCiAgICB0ZW1wbGF0ZTogc3BlYy5tZAogICAgaW5zdHJ1Y3Rpb246IHwKICAgICAgQ3JlYXRlIHNwZWNpZmljYXRpb24gZmlsZXMgdGhhdCBkZWZpbmUgV0hBVCB0aGUgc3lzdGVtIHNob3VsZCBkby4KCiAgICAgIEEgc3BlYyBpcyBhIGJlaGF2aW9yIGNvbnRyYWN0LCBub3QgYW4gaW1wbGVtZW50YXRpb24gcGxhbi4KCiAgICAgIEdvb2Qgc3BlYyBjb250ZW50OgogICAgICAtIE9ic2VydmFibGUgYmVoYXZpb3IgdXNlcnMgb3IgZG93bnN0cmVhbSBzeXN0ZW1zIHJlbHkgb24KICAgICAgLSBJbnB1dHMsIG91dHB1dHMsIGFuZCBlcnJvciBjb25kaXRpb25zCiAgICAgIC0gRXh0ZXJuYWwgY29uc3RyYWludHMgKHNlY3VyaXR5LCBwcml2YWN5LCByZWxpYWJpbGl0eSwgY29tcGF0aWJpbGl0eSkKICAgICAgLSBTY2VuYXJpb3MgdGhhdCBjYW4gYmUgdGVzdGVkIG9yIGV4cGxpY2l0bHkgdmFsaWRhdGVkCgogICAgICBBdm9pZCBpbiBzcGVjczoKICAgICAgLSBJbnRlcm5hbCBjbGFzcy9mdW5jdGlvbiBuYW1lcwogICAgICAtIExpYnJhcnkgb3IgZnJhbWV3b3JrIGNob2ljZXMKICAgICAgLSBTdGVwLWJ5LXN0ZXAgaW1wbGVtZW50YXRpb24gZGV0YWlscwogICAgICAtIERldGFpbGVkIGV4ZWN1dGlvbiBwbGFucyAodGhvc2UgYmVsb25nIGluIGRlc2lnbi5tZCBvciB0YXNrcy5tZCkKCiAgICAgIFF1aWNrIHRlc3Q6IGlmIHRoZSBpbXBsZW1lbnRhdGlvbiBjYW4gY2hhbmdlIHdpdGhvdXQgY2hhbmdpbmcgZXh0ZXJuYWxseQogICAgICB2aXNpYmxlIGJlaGF2aW9yLCBpdCBsaWtlbHkgZG9lcyBub3QgYmVsb25nIGluIHRoZSBzcGVjLgoKICAgICAgQ3JlYXRlIG9uZSBzcGVjIGZpbGUgcGVyIGNhcGFiaWxpdHkgbGlzdGVkIGluIHRoZSBwcm9wb3NhbCdzIENhcGFiaWxpdGllcyBzZWN0aW9uLgogICAgICBgPGNhcGFiaWxpdHktcGF0aD5gIGlzIHRoZSBzcGVjIGRpcmVjdG9yeSByZWxhdGl2ZSB0byBgc3BlY3MvYCAoZm9yIGV4YW1wbGUsCiAgICAgIGB1c2VyLWF1dGhgIG9yIGBpZGVudGl0eS91c2VyLWF1dGhgKS4gUHJlc2VydmUgdGhlIGZ1bGwgcGF0aDoKICAgICAgLSBOZXcgY2FwYWJpbGl0aWVzOiB1c2UgdGhlIGV4YWN0IHBhdGggZnJvbSB0aGUgcHJvcG9zYWwgYXQgYHNwZWNzLzxjYXBhYmlsaXR5LXBhdGg+L3NwZWMubWRgLiBBbnkgcGF0aCBzZWdtZW50IG5ld2x5IGludHJvZHVjZWQgaW4gdGhlIHByb3Bvc2FsIG11c3QgYmUga2ViYWItY2FzZS4gRm9sbG93IHRoZSBwcm9qZWN0J3MgZXhpc3Rpbmcgb3JnYW5pemF0aW9uOyBkbyBub3QgYWRkIGEgbmV3IGRvbWFpbiBsZXZlbCB3aGVuIHRoZSBwcm9qZWN0IHVzZXMgYSBmbGF0IGxheW91dC4KICAgICAgLSBNb2RpZmllZCBjYXBhYmlsaXRpZXM6IHVzZSB0aGUgZXhhY3QgZXhpc3RpbmcgcGF0aCBmcm9tIGBvcGVuc3BlYy9zcGVjcy88Y2FwYWJpbGl0eS1wYXRoPi9gIHdoZW4gY3JlYXRpbmcgdGhlIGRlbHRhIGF0IGBzcGVjcy88Y2FwYWJpbGl0eS1wYXRoPi9zcGVjLm1kYC4gUnVuIGBvcGVuc3BlYyBsaXN0IC0tc3BlY3NgIHRvIGNvbmZpcm0gdGhhdCBwYXRoIGJlZm9yZSB3cml0aW5nIHRoZSBkZWx0YSwgYXBwZW5kaW5nIGAtLXN0b3JlICI8aWQ+ImAgb25seSBmb3IgYSByZWdpc3RlcmVkIHN0YW5kYWxvbmUgc3RvcmUgLSBhIG1pc3R5cGVkIG9yIGludmVudGVkIHBhdGggdGFyZ2V0cyBhIGNhcGFiaWxpdHkgdGhhdCBkb2VzIG5vdCBleGlzdCByYXRoZXIgdGhhbiB0aGUgb25lIHlvdSBtZWFudC4gRG8gbm90IG1vdmUgb3IgcmVuYW1lIHRoZSBjYXBhYmlsaXR5LgoKICAgICAgV3JpdGUgdGhlIHNwZWMgZmlsZXMgb25lIGF0IGEgdGltZSwgc28gdGhlIHVzZXIgc2VlcyBwcm9ncmVzcyBhbmQgYW4KICAgICAgaW50ZXJydXB0ZWQgcnVuIGtlZXBzIHRoZSBmaWxlcyBpdCBhbHJlYWR5IHdyb3RlOgogICAgICAtIEJlZm9yZSB3cml0aW5nIGFueXRoaW5nLCBjb21wYXJlIHRoZSBjYXBhYmlsaXRpZXMgdGhlIHByb3Bvc2FsIGxpc3RzCiAgICAgICAgd2l0aCB0aGUgYHNwZWNzLzxjYXBhYmlsaXR5LXBhdGg+L3NwZWMubWRgIGZpbGVzIHRoYXQgYWxyZWFkeSBleGlzdCwKICAgICAgICBhbmQgc3RhcnQgd2l0aCB0aGUgZmlyc3QgY2FwYWJpbGl0eSB0aGF0IGhhcyBubyBmaWxlLiBEbyBub3QgcmV3cml0ZQogICAgICAgIGFuIGV4aXN0aW5nIGZpbGUgdW5sZXNzIHRoZSB1c2VyIGFza3MgeW91IHRvLgogICAgICAtIEJlZm9yZSBlYWNoIGZpbGUsIHNheSBpbiBvbmUgbGluZSB3aGljaCBjYXBhYmlsaXR5IHlvdSBhcmUgd3JpdGluZy4KICAgICAgLSBXcml0ZSBlYWNoIGZpbGUgYXMgc29vbiBhcyB5b3UgaGF2ZSBkcmFmdGVkIGl0LiBEbyBub3QgcGxhbiBldmVyeSBmaWxlCiAgICAgICAgYmVmb3JlIHdyaXRpbmcgdGhlIGZpcnN0LgogICAgICAtIFN0b3Agd2hlbiBldmVyeSBjYXBhYmlsaXR5IHRoZSBwcm9wb3NhbCBsaXN0cyBoYXMgaXRzIGZpbGUuCgogICAgICBUaGVyZSBtdXN0IGJlIGF0IGxlYXN0IG9uZSBzcGVjIGZpbGUgdW5sZXNzIHRoZSBjaGFuZ2UncyBgLm9wZW5zcGVjLnlhbWxgCiAgICAgIHNldHMgYHNraXBfc3BlY3M6IHRydWVgIChubyBzcGVjLWxldmVsIGJlaGF2aW9yIGNoYW5nZSkgLSBgb3BlbnNwZWMgdmFsaWRhdGVgCiAgICAgIHJlamVjdHMgYSB6ZXJvLWRlbHRhIGNoYW5nZSB3aXRob3V0IHRoYXQgbWFya2VyLiBJZiB0aGUgcHJvcG9zYWwgbGlzdHMgbm8KICAgICAgY2FwYWJpbGl0aWVzIGFuZCBgc2tpcF9zcGVjc2AgaXMgbm90IHNldCwgcmV2aXNpdCB0aGUgcHJvcG9zYWwgZmlyc3QuCgogICAgICBEZWx0YSBvcGVyYXRpb25zICh1c2UgIyMgaGVhZGVycyk6CiAgICAgIC0gKipBRERFRCBSZXF1aXJlbWVudHMqKjogTmV3IGNhcGFiaWxpdGllcwogICAgICAtICoqTU9ESUZJRUQgUmVxdWlyZW1lbnRzKio6IENoYW5nZWQgYmVoYXZpb3IgLSBNVVNUIGluY2x1ZGUgZnVsbCB1cGRhdGVkIGNvbnRlbnQKICAgICAgLSAqKlJFTU9WRUQgUmVxdWlyZW1lbnRzKio6IERlcHJlY2F0ZWQgZmVhdHVyZXMgLSBNVVNUIGluY2x1ZGUgKipSZWFzb24qKiBhbmQgKipNaWdyYXRpb24qKgogICAgICAtICoqUkVOQU1FRCBSZXF1aXJlbWVudHMqKjogTmFtZSBjaGFuZ2VzIG9ubHkgLSB1c2UgRlJPTTovVE86IGZvcm1hdAoKICAgICAgRm9ybWF0IHJlcXVpcmVtZW50czoKICAgICAgLSBFYWNoIHJlcXVpcmVtZW50OiBgIyMjIFJlcXVpcmVtZW50OiA8bmFtZT5gIGZvbGxvd2VkIGJ5IGRlc2NyaXB0aW9uCiAgICAgIC0gVXNlIFNIQUxML01VU1QgZm9yIG5vcm1hdGl2ZSByZXF1aXJlbWVudHMgKGF2b2lkIHNob3VsZC9tYXkpCiAgICAgIC0gRWFjaCBzY2VuYXJpbzogYCMjIyMgU2NlbmFyaW86IDxuYW1lPmAgd2l0aCBXSEVOL1RIRU4gZm9ybWF0CiAgICAgIC0gKipDUklUSUNBTCoqOiBTY2VuYXJpb3MgTVVTVCB1c2UgZXhhY3RseSA0IGhhc2h0YWdzIChgIyMjI2ApLiBVc2luZyAzIGhhc2h0YWdzIG9yIGJ1bGxldHMgd2lsbCBmYWlsIHNpbGVudGx5LgogICAgICAtIEV2ZXJ5IHJlcXVpcmVtZW50IE1VU1QgaGF2ZSBhdCBsZWFzdCBvbmUgc2NlbmFyaW8uCiAgICAgIC0gS2VlcCBlYWNoIHJlcXVpcmVtZW50J3MgZGVzY3JpcHRpb24gKHRoZSB0ZXh0IGJldHdlZW4gYCMjIyBSZXF1aXJlbWVudDpgIGFuZCBpdHMgZmlyc3Qgc2NlbmFyaW8pIHRvIDUwMCBjaGFyYWN0ZXJzIG9yIGZld2VyLiBgb3BlbnNwZWMgdmFsaWRhdGVgIGZsYWdzIGxvbmdlciBkZXNjcmlwdGlvbnMgaW4gQURERUQgcmVxdWlyZW1lbnRzIGFuZCBpbiB0aGUgbWFpbiBzcGVjLiBUaGlzIGlzIGEgd2FybmluZzogbm9ybWFsIHZhbGlkYXRpb24gc3RpbGwgcGFzc2VzLCBidXQgYG9wZW5zcGVjIHZhbGlkYXRlIC0tc3RyaWN0YCBmYWlscyBvbiBpdC4gV2hlbiB3cml0aW5nIGEgbmV3IHJlcXVpcmVtZW50LCBzdGF0ZSBvbmUgYmVoYXZpb3IgcGVyIHJlcXVpcmVtZW50OiBtb3ZlIGV4YW1wbGVzIGFuZCBlZGdlIGNhc2VzIGludG8gc2NlbmFyaW9zLCBhbmQgc3BsaXQgYSByZXF1aXJlbWVudCB0aGF0IGNvdmVycyBzZXZlcmFsIGJlaGF2aW9ycyBpbnRvIHNlcGFyYXRlIGAjIyMgUmVxdWlyZW1lbnQ6YCBibG9ja3MsIGVhY2ggd2l0aCBpdHMgb3duIHNjZW5hcmlvcy4gVW5kZXIgTU9ESUZJRUQsIGtlZXAgdGhlIGV4aXN0aW5nIHJlcXVpcmVtZW50IGJsb2NrIHdob2xlOyBuZXZlciBzcGxpdCwgdHJpbSBvciByZXdyaXRlIGV4aXN0aW5nIHRleHQganVzdCB0byBtZWV0IHRoZSBsZW5ndGguIFNwbGl0IGFuIGV4aXN0aW5nIGxvbmcgcmVxdWlyZW1lbnQgb25seSB3aGVuIHRoZSB1c2VyIGFza3MgZm9yIGl0LCBpbiBhIGNoYW5nZSBtYWRlIGZvciB0aGF0IHB1cnBvc2U6IHVuZGVyIE1PRElGSUVELCBrZWVwIGl0cyBoZWFkZXIgYW5kIGV2ZXJ5IHNjZW5hcmlvIGFuZCBjdXQgaXRzIGRlc2NyaXB0aW9uIGRvd24gdG8gb25lIGJlaGF2aW9yIHdpdGhvdXQgY2hhbmdpbmcgaXRzIG1lYW5pbmcsIHRoZW4gYWRkIGVhY2ggYmVoYXZpb3IgeW91IHJlbW92ZWQgYXMgaXRzIG93biBBRERFRCByZXF1aXJlbWVudCB3aXRoIGl0cyBvd24gc2NlbmFyaW9zLgoKICAgICAgTmV3IGNhcGFiaWxpdGllcyBvbmx5OiB0aGUgZGVsdGEgc3BlYydzIGZpcnN0IHNlY3Rpb24gaXMgYCMjIFB1cnBvc2VgIC0KICAgICAgb25lIG9yIHR3byBzZW50ZW5jZXMgKDUwKyBjaGFyYWN0ZXJzLCBvciBgb3BlbnNwZWMgdmFsaWRhdGUgLS1zdHJpY3RgCiAgICAgIHJlcG9ydHMgaXQgYXMgdG9vIGJyaWVmKSBkZXNjcmliaW5nIHdoYXQgdGhlIGNhcGFiaWxpdHkgaXMgZm9yLiBBcmNoaXZlCiAgICAgIGNvcGllcyBpdCBpbnRvIHRoZSBtYWluIHNwZWMgaXQgY3JlYXRlczsgd2l0aG91dCBpdCB0aGUgbmV3IG1haW4gc3BlYyBpcwogICAgICBsZWZ0IHdpdGggYSBgVEJEIC4uLiBVcGRhdGUgUHVycG9zZSBhZnRlciBhcmNoaXZlYCBwbGFjZWhvbGRlciB0byBmaWxsIGluCiAgICAgIGJ5IGhhbmQuIERvIE5PVCBhZGQgYCMjIFB1cnBvc2VgIHRvIGEgZGVsdGEgZm9yIGFuIGV4aXN0aW5nIGNhcGFiaWxpdHkgLQogICAgICB0aGF0IHNwZWMgYWxyZWFkeSBoYXMgb25lIGFuZCB0aGUgZGVsdGEncyBpcyBpZ25vcmVkLiBUbyBjaGFuZ2UgYW4KICAgICAgZXhpc3RpbmcgY2FwYWJpbGl0eSdzIFB1cnBvc2UgLSBpbmNsdWRpbmcgYSBsZWZ0b3ZlciBgVEJEYCBwbGFjZWhvbGRlciAtCiAgICAgIGVkaXQgYDxwbGFubmluZ0hvbWUucm9vdD4vb3BlbnNwZWMvc3BlY3MvPGNhcGFiaWxpdHktcGF0aD4vc3BlYy5tZGAKICAgICAgZGlyZWN0bHkuIGBwbGFubmluZ0hvbWUucm9vdGAgY29tZXMgZnJvbSB0aGUgYG9wZW5zcGVjIGluc3RydWN0aW9ucyAuLi4KICAgICAgLS1qc29uYCByZXNwb25zZS4gQWx3YXlzIHVzZSBpdCByYXRoZXIgdGhhbiBhIHJlcG8tcmVsYXRpdmUgcGF0aDogaXQKICAgICAgcmVzb2x2ZXMgdG8gdGhlIHN0b3JlIHdoZW5ldmVyIHRoZSBjaGFuZ2UgbGl2ZXMgaW4gb25lIC0gd2hldGhlciB0aGF0CiAgICAgIGNhbWUgZnJvbSBgLS1zdG9yZWAsIGEgcHJvamVjdCBgc3RvcmU6YCBwb2ludGVyLCBvciBhIGdsb2JhbCBkZWZhdWx0CiAgICAgIHN0b3JlIC0gYW5kIHRvIHRoZSBjdXJyZW50IHJlcG9zaXRvcnkgb3RoZXJ3aXNlLiBEbyBub3QgdHJ5IHRvIHdvcmsgb3V0CiAgICAgIHdoaWNoIGNhc2UgYXBwbGllczsgdGhlIGZpZWxkIGFscmVhZHkgaGFzLgoKICAgICAgTU9ESUZJRUQgcmVxdWlyZW1lbnRzIHdvcmtmbG93OgogICAgICAxLiBMb2NhdGUgdGhlIGV4aXN0aW5nIHJlcXVpcmVtZW50IGluIGA8cGxhbm5pbmdIb21lLnJvb3Q+L29wZW5zcGVjL3NwZWNzLzxjYXBhYmlsaXR5LXBhdGg+L3NwZWMubWRgICh0aGUgc2FtZSBzdG9yZS1hd2FyZSByb290IGFzIGFib3ZlKQogICAgICAyLiBDb3B5IHRoZSBFTlRJUkUgcmVxdWlyZW1lbnQgYmxvY2sgKGZyb20gYCMjIyBSZXF1aXJlbWVudDpgIHRocm91Z2ggYWxsIHNjZW5hcmlvcykKICAgICAgMy4gUGFzdGUgdW5kZXIgYCMjIE1PRElGSUVEIFJlcXVpcmVtZW50c2AgYW5kIGVkaXQgdG8gcmVmbGVjdCBuZXcgYmVoYXZpb3IKICAgICAgNC4gRW5zdXJlIGhlYWRlciB0ZXh0IG1hdGNoZXMgZXhhY3RseSAod2hpdGVzcGFjZS1pbnNlbnNpdGl2ZSkKCiAgICAgIENvbW1vbiBwaXRmYWxsOiBVc2luZyBNT0RJRklFRCB3aXRoIHBhcnRpYWwgY29udGVudCBsb3NlcyBkZXRhaWwgYXQgYXJjaGl2ZSB0aW1lLgogICAgICBJZiBhZGRpbmcgbmV3IGNvbmNlcm5zIHdpdGhvdXQgY2hhbmdpbmcgZXhpc3RpbmcgYmVoYXZpb3IsIHVzZSBBRERFRCBpbnN0ZWFkLgoKICAgICAgRXhhbXBsZSAoYSBuZXcgY2FwYWJpbGl0eSwgc28gaXRzIGZpcnN0IHNlY3Rpb24gaXMgYCMjIFB1cnBvc2VgKToKICAgICAgYGBgCiAgICAgICMgU3BlYyBEZWx0YQoKICAgICAgIyMgUHVycG9zZQoKICAgICAgTGV0cyB1c2VycyB0YWtlIHRoZWlyIGRhdGEgb3V0IG9mIHRoZSBwcm9kdWN0IGluIGEgcG9ydGFibGUgZm9ybWF0LgoKICAgICAgIyMgQURERUQgUmVxdWlyZW1lbnRzCgogICAgICAjIyMgUmVxdWlyZW1lbnQ6IFVzZXIgY2FuIGV4cG9ydCBkYXRhCiAgICAgIFRoZSBzeXN0ZW0gU0hBTEwgYWxsb3cgdXNlcnMgdG8gZXhwb3J0IHRoZWlyIGRhdGEgaW4gQ1NWIGZvcm1hdC4KCiAgICAgICMjIyMgU2NlbmFyaW86IFN1Y2Nlc3NmdWwgZXhwb3J0CiAgICAgIC0gKipXSEVOKiogdXNlciBjbGlja3MgIkV4cG9ydCIgYnV0dG9uCiAgICAgIC0gKipUSEVOKiogc3lzdGVtIGRvd25sb2FkcyBhIENTViBmaWxlIHdpdGggYWxsIHVzZXIgZGF0YQoKICAgICAgIyMgUkVNT1ZFRCBSZXF1aXJlbWVudHMKCiAgICAgICMjIyBSZXF1aXJlbWVudDogTGVnYWN5IGV4cG9ydAogICAgICAqKlJlYXNvbioqOiBSZXBsYWNlZCBieSBuZXcgZXhwb3J0IHN5c3RlbQogICAgICAqKk1pZ3JhdGlvbioqOiBVc2UgbmV3IGV4cG9ydCBlbmRwb2ludCBhdCAvYXBpL3YyL2V4cG9ydAogICAgICBgYGAKCgogICAgICBTdGFibGUgSURzIChzcGVjLWN0eCk6CiAgICAgIC0gRXZlcnkgcmVxdWlyZW1lbnQgaGVhZGVyIHN0YXJ0cyB3aXRoIGFuIElEOiBgIyMjIFJlcXVpcmVtZW50OiBSRVEtPENBUD4tTk5OIDxuYW1lPmAuCiAgICAgICAgR2V0IGEgbmV3IElEIGZyb20gYHNwZWNjdHggaWQgbmV3IFJFUSA8Q0FQPmAuIE5ldmVyIGNvdW50IG51bWJlcnMgYnkgaGFuZC4KICAgICAgICBgPENBUD5gIGlzIGEgY2FwYWJpbGl0eSBjb2RlIGZyb20gYFtpZHNdIGNhcHNgIGluIGBzcGVjLWN0eC50b21sYC4KICAgICAgLSBFdmVyeSBzY2VuYXJpbyBoZWFkZXIgc3RhcnRzIHdpdGggYW4gSUQ6IGAjIyMjIFNjZW5hcmlvOiBTQ04tPENBUD4tTk5OLTxuPiA8bmFtZT5gLgogICAgICAgIEdldCBpdCBmcm9tIGBzcGVjY3R4IGlkIG5ldyBTQ04gPENBUD4gLS1mb3IgUkVRLTxDQVA+LU5OTmAuCiAgICAgIC0gVW5kZXIgTU9ESUZJRUQsIFJFTU9WRUQsIG9yIFJFTkFNRUQsIGtlZXAgdGhlIGV4aXN0aW5nIElELiBBbiBJRCBuZXZlciBjaGFuZ2VzLgogICAgICAtIExpbmsgcmVsYXRlZCBJRHMgd2l0aCBvbmUgbGluZSBgUmVmczogSUQsIElEYCBhZnRlciB0aGUgcmVxdWlyZW1lbnQgdGV4dC4KICAgICAgLSBSZXBsYWNlIGV2ZXJ5IHBsYWNlaG9sZGVyIG9mIHRoZSB0ZW1wbGF0ZS4gYHNwZWNjdHggY2hlY2tgIHJlcG9ydHMgYSBoZWFkZXIgd2l0aAogICAgICAgIG5vIElEIGFzIGBtaXNzaW5nLWlkYC4KCiAgICAgIFNwZWNzIHNob3VsZCBiZSB0ZXN0YWJsZSAtIGVhY2ggc2NlbmFyaW8gaXMgYSBwb3RlbnRpYWwgdGVzdCBjYXNlLgogICAgcmVxdWlyZXM6CiAgICAgIC0gcHJvcG9zYWwKCiAgLSBpZDogZGVzaWduCiAgICBnZW5lcmF0ZXM6IGRlc2lnbi5tZAogICAgZGVzY3JpcHRpb246IFRlY2huaWNhbCBkZXNpZ24gZG9jdW1lbnQgd2l0aCBpbXBsZW1lbnRhdGlvbiBkZXRhaWxzCiAgICB0ZW1wbGF0ZTogZGVzaWduLm1kCiAgICBpbnN0cnVjdGlvbjogfAogICAgICBDcmVhdGUgdGhlIGRlc2lnbiBkb2N1bWVudCB0aGF0IGV4cGxhaW5zIEhPVyB0byBpbXBsZW1lbnQgdGhlIGNoYW5nZS4KCiAgICAgIFdoZW4gdG8gaW5jbHVkZSBkZXNpZ24ubWQgKGNyZWF0ZSBvbmx5IGlmIGFueSBhcHBseSk6CiAgICAgIC0gQ3Jvc3MtY3V0dGluZyBjaGFuZ2UgKG11bHRpcGxlIHNlcnZpY2VzL21vZHVsZXMpIG9yIG5ldyBhcmNoaXRlY3R1cmFsIHBhdHRlcm4KICAgICAgLSBOZXcgZXh0ZXJuYWwgZGVwZW5kZW5jeSBvciBzaWduaWZpY2FudCBkYXRhIG1vZGVsIGNoYW5nZXMKICAgICAgLSBTZWN1cml0eSwgcGVyZm9ybWFuY2UsIG9yIG1pZ3JhdGlvbiBjb21wbGV4aXR5CiAgICAgIC0gQW1iaWd1aXR5IHRoYXQgYmVuZWZpdHMgZnJvbSB0ZWNobmljYWwgZGVjaXNpb25zIGJlZm9yZSBjb2RpbmcKCiAgICAgIFNlY3Rpb25zOgogICAgICAtICoqQ29udGV4dCoqOiBPbmx5IHRoZSBjdXJyZW50IHN0YXRlIGFuZCBjb25zdHJhaW50cyBuZWVkZWQgdG8gZXhwbGFpbiB0aGUgYXBwcm9hY2guIFJlZmVyZW5jZSB0aGUgcHJvcG9zYWwgZm9yIG1vdGl2YXRpb24gaW5zdGVhZCBvZiByZXN0YXRpbmcgaXQgKGUuZy4sICJTZWUgcHJvcG9zYWwubWQgLSBXaHkiKS4KICAgICAgLSAqKkdvYWxzIC8gTm9uLUdvYWxzKio6IFdoYXQgdGhpcyBkZXNpZ24gYWNoaWV2ZXMgYW5kIGV4cGxpY2l0bHkgZXhjbHVkZXMuIERvbid0IHJlc3RhdGUgdGhlIHByb3Bvc2FsJ3Mgc2NvcGUgLSBhZGQgb25seSBkZXNpZ24tbGV2ZWwgYm91bmRhcmllcy4KICAgICAgLSAqKkRlY2lzaW9ucyoqOiBLZXkgdGVjaG5pY2FsIGNob2ljZXMgd2l0aCByYXRpb25hbGUgKHdoeSBYIG92ZXIgWT8pLiBJbmNsdWRlIGFsdGVybmF0aXZlcyBjb25zaWRlcmVkIGZvciBlYWNoIGRlY2lzaW9uLgogICAgICAtICoqUmlza3MgLyBUcmFkZS1vZmZzKio6IEtub3duIGxpbWl0YXRpb25zLCB0aGluZ3MgdGhhdCBjb3VsZCBnbyB3cm9uZy4gRm9ybWF0OiBbUmlza10g4oaSIE1pdGlnYXRpb24KICAgICAgLSAqKk1pZ3JhdGlvbiBQbGFuKio6IFN0ZXBzIHRvIGRlcGxveSwgcm9sbGJhY2sgc3RyYXRlZ3kgKGlmIGFwcGxpY2FibGUpCiAgICAgIC0gKipPcGVuIFF1ZXN0aW9ucyoqOiBVbmtub3ducyB0aGF0IGNhbiBzYWZlbHkgYmUgYW5zd2VyZWQgbGF0ZXIgd2l0aG91dAogICAgICAgIGNoYW5naW5nIHRoZSBzcGVjcywgdGhlIGFwcHJvYWNoLCBvciB0aGUgdGFzayBicmVha2Rvd24uIE9taXQgaWYgbm9uZS4KCiAgICAgIE9wZW4gcXVlc3Rpb25zIGFyZSBmb3IgZ2VudWluZWx5IGRlZmVycmFibGUgdW5rbm93bnMsIG5vdCBkZWNpc2lvbnMgeW91CiAgICAgIHNraXBwZWQuIElmIGEgcXVlc3Rpb24gd291bGQgY2hhbmdlIHRoZSBzcGVjcywgdGhlIGNob3NlbiBhcHByb2FjaCwgb3IKICAgICAgdGhlIHRhc2sgYnJlYWtkb3duLCByZXNvbHZlIGl0IG5vdyAtIGFzayB0aGUgdXNlciBpbnN0ZWFkIG9mIGd1ZXNzaW5nLgoKICAgICAgRm9jdXMgb24gYXJjaGl0ZWN0dXJlIGFuZCBhcHByb2FjaCwgbm90IGxpbmUtYnktbGluZSBpbXBsZW1lbnRhdGlvbi4KICAgICAgVGhlIHByb3Bvc2FsIGNvdmVycyB3aHkgYW5kIHdoYXQ7IGRlc2lnbiBjb3ZlcnMgaG93LiBSZWZlcmVuY2UgdGhlCiAgICAgIHByb3Bvc2FsIGZvciBtb3RpdmF0aW9uIGFuZCwgb25jZSB3cml0dGVuLCB0aGUgc3BlY3MgZm9yIHJlcXVpcmVtZW50cyAtCiAgICAgIGlmIGEgc2VjdGlvbiB3b3VsZCBvbmx5IHJlc3RhdGUgdGhlbSwgcG9pbnQgdG8gdGhlbSBpbnN0ZWFkLgoKCiAgICAgIFN0YWJsZSBJRHMgKHNwZWMtY3R4KToKICAgICAgLSBFYWNoIGJ1bGxldCB1bmRlciBgIyMgRGVjaXNpb25zYCBpcyBvbmUgZGVjaXNpb24uIEl0cyBJRCBpcyBgPGNoYW5nZSBudW1iZXI+L0Q8bj5gCiAgICAgICAgYnkgcG9zaXRpb24sIHNvIGFkZCBuZXcgZGVjaXNpb25zIGF0IHRoZSBlbmQgYW5kIG5ldmVyIHJlb3JkZXIgdGhlbS4KICAgICAgLSBFbmQgYSBkZWNpc2lvbiB3aXRoIGBSZWZzOiBgIGFuZCB0aGUgUkVRIG9yIEFEUiBJRHMgaXQgc2VydmVzLiBUaGVuIGBzcGVjY3R4IGJ1bmRsZWAKICAgICAgICBwcmludHMgdGhlIGRlY2lzaW9uIHdpdGggdGhvc2UgcmVxdWlyZW1lbnRzLgoKICAgICAgR29vZCBkZXNpZ24gZG9jcyBleHBsYWluIHRoZSAid2h5IiBiZWhpbmQgdGVjaG5pY2FsIGRlY2lzaW9ucy4KICAgIHJlcXVpcmVzOgogICAgICAtIHByb3Bvc2FsCgogIC0gaWQ6IHRhc2tzCiAgICBnZW5lcmF0ZXM6IHRhc2tzLm1kCiAgICBkZXNjcmlwdGlvbjogSW1wbGVtZW50YXRpb24gY2hlY2tsaXN0IHdpdGggdHJhY2thYmxlIHRhc2tzCiAgICB0ZW1wbGF0ZTogdGFza3MubWQKICAgIGluc3RydWN0aW9uOiB8CiAgICAgIENyZWF0ZSB0aGUgdGFzayBsaXN0IHRoYXQgYnJlYWtzIGRvd24gdGhlIGltcGxlbWVudGF0aW9uIHdvcmsuCgogICAgICBCZWZvcmUgd3JpdGluZyB0YXNrcywgY2hlY2sgZGVzaWduLm1kIGZvciBPcGVuIFF1ZXN0aW9ucy4gSWYgYW55IG9mIHRoZW0KICAgICAgd291bGQgY2hhbmdlIHdoYXQgZ2V0cyBidWlsdCwgcmVzb2x2ZSB0aGVtIHdpdGggdGhlIHVzZXIgZmlyc3QgLSBkbyBub3QKICAgICAgYmFrZSBhbiB1bnN0YXRlZCBhc3N1bXB0aW9uIGludG8gdGhlIHRhc2sgbGlzdC4KCiAgICAgICoqSU1QT1JUQU5UOiBGb2xsb3cgdGhlIHRlbXBsYXRlIGJlbG93IGZvciB0cmFja2VkIHRhc2tzLioqIFRoZSBhcHBseSBwaGFzZSBwYXJzZXMKICAgICAgY2hlY2tib3ggZm9ybWF0IHRvIHRyYWNrIHByb2dyZXNzLiBBIGJveCBob2xkaW5nIG9ubHkgYHhgIGNvdW50cyBhcyBkb25lLAogICAgICB1cHBlciBvciBsb3dlciBjYXNlIGFuZCB3aXRoIGFueSBzcGFjaW5nLCBzbyBgLSBbIHhdYCBpcyBkb25lIHRvby4gRXZlcnkKICAgICAgb3RoZXIgbWFya2VyLCBpbmNsdWRpbmcgYC0gW35dYCwgYC0gWy1dYCBhbmQgYW4gZW1wdHkgYC0gW11gLCByZWFkcyBhcwogICAgICB1bmZpbmlzaGVkLiBBIGxpbmUgd2l0aCBubyBjaGVja2JveCBpcyBub3QgdHJhY2tlZCBhdCBhbGwuCgogICAgICBHdWlkZWxpbmVzOgogICAgICAtIEdyb3VwIHJlbGF0ZWQgdHJhY2tlZCB0YXNrcyB1bmRlciAjIyBudW1iZXJlZCBoZWFkaW5ncwogICAgICAtIEVhY2ggdHJhY2tlZCB0YXNrIE1VU1QgYmUgYSBjaGVja2JveDogYC0gWyBdIFguWSBUYXNrIGRlc2NyaXB0aW9uYAogICAgICAtIFRhc2tzIHNob3VsZCBiZSBzbWFsbCBlbm91Z2ggdG8gY29tcGxldGUgaW4gb25lIHNlc3Npb24KICAgICAgLSBPcmRlciB0YXNrcyBieSBkZXBlbmRlbmN5ICh3aGF0IG11c3QgYmUgZG9uZSBmaXJzdD8pCiAgICAgIC0gVHJhY2sgaW1wbGVtZW50YXRpb24gYW5kIHZlcmlmaWNhdGlvbiB3b3JrIHRoYXQgY2FuIGJlIGNvbXBsZXRlZCBiZWZvcmUKICAgICAgICBhcmNoaXZlLiBJZiB0aGUgcmVxdWVzdGVkIHdvcmtmbG93IGluY2x1ZGVzIGFyY2hpdmUgb3Igd29yayB0aGF0IHJlcXVpcmVzCiAgICAgICAgdGhpcyBjaGFuZ2UgdG8gYmUgYXJjaGl2ZWQsIHByZXNlcnZlIHRob3NlIHN0ZXBzIGFzIHBsYWluIGJ1bGxldHMgaW4gYW4KICAgICAgICBvcHRpb25hbCBgIyMgV29ya2Zsb3cgZm9sbG93LXVwYCBzZWN0aW9uIGF0IHRoZSBlbmQgb2YgdGFza3MubWQuIFRoZXNlCiAgICAgICAgYnVsbGV0cyBhcmUgcmVmZXJlbmNlIGluZm9ybWF0aW9uIG91dHNpZGUgdHJhY2tlZCB0YXNrIHByb2dyZXNzLgogICAgICAtIEVhY2ggdGFzayBNVVNUIHN0YXRlIGhvdyB0byB2ZXJpZnkgY29tcGxldGlvbiAoYSB0ZXN0LCBjb21tYW5kLAogICAgICAgIG9ic2VydmFibGUgYmVoYXZpb3IsIG9yIGRlbGl2ZXJlZCBhcnRpZmFjdCkuIFB1dCB0aGUgdmVyaWZpY2F0aW9uIGluCiAgICAgICAgdGhhdCB0YXNrJ3MgY2hlY2tib3ggZGVzY3JpcHRpb24uIFVzZSBhIHNlcGFyYXRlIHZlcmlmaWNhdGlvbiB0YXNrIG9ubHkKICAgICAgICB3aGVuIGl0IGNoZWNrcyBicm9hZGVyIGludGVncmF0aW9uIG9yIHN5c3RlbSBiZWhhdmlvciB0aGF0IHNwYW5zCiAgICAgICAgbXVsdGlwbGUgaW1wbGVtZW50YXRpb24gdGFza3MuCiAgICAgIC0gRWFjaCB0YXNrIGdyb3VwIE1VU1QgbGFuZCB0aGUgdGVzdHMgYW5kIGRvY3VtZW50YXRpb24gaXRzIG93biB3b3JrCiAgICAgICAgY2FsbHMgZm9yLiBEbyBOT1QgY29sbGVjdCB0ZXN0aW5nIG9yIGRvY3VtZW50YXRpb24gaW50byBhIGZpbmFsIGdyb3VwIC0KICAgICAgICB3aGVuIGEgbGF0ZSBncm91cCBmaXJzdCBleGVyY2lzZXMgd29yayBmcm9tIGFuIGVhcmx5IG9uZSwgdGhlIGZhaWx1cmVzCiAgICAgICAgY2FzY2FkZSBiYWNrIHRocm91Z2ggZXZlcnkgZ3JvdXAgaW4gYmV0d2VlbiBhbmQgZm9yY2UgcmV3b3JrLiBBIGdyb3VwCiAgICAgICAgd2hvc2Ugd29yayBjYWxscyBmb3IgbmVpdGhlciwgc3VjaCBhcyBzY2FmZm9sZGluZyBvciBkZXBlbmRlbmN5IHNldHVwLAogICAgICAgIGNhcnJpZXMgbmVpdGhlci4gQSBmaW5hbCBncm91cCBpcyBmb3IgaW50ZWdyYXRpb24gY2hlY2tzIG9ubHksIG5vdCBmb3IKICAgICAgICB0aGUgdGVzdHMgYW5kIGRvY3MgYW4gZWFybGllciBncm91cCBvd2VkLgoKICAgICAgRXhhbXBsZToKICAgICAgYGBgCiAgICAgICMgVGFza3MKCiAgICAgICMjIDEuIFNldHVwCgogICAgICAtIFsgXSAxLjEgQ3JlYXRlIG5ldyBtb2R1bGUgc3RydWN0dXJlIGFuZCB2ZXJpZnkgZXhwZWN0ZWQgZmlsZXMgYXJlIHByZXNlbnQKICAgICAgLSBbIF0gMS4yIEFkZCBkZXBlbmRlbmNpZXMgdG8gcGFja2FnZS5qc29uIGFuZCB2ZXJpZnkgcGFja2FnZSBpbnN0YWxsYXRpb24gc3VjY2VlZHMKCiAgICAgICMjIDIuIENvcmUgSW1wbGVtZW50YXRpb24KCiAgICAgIC0gWyBdIDIuMSBJbXBsZW1lbnQgZGF0YSBleHBvcnQgZnVuY3Rpb24gYW5kIHZlcmlmeSB0aGUgZXhwb3J0IHRlc3QgcGFzc2VzCiAgICAgIC0gWyBdIDIuMiBBZGQgQ1NWIGZvcm1hdHRpbmcgdXRpbGl0aWVzIGFuZCB2ZXJpZnkgdW5pdCB0ZXN0cyBjb3ZlciBxdW90aW5nIGFuZCBkZWxpbWl0ZXJzCiAgICAgIC0gWyBdIDIuMyBEb2N1bWVudCB0aGUgZXhwb3J0IEFQSSBpbiBkb2NzL2V4cG9ydC5tZCBhbmQgdmVyaWZ5IHRoZSBkb2N1bWVudGVkIGNvbW1hbmQgcnVucyBhcyB3cml0dGVuCiAgICAgIGBgYAoKICAgICAgV2hlbiBhcHBsaWNhYmxlLCBhcHBlbmQgd29ya2Zsb3cgZm9sbG93LXVwIGFzIHBsYWluIGJ1bGxldHMsIGZvciBleGFtcGxlOgogICAgICBgYGAKICAgICAgIyMgV29ya2Zsb3cgZm9sbG93LXVwCgogICAgICAtIEFyY2hpdmUgdGhlIGNoYW5nZSBhZnRlciB0aGUgcHJvamVjdCdzIHJldmlldyByZXF1aXJlbWVudHMgYXJlIHNhdGlzZmllZC4KICAgICAgLSBWZXJpZnkgdGhlIGFyY2hpdmVkIHJlc3VsdC4KICAgICAgYGBgCgoKICAgICAgU3RhYmxlIElEcyBhbmQgVmVyaWZ5IChzcGVjLWN0eCk6CiAgICAgIC0gRXZlcnkgdGFzayBjaXRlcyBhdCBsZWFzdCBvbmUgcmVxdWlyZW1lbnQgaW4gc3F1YXJlIGJyYWNrZXRzOiBgW1JFUS08Q0FQPi1OTk5dYC4KICAgICAgLSBFdmVyeSB0YXNrIGVuZHMgd2l0aCBgVmVyaWZ5OmAgYW5kIHRoZSBjb21tYW5kIGluIGEgY29kZSBzcGFuLCBmb3IgZXhhbXBsZQogICAgICAgIGBgVmVyaWZ5OiBgbnBtIHRlc3QgLS0gdGVzdHMvZXhwb3J0LnRlc3QudHNgIGBgLiBUd28gc3BhbnMgcnVuIGpvaW5lZCB3aXRoIGAmJmAuCiAgICAgIC0gVXNlIHByb3NlIGFmdGVyIGBWZXJpZnk6YCBvbmx5IHdoZW4gbm8gY29tbWFuZCBjYW4gY2hlY2sgdGhlIHdvcmsuIFRoZW4KICAgICAgICBgc3BlY2N0eCB0YXNrIGRvbmUgPGlkPiAtLW1hbnVhbCAiPG5vdGU+ImAgcmVjb3JkcyBpdC4KICAgICAgLSBDbG9zZSBhIHRhc2sgb25seSB3aXRoIGBzcGVjY3R4IHRhc2sgZG9uZSA8aWQ+YC4gSXQgcnVucyB0aGUgY29tbWFuZCwgd3JpdGVzCiAgICAgICAgZXZpZGVuY2UgdW5kZXIgYC5jdHgvZXZpZGVuY2UvYCwgYW5kIHNldHMgdGhlIGNoZWNrYm94LgoKICAgICAgUmVmZXJlbmNlIHNwZWNzIGZvciB3aGF0IG5lZWRzIHRvIGJlIGJ1aWx0LCBkZXNpZ24gZm9yIGhvdyB0byBidWlsZCBpdC4KICAgIHJlcXVpcmVzOgogICAgICAtIHNwZWNzCiAgICAgIC0gZGVzaWduCgphcHBseToKICByZXF1aXJlczogWyB0YXNrcyBdCiAgdHJhY2tzOiB0YXNrcy5tZAogIGluc3RydWN0aW9uOiB8CiAgICBSZWFkIGNvbnRleHQgZmlsZXMsIHdvcmsgdGhyb3VnaCBwZW5kaW5nIHRhc2tzLCBtYXJrIGNvbXBsZXRlIGFzIHlvdSBnby4KICAgIFBhdXNlIGlmIHlvdSBoaXQgYmxvY2tlcnMgb3IgbmVlZCBjbGFyaWZpY2F0aW9uLgo=",
4
+ "schemas/spec-driven-ids/README.md": "IyBzcGVjLWRyaXZlbi1pZHMKClRlbXBsYXRlcyBhbmQgY29uZmlnIHJ1bGVzIHRoYXQgYWRkIHN0YWJsZSBJRHMgZnJvbSBzcGVjLWN0eCB0byB0aGUgT3BlblNwZWMgYHNwZWMtZHJpdmVuYCB3b3JrZmxvdy4gVGhlIHByb2plY3Qga2VlcHMgYHNjaGVtYTogc3BlYy1kcml2ZW5gIGluIGBvcGVuc3BlYy9jb25maWcueWFtbGAuIFVwc3RyZWFtIE9wZW5TcGVjIGluamVjdHMgdGhlIGBydWxlc2AgYW5kIGBvcGVyYXRpb25zYCBiZWxvdyBpbnRvIGV2ZXJ5IGFydGlmYWN0IGluc3RydWN0aW9uLCBzbyB0aGUgYWdlbnQgbGVhcm5zIHRoZSBJRCBjb21tYW5kcyBmcm9tIHRoZXJlLgoKLSBgdGVtcGxhdGVzL3NwZWMubWRgIHN0YXJ0cyBlYWNoIHJlcXVpcmVtZW50IHdpdGggYFJFUS08Q0FQPi1OTk5gIGFuZCBlYWNoIHNjZW5hcmlvIHdpdGggYFNDTi08Q0FQPi1OTk4tPG4+YC4KLSBgdGVtcGxhdGVzL3Rhc2tzLm1kYCBjaXRlcyBSRVEgSURzIGFuZCBwdXRzIHRoZSBgVmVyaWZ5OmAgY29tbWFuZCBpbiBhIGNvZGUgc3Bhbiwgc28gYHNwZWNjdHggdGFzayBkb25lYCBjYW4gcnVuIGl0LgotIGB0ZW1wbGF0ZXMvZGVzaWduLm1kYCBlbmRzIGVhY2ggZGVjaXNpb24gd2l0aCBhIGBSZWZzOmAgbGluZS4KLSBgY29uZmlnLWZyYWdtZW50LnlhbWxgIGhvbGRzIHRoZSBgcnVsZXNgIGFuZCBgb3BlcmF0aW9uc2AgZm9yIGBvcGVuc3BlYy9jb25maWcueWFtbGAuIFRoZSBydWxlcyB0ZWxsIHRoZSBhZ2VudCB0byBnZXQgSURzIGZyb20gYHNwZWNjdHggaWQgbmV3YCBhbmQgbmFtZSB0aGUgdGVtcGxhdGVzIHBhdGguIFRoZSBgYXBwbHlgIGd1aWRhbmNlIHNheXMgdGhhdCBhIHRhc2sgY2xvc2VzIG9ubHkgd2l0aCBgc3BlY2N0eCB0YXNrIGRvbmUgPGlkPmAgYW5kIHRoYXQgdGhlIGFnZW50IHJ1bnMgdGhlIGBzcGVjY3R4LXJ1bmAgc2tpbGwsIG5ldmVyIGAvb3BzeDphcHBseWAuCgojIyBJbnN0YWxsIGJ5IGNvcHkKCi0gQ2xvbmUgdGhlIHJlcG9zaXRvcnk6IGBnaXQgY2xvbmUgaHR0cHM6Ly9naXRodWIuY29tL3NvbnFoL3NwZWMtY3R4YC4KLSBDb3B5IGBzY2hlbWFzL3NwZWMtZHJpdmVuLWlkcy90ZW1wbGF0ZXNgIHRvIGBvcGVuc3BlYy90ZW1wbGF0ZXMvc3BlYy1kcml2ZW4taWRzYCBpbiB5b3VyIHByb2plY3QuCi0gS2VlcCBgc2NoZW1hOiBzcGVjLWRyaXZlbmAgaW4gYG9wZW5zcGVjL2NvbmZpZy55YW1sYC4KLSBNZXJnZSBgY29uZmlnLWZyYWdtZW50LnlhbWxgIGludG8gYG9wZW5zcGVjL2NvbmZpZy55YW1sYCBieSBoYW5kLiBBZGQgaXRzIGBydWxlc2AgYW5kIGBvcGVyYXRpb25zYCBrZXlzLiBLZWVwIGV2ZXJ5IGl0ZW0gcXVvdGVkLgotIFJ1biBgb3BlbnNwZWMgdmFsaWRhdGUgLS1hbGxgLgoKIyMgSW5zdGFsbCB3aXRoIGluaXQgLS1zY2hlbWEKCmBgYGJhc2gKbnB4IC15IHNwZWMtY3R4IGluaXQgLS1zY2hlbWEKYGBgCgotIFRoZSBjb21tYW5kIGNvcGllcyB0aGUgZm91ciB0ZW1wbGF0ZXMgdG8gYG9wZW5zcGVjL3RlbXBsYXRlcy9zcGVjLWRyaXZlbi1pZHMvYC4KLSBJdCBhZGRzIHRoZSBgcnVsZXNgIGFuZCBgb3BlcmF0aW9uc2Aga2V5cyB0aGF0IHRoZSBjb25maWcgZG9lcyBub3QgaGF2ZSB5ZXQuIEEga2V5IHRoYXQgZXhpc3RzIGdldHMgdGhlIGl0ZW1zIGl0IGxhY2tzLiBPdGhlciBrZXlzIHN0YXkgYXMgdGhleSBhcmUuCi0gSXQgcXVvdGVzIGEgbGlzdCBpdGVtIHRoYXQgWUFNTCB3b3VsZCByZWFkIGFzIGEgbWFwcGluZy4KLSBJdCBkb2VzIG5vdCB0b3VjaCB0aGUgYHNjaGVtYWAga2V5LiBBIHByb2plY3QgdGhhdCBzdGlsbCBzYXlzIGBzY2hlbWE6IHNwZWMtZHJpdmVuLWlkc2AgZ2V0cyBhIG5vdGUuIFNldCBgc2NoZW1hOiBzcGVjLWRyaXZlbmAgYnkgaGFuZCBhbmQgZGVsZXRlIGBvcGVuc3BlYy9zY2hlbWFzL3NwZWMtZHJpdmVuLWlkcy9gLgoKIyMgVmVyc2lvbgoKVGhlIHRlbXBsYXRlcyBmb2xsb3cgdGhlIGBzcGVjLWRyaXZlbmAgdGVtcGxhdGVzIG9mIE9wZW5TcGVjIDEuMTQuMyB3aXRoIHRoZSBJRCBwbGFjZWhvbGRlcnMgYWRkZWQuIGB0ZXN0cy9zY2hlbWEvdmFsaWRhdGUuc2hgIGNoZWNrcyB0aGVtIG9uIHVwc3RyZWFtIE9wZW5TcGVjIGluIENJLgo=",
5
+ "schemas/spec-driven-ids/config-fragment.yaml": "IyBzcGVjLWN0eCBmcmFnbWVudCBmb3Igb3BlbnNwZWMvY29uZmlnLnlhbWwuIHNwZWNjdHggaW5pdCAtLXNjaGVtYSBhZGRzIGVhY2ggdG9wLWxldmVsIGtleQojIHRoYXQgdGhlIHByb2plY3QgY29uZmlnIGRvZXMgbm90IGhhdmUgeWV0LiBBIGtleSB0aGF0IGV4aXN0cyBnZXRzIHRoZSBpdGVtcyBpdCBsYWNrcy4KcnVsZXM6CiAgc3BlY3M6CiAgICAtICdFdmVyeSByZXF1aXJlbWVudCBoZWFkZXIgc3RhcnRzIHdpdGggaXRzIElELCBlLmcuICIjIyMgUmVxdWlyZW1lbnQ6IFJFUS1BQkMtMDAxIE5hbWUiLiBHZXQgdGhlIElEIGZyb20gYHNwZWNjdHggaWQgbmV3IFJFUSBBQkNgLicKICAgIC0gJ0V2ZXJ5IHNjZW5hcmlvIGhlYWRlciBzdGFydHMgd2l0aCBpdHMgSUQsIGUuZy4gIiMjIyMgU2NlbmFyaW86IFNDTi1BQkMtMDAxLTEgTmFtZSIuJwogICAgLSAnQSByZXF1aXJlbWVudCBtYXkgZW5kIHdpdGggYSBsaW5lICJSZWZzOiBSRVEtQUJDLTAwMiwgQURSLTAwMSIgdG8gbGluayByZWxhdGVkIElEcy4nCiAgICAtICdSZXF1aXJlbWVudCB0ZXh0IHN0YXlzIHVuZGVyIDUwMCBjaGFyYWN0ZXJzLiBNb3ZlIGRldGFpbCBpbnRvIHNjZW5hcmlvcy4nCiAgICAtICdUaGUgdGVtcGxhdGVzIHdpdGggdGhlIElEIHBsYWNlaG9sZGVycyBhcmUgaW4gb3BlbnNwZWMvdGVtcGxhdGVzL3NwZWMtZHJpdmVuLWlkcy8uIFN0YXJ0IGEgc3BlYyBmcm9tIHNwZWMubWQgYW5kIGEgdGFzayBsaXN0IGZyb20gdGFza3MubWQgdGhlcmUuJwogIGRlc2lnbjoKICAgIC0gJ0VhY2ggZGVjaXNpb24gaXMgb25lIGJ1bGxldCB1bmRlciAiIyMgRGVjaXNpb25zIi4gQWRkIG5ldyBkZWNpc2lvbnMgYXQgdGhlIGVuZC4nCiAgdGFza3M6CiAgICAtICdFdmVyeSB0YXNrIGNpdGVzIGF0IGxlYXN0IG9uZSBSRVEgSUQgaW4gc3F1YXJlIGJyYWNrZXRzLCBlLmcuICJbUkVRLUFCQy0wMDFdIi4nCiAgICAtICdFdmVyeSB0YXNrIHN0YXRlcyBpdHMgdmVyaWZpY2F0aW9uIGFzIGEgY29tbWFuZCBpbiBhIGNvZGUgc3BhbiBhZnRlciAiVmVyaWZ5OiIuJwoKb3BlcmF0aW9uczoKICBhcHBseToKICAgIGd1aWRhbmNlOgogICAgICAtICdTdGFydCBlYWNoIHRhc2sgd2l0aCBgc3BlY2N0eCB0YXNrIHN0YXJ0IDxpZD5gIGFuZCByZWFkIHRoZSBidW5kbGUgaXQgcHJpbnRzIGJlZm9yZSB5b3UgcmVhZCBzcGVjcy4nCiAgICAgIC0gJ1RhZyBjb2RlIHdpdGggdGhlIFJFUSBJRCBpdCBpbXBsZW1lbnRzIChhIGNvbW1lbnQgYC8vIFJFUS1BQkMtMDAxYCkuIFRhZyB0ZXN0cyB3aXRoIGAvLyBDb3ZlcnM6IFJFUS1BQkMtMDAxYC4nCiAgICAgIC0gJ0Nsb3NlIGVhY2ggdGFzayBvbmx5IHdpdGggYHNwZWNjdHggdGFzayBkb25lIDxpZD5gLiBOZXZlciBlZGl0IGEgY2hlY2tib3guIE5ldmVyIHJ1biBgL29wc3g6YXBwbHlgOyBydW4gdGhlIGBzcGVjY3R4LXJ1bmAgc2tpbGwuJwogICAgICAtICdSdW4gYHNwZWNjdHggY2hlY2sgLS1zdHJpY3RgIGFmdGVyIGVhY2ggdGFzayBncm91cC4nCiAgYXJjaGl2ZToKICAgIGd1aWRhbmNlOgogICAgICAtICdSdW4gYHNwZWNjdHggY2hlY2sgLS1zdHJpY3RgIGFuZCBgb3BlbnNwZWMgdmFsaWRhdGUgLS1hbGwgLS1zdHJpY3RgLiBCb3RoIG11c3QgcGFzcyBiZWZvcmUgYXJjaGl2ZS4nCiAgICAgIC0gJ1J1biBgb3BlbnNwZWMgdmFsaWRhdGUgLS1hbGwgLS1zdHJpY3RgIGFnYWluIGFmdGVyIGFyY2hpdmUgYW5kIGJlZm9yZSBwdXNoLicK",
7
6
  "schemas/spec-driven-ids/templates/design.md": "IyBEZXNpZ24KCiMjIENvbnRleHQKCjwhLS0gVGhlIGN1cnJlbnQgc3RhdGUgYW5kIHRoZSBjb25zdHJhaW50cyB0aGF0IHNoYXBlIHRoZSBhcHByb2FjaC4gVGhlIHByb3Bvc2FsIGhvbGRzIHRoZSBtb3RpdmF0aW9uLiAtLT4KCiMjIEdvYWxzIC8gTm9uLUdvYWxzCgoqKkdvYWxzOioqCjwhLS0gV2hhdCB0aGlzIGRlc2lnbiBnaXZlcyAtLT4KCioqTm9uLUdvYWxzOioqCjwhLS0gV2hhdCBzdGF5cyBvdXQgb2Ygc2NvcGUgLS0+CgojIyBEZWNpc2lvbnMKCjwhLS0gT25lIGJ1bGxldCBwZXIgZGVjaXNpb24uIFRoZSBJRCBvZiBhIGRlY2lzaW9uIGlzIDxjaGFuZ2UgbnVtYmVyPi9EPG4+IGJ5IHBvc2l0aW9uLiBBZGQgbmV3IG9uZXMgYXQgdGhlIGVuZC4gLS0+Ci0gPCEtLSBUaGUgZGVjaXNpb24sIHRoZSBhbHRlcm5hdGl2ZSwgYW5kIHdoeS4gLS0+IFJlZnM6IDwhLS0gUkVRLTxDQVA+LU5OTiwgQURSLU5OTiAtLT4KCiMjIFJpc2tzIC8gVHJhZGUtb2ZmcwoKPCEtLSBLbm93biByaXNrcyBhbmQgdGhlIG1pdGlnYXRpb24gZm9yIGVhY2ggLS0+Cg==",
8
7
  "schemas/spec-driven-ids/templates/proposal.md": "IyBQcm9wb3NhbAoKIyMgV2h5Cgo8IS0tIEV4cGxhaW4gdGhlIG1vdGl2YXRpb24gZm9yIHRoaXMgY2hhbmdlLiBXaGF0IHByb2JsZW0gZG9lcyB0aGlzIHNvbHZlPyBXaHkgbm93PyAtLT4KCiMjIFdoYXQgQ2hhbmdlcwoKPCEtLSBEZXNjcmliZSB3aGF0IHdpbGwgY2hhbmdlLiBCZSBzcGVjaWZpYyBhYm91dCBuZXcgY2FwYWJpbGl0aWVzLCBtb2RpZmljYXRpb25zLCBvciByZW1vdmFscy4gLS0+CgojIyBDYXBhYmlsaXRpZXMKCiMjIyBOZXcgQ2FwYWJpbGl0aWVzCjwhLS0gQ2FwYWJpbGl0aWVzIGJlaW5nIGludHJvZHVjZWQuIE5hbWUgZWFjaCBjYXBhYmlsaXR5IGZvciBhIGNvaGVzaXZlIHN5c3RlbQogICAgIGJlaGF2aW9yIHRoYXQgY2FuIG93biByZWxhdGVkIHJlcXVpcmVtZW50cyBhcyB0aGUgc3lzdGVtIGV2b2x2ZXMuIERvIG5vdCBuYW1lCiAgICAgaW1wbGVtZW50YXRpb24gdGFza3Mgb3IgcHJvcG9zYWwgc2VjdGlvbnMuIEF2b2lkIGJyb2FkIGNhdGNoLWFsbCBuYW1lcy4gVXNlCiAgICAga2ViYWItY2FzZSBmb3IgcGF0aCBzZWdtZW50cyB5b3UgaW50cm9kdWNlIChlLmcuLCB1c2VyLWF1dGggb3IgaWRlbnRpdHkvdXNlci1hdXRoKQogICAgIHRoYXQgZm9sbG93IHRoZSBwcm9qZWN0J3MgZXhpc3Rpbmcgc3BlYyBvcmdhbml6YXRpb24uIEVhY2ggY3JlYXRlcwogICAgIHNwZWNzLzxjYXBhYmlsaXR5LXBhdGg+L3NwZWMubWQuIC0tPgotIGA8Y2FwYWJpbGl0eS1wYXRoPmA6IDxicmllZiBkZXNjcmlwdGlvbiBvZiB3aGF0IHRoaXMgY2FwYWJpbGl0eSBjb3ZlcnM+CgojIyMgTW9kaWZpZWQgQ2FwYWJpbGl0aWVzCjwhLS0gRXhpc3RpbmcgY2FwYWJpbGl0aWVzIHdob3NlIFJFUVVJUkVNRU5UUyBhcmUgY2hhbmdpbmcgKG5vdCBqdXN0IGltcGxlbWVudGF0aW9uKS4KICAgICBPbmx5IGxpc3QgaGVyZSBpZiBzcGVjLWxldmVsIGJlaGF2aW9yIGNoYW5nZXMuIEVhY2ggbmVlZHMgYSBkZWx0YSBzcGVjIGZpbGUuCiAgICAgVXNlIHRoZSBleGFjdCBleGlzdGluZyBwYXRoIHVuZGVyIG9wZW5zcGVjL3NwZWNzLy4gTGVhdmUgZW1wdHkgaWYgbm8gcmVxdWlyZW1lbnQKICAgICBjaGFuZ2VzLiBBIGNoYW5nZSB3aXRoIG5vIGNhcGFiaWxpdGllcyBhdCBhbGwgKHB1cmUgcmVmYWN0b3IsIHRvb2xpbmcsIGRvY3MpCiAgICAgbXVzdCBzZXQgYHNraXBfc3BlY3M6IHRydWVgIGluIGl0cyAub3BlbnNwZWMueWFtbCAtIG9wZW5zcGVjIHZhbGlkYXRlIHJlamVjdHMKICAgICBhIHplcm8tZGVsdGEgY2hhbmdlIHdpdGhvdXQgdGhhdCBtYXJrZXIuIERvIG5vdCBpbnZlbnQgYSByZXF1aXJlbWVudCBqdXN0IHRvCiAgICAgc2F0aXNmeSB2YWxpZGF0aW9uLiAtLT4KLSBgPGV4aXN0aW5nLWNhcGFiaWxpdHktcGF0aD5gOiA8d2hhdCByZXF1aXJlbWVudCBpcyBjaGFuZ2luZz4KCiMjIEltcGFjdAoKPCEtLSBBZmZlY3RlZCBjb2RlLCBBUElzLCBkZXBlbmRlbmNpZXMsIHN5c3RlbXMgLS0+Cg==",
9
8
  "schemas/spec-driven-ids/templates/spec.md": "IyBTcGVjIERlbHRhCgojIyBQdXJwb3NlCjwhLS0gTmV3IGNhcGFiaWxpdHkgb25seS4gV3JpdGUgb25lIG9yIHR3byBzZW50ZW5jZXMgb2YgNTAgY2hhcmFjdGVycyBvciBtb3JlLiBEZWxldGUgdGhpcyBzZWN0aW9uIGZvciBhbiBleGlzdGluZyBjYXBhYmlsaXR5LiAtLT4KCiMjIEFEREVEIFJlcXVpcmVtZW50cwoKIyMjIFJlcXVpcmVtZW50OiBSRVEtPENBUD4tTk5OIDwhLS0gcmVxdWlyZW1lbnQgbmFtZSAtLT4KPCEtLSBSZXF1aXJlbWVudCB0ZXh0LiBSZXBsYWNlIFJFUS08Q0FQPi1OTk4gd2l0aCB0aGUgb3V0cHV0IG9mIGBzcGVjY3R4IGlkIG5ldyBSRVEgPENBUD5gLiAtLT4KClJlZnM6IDwhLS0gcmVsYXRlZCBJRHMgc3VjaCBhcyBBRFItMDAxLiBEZWxldGUgdGhpcyBsaW5lIHdoZW4gdGhlcmUgYXJlIG5vbmUuIC0tPgoKIyMjIyBTY2VuYXJpbzogU0NOLTxDQVA+LU5OTi0xIDwhLS0gc2NlbmFyaW8gbmFtZS4gR2V0IHRoZSBJRCBmcm9tIGBzcGVjY3R4IGlkIG5ldyBTQ04gPENBUD4gLS1mb3IgUkVRLTxDQVA+LU5OTmAuIC0tPgotICoqV0hFTioqIDwhLS0gY29uZGl0aW9uIC0tPgotICoqVEhFTioqIDwhLS0gZXhwZWN0ZWQgb3V0Y29tZSAtLT4K",
10
9
  "schemas/spec-driven-ids/templates/tasks.md": "IyBUYXNrcwoKIyMgMS4gPCEtLSBUYXNrIGdyb3VwIG5hbWUgLS0+CgotIFsgXSAxLjEgPCEtLSBUYXNrIGRlc2NyaXB0aW9uIC0tPiBbUkVRLTxDQVA+LU5OTl0gVmVyaWZ5OiBgPCEtLSBjb21tYW5kIC0tPmAKLSBbIF0gMS4yIDwhLS0gVGFzayBkZXNjcmlwdGlvbiAtLT4gW1JFUS08Q0FQPi1OTk5dIFZlcmlmeTogYDwhLS0gY29tbWFuZCAtLT5gCgojIyAyLiA8IS0tIFRhc2sgZ3JvdXAgbmFtZSAtLT4KCi0gWyBdIDIuMSA8IS0tIFRhc2sgZGVzY3JpcHRpb24gLS0+IFtSRVEtPENBUD4tTk5OXSBWZXJpZnk6IGA8IS0tIGNvbW1hbmQgLS0+YAo=",
11
- "skills/specctx-bootstrap/SKILL.md": "LS0tCm5hbWU6IHNwZWNjdHgtYm9vdHN0cmFwCmRlc2NyaXB0aW9uOiBTdGFydCBhIHNlc3Npb24gaW4gYW4gT3BlblNwZWMgcHJvamVjdCB0aGF0IHVzZXMgc3BlYy1jdHguIFVzZSBhdCB0aGUgc3RhcnQgb2YgZXZlcnkgc2Vzc2lvbiwgYW5kIG9uICJzdGFydCIsICJib290c3RyYXAiLCBvciAid2hhdCBzaG91bGQgSSB3b3JrIG9uIi4gTG9hZHMgb25seSB0aGUgc3BlYyB0ZXh0IHRoYXQgdGhlIG5leHQgdGFzayBuZWVkcy4KLS0tCgojIHNwZWNjdHgtYm9vdHN0cmFwCgpMb2FkIHRoZSBtaW5pbXVtIGNvbnRleHQgZm9yIG9uZSB0YXNrLiBSdW4gYHNwZWNjdHhgIGFzIGBucHggc3BlYy1jdHhgIHdoZW4gaXQgaXMgbm90IGluc3RhbGxlZC4KCiMjIFN0ZXBzCgoxLiBSdW4gYHNwZWNjdHggc3RhdHVzYC4gSXQgcmVidWlsZHMgYSBzdGFsZSBpbmRleCBmaXJzdC4gTm90ZSB0aGUgYWN0aXZlIGNoYW5nZSwgdGhlIGN1cnJlbnQgdGFzaywgYW5kIHRoZSBjb3VudCBvZiBvcGVuIHF1ZXN0aW9ucy4gVGhlIGxhc3QgbGluZSBgbmV4dDogPHN0ZXA+YCBuYW1lcyB0aGUgbmV4dCBzdGVwLiBFeGl0IDIgd2l0aCBgbm90IGFuIE9wZW5TcGVjIHByb2plY3RgIG1lYW5zIHRoZSBmb2xkZXIgaGFzIG5vIGBvcGVuc3BlYy9gLiBUZWxsIHRoZSB1c2VyIHRvIHJ1biBgbnB4IC15IEBmaXNzaW9uLWFpL29wZW5zcGVjQGxhdGVzdCBpbml0YCBhbmQgc3RvcC4KMi4gUmVhZCBgLmN0eC9oYW5kb2ZmLm1kYCBpZiBpdCBleGlzdHMuIE5vdGUgYGN1cnJlbnRgLCBgcmVvcGVuZWRgLCBhbmQgYG9wZW5fcXVlc3Rpb25zYC4KMy4gSWYgYHN0YXR1c2AgcHJpbnRzIGBubyBhY3RpdmUgY2hhbmdlYCwgc2hvdyB0aGUgb3BlbiBxdWVzdGlvbnMgdG8gdGhlIHVzZXIuIEFzayB3aGljaCBjaGFuZ2UgdG8gc3RhcnQuIFN0b3AgaGVyZS4KNC4gUGljayB0aGUgdGFzay4gVXNlIGBjdXJyZW50YCBmcm9tIHRoZSBoYW5kb2ZmLCB0aGVuIHRoZSB1c2VyJ3MgbWVzc2FnZSwgdGhlbiB0aGUgb3V0cHV0IG9mIGBzcGVjY3R4IHRhc2sgbmV4dGAuCjUuIFJ1biBgc3BlY2N0eCB0YXNrIHN0YXJ0IDx0YXNrPmAuIEl0IHByaW50cyB0aGUgYnVuZGxlIGZvciB0aGUgUkVRIElEcyBvZiB0aGUgdGFzayBhbmQgc2V0cyB0aGUgY3VycmVudCB0YXNrLgo2LiBSZWFkIHRoZSBidW5kbGUuIEVhY2ggYmxvY2sgc3RhcnRzIHdpdGggYC0tIDxpZD4gfCA8ZmlsZT46PGxpbmU+IHwgPHN0YXR1cz4gfCA8cmVhc29uPmAuIEEgYG1vZGlmaWVkYCBibG9jayBpcyB0aGUgcGVuZGluZyB0ZXh0IG9mIGFuIGFjdGl2ZSBjaGFuZ2UuIFRydXN0IGl0IG92ZXIgdGhlIG1haW4gc3BlYy4KNy4gSWYgdGhlIGJ1bmRsZSBlbmRzIHdpdGggYHRydW5jYXRlZDogTiBlbnRyaWVzIG9taXR0ZWQ6IDxpZHM+YCwgcnVuIGBzcGVjY3R4IGJ1bmRsZSA8aWQ+YCBmb3IgZWFjaCBJRCB0aGF0IHRoZSB0YXNrIG5lZWRzLgo4LiBTYXkgaW4gb25lIGxpbmUgd2hpY2ggdGFzayB5b3UgYXJlIG9uIGFuZCB3aGljaCBJRHMgeW91IGxvYWRlZC4gVGhlbiBzdGFydCB0aGUgd29yay4KCiMjIFJ1bGVzCgotIERvIG5vdCBvcGVuIGBvcGVuc3BlYy9zcGVjcy9gIG9yIGBvcGVuc3BlYy9jaGFuZ2VzLyovc3BlY3MvYCBieSBoYW5kLiBVc2UgYHNwZWNjdHggYnVuZGxlYCBvciBgc3BlY2N0eCB0YXNrIHN0YXJ0YC4KLSBSZWFkIGF0IG1vc3QgMTAsMDAwIGNoYXJhY3RlcnMgb2Ygc3BlYyB0ZXh0IGJlZm9yZSB0aGUgZmlyc3QgY29kZSBlZGl0LgotIFRhZyBjb2RlIHdpdGggYC8vIFJFUS1BQkMtMDAxYCBhbmQgdGVzdHMgd2l0aCBgLy8gQ292ZXJzOiBSRVEtQUJDLTAwMWAuCi0gR2V0IGEgbmV3IElEIGZyb20gYHNwZWNjdHggaWQgbmV3IFJFUSA8Q0FQPmAuIE5ldmVyIGNvdW50IG51bWJlcnMgYnkgaGFuZC4KLSBDbG9zZSB0aGUgdGFzayB3aXRoIHRoZSBgc3BlY2N0eC1kb25lYCBza2lsbC4K",
12
- "skills/specctx-done/SKILL.md": "LS0tCm5hbWU6IHNwZWNjdHgtZG9uZQpkZXNjcmlwdGlvbjogQ2xvc2UgYSB0YXNrIGluIGFuIE9wZW5TcGVjIHByb2plY3QgdGhhdCB1c2VzIHNwZWMtY3R4LiBSdW5zIHRoZSBWZXJpZnkgY29tbWFuZCwgd3JpdGVzIGV2aWRlbmNlLCBzZXRzIHRoZSBjaGVja2JveCwgd3JpdGVzIHRoZSBoYW5kb2ZmLCBhbmQgc2hvd3MgdGhlIG1ldHJpY3MuIFVzZSB3aGVuIHRoZSB3b3JrIG9mIGEgdGFzayBpcyBjb21wbGV0ZSwgb3Igb24gImRvbmUiLCAiY2xvc2UgdGhlIHRhc2siLCBhbmQgImVuZCB0aGUgc2Vzc2lvbiIuCi0tLQoKIyBzcGVjY3R4LWRvbmUKCkNsb3NlIHRoZSBjdXJyZW50IHRhc2sgd2l0aCBldmlkZW5jZS4gUnVuIGBzcGVjY3R4YCBhcyBgbnB4IHNwZWMtY3R4YCB3aGVuIGl0IGlzIG5vdCBpbnN0YWxsZWQuCgojIyBTdGVwcwoKMS4gUnVuIGBzcGVjY3R4IHRhc2sgZG9uZSA8dGFzaz5gLiBJdCBydW5zIHRoZSBgVmVyaWZ5OmAgY29tbWFuZCBvZiB0aGUgdGFzayBpbiB0aGUgcHJvamVjdCByb290LgoyLiBPbiBleGl0IDAgaXQgd3JpdGVzIGAuY3R4L2V2aWRlbmNlLzxjaGFuZ2U+Lzx0YXNrPi5qc29uYCBhbmQgc2V0cyBgW3hdYCBvbiB0aGUgdGFzayBsaW5lLiBOb3RoaW5nIGVsc2UgaW4gYHRhc2tzLm1kYCBjaGFuZ2VzLgozLiBPbiBhIGZhaWx1cmUgaXQgcHJpbnRzIHRoZSBsYXN0IDIwIGxpbmVzIG9mIG91dHB1dCBhbmQgdGhlbiB0aGUgbGluZSBgVmVyaWZ5IGZhaWxlZCAoZXhpdCA8bj4pLiBUaGUgdGFzayBzdGF5cyBvcGVuLmAgSXQgZXhpdHMgMS4gRml4IHRoZSBjYXVzZSBhbmQgcnVuIHN0ZXAgMSBhZ2Fpbi4KNC4gSWYgdGhlIHRhc2sgaGFzIHByb3NlIGFmdGVyIGBWZXJpZnk6YCBhbmQgbm8gY29tbWFuZCwgcnVuIGBzcGVjY3R4IHRhc2sgZG9uZSA8dGFzaz4gLS1tYW51YWwgIjx3aGF0IHlvdSBjaGVja2VkPiJgLgo1LiBBZnRlciB0aGUgbGFzdCB0YXNrIG9mIGEgZ3JvdXAsIHJ1biBgc3BlY2N0eCBjaGVjayAtLXN0cmljdGAuIEZpeCBldmVyeSBmaW5kaW5nIGJlZm9yZSB0aGUgbmV4dCBncm91cC4KNi4gUnVuIGBzcGVjY3R4IGhhbmRvZmYgd3JpdGVgLiBJdCB3cml0ZXMgYC5jdHgvaGFuZG9mZi5tZGAgZnJvbSB0aGUgaW5kZXgsIHRoZSBldmlkZW5jZSwgYW5kIHRoZSBvcGVuIHF1ZXN0aW9ucy4KNy4gUnVuIGBzcGVjY3R4IHN0YXRzIC0tY2hhbmdlIDxjaGFuZ2U+YC4gUmVwb3J0IHRoZSBmaXZlIG1ldHJpY3Mgb2YgdGhlIGNoYW5nZSBpbiBvbmUgbGluZSBlYWNoLgo4LiBDb21taXQgdGhlIHdvcmsgdG9nZXRoZXIgd2l0aCBgLmN0eC9gLiBMZWF2ZSBgLmN0eC9pbmRleC5qc29uYCBvdXQgb2YgZ2l0LgoKIyMgUnVsZXMKCi0gTmV2ZXIgdGljayBhIGNoZWNrYm94IGJ5IGhhbmQuIGBjaGVjayAtLXN0cmljdGAgcmVwb3J0cyBhIHRpY2tlZCB0YXNrIHdpdGggbm8gZXZpZGVuY2UgYXMgYGRvbmUtd2l0aG91dC1ldmlkZW5jZWAuCi0gSWYgYSBzcGVjIGNoYW5nZWQgYWZ0ZXIgeW91IGNsb3NlZCBhIHRhc2ssIHJ1biBgc3BlY2N0eCB0YXNrIHJlb3BlbiA8dGFzaz4gIjxyZWFzb24+ImAuCi0gVG8gbGVhdmUgYSBxdWVzdGlvbiBmb3IgdGhlIG5leHQgc2Vzc2lvbiwgcnVuIGBzcGVjY3R4IGhhbmRvZmYgYXNrICI8cXVlc3Rpb24+ImAgYmVmb3JlIHN0ZXAgNi4K",
13
- "skills/specctx-next/SKILL.md": "LS0tCm5hbWU6IHNwZWNjdHgtbmV4dApkZXNjcmlwdGlvbjogUGljayBhbmQgc3RhcnQgdGhlIG5leHQgdGFzayBpbiB0aGUgbWlkZGxlIG9mIGEgc2Vzc2lvbiBpbiBhbiBPcGVuU3BlYyBwcm9qZWN0IHRoYXQgdXNlcyBzcGVjLWN0eC4gVXNlIGFmdGVyIHlvdSBjbG9zZSBhIHRhc2ssIG9yIG9uICJuZXh0IHRhc2siIGFuZCAid2hhdCBpcyBuZXh0Ii4KLS0tCgojIHNwZWNjdHgtbmV4dAoKTW92ZSB0byB0aGUgbmV4dCBvcGVuIHRhc2suIFJ1biBgc3BlY2N0eGAgYXMgYG5weCBzcGVjLWN0eGAgd2hlbiBpdCBpcyBub3QgaW5zdGFsbGVkLgoKIyMgU3RlcHMKCjEuIFJ1biBgc3BlY2N0eCB0YXNrIG5leHRgLiBJdCBwcmludHMgdGhlIHRhc2sgSUQgYW5kIHRleHQsIHRoZW4gYHJlcXM6YCBhbmQgYHZlcmlmeTpgLgoyLiBJZiBpdCBwcmludHMgYG5vIG9wZW4gdGFzay4gRXZlcnkgdGFzayBpbiB0aGUgYWN0aXZlIGNoYW5nZXMgaXMgZG9uZS4gTmV4dDogYXJjaGl2ZSA8Y2hhbmdlPi5gLCBldmVyeSB0YXNrIG9mIHRoZSBhY3RpdmUgY2hhbmdlcyBoYXMgaXRzIGNoZWNrYm94IHNldC4gUnVuIGBzcGVjY3R4IHN0YXR1c2AuIEl0cyBsYXN0IGxpbmUgaXMgYG5leHQ6IGFyY2hpdmUgPGNoYW5nZT5gLiBUZWxsIHRoZSB1c2VyIHRoYXQgdGhlIGNoYW5nZSBpcyByZWFkeSBmb3IgYHNwZWNjdHggY2hlY2sgLS1zdHJpY3RgIGFuZCBhcmNoaXZlLiBTdG9wIGhlcmUuCjMuIFJ1biBgc3BlY2N0eCB0YXNrIHN0YXJ0IDx0YXNrPmAuIEl0IHByaW50cyB0aGUgYnVuZGxlIGZvciB0aGUgUkVRIElEcyBvZiB0aGUgdGFzayBhbmQgc2V0cyB0aGUgY3VycmVudCB0YXNrIGluIGAuY3R4L2N1cnJlbnQuanNvbmAuCjQuIFJlYWQgdGhlIGJ1bmRsZS4gUmVxdWVzdCBhbiBvbWl0dGVkIElEIHdpdGggYHNwZWNjdHggYnVuZGxlIDxpZD5gIG9ubHkgd2hlbiB0aGUgdGFzayBuZWVkcyBpdC4KNS4gUnVuIGBzcGVjY3R4IHRhc2sgdmVyaWZ5IDx0YXNrPmAgb25jZSBiZWZvcmUgdGhlIHdvcmsuIEl0IHJ1bnMgdGhlIGBWZXJpZnk6YCBjb21tYW5kIGFuZCB3cml0ZXMgbm90aGluZy4gQSBmYWlsdXJlIG5vdyBzaG93cyB3aGF0IHRoZSB3b3JrIG11c3QgZml4Lgo2LiBTYXkgaW4gb25lIGxpbmUgd2hpY2ggdGFzayB5b3UgYXJlIG9uLiBUaGVuIHN0YXJ0IHRoZSB3b3JrLgoKIyMgUnVsZXMKCi0gVGFrZSB0aGUgdGFza3MgaW4gdGhlIG9yZGVyIHRoYXQgYHNwZWNjdHggdGFzayBuZXh0YCBnaXZlcy4gRWFybGllciB0YXNrcyBpbiBhIGdyb3VwIGNvbWUgZmlyc3QuCi0gQSBxdWVzdGlvbiB0aGF0IGJsb2NrcyB5b3UgZ29lcyB0byBgc3BlY2N0eCBoYW5kb2ZmIGFzayAiPHF1ZXN0aW9uPiJgLiBUaGVuIGNvbnRpbnVlIHdpdGggd2hhdCB5b3UgY2FuIGRvLgotIENsb3NlIHRoZSB0YXNrIHdpdGggdGhlIGBzcGVjY3R4LWRvbmVgIHNraWxsLgo=",
10
+ "skills/specctx-bootstrap/SKILL.md": "LS0tCm5hbWU6IHNwZWNjdHgtYm9vdHN0cmFwCmRlc2NyaXB0aW9uOiBTdGFydCBhIHNlc3Npb24gaW4gYW4gT3BlblNwZWMgcHJvamVjdCB0aGF0IHVzZXMgc3BlYy1jdHguIFVzZSBhdCB0aGUgc3RhcnQgb2YgZXZlcnkgc2Vzc2lvbiwgYW5kIG9uICJzdGFydCIsICJib290c3RyYXAiLCBvciAid2hhdCBzaG91bGQgSSB3b3JrIG9uIi4gTG9hZHMgb25seSB0aGUgc3BlYyB0ZXh0IHRoYXQgdGhlIG5leHQgdGFzayBuZWVkcy4KLS0tCgpUaGlzIHNraWxsIGlzIG5vdyBgc3BlY2N0eC1ydW5gLiBSdW4gaXQuCg==",
11
+ "skills/specctx-done/SKILL.md": "LS0tCm5hbWU6IHNwZWNjdHgtZG9uZQpkZXNjcmlwdGlvbjogQ2xvc2UgYSB0YXNrIGluIGFuIE9wZW5TcGVjIHByb2plY3QgdGhhdCB1c2VzIHNwZWMtY3R4LiBSdW5zIHRoZSBWZXJpZnkgY29tbWFuZCwgd3JpdGVzIGV2aWRlbmNlLCBzZXRzIHRoZSBjaGVja2JveCwgd3JpdGVzIHRoZSBoYW5kb2ZmLCBhbmQgc2hvd3MgdGhlIG1ldHJpY3MuIFVzZSB3aGVuIHRoZSB3b3JrIG9mIGEgdGFzayBpcyBjb21wbGV0ZSwgb3Igb24gImRvbmUiLCAiY2xvc2UgdGhlIHRhc2siLCBhbmQgImVuZCB0aGUgc2Vzc2lvbiIuCi0tLQoKVGhpcyBza2lsbCBpcyBub3cgYHNwZWNjdHgtcnVuYC4gUnVuIGl0Lgo=",
12
+ "skills/specctx-next/SKILL.md": "LS0tCm5hbWU6IHNwZWNjdHgtbmV4dApkZXNjcmlwdGlvbjogUGljayBhbmQgc3RhcnQgdGhlIG5leHQgdGFzayBpbiB0aGUgbWlkZGxlIG9mIGEgc2Vzc2lvbiBpbiBhbiBPcGVuU3BlYyBwcm9qZWN0IHRoYXQgdXNlcyBzcGVjLWN0eC4gVXNlIGFmdGVyIHlvdSBjbG9zZSBhIHRhc2ssIG9yIG9uICJuZXh0IHRhc2siIGFuZCAid2hhdCBpcyBuZXh0Ii4KLS0tCgpUaGlzIHNraWxsIGlzIG5vdyBgc3BlY2N0eC1ydW5gLiBSdW4gaXQuCg==",
13
+ "skills/specctx-run/SKILL.md": "LS0tCm5hbWU6IHNwZWNjdHgtcnVuCmRlc2NyaXB0aW9uOiBSdW4gdGhlIHNwZWMtY3R4IGxvb3AgaW4gYW4gT3BlblNwZWMgcHJvamVjdC4gVXNlIG9uICJydW4iLCAiY29udGludWUiLCAibmV4dCB0YXNrIiwgImJ1aWxkIHRoaXMiLCAiY2Fycnkgb24iLCBhbmQgb24gYSBmaXJzdCBtZXNzYWdlIHRoYXQgZGVzY3JpYmVzIGEgY2hhbmdlIHRvIGJ1aWxkLiBUaGUgZW5naW5lIHBpY2tzIHRoZSBuZXh0IGFjdGlvbi4gVGhlIHNraWxsIGFjdHMgb24gaXQgdW50aWwgdGhlIGNoYW5nZSByZWFjaGVzIHRoZSBhcmNoaXZlIG9yIGEgaHVtYW4gbXVzdCBkZWNpZGUuCi0tLQoKIyBzcGVjY3R4LXJ1bgoKUnVuIGBzcGVjY3R4YCBhcyBgbnB4IHNwZWMtY3R4YCB3aGVuIGl0IGlzIG5vdCBpbnN0YWxsZWQuIGBvcGVuc3BlY2AgaXMgdGhlIGNvbW1hbmQgaW4gYFtnYXRlXSBvcGVuc3BlY2Agb2YgYHNwZWMtY3R4LnRvbWxgLgoKIyMgVGhlIGxvb3AKCjEuIFJ1biBgc3BlY2N0eCBuZXh0IC0tanNvbmAuIFJlYWQgYGFjdGlvbmAsIGBjaGFuZ2VgIChgPGM+YCksIGB0YXNrYCAoYDx0PmApLCBgY29tbWFuZGAsIGByZWFzb25gLCBhbmQgYGh1bWFuYC4KMi4gQWN0IG9uIGBhY3Rpb25gIGFzIHRoZSB0YWJsZSBiZWxvdyBzYXlzLgozLiBSdW4gYHNwZWNjdHggaGFuZG9mZiB3cml0ZWAuCjQuIFJlcGVhdCBmcm9tIHN0ZXAgMSB1bnRpbCBgYWN0aW9uYCBpcyBgc3RvcGAgb3IgYGh1bWFuYCBpcyB0cnVlLgoKIyMgQWN0aW9ucwoKLSBgcGxhbmA6IGZvbGxvdyB0aGUgdXBzdHJlYW0gYG9wZW5zcGVjLXByb3Bvc2VgIHNraWxsIGZvciB0aGUgY2hhbmdlIGluIGBjb21tYW5kYC4gVGFrZSBldmVyeSBJRCBmcm9tIGBzcGVjY3R4IGlkIG5ldyBSRVEgPENBUD5gIGFuZCBgc3BlY2N0eCBpZCBuZXcgU0NOIDxDQVA+IC0tZm9yIDxSRVE+YC4gR2l2ZSBldmVyeSB0YXNrIGEgYFtSRVEtLi4uXWAgY2l0YXRpb24gYW5kIGEgYFZlcmlmeTpgIGNvZGUgc3Bhbi4gVGhlbiBydW4gYHNwZWNjdHggY2hlY2sgLS1zdHJpY3RgIGFuZCBgb3BlbnNwZWMgdmFsaWRhdGUgPGM+IC0tc3RyaWN0YC4gRml4IGV2ZXJ5IGZpbmRpbmcuIFN0b3AgYW5kIHNob3cgdGhlIHBsYW4gdG8gdGhlIHVzZXIuIFRoaXMgaXMgdGhlIHBsYW4gc3RvcC4KLSBgY2l0ZWA6IHJ1biBgc3BlY2N0eCBxdWVyeSAtLWNoYW5nZSA8Yz4gLS1raW5kIHJlcWAuIEFkZCB0aGUgYFtSRVEtLi4uXWAgY2l0YXRpb24gYW5kIGEgYFZlcmlmeTpgIGNvZGUgc3BhbiB0byB0aGUgdGFzayBsaW5lIG5hbWVkIGluIGB0YXNrYC4gUnVuIGBzcGVjY3R4IGNoZWNrYC4gQ29udGludWUuCi0gYHN0YXJ0YDogcnVuIGBzcGVjY3R4IHRhc2sgc3RhcnQgPHQ+YC4gUmVhZCB0aGUgYnVuZGxlIGl0IHByaW50cy4gQ29udGludWUuCi0gYHdvcmtgOiBpbXBsZW1lbnQgdGhlIHRhc2suIFRhZyBjb2RlIHdpdGggYC8vIFJFUS0uLi5gLiBUYWcgdGVzdHMgd2l0aCBgLy8gQ292ZXJzOiBSRVEtLi4uYC4gVGhlbiBydW4gYHNwZWNjdHggdGFzayBkb25lIDx0PmAuCi0gYGZpeGA6IHJlYWQgYHJlYXNvbmAuIEl0IGhvbGRzIHRoZSB0YWlsIG9mIHRoZSBmYWlsZWQgVmVyaWZ5IG91dHB1dC4gRml4IHRoZSBjYXVzZS4gUnVuIGBzcGVjY3R4IHRhc2sgZG9uZSA8dD5gIGFnYWluLgotIGByZXBhaXJgOiBydW4gYHNwZWNjdHggdGFzayBkb25lIDx0PmAuIEl0IHJ1bnMgVmVyaWZ5IGZvciBhIHRpY2tlZCB0YXNrIHRoYXQgaGFzIG5vIGV2aWRlbmNlLgotIGBnYXRlYDogcnVuIGBzcGVjY3R4IGdhdGUgLS1zdHJpY3RgLiBGaXggZXZlcnkgZmluZGluZy4gUnVuIGl0IGFnYWluIHVudGlsIGl0IGV4aXRzIDAuCi0gYGFyY2hpdmVgOiB3aGVuIGBodW1hbmAgaXMgdHJ1ZSwgc3RvcCBhbmQgYXNrIHRoZSB1c2VyIGluIG9uZSBsaW5lIHdoZXRoZXIgdG8gYXJjaGl2ZSBgPGM+YC4gV2hlbiBgaHVtYW5gIGlzIGZhbHNlLCBmb2xsb3cgdGhlIHVwc3RyZWFtIGBvcGVuc3BlYy1hcmNoaXZlLWNoYW5nZWAgc2tpbGwuIFRoZW4gcnVuIGBvcGVuc3BlYyB2YWxpZGF0ZSAtLWFsbCAtLXN0cmljdGAsIGBzcGVjY3R4IGNoZWNrIC0tc3RyaWN0YCwgYW5kIGBzcGVjY3R4IGhhbmRvZmYgd3JpdGVgLgotIGBhc2tgOiBwcmludCBgcmVhc29uYC4gSXQgaXMgdGhlIG9wZW4gcXVlc3Rpb24uIFN0b3AuIFRoZSB1c2VyIGFuc3dlcnMgd2l0aCBgc3BlY2N0eCBoYW5kb2ZmIHJlc29sdmUgPG4+ICI8YW5zd2VyPiJgLgotIGBzdG9wYDogcHJpbnQgYHJlYXNvbmAuIFN0b3AuCgojIyBSdWxlcwoKLSBOZXZlciB0aWNrIGEgY2hlY2tib3ggYnkgaGFuZC4gYHNwZWNjdHggdGFzayBkb25lYCBpcyB0aGUgb25seSB3YXkgYSB0YXNrIGNsb3Nlcy4KLSBOZXZlciB1c2UgYC0tbWFudWFsYCBvbiBhIHRhc2sgd2l0aCBhIFZlcmlmeSBjb21tYW5kLgotIE5ldmVyIGNhbGwgYC9vcHN4OmFwcGx5YC4gVGhpcyBza2lsbCByZXBsYWNlcyBpdC4KLSBOZXZlciByZWFkIGBvcGVuc3BlYy9zcGVjcy9gIG9yIGBvcGVuc3BlYy9jaGFuZ2VzLyovc3BlY3MvYCBkaXJlY3RseS4gVXNlIHRoZSBidW5kbGUgZnJvbSBgdGFzayBzdGFydGAgb3IgYHNwZWNjdHggYnVuZGxlIDxpZD5gLgotIFN0b3Agb24gYW55IGBhY3Rpb25gIG5vdCBpbiB0aGUgbGlzdCBhYm92ZS4gUHJpbnQgdGhlIG9iamVjdCBhbmQgYXNrIHRoZSB1c2VyLgotIEtlZXAgbm8gc3RhdGUgaW4geW91ciBjb250ZXh0LiBBIG5ldyBzZXNzaW9uIHN0YXJ0cyB0aGUgc2FtZSBsb29wIGFnYWluIHdpdGggc3RlcCAxLgo=",
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,81 @@
1
+ // REQ-ADOPT-008 the baseline against the merge base: new entries fail the gate (020/D2).
2
+ import { spawnSync } from "node:child_process";
3
+ import { parseLintLine } from "../lint/counts.js";
4
+ import { cmpStr } from "../util/pystr.js";
5
+ import { BASELINE_PATH } from "./baseline.js";
6
+ /**
7
+ * Lines of `current` that are new debt against `base`.
8
+ * A line that the base lacks is new. A `lint <file> <rule> <count>` line with a count above
9
+ * the base line of the same key is new, and reads `lint <file> <rule> <count> (base <n>)`.
10
+ */
11
+ export function newEntries(current, base) {
12
+ const baseSet = new Set(base);
13
+ const baseLint = new Map();
14
+ for (const b of base) {
15
+ const l = parseLintLine(b);
16
+ if (l)
17
+ baseLint.set(l.key, l.count);
18
+ }
19
+ const out = [];
20
+ for (const c of current) {
21
+ if (baseSet.has(c))
22
+ continue;
23
+ const l = parseLintLine(c);
24
+ if (l) {
25
+ const n = baseLint.get(l.key);
26
+ if (n === undefined)
27
+ out.push(c);
28
+ else if (l.count > n)
29
+ out.push(`${c} (base ${n})`);
30
+ continue;
31
+ }
32
+ out.push(c);
33
+ }
34
+ return [...new Set(out)].sort(cmpStr);
35
+ }
36
+ function git(root, args) {
37
+ const r = spawnSync("git", args, { cwd: root, encoding: "utf8" });
38
+ return { ok: r.status === 0, out: (r.stdout ?? "").trim() };
39
+ }
40
+ /** `.ctx/baseline.json` at `git merge-base HEAD <base>`, or the reason to skip the step. */
41
+ export function baseAtMergeBase(root, base) {
42
+ const inside = git(root, ["rev-parse", "--is-inside-work-tree"]);
43
+ if (!inside.ok || inside.out !== "true")
44
+ return { skip: "no git repository" };
45
+ const mb = git(root, ["merge-base", "HEAD", base]);
46
+ if (!mb.ok || !mb.out)
47
+ return { skip: `no merge base with ${base}` };
48
+ const sha = mb.out;
49
+ const show = spawnSync("git", ["show", `${sha}:${BASELINE_PATH}`], { cwd: root, encoding: "utf8" });
50
+ if (show.status !== 0)
51
+ return { skip: `no ${BASELINE_PATH} at ${sha.slice(0, 7)}` };
52
+ let v;
53
+ try {
54
+ v = JSON.parse(show.stdout);
55
+ }
56
+ catch {
57
+ return { skip: `no ${BASELINE_PATH} at ${sha.slice(0, 7)}` };
58
+ }
59
+ if (!Array.isArray(v) || !v.every((x) => typeof x === "string"))
60
+ return { skip: `no ${BASELINE_PATH} at ${sha.slice(0, 7)}` };
61
+ return { lines: v, sha };
62
+ }
63
+ /** True when the subject starts with `baseline:`, the same pattern as REQ-GOV-007 for `release:`. */
64
+ export const isBaselineSubject = (subject) => subject.trimStart().startsWith("baseline:");
65
+ /**
66
+ * The subject of HEAD. On a merge commit, such as a pull request checkout in CI, the subject of the
67
+ * second parent counts too, because that is the commit the author wrote (020/D4).
68
+ */
69
+ export function headSubjects(root) {
70
+ const head = git(root, ["log", "-1", "--format=%s", "HEAD"]);
71
+ if (!head.ok)
72
+ return [];
73
+ const out = [head.out];
74
+ const parents = git(root, ["rev-list", "--parents", "-n", "1", "HEAD"]);
75
+ if (parents.ok && parents.out.split(/\s+/).length > 2) {
76
+ const second = git(root, ["log", "-1", "--format=%s", "HEAD^2"]);
77
+ if (second.ok)
78
+ out.push(second.out);
79
+ }
80
+ return out;
81
+ }