claude-review-tool 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +17 -0
- package/dist/args.js +28 -0
- package/dist/args.js.map +1 -0
- package/dist/capture-schema.js +265 -0
- package/dist/capture-schema.js.map +1 -0
- package/dist/captures.js +86 -0
- package/dist/captures.js.map +1 -0
- package/dist/cli.js +137 -0
- package/dist/cli.js.map +1 -0
- package/dist/early.js +1 -0
- package/dist/errors.js +13 -0
- package/dist/errors.js.map +1 -0
- package/dist/http.js +82 -0
- package/dist/http.js.map +1 -0
- package/dist/init.js +52 -0
- package/dist/init.js.map +1 -0
- package/dist/inject.js +104 -0
- package/dist/inject.js.map +1 -0
- package/dist/intake-message.js +130 -0
- package/dist/intake-message.js.map +1 -0
- package/dist/intake.md +35 -0
- package/dist/overlay.js +215 -0
- package/dist/permissions.js +96 -0
- package/dist/permissions.js.map +1 -0
- package/dist/project.js +19 -0
- package/dist/project.js.map +1 -0
- package/dist/proxy.js +242 -0
- package/dist/proxy.js.map +1 -0
- package/dist/serve.js +114 -0
- package/dist/serve.js.map +1 -0
- package/dist/session-events.js +8 -0
- package/dist/session-events.js.map +1 -0
- package/dist/session-stub.js +232 -0
- package/dist/session-stub.js.map +1 -0
- package/dist/session.js +404 -0
- package/dist/session.js.map +1 -0
- package/dist/sessions.js +293 -0
- package/dist/sessions.js.map +1 -0
- package/dist/target.js +72 -0
- package/dist/target.js.map +1 -0
- package/dist/tasks.js +573 -0
- package/dist/tasks.js.map +1 -0
- package/package.json +51 -0
package/dist/tasks.js
ADDED
|
@@ -0,0 +1,573 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task store (PRD §6.5: F-31 ids, F-32 file format, F-33 listing, F-34 index; F-23 asset move).
|
|
3
|
+
*
|
|
4
|
+
* A task is `<tasksDir>/<ID>-<slug>.md`: YAML frontmatter (a fixed set of scalar/list keys — the
|
|
5
|
+
* tiny parser below handles exactly the subset the format uses) followed by seven `##` sections in
|
|
6
|
+
* a fixed order. IDs are allocated by scanning the directory for the highest existing one, so
|
|
7
|
+
* there is no counter file to conflict on. `README.md` in the same directory is a generated table
|
|
8
|
+
* and is rewritten whenever a task is created or `crt tasks` notices it is stale.
|
|
9
|
+
* Everything is written with `\n` line endings.
|
|
10
|
+
*/
|
|
11
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
12
|
+
import { basename, join, relative, resolve } from "node:path";
|
|
13
|
+
import { validateCaptureBundle } from "./capture-schema.js";
|
|
14
|
+
import { capturesDir } from "./captures.js";
|
|
15
|
+
export const TASK_STATUSES = ["backlog", "in_progress", "review", "done", "blocked"];
|
|
16
|
+
export const TASK_PRIORITIES = ["low", "normal", "high"];
|
|
17
|
+
export const SECTION_NAMES = ["Summary", "Context", "Evidence", "Ask", "Definition of Done", "Notes", "Log"];
|
|
18
|
+
export const FRONTMATTER_KEYS = [
|
|
19
|
+
"id",
|
|
20
|
+
"title",
|
|
21
|
+
"status",
|
|
22
|
+
"priority",
|
|
23
|
+
"created",
|
|
24
|
+
"updated",
|
|
25
|
+
"url",
|
|
26
|
+
"route",
|
|
27
|
+
"session",
|
|
28
|
+
"tags",
|
|
29
|
+
"files",
|
|
30
|
+
];
|
|
31
|
+
export const TASK_ID_RE = /^CRT-\d{4}$/;
|
|
32
|
+
export const TASK_FILE_RE = /^(CRT-\d{4})-([a-z0-9-]+)\.md$/;
|
|
33
|
+
export const MAX_SLUG_LENGTH = 40;
|
|
34
|
+
export const ASSETS_DIRNAME = "assets";
|
|
35
|
+
export const INDEX_FILENAME = "README.md";
|
|
36
|
+
export class TaskFormatError extends Error {
|
|
37
|
+
errors;
|
|
38
|
+
constructor(errors, what = "task") {
|
|
39
|
+
super(`invalid ${what}: ${errors.slice(0, 5).join("; ")}${errors.length > 5 ? ` (+${errors.length - 5} more)` : ""}`);
|
|
40
|
+
this.name = "TaskFormatError";
|
|
41
|
+
this.errors = errors;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// ---------------------------------------------------------------------------------------------
|
|
45
|
+
// Time
|
|
46
|
+
// ---------------------------------------------------------------------------------------------
|
|
47
|
+
/** `2026-09-14T10:32:00+08:00`: local wall-clock time with the machine's UTC offset (F-32). */
|
|
48
|
+
export function localIso(d = new Date(), seconds = true) {
|
|
49
|
+
const p = (n) => String(n).padStart(2, "0");
|
|
50
|
+
const off = -d.getTimezoneOffset();
|
|
51
|
+
const sign = off >= 0 ? "+" : "-";
|
|
52
|
+
const abs = Math.abs(off);
|
|
53
|
+
const tz = `${sign}${p(Math.floor(abs / 60))}:${p(abs % 60)}`;
|
|
54
|
+
const hm = `${p(d.getHours())}:${p(d.getMinutes())}`;
|
|
55
|
+
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}T${hm}${seconds ? `:${p(d.getSeconds())}` : ""}${tz}`;
|
|
56
|
+
}
|
|
57
|
+
/** Log-entry stamp: minute precision, per the F-32 example. */
|
|
58
|
+
export function logStamp(d = new Date()) {
|
|
59
|
+
return localIso(d, false);
|
|
60
|
+
}
|
|
61
|
+
export function parseFrontmatter(text) {
|
|
62
|
+
const m = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(text);
|
|
63
|
+
if (!m)
|
|
64
|
+
return null;
|
|
65
|
+
const data = {};
|
|
66
|
+
for (const rawLine of m[1].split(/\r?\n/)) {
|
|
67
|
+
const line = stripComment(rawLine);
|
|
68
|
+
if (!line.trim())
|
|
69
|
+
continue;
|
|
70
|
+
const kv = /^([A-Za-z_][\w-]*):(?:\s+(.*))?$/.exec(line);
|
|
71
|
+
if (!kv)
|
|
72
|
+
continue;
|
|
73
|
+
const key = kv[1];
|
|
74
|
+
const value = (kv[2] ?? "").trim();
|
|
75
|
+
data[key] = value.startsWith("[") ? parseFlowList(value) : parseScalar(value);
|
|
76
|
+
}
|
|
77
|
+
return { data, body: text.slice(m[0].length) };
|
|
78
|
+
}
|
|
79
|
+
/** Drop a trailing ` # comment` that is not inside quotes. */
|
|
80
|
+
function stripComment(line) {
|
|
81
|
+
let quote = null;
|
|
82
|
+
for (let i = 0; i < line.length; i++) {
|
|
83
|
+
const c = line[i];
|
|
84
|
+
if (quote) {
|
|
85
|
+
if (c === quote)
|
|
86
|
+
quote = null;
|
|
87
|
+
}
|
|
88
|
+
else if (c === '"' || c === "'") {
|
|
89
|
+
quote = c;
|
|
90
|
+
}
|
|
91
|
+
else if (c === "#" && (i === 0 || /\s/.test(line[i - 1]))) {
|
|
92
|
+
return line.slice(0, i);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return line;
|
|
96
|
+
}
|
|
97
|
+
function parseScalar(value) {
|
|
98
|
+
if (value === "" || value === "null" || value === "~")
|
|
99
|
+
return null;
|
|
100
|
+
if (value.startsWith('"') && value.endsWith('"') && value.length >= 2) {
|
|
101
|
+
try {
|
|
102
|
+
return JSON.parse(value);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
return value.slice(1, -1);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (value.startsWith("'") && value.endsWith("'") && value.length >= 2)
|
|
109
|
+
return value.slice(1, -1).replace(/''/g, "'");
|
|
110
|
+
return value;
|
|
111
|
+
}
|
|
112
|
+
function parseFlowList(value) {
|
|
113
|
+
const inner = value.replace(/^\[/, "").replace(/\]\s*$/, "");
|
|
114
|
+
const items = [];
|
|
115
|
+
let cur = "";
|
|
116
|
+
let quote = null;
|
|
117
|
+
const push = () => {
|
|
118
|
+
const v = cur.trim();
|
|
119
|
+
if (v !== "")
|
|
120
|
+
items.push(parseScalar(v));
|
|
121
|
+
cur = "";
|
|
122
|
+
};
|
|
123
|
+
for (const c of inner) {
|
|
124
|
+
if (quote) {
|
|
125
|
+
cur += c;
|
|
126
|
+
if (c === quote)
|
|
127
|
+
quote = null;
|
|
128
|
+
}
|
|
129
|
+
else if (c === '"' || c === "'") {
|
|
130
|
+
quote = c;
|
|
131
|
+
cur += c;
|
|
132
|
+
}
|
|
133
|
+
else if (c === ",") {
|
|
134
|
+
push();
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
cur += c;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
push();
|
|
141
|
+
return items;
|
|
142
|
+
}
|
|
143
|
+
/** Quote a scalar only when YAML would otherwise misread it. */
|
|
144
|
+
export function yamlScalar(value) {
|
|
145
|
+
if (value === null)
|
|
146
|
+
return "null";
|
|
147
|
+
if (value === "" || /^[\s"'#&*!|>%@`[{\]}-]|: |#|\s$|^(null|~|true|false|yes|no|on|off)$|^[\d.+-]+$/i.test(value) || /[\r\n\t]/.test(value)) {
|
|
148
|
+
return JSON.stringify(value);
|
|
149
|
+
}
|
|
150
|
+
return value;
|
|
151
|
+
}
|
|
152
|
+
function yamlList(items) {
|
|
153
|
+
return `[${items.map(yamlScalar).join(", ")}]`;
|
|
154
|
+
}
|
|
155
|
+
// ---------------------------------------------------------------------------------------------
|
|
156
|
+
// Parse / validate / serialise
|
|
157
|
+
// ---------------------------------------------------------------------------------------------
|
|
158
|
+
const ISO_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(:\d{2})?(\.\d+)?(Z|[+-]\d{2}:\d{2})$/;
|
|
159
|
+
/**
|
|
160
|
+
* Validate a task file's text against F-32. `fileName` (optional) lets the id/slug be checked
|
|
161
|
+
* against the file name. Returns an empty list for a well-formed task.
|
|
162
|
+
*/
|
|
163
|
+
export function validateTaskText(text, fileName) {
|
|
164
|
+
const errors = [];
|
|
165
|
+
const fm = parseFrontmatter(text);
|
|
166
|
+
if (!fm)
|
|
167
|
+
return ["missing YAML frontmatter (--- … ---) at the top of the file"];
|
|
168
|
+
const d = fm.data;
|
|
169
|
+
const str = (key, nullable = false) => {
|
|
170
|
+
const v = d[key];
|
|
171
|
+
if (v === undefined) {
|
|
172
|
+
errors.push(`frontmatter: missing "${key}"`);
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
if (Array.isArray(v)) {
|
|
176
|
+
errors.push(`frontmatter: "${key}" must be a scalar`);
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
if (v === null && !nullable)
|
|
180
|
+
errors.push(`frontmatter: "${key}" must not be empty`);
|
|
181
|
+
return v;
|
|
182
|
+
};
|
|
183
|
+
const list = (key) => {
|
|
184
|
+
const v = d[key];
|
|
185
|
+
if (v === undefined)
|
|
186
|
+
errors.push(`frontmatter: missing "${key}"`);
|
|
187
|
+
else if (!Array.isArray(v))
|
|
188
|
+
errors.push(`frontmatter: "${key}" must be a list like [a, b]`);
|
|
189
|
+
else if (v.some((x) => x === null))
|
|
190
|
+
errors.push(`frontmatter: "${key}" has an empty item`);
|
|
191
|
+
};
|
|
192
|
+
const id = str("id");
|
|
193
|
+
if (id !== null && !TASK_ID_RE.test(id))
|
|
194
|
+
errors.push(`frontmatter: id "${id}" is not CRT-NNNN`);
|
|
195
|
+
const title = str("title");
|
|
196
|
+
if (title !== null && title.trim() === "")
|
|
197
|
+
errors.push("frontmatter: title is empty");
|
|
198
|
+
const status = str("status");
|
|
199
|
+
if (status !== null && !TASK_STATUSES.includes(status)) {
|
|
200
|
+
errors.push(`frontmatter: status "${status}" is not one of ${TASK_STATUSES.join("|")}`);
|
|
201
|
+
}
|
|
202
|
+
const priority = str("priority");
|
|
203
|
+
if (priority !== null && !TASK_PRIORITIES.includes(priority)) {
|
|
204
|
+
errors.push(`frontmatter: priority "${priority}" is not one of ${TASK_PRIORITIES.join("|")}`);
|
|
205
|
+
}
|
|
206
|
+
for (const key of ["created", "updated"]) {
|
|
207
|
+
const v = str(key);
|
|
208
|
+
if (v !== null && !ISO_RE.test(v))
|
|
209
|
+
errors.push(`frontmatter: ${key} "${v}" is not an ISO-8601 timestamp with offset`);
|
|
210
|
+
}
|
|
211
|
+
str("url", true);
|
|
212
|
+
str("route", true);
|
|
213
|
+
str("session", true);
|
|
214
|
+
list("tags");
|
|
215
|
+
list("files");
|
|
216
|
+
for (const key of Object.keys(d)) {
|
|
217
|
+
if (!FRONTMATTER_KEYS.includes(key))
|
|
218
|
+
errors.push(`frontmatter: unknown key "${key}"`);
|
|
219
|
+
}
|
|
220
|
+
if (fileName !== undefined) {
|
|
221
|
+
const fm2 = TASK_FILE_RE.exec(fileName);
|
|
222
|
+
if (!fm2)
|
|
223
|
+
errors.push(`file name "${fileName}" is not CRT-NNNN-<slug>.md`);
|
|
224
|
+
else if (id !== null && fm2[1] !== id)
|
|
225
|
+
errors.push(`file name id ${fm2[1]} does not match frontmatter id ${id}`);
|
|
226
|
+
}
|
|
227
|
+
const headings = [...fm.body.matchAll(/^## (.*)$/gm)].map((m) => m[1].trim());
|
|
228
|
+
const expected = SECTION_NAMES;
|
|
229
|
+
if (headings.length !== expected.length || headings.some((h, i) => h !== expected[i])) {
|
|
230
|
+
errors.push(`sections must be exactly, in order: ${expected.map((s) => `## ${s}`).join(", ")} (found: ${headings.map((h) => `## ${h}`).join(", ") || "none"})`);
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
const sections = splitSections(fm.body);
|
|
234
|
+
if (!sections.Summary.trim())
|
|
235
|
+
errors.push("## Summary is empty");
|
|
236
|
+
if (!sections.Ask.trim())
|
|
237
|
+
errors.push("## Ask is empty");
|
|
238
|
+
if (!/^- \[[ xX]\] \S/m.test(sections["Definition of Done"]))
|
|
239
|
+
errors.push("## Definition of Done needs at least one `- [ ] item`");
|
|
240
|
+
if (!/^- \S/m.test(sections.Log))
|
|
241
|
+
errors.push("## Log needs at least one `- <timestamp> — …` entry");
|
|
242
|
+
}
|
|
243
|
+
if (/\r\n/.test(text))
|
|
244
|
+
errors.push("file uses CRLF line endings; tasks are written with \\n");
|
|
245
|
+
return errors;
|
|
246
|
+
}
|
|
247
|
+
function splitSections(body) {
|
|
248
|
+
const out = {};
|
|
249
|
+
for (const name of SECTION_NAMES)
|
|
250
|
+
out[name] = "";
|
|
251
|
+
const parts = body.split(/^## (?=.)/m);
|
|
252
|
+
for (const part of parts.slice(1)) {
|
|
253
|
+
const nl = part.indexOf("\n");
|
|
254
|
+
const name = (nl === -1 ? part : part.slice(0, nl)).trim();
|
|
255
|
+
if (SECTION_NAMES.includes(name))
|
|
256
|
+
out[name] = (nl === -1 ? "" : part.slice(nl + 1)).replace(/^\n+|\s+$/g, "");
|
|
257
|
+
}
|
|
258
|
+
return out;
|
|
259
|
+
}
|
|
260
|
+
/** Parse a task file's text; throws TaskFormatError when it does not validate. */
|
|
261
|
+
export function parseTask(text, fileName) {
|
|
262
|
+
const errors = validateTaskText(text, fileName);
|
|
263
|
+
if (errors.length)
|
|
264
|
+
throw new TaskFormatError(errors, fileName ?? "task");
|
|
265
|
+
const { data, body } = parseFrontmatter(text);
|
|
266
|
+
const s = (k) => data[k];
|
|
267
|
+
const n = (k) => data[k] ?? null;
|
|
268
|
+
return {
|
|
269
|
+
frontmatter: {
|
|
270
|
+
id: s("id"),
|
|
271
|
+
title: s("title"),
|
|
272
|
+
status: s("status"),
|
|
273
|
+
priority: s("priority"),
|
|
274
|
+
created: s("created"),
|
|
275
|
+
updated: s("updated"),
|
|
276
|
+
url: n("url"),
|
|
277
|
+
route: n("route"),
|
|
278
|
+
session: n("session"),
|
|
279
|
+
tags: data.tags,
|
|
280
|
+
files: data.files,
|
|
281
|
+
},
|
|
282
|
+
sections: splitSections(body),
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
/** Render a task back to text in the F-32 layout. `parseTask(serializeTask(t))` round-trips. */
|
|
286
|
+
export function serializeTask(task) {
|
|
287
|
+
const f = task.frontmatter;
|
|
288
|
+
const lines = [
|
|
289
|
+
"---",
|
|
290
|
+
`id: ${f.id}`,
|
|
291
|
+
`title: ${yamlScalar(f.title)}`,
|
|
292
|
+
`status: ${f.status}`,
|
|
293
|
+
`priority: ${f.priority}`,
|
|
294
|
+
`created: ${f.created}`,
|
|
295
|
+
`updated: ${f.updated}`,
|
|
296
|
+
`url: ${yamlScalar(f.url)}`,
|
|
297
|
+
`route: ${yamlScalar(f.route)}`,
|
|
298
|
+
`session: ${yamlScalar(f.session)}`,
|
|
299
|
+
`tags: ${yamlList(f.tags)}`,
|
|
300
|
+
`files: ${yamlList(f.files)}`,
|
|
301
|
+
"---",
|
|
302
|
+
];
|
|
303
|
+
for (const name of SECTION_NAMES) {
|
|
304
|
+
lines.push("", `## ${name}`, task.sections[name].replace(/^\n+|\s+$/g, ""));
|
|
305
|
+
}
|
|
306
|
+
return lines.join("\n") + "\n";
|
|
307
|
+
}
|
|
308
|
+
// ---------------------------------------------------------------------------------------------
|
|
309
|
+
// Directory operations
|
|
310
|
+
// ---------------------------------------------------------------------------------------------
|
|
311
|
+
/** F-31: `CRT-` + zero-padded 4 digits, one above the highest id present in the directory. */
|
|
312
|
+
export function allocateTaskId(tasksDir) {
|
|
313
|
+
let max = 0;
|
|
314
|
+
for (const name of safeReaddir(tasksDir)) {
|
|
315
|
+
const m = /^CRT-(\d{4})\b/.exec(name);
|
|
316
|
+
if (m)
|
|
317
|
+
max = Math.max(max, Number(m[1]));
|
|
318
|
+
}
|
|
319
|
+
return `CRT-${String(max + 1).padStart(4, "0")}`;
|
|
320
|
+
}
|
|
321
|
+
/** F-31: ≤ 40 chars, lowercase, hyphenated, never empty. */
|
|
322
|
+
export function slugify(title) {
|
|
323
|
+
let slug = title
|
|
324
|
+
.normalize("NFKD")
|
|
325
|
+
.replace(/[\u0300-\u036f]/g, "")
|
|
326
|
+
.toLowerCase()
|
|
327
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
328
|
+
.replace(/^-+|-+$/g, "");
|
|
329
|
+
if (slug.length > MAX_SLUG_LENGTH) {
|
|
330
|
+
const cut = slug.slice(0, MAX_SLUG_LENGTH);
|
|
331
|
+
// Cut on a word boundary: drop a partial trailing word unless the cut already lands on one.
|
|
332
|
+
slug = slug[MAX_SLUG_LENGTH] === "-" ? cut : cut.replace(/-[^-]*$/, "") || cut;
|
|
333
|
+
}
|
|
334
|
+
return slug.replace(/^-+|-+$/g, "") || "task";
|
|
335
|
+
}
|
|
336
|
+
export function taskFileName(id, title) {
|
|
337
|
+
return `${id}-${slugify(title)}.md`;
|
|
338
|
+
}
|
|
339
|
+
/** Find the file for an id (exact match on the `CRT-NNNN-` prefix). */
|
|
340
|
+
export function findTaskFile(tasksDir, id) {
|
|
341
|
+
const upper = id.toUpperCase();
|
|
342
|
+
for (const name of safeReaddir(tasksDir)) {
|
|
343
|
+
const m = TASK_FILE_RE.exec(name);
|
|
344
|
+
if (m && m[1] === upper)
|
|
345
|
+
return join(tasksDir, name);
|
|
346
|
+
}
|
|
347
|
+
return null;
|
|
348
|
+
}
|
|
349
|
+
/** F-33: every well-formed task in the directory, sorted by id. Malformed files are skipped. */
|
|
350
|
+
export function listTasks(tasksDir) {
|
|
351
|
+
const out = [];
|
|
352
|
+
for (const name of safeReaddir(tasksDir)) {
|
|
353
|
+
if (!TASK_FILE_RE.test(name))
|
|
354
|
+
continue;
|
|
355
|
+
let text;
|
|
356
|
+
try {
|
|
357
|
+
text = readFileSync(join(tasksDir, name), "utf8");
|
|
358
|
+
}
|
|
359
|
+
catch {
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
const fm = parseFrontmatter(text);
|
|
363
|
+
if (!fm)
|
|
364
|
+
continue;
|
|
365
|
+
const d = fm.data;
|
|
366
|
+
const status = typeof d.status === "string" && TASK_STATUSES.includes(d.status) ? d.status : null;
|
|
367
|
+
if (!status || typeof d.id !== "string" || typeof d.title !== "string")
|
|
368
|
+
continue;
|
|
369
|
+
out.push({
|
|
370
|
+
id: d.id,
|
|
371
|
+
status,
|
|
372
|
+
priority: typeof d.priority === "string" && TASK_PRIORITIES.includes(d.priority) ? d.priority : "normal",
|
|
373
|
+
title: d.title,
|
|
374
|
+
updated: typeof d.updated === "string" ? d.updated : "",
|
|
375
|
+
file: name,
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
return out.sort((a, b) => a.id.localeCompare(b.id));
|
|
379
|
+
}
|
|
380
|
+
/** F-34: the generated README table. Never hand-edited. */
|
|
381
|
+
export function renderIndex(tasks) {
|
|
382
|
+
const rows = tasks.map((t) => `| [${t.id}](${t.file}) | ${t.status} | ${t.priority} | ${t.title.replace(/\|/g, "\\|")} | ${t.updated.slice(0, 10)} |`);
|
|
383
|
+
return [
|
|
384
|
+
"# CRT tasks",
|
|
385
|
+
"",
|
|
386
|
+
"Generated index — do not edit by hand (PRD F-34). Regenerated by the CRT server whenever a task is written and by `crt tasks`.",
|
|
387
|
+
"",
|
|
388
|
+
"| ID | Status | Priority | Title | Updated |",
|
|
389
|
+
"|---|---|---|---|---|",
|
|
390
|
+
...rows,
|
|
391
|
+
"",
|
|
392
|
+
].join("\n");
|
|
393
|
+
}
|
|
394
|
+
/** Rewrite `README.md` when its content is stale. Returns whether it was written. */
|
|
395
|
+
export function writeIndex(tasksDir) {
|
|
396
|
+
if (!existsSync(tasksDir))
|
|
397
|
+
return false;
|
|
398
|
+
const path = join(tasksDir, INDEX_FILENAME);
|
|
399
|
+
const next = renderIndex(listTasks(tasksDir));
|
|
400
|
+
let current = null;
|
|
401
|
+
try {
|
|
402
|
+
current = readFileSync(path, "utf8");
|
|
403
|
+
}
|
|
404
|
+
catch {
|
|
405
|
+
// absent
|
|
406
|
+
}
|
|
407
|
+
if (current === next)
|
|
408
|
+
return false;
|
|
409
|
+
writeFileSync(path, next, "utf8");
|
|
410
|
+
return true;
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Allocate an id, render the F-32 file, move the capture's assets (F-23), write the file and
|
|
414
|
+
* regenerate the index (F-34). All inside `<root>/.crt/` (N-5).
|
|
415
|
+
*/
|
|
416
|
+
export function createTask(root, tasksDir, input, now = new Date()) {
|
|
417
|
+
const errors = [];
|
|
418
|
+
if (!input.title?.trim())
|
|
419
|
+
errors.push("title is required");
|
|
420
|
+
if (!input.summary?.trim())
|
|
421
|
+
errors.push("summary is required");
|
|
422
|
+
if (!input.ask?.trim())
|
|
423
|
+
errors.push("ask is required");
|
|
424
|
+
if (!Array.isArray(input.definitionOfDone) || !input.definitionOfDone.some((d) => d.trim()))
|
|
425
|
+
errors.push("definitionOfDone needs at least one item");
|
|
426
|
+
if (input.priority !== undefined && !TASK_PRIORITIES.includes(input.priority))
|
|
427
|
+
errors.push(`priority must be one of ${TASK_PRIORITIES.join("|")}`);
|
|
428
|
+
if (errors.length)
|
|
429
|
+
throw new TaskFormatError(errors, "task input");
|
|
430
|
+
mkdirSync(tasksDir, { recursive: true });
|
|
431
|
+
const id = allocateTaskId(tasksDir);
|
|
432
|
+
const file = taskFileName(id, input.title.trim());
|
|
433
|
+
const path = join(tasksDir, file);
|
|
434
|
+
let capture = null;
|
|
435
|
+
let captureDir = null;
|
|
436
|
+
if (input.captureId) {
|
|
437
|
+
captureDir = join(capturesDir(root), input.captureId);
|
|
438
|
+
capture = readCapture(captureDir);
|
|
439
|
+
}
|
|
440
|
+
let assetsDir = null;
|
|
441
|
+
let assetFiles = [];
|
|
442
|
+
if (captureDir && capture) {
|
|
443
|
+
assetsDir = join(tasksDir, ASSETS_DIRNAME, id);
|
|
444
|
+
assetFiles = moveAssets(captureDir, assetsDir);
|
|
445
|
+
}
|
|
446
|
+
const stamp = localIso(now);
|
|
447
|
+
const dod = input.definitionOfDone.map((d) => d.trim()).filter(Boolean).map((d) => (/^- \[[ x]\]/i.test(d) ? d : `- [ ] ${d.replace(/^-\s*/, "")}`));
|
|
448
|
+
const who = input.session ? `intake session ${input.session}` : "intake";
|
|
449
|
+
const task = {
|
|
450
|
+
frontmatter: {
|
|
451
|
+
id,
|
|
452
|
+
title: input.title.trim(),
|
|
453
|
+
status: "backlog",
|
|
454
|
+
priority: input.priority ?? "normal",
|
|
455
|
+
created: stamp,
|
|
456
|
+
updated: stamp,
|
|
457
|
+
url: capture?.page.url ?? null,
|
|
458
|
+
route: capture?.framework.route ?? capture?.page.pathname ?? null,
|
|
459
|
+
session: input.session,
|
|
460
|
+
tags: (input.tags ?? []).map((t) => t.trim()).filter(Boolean),
|
|
461
|
+
files: (input.files ?? []).map((f) => f.trim()).filter(Boolean),
|
|
462
|
+
},
|
|
463
|
+
sections: {
|
|
464
|
+
Summary: input.summary.trim(),
|
|
465
|
+
Context: input.context?.trim() || "See Evidence.",
|
|
466
|
+
Evidence: renderEvidence(id, capture, assetFiles, input.evidence),
|
|
467
|
+
Ask: input.ask.trim(),
|
|
468
|
+
"Definition of Done": dod.join("\n"),
|
|
469
|
+
Notes: input.notes?.trim() || "None.",
|
|
470
|
+
Log: `- ${logStamp(now)} — created by ${who}${input.captureId ? ` from capture ${input.captureId}` : ""}.`,
|
|
471
|
+
},
|
|
472
|
+
};
|
|
473
|
+
const text = serializeTask(task);
|
|
474
|
+
const problems = validateTaskText(text, file);
|
|
475
|
+
if (problems.length)
|
|
476
|
+
throw new TaskFormatError(problems, file);
|
|
477
|
+
writeFileSync(path, text, "utf8");
|
|
478
|
+
writeIndex(tasksDir);
|
|
479
|
+
return { id, path, file, assetsDir };
|
|
480
|
+
}
|
|
481
|
+
function readCapture(dir) {
|
|
482
|
+
let raw;
|
|
483
|
+
try {
|
|
484
|
+
raw = JSON.parse(readFileSync(join(dir, "capture.json"), "utf8"));
|
|
485
|
+
}
|
|
486
|
+
catch (err) {
|
|
487
|
+
throw new TaskFormatError([`capture ${basename(dir)} not found or unreadable (${err.message})`], "capture");
|
|
488
|
+
}
|
|
489
|
+
const errors = validateCaptureBundle(raw);
|
|
490
|
+
if (errors.length)
|
|
491
|
+
throw new TaskFormatError(errors, "capture");
|
|
492
|
+
return raw;
|
|
493
|
+
}
|
|
494
|
+
/** F-23: move every file of the capture into the task's asset dir, then remove the capture dir. */
|
|
495
|
+
function moveAssets(captureDir, assetsDir) {
|
|
496
|
+
mkdirSync(assetsDir, { recursive: true });
|
|
497
|
+
const moved = [];
|
|
498
|
+
for (const name of safeReaddir(captureDir)) {
|
|
499
|
+
const from = join(captureDir, name);
|
|
500
|
+
const to = join(assetsDir, name);
|
|
501
|
+
try {
|
|
502
|
+
renameSync(from, to);
|
|
503
|
+
}
|
|
504
|
+
catch {
|
|
505
|
+
// Cross-device or locked: copy then delete.
|
|
506
|
+
writeFileSync(to, readFileSync(from));
|
|
507
|
+
rmSync(from, { force: true });
|
|
508
|
+
}
|
|
509
|
+
moved.push(name);
|
|
510
|
+
}
|
|
511
|
+
rmSync(captureDir, { recursive: true, force: true });
|
|
512
|
+
return moved.sort();
|
|
513
|
+
}
|
|
514
|
+
function renderEvidence(id, capture, assetFiles, extra) {
|
|
515
|
+
const lines = [];
|
|
516
|
+
if (capture) {
|
|
517
|
+
const rel = (name) => `${ASSETS_DIRNAME}/${id}/${name}`;
|
|
518
|
+
const has = (name) => name !== null && assetFiles.includes(name);
|
|
519
|
+
if (has(capture.screenshots.annotated))
|
|
520
|
+
lines.push(`})`);
|
|
521
|
+
else if (has(capture.screenshots.viewport))
|
|
522
|
+
lines.push(`})`);
|
|
523
|
+
for (const a of capture.annotations) {
|
|
524
|
+
if (has(a.image))
|
|
525
|
+
lines.push(`})`);
|
|
526
|
+
}
|
|
527
|
+
if (lines.length)
|
|
528
|
+
lines.push("");
|
|
529
|
+
for (const a of capture.annotations)
|
|
530
|
+
lines.push(describeAnnotation(a));
|
|
531
|
+
lines.push("", `Capture bundle: \`${rel("capture.json")}\` (page ${capture.page.url}, ${capture.page.viewport.width}×${capture.page.viewport.height} @ ${capture.page.devicePixelRatio}x, ${capture.page.timestamp}).`);
|
|
532
|
+
if (capture.console.length) {
|
|
533
|
+
const errs = capture.console.filter((c) => c.level !== "warn").length;
|
|
534
|
+
lines.push(`Console at send time: ${capture.console.length} entries (${errs} errors) — see capture.json.`);
|
|
535
|
+
}
|
|
536
|
+
if (capture.network.length) {
|
|
537
|
+
const first = capture.network[0];
|
|
538
|
+
lines.push(`Failed requests at send time: ${capture.network.length} (first: ${first.method} ${first.url} → ${first.status ?? first.error ?? "failed"}) — see capture.json.`);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
if (extra?.trim())
|
|
542
|
+
lines.push("", extra.trim());
|
|
543
|
+
return lines.join("\n").trim() || "None.";
|
|
544
|
+
}
|
|
545
|
+
function describeAnnotation(a) {
|
|
546
|
+
const note = a.note ? `"${a.note}"` : "(no note)";
|
|
547
|
+
if (a.kind === "select" && a.element) {
|
|
548
|
+
const el = a.element;
|
|
549
|
+
const tag = `<${el.tag}${el.id ? ` id="${el.id}"` : ""}${el.classes.length ? ` class="${el.classes.join(" ")}"` : ""}>`;
|
|
550
|
+
const comp = el.components[0]?.name;
|
|
551
|
+
const src = el.source ? `${el.source.file}${el.source.line ? `:${el.source.line}` : ""}` : null;
|
|
552
|
+
const where = comp ? ` in \`${comp}\`${src ? ` (${src})` : ""}` : src ? ` (${src})` : "";
|
|
553
|
+
return `Annotation ${a.n} — \`${tag}\`${where}, selector \`${el.selector}\`: ${note}`;
|
|
554
|
+
}
|
|
555
|
+
if (a.kind === "box") {
|
|
556
|
+
const inside = a.elements.slice(0, 3).map((e) => `\`${e.selector}\``).join(", ");
|
|
557
|
+
return `Annotation ${a.n} — box ${Math.round(a.rect.width)}×${Math.round(a.rect.height)} at (${Math.round(a.rect.x)}, ${Math.round(a.rect.y)})${inside ? ` containing ${inside}` : ""}: ${note}`;
|
|
558
|
+
}
|
|
559
|
+
return `Annotation ${a.n} — pin at (${Math.round(a.rect.x)}, ${Math.round(a.rect.y)}): ${note}`;
|
|
560
|
+
}
|
|
561
|
+
function safeReaddir(dir) {
|
|
562
|
+
try {
|
|
563
|
+
return readdirSync(dir);
|
|
564
|
+
}
|
|
565
|
+
catch {
|
|
566
|
+
return [];
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
/** Path of a task file relative to the project root, forward slashes, for messages and logs. */
|
|
570
|
+
export function displayPath(root, path) {
|
|
571
|
+
return relative(resolve(root), resolve(path)).split("\\").join("/");
|
|
572
|
+
}
|
|
573
|
+
//# sourceMappingURL=tasks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tasks.js","sourceRoot":"","sources":["../src/tasks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC9G,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC9D,OAAO,EAAsB,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAChF,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,SAAS,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAU,CAAC;AAE9F,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAU,CAAC;AAElE,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,oBAAoB,EAAE,OAAO,EAAE,KAAK,CAAU,CAAC;AAEtH,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,IAAI;IACJ,OAAO;IACP,QAAQ;IACR,UAAU;IACV,SAAS;IACT,SAAS;IACT,KAAK;IACL,OAAO;IACP,SAAS;IACT,MAAM;IACN,OAAO;CACC,CAAC;AAEX,MAAM,CAAC,MAAM,UAAU,GAAG,aAAa,CAAC;AACxC,MAAM,CAAC,MAAM,YAAY,GAAG,gCAAgC,CAAC;AAC7D,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,CAAC;AAClC,MAAM,CAAC,MAAM,cAAc,GAAG,QAAQ,CAAC;AACvC,MAAM,CAAC,MAAM,cAAc,GAAG,WAAW,CAAC;AAgC1C,MAAM,OAAO,eAAgB,SAAQ,KAAK;IAC/B,MAAM,CAAW;IAC1B,YAAY,MAAgB,EAAE,IAAI,GAAG,MAAM;QACzC,KAAK,CAAC,WAAW,IAAI,KAAK,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,MAAM,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACtH,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAC9B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAED,gGAAgG;AAChG,OAAO;AACP,gGAAgG;AAEhG,+FAA+F;AAC/F,MAAM,UAAU,QAAQ,CAAC,IAAU,IAAI,IAAI,EAAE,EAAE,OAAO,GAAG,IAAI;IAC3D,MAAM,CAAC,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACpD,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC;IACnC,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IAClC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC1B,MAAM,EAAE,GAAG,GAAG,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,CAAC;IAC9D,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC;IACrD,OAAO,GAAG,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC;AAC3H,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,QAAQ,CAAC,IAAU,IAAI,IAAI,EAAE;IAC3C,OAAO,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AAC5B,CAAC;AASD,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,MAAM,CAAC,GAAG,mCAAmC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzD,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,MAAM,IAAI,GAA8B,EAAE,CAAC;IAC3C,KAAK,MAAM,OAAO,IAAI,CAAC,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3C,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YAAE,SAAS;QAC3B,MAAM,EAAE,GAAG,kCAAkC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzD,IAAI,CAAC,EAAE;YAAE,SAAS;QAClB,MAAM,GAAG,GAAG,EAAE,CAAC,CAAC,CAAE,CAAC;QACnB,MAAM,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACnC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IAChF,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;AACjD,CAAC;AAED,8DAA8D;AAC9D,SAAS,YAAY,CAAC,IAAY;IAChC,IAAI,KAAK,GAAkB,IAAI,CAAC;IAChC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;QACnB,IAAI,KAAK,EAAE,CAAC;YACV,IAAI,CAAC,KAAK,KAAK;gBAAE,KAAK,GAAG,IAAI,CAAC;QAChC,CAAC;aAAM,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YAClC,KAAK,GAAG,CAAC,CAAC;QACZ,CAAC;aAAM,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAE,CAAC,CAAC,EAAE,CAAC;YAC7D,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,WAAW,CAAC,KAAa;IAChC,IAAI,KAAK,KAAK,EAAE,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IACnE,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;QACtE,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAW,CAAC;QACrC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IACD,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACrH,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,aAAa,CAAC,KAAa;IAClC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC7D,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,IAAI,KAAK,GAAkB,IAAI,CAAC;IAChC,MAAM,IAAI,GAAG,GAAG,EAAE;QAChB,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QACrB,IAAI,CAAC,KAAK,EAAE;YAAE,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;QACzC,GAAG,GAAG,EAAE,CAAC;IACX,CAAC,CAAC;IACF,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,KAAK,EAAE,CAAC;YACV,GAAG,IAAI,CAAC,CAAC;YACT,IAAI,CAAC,KAAK,KAAK;gBAAE,KAAK,GAAG,IAAI,CAAC;QAChC,CAAC;aAAM,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YAClC,KAAK,GAAG,CAAC,CAAC;YACV,GAAG,IAAI,CAAC,CAAC;QACX,CAAC;aAAM,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YACrB,IAAI,EAAE,CAAC;QACT,CAAC;aAAM,CAAC;YACN,GAAG,IAAI,CAAC,CAAC;QACX,CAAC;IACH,CAAC;IACD,IAAI,EAAE,CAAC;IACP,OAAO,KAAK,CAAC;AACf,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,UAAU,CAAC,KAAoB;IAC7C,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC;IAClC,IAAI,KAAK,KAAK,EAAE,IAAI,iFAAiF,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5I,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,QAAQ,CAAC,KAAe;IAC/B,OAAO,IAAI,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;AACjD,CAAC;AAED,gGAAgG;AAChG,+BAA+B;AAC/B,gGAAgG;AAEhG,MAAM,MAAM,GAAG,qEAAqE,CAAC;AAErF;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,QAAiB;IAC9D,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,EAAE,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAClC,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,6DAA6D,CAAC,CAAC;IAChF,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;IAElB,MAAM,GAAG,GAAG,CAAC,GAAW,EAAE,QAAQ,GAAG,KAAK,EAAiB,EAAE;QAC3D,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;QACjB,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;YACpB,MAAM,CAAC,IAAI,CAAC,yBAAyB,GAAG,GAAG,CAAC,CAAC;YAC7C,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;YACrB,MAAM,CAAC,IAAI,CAAC,iBAAiB,GAAG,oBAAoB,CAAC,CAAC;YACtD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,QAAQ;YAAE,MAAM,CAAC,IAAI,CAAC,iBAAiB,GAAG,qBAAqB,CAAC,CAAC;QACpF,OAAO,CAAC,CAAC;IACX,CAAC,CAAC;IACF,MAAM,IAAI,GAAG,CAAC,GAAW,EAAQ,EAAE;QACjC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;QACjB,IAAI,CAAC,KAAK,SAAS;YAAE,MAAM,CAAC,IAAI,CAAC,yBAAyB,GAAG,GAAG,CAAC,CAAC;aAC7D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,iBAAiB,GAAG,8BAA8B,CAAC,CAAC;aACvF,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,iBAAiB,GAAG,qBAAqB,CAAC,CAAC;IAC7F,CAAC,CAAC;IAEF,MAAM,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC;IACrB,IAAI,EAAE,KAAK,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,oBAAoB,EAAE,mBAAmB,CAAC,CAAC;IAChG,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC;IAC3B,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,MAAM,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;IACtF,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC7B,IAAI,MAAM,KAAK,IAAI,IAAI,CAAE,aAAmC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC9E,MAAM,CAAC,IAAI,CAAC,wBAAwB,MAAM,mBAAmB,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC1F,CAAC;IACD,MAAM,QAAQ,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC;IACjC,IAAI,QAAQ,KAAK,IAAI,IAAI,CAAE,eAAqC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACpF,MAAM,CAAC,IAAI,CAAC,0BAA0B,QAAQ,mBAAmB,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChG,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,CAAC;QACzC,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;QACnB,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC,4CAA4C,CAAC,CAAC;IACxH,CAAC;IACD,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACjB,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACnB,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IACrB,IAAI,CAAC,MAAM,CAAC,CAAC;IACb,IAAI,CAAC,OAAO,CAAC,CAAC;IACd,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QACjC,IAAI,CAAE,gBAAsC,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,6BAA6B,GAAG,GAAG,CAAC,CAAC;IAC/G,CAAC;IACD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxC,IAAI,CAAC,GAAG;YAAE,MAAM,CAAC,IAAI,CAAC,cAAc,QAAQ,6BAA6B,CAAC,CAAC;aACtE,IAAI,EAAE,KAAK,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE;YAAE,MAAM,CAAC,IAAI,CAAC,gBAAgB,GAAG,CAAC,CAAC,CAAC,kCAAkC,EAAE,EAAE,CAAC,CAAC;IACnH,CAAC;IAED,MAAM,QAAQ,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,IAAI,EAAE,CAAC,CAAC;IAC/E,MAAM,QAAQ,GAAG,aAAkC,CAAC;IACpD,IAAI,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACtF,MAAM,CAAC,IAAI,CAAC,uCAAuC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC;IAClK,CAAC;SAAM,CAAC;QACN,MAAM,QAAQ,GAAG,aAAa,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE;YAAE,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QACjE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE;YAAE,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QACzD,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,uDAAuD,CAAC,CAAC;QACnI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAC;IACvG,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,yDAAyD,CAAC,CAAC;IAC9F,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,aAAa,CAAC,IAAY;IACjC,MAAM,GAAG,GAAG,EAAiC,CAAC;IAC9C,KAAK,MAAM,IAAI,IAAI,aAAa;QAAE,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;IACjD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IACvC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QAClC,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC9B,MAAM,IAAI,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAiB,CAAC;QAC1E,IAAK,aAAmC,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACvI,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,QAAiB;IACvD,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAChD,IAAI,MAAM,CAAC,MAAM;QAAE,MAAM,IAAI,eAAe,CAAC,MAAM,EAAE,QAAQ,IAAI,MAAM,CAAC,CAAC;IACzE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,gBAAgB,CAAC,IAAI,CAAE,CAAC;IAC/C,MAAM,CAAC,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAW,CAAC;IAC3C,MAAM,CAAC,GAAG,CAAC,CAAS,EAAE,EAAE,CAAE,IAAI,CAAC,CAAC,CAAY,IAAI,IAAI,CAAC;IACrD,OAAO;QACL,WAAW,EAAE;YACX,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC;YACX,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC;YACjB,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAe;YACjC,QAAQ,EAAE,CAAC,CAAC,UAAU,CAAiB;YACvC,OAAO,EAAE,CAAC,CAAC,SAAS,CAAC;YACrB,OAAO,EAAE,CAAC,CAAC,SAAS,CAAC;YACrB,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC;YACb,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC;YACjB,OAAO,EAAE,CAAC,CAAC,SAAS,CAAC;YACrB,IAAI,EAAE,IAAI,CAAC,IAAgB;YAC3B,KAAK,EAAE,IAAI,CAAC,KAAiB;SAC9B;QACD,QAAQ,EAAE,aAAa,CAAC,IAAI,CAAC;KAC9B,CAAC;AACJ,CAAC;AAED,gGAAgG;AAChG,MAAM,UAAU,aAAa,CAAC,IAAU;IACtC,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC;IAC3B,MAAM,KAAK,GAAG;QACZ,KAAK;QACL,OAAO,CAAC,CAAC,EAAE,EAAE;QACb,UAAU,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE;QAC/B,WAAW,CAAC,CAAC,MAAM,EAAE;QACrB,aAAa,CAAC,CAAC,QAAQ,EAAE;QACzB,YAAY,CAAC,CAAC,OAAO,EAAE;QACvB,YAAY,CAAC,CAAC,OAAO,EAAE;QACvB,QAAQ,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE;QAC3B,UAAU,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE;QAC/B,YAAY,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE;QACnC,SAAS,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE;QAC3B,UAAU,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE;QAC7B,KAAK;KACN,CAAC;IACF,KAAK,MAAM,IAAI,IAAI,aAAa,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,CAAC;IAC9E,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AACjC,CAAC;AAED,gGAAgG;AAChG,uBAAuB;AACvB,gGAAgG;AAEhG,8FAA8F;AAC9F,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzC,MAAM,CAAC,GAAG,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,CAAC;YAAE,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,OAAO,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;AACnD,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,OAAO,CAAC,KAAa;IACnC,IAAI,IAAI,GAAG,KAAK;SACb,SAAS,CAAC,MAAM,CAAC;SACjB,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;SAC/B,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC3B,IAAI,IAAI,CAAC,MAAM,GAAG,eAAe,EAAE,CAAC;QAClC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC;QAC3C,4FAA4F;QAC5F,IAAI,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC;IACjF,CAAC;IACD,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,EAAU,EAAE,KAAa;IACpD,OAAO,GAAG,EAAE,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;AACtC,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,YAAY,CAAC,QAAgB,EAAE,EAAU;IACvD,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzC,MAAM,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK;YAAE,OAAO,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,gGAAgG;AAChG,MAAM,UAAU,SAAS,CAAC,QAAgB;IACxC,MAAM,GAAG,GAAkB,EAAE,CAAC;IAC9B,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,SAAS;QACvC,IAAI,IAAY,CAAC;QACjB,IAAI,CAAC;YACH,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;QACpD,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,MAAM,EAAE,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,CAAC,EAAE;YAAE,SAAS;QAClB,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;QAClB,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,IAAK,aAAmC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC,MAAqB,CAAC,CAAC,CAAC,IAAI,CAAC;QACzI,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ;YAAE,SAAS;QACjF,GAAG,CAAC,IAAI,CAAC;YACP,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,MAAM;YACN,QAAQ,EAAE,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ,IAAK,eAAqC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC,QAAyB,CAAC,CAAC,CAAC,QAAQ;YACjJ,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,OAAO,EAAE,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;YACvD,IAAI,EAAE,IAAI;SACX,CAAC,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACtD,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,WAAW,CAAC,KAAoB;IAC9C,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CACpB,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,QAAQ,MAAM,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAC/H,CAAC;IACF,OAAO;QACL,aAAa;QACb,EAAE;QACF,gIAAgI;QAChI,EAAE;QACF,8CAA8C;QAC9C,uBAAuB;QACvB,GAAG,IAAI;QACP,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,UAAU,CAAC,QAAgB;IACzC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IACxC,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;IAC5C,MAAM,IAAI,GAAG,WAAW,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC9C,IAAI,OAAO,GAAkB,IAAI,CAAC;IAClC,IAAI,CAAC;QACH,OAAO,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,SAAS;IACX,CAAC;IACD,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IACnC,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAClC,OAAO,IAAI,CAAC;AACd,CAAC;AA+BD;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,QAAgB,EAAE,KAAmB,EAAE,MAAY,IAAI,IAAI,EAAE;IACpG,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE;QAAE,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAC3D,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE;QAAE,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;IAC/D,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE;QAAE,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IACvD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC;IACrJ,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,IAAI,CAAE,eAAqC,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,2BAA2B,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC1K,IAAI,MAAM,CAAC,MAAM;QAAE,MAAM,IAAI,eAAe,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAEnE,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,MAAM,EAAE,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,YAAY,CAAC,EAAE,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IAClD,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAElC,IAAI,OAAO,GAAyB,IAAI,CAAC;IACzC,IAAI,UAAU,GAAkB,IAAI,CAAC;IACrC,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;QACpB,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;QACtD,OAAO,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC;IACpC,CAAC;IAED,IAAI,SAAS,GAAkB,IAAI,CAAC;IACpC,IAAI,UAAU,GAAa,EAAE,CAAC;IAC9B,IAAI,UAAU,IAAI,OAAO,EAAE,CAAC;QAC1B,SAAS,GAAG,IAAI,CAAC,QAAQ,EAAE,cAAc,EAAE,EAAE,CAAC,CAAC;QAC/C,UAAU,GAAG,UAAU,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IACjD,CAAC;IAED,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC5B,MAAM,GAAG,GAAG,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACrJ,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,kBAAkB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;IACzE,MAAM,IAAI,GAAS;QACjB,WAAW,EAAE;YACX,EAAE;YACF,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE;YACzB,MAAM,EAAE,SAAS;YACjB,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,QAAQ;YACpC,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,KAAK;YACd,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,IAAI,IAAI;YAC9B,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,KAAK,IAAI,OAAO,EAAE,IAAI,CAAC,QAAQ,IAAI,IAAI;YACjE,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;YAC7D,KAAK,EAAE,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;SAChE;QACD,QAAQ,EAAE;YACR,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE;YAC7B,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,eAAe;YACjD,QAAQ,EAAE,cAAc,CAAC,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,CAAC,QAAQ,CAAC;YACjE,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE;YACrB,oBAAoB,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;YACpC,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,OAAO;YACrC,GAAG,EAAE,KAAK,QAAQ,CAAC,GAAG,CAAC,iBAAiB,GAAG,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG;SAC3G;KACF,CAAC;IACF,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACjC,MAAM,QAAQ,GAAG,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC9C,IAAI,QAAQ,CAAC,MAAM;QAAE,MAAM,IAAI,eAAe,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC/D,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAClC,UAAU,CAAC,QAAQ,CAAC,CAAC;IACrB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;AACvC,CAAC;AAED,SAAS,WAAW,CAAC,GAAW;IAC9B,IAAI,GAAY,CAAC;IACjB,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;IACpE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,eAAe,CAAC,CAAC,WAAW,QAAQ,CAAC,GAAG,CAAC,6BAA8B,GAAa,CAAC,OAAO,GAAG,CAAC,EAAE,SAAS,CAAC,CAAC;IACzH,CAAC;IACD,MAAM,MAAM,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC;IAC1C,IAAI,MAAM,CAAC,MAAM;QAAE,MAAM,IAAI,eAAe,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAChE,OAAO,GAAoB,CAAC;AAC9B,CAAC;AAED,mGAAmG;AACnG,SAAS,UAAU,CAAC,UAAkB,EAAE,SAAiB;IACvD,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QACpC,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QACjC,IAAI,CAAC;YACH,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACvB,CAAC;QAAC,MAAM,CAAC;YACP,4CAA4C;YAC5C,aAAa,CAAC,EAAE,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;YACtC,MAAM,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAChC,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC;IACD,MAAM,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACrD,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC;AACtB,CAAC;AAED,SAAS,cAAc,CAAC,EAAU,EAAE,OAA6B,EAAE,UAAoB,EAAE,KAAc;IACrG,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,GAAG,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,GAAG,cAAc,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC;QAChE,MAAM,GAAG,GAAG,CAAC,IAAmB,EAAE,EAAE,CAAC,IAAI,KAAK,IAAI,IAAI,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAChF,IAAI,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,SAAS,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,2BAA2B,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,SAAU,CAAC,GAAG,CAAC,CAAC;aACjH,IAAI,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,eAAe,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,QAAS,CAAC,GAAG,CAAC,CAAC;QAC7G,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;YACpC,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC;gBAAE,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,KAAM,CAAC,GAAG,CAAC,CAAC;QACzE,CAAC;QACD,IAAI,KAAK,CAAC,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACjC,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,WAAW;YAAE,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC;QACvE,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,qBAAqB,GAAG,CAAC,cAAc,CAAC,YAAY,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,MAAM,OAAO,CAAC,IAAI,CAAC,gBAAgB,MAAM,OAAO,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC;QACxN,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YAC3B,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,MAAM,CAAC;YACtE,KAAK,CAAC,IAAI,CAAC,yBAAyB,OAAO,CAAC,OAAO,CAAC,MAAM,aAAa,IAAI,8BAA8B,CAAC,CAAC;QAC7G,CAAC;QACD,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YAC3B,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAE,CAAC;YAClC,KAAK,CAAC,IAAI,CAAC,iCAAiC,OAAO,CAAC,OAAO,CAAC,MAAM,YAAY,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,GAAG,MAAM,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,KAAK,IAAI,QAAQ,uBAAuB,CAAC,CAAC;QAC/K,CAAC;IACH,CAAC;IACD,IAAI,KAAK,EAAE,IAAI,EAAE;QAAE,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IAChD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,OAAO,CAAC;AAC5C,CAAC;AAED,SAAS,kBAAkB,CAAC,CAAuC;IACjE,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC;IAClD,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;QACrC,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC;QACrB,MAAM,GAAG,GAAG,IAAI,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC;QACxH,MAAM,IAAI,GAAG,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;QACpC,MAAM,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QAChG,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACzF,OAAO,cAAc,CAAC,CAAC,CAAC,QAAQ,GAAG,KAAK,KAAK,gBAAgB,EAAE,CAAC,QAAQ,OAAO,IAAI,EAAE,CAAC;IACxF,CAAC;IACD,IAAI,CAAC,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;QACrB,MAAM,MAAM,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjF,OAAO,cAAc,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,eAAe,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC;IACnM,CAAC;IACD,OAAO,cAAc,CAAC,CAAC,CAAC,cAAc,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC;AAClG,CAAC;AAED,SAAS,WAAW,CAAC,GAAW;IAC9B,IAAI,CAAC;QACH,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,gGAAgG;AAChG,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,IAAY;IACpD,OAAO,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACtE,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "claude-review-tool",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Claude Review Tool (CRT): annotate your local site in the browser, talk to Claude in-page, get a self-contained task file in your repo.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://github.com/simv/crt#readme",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/simv/crt.git",
|
|
10
|
+
"directory": "packages/server"
|
|
11
|
+
},
|
|
12
|
+
"bugs": "https://github.com/simv/crt/issues",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"claude",
|
|
15
|
+
"claude-code",
|
|
16
|
+
"review",
|
|
17
|
+
"annotate",
|
|
18
|
+
"feedback",
|
|
19
|
+
"proxy",
|
|
20
|
+
"overlay"
|
|
21
|
+
],
|
|
22
|
+
"type": "module",
|
|
23
|
+
"bin": {
|
|
24
|
+
"crt": "dist/cli.js"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist"
|
|
28
|
+
],
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=20"
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsc -p tsconfig.json && node scripts/copy-intake.mjs",
|
|
34
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
35
|
+
"test": "vitest run",
|
|
36
|
+
"dev": "tsc -p tsconfig.json --watch",
|
|
37
|
+
"e2e": "playwright test"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@playwright/test": "^1.63.0",
|
|
41
|
+
"@types/node": "^22.10.0",
|
|
42
|
+
"react": "^18.3.1",
|
|
43
|
+
"react-dom": "^18.3.1",
|
|
44
|
+
"typescript": "^5.7.0",
|
|
45
|
+
"vitest": "^3.0.0"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@anthropic-ai/claude-agent-sdk": "0.3.270",
|
|
49
|
+
"zod": "^4.0.0"
|
|
50
|
+
}
|
|
51
|
+
}
|