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.
@@ -0,0 +1,293 @@
1
+ /**
2
+ * Session registry and its HTTP routes (PRD F-14, F-24, F-25, F-28, F-29, F-30).
3
+ *
4
+ * POST /__crt/sessions { captureId?, quick? } → 201 { id } start intake
5
+ * POST /__crt/sessions/<id>/capture { captureId } → 200 first message (warm start)
6
+ * GET /__crt/sessions → { sessions: SessionInfo[] }
7
+ * GET /__crt/sessions/<id>/events SSE; `Last-Event-ID` or `?after=<seq>` replays
8
+ * POST /__crt/sessions/<id>/messages { text } → 202
9
+ * POST /__crt/sessions/<id>/interrupt → 202
10
+ * POST /__crt/sessions/<id>/permission { id, behavior } → 200 | 404 | 409
11
+ * DELETE /__crt/sessions/<id> → 200 close ("New session")
12
+ *
13
+ * Every event a driver emits is numbered and kept in memory for the life of the server, so a
14
+ * panel that reloads the page (or the developer opening the session list) can rebuild the
15
+ * transcript by replaying from 0. The driver behind each session is whatever `SessionStarter`
16
+ * the server was created with: the SDK one (session.ts) or the stub (session-stub.ts).
17
+ *
18
+ * Warm start (N-2): the overlay may POST /__crt/sessions with no capture as soon as Send is
19
+ * clicked, so the Claude Code process boots while the page is still being rasterised; the
20
+ * capture is attached with POST …/capture once it is saved, which sends the first message.
21
+ */
22
+ import { randomUUID } from "node:crypto";
23
+ import { join } from "node:path";
24
+ import { capturesDir } from "./captures.js";
25
+ import { json, readJson } from "./http.js";
26
+ import { buildIntakeMessage, readCaptureBundle, summarizeCapture } from "./intake-message.js";
27
+ import { decidePermission } from "./permissions.js";
28
+ import { createTask, displayPath } from "./tasks.js";
29
+ export const SESSIONS_PATH = "/__crt/sessions";
30
+ const MAX_BODY = 1024 * 1024;
31
+ const KEEPALIVE_MS = 15_000;
32
+ export class SessionRegistry {
33
+ opts;
34
+ entries = new Map();
35
+ constructor(opts) {
36
+ this.opts = opts;
37
+ }
38
+ /**
39
+ * F-24: start an intake session. With a capture id the first message is sent immediately;
40
+ * without one the process boots and waits for `attachCapture` (warm start, N-2). `quick`
41
+ * (F-14) makes the first message tell Claude to write the task without waiting for confirmation.
42
+ * Throws when the capture is missing (nothing is started in that case).
43
+ */
44
+ create(captureId, opts = {}) {
45
+ const quick = opts.quick === true;
46
+ const id = randomUUID();
47
+ const entry = {
48
+ info: { id, captureId, startedAt: new Date().toISOString(), state: "starting", taskId: null, quick, summary: null, url: null },
49
+ driver: undefined,
50
+ events: [],
51
+ subscribers: new Set(),
52
+ };
53
+ const first = captureId ? this.firstMessage(entry, captureId) : undefined;
54
+ this.entries.set(id, entry);
55
+ const driverOpts = {
56
+ id,
57
+ cwd: this.opts.projectRoot,
58
+ systemPromptAppend: this.opts.intakePrompt.split("$ARGUMENTS").join("the capture directory named in the first message"),
59
+ ...(first ? { first } : {}),
60
+ decide: (toolName, input) => decidePermission(toolName, input, this.opts.projectRoot),
61
+ writeTask: async (request) => {
62
+ const created = createTask(this.opts.projectRoot, this.opts.tasksDir, { ...request, session: id, captureId: entry.info.captureId });
63
+ entry.info.taskId = created.id;
64
+ return { id: created.id, path: displayPath(this.opts.projectRoot, created.path) };
65
+ },
66
+ log: this.opts.log,
67
+ ...(this.opts.permissionTimeoutMs !== undefined ? { permissionTimeoutMs: this.opts.permissionTimeoutMs } : {}),
68
+ };
69
+ entry.driver = this.opts.start(driverOpts);
70
+ entry.driver.onEvent((event) => this.record(entry, event));
71
+ this.opts.log?.(`crt: ${quick ? "quick-note" : "intake"} session ${id} started${captureId ? ` for capture ${captureId}` : ""} (claude --resume ${id})`);
72
+ return { ...entry.info };
73
+ }
74
+ /** Warm start, step 2: send the capture as the first message. Throws when the capture is missing. */
75
+ attachCapture(id, captureId) {
76
+ const e = this.entries.get(id);
77
+ if (!e || isOver(e.info.state))
78
+ return "no_session";
79
+ if (e.info.captureId !== null)
80
+ return "already_started";
81
+ const first = this.firstMessage(e, captureId);
82
+ e.info.captureId = captureId;
83
+ e.driver.send(first);
84
+ this.opts.log?.(`crt: intake session ${id} received capture ${captureId}`);
85
+ return "ok";
86
+ }
87
+ /** Build the F-24 first message and fill the F-30 list fields from the same bundle. */
88
+ firstMessage(entry, captureId) {
89
+ const dir = join(capturesDir(this.opts.projectRoot), captureId);
90
+ const bundle = readCaptureBundle(dir);
91
+ entry.info.summary = summarizeCapture(bundle);
92
+ entry.info.url = bundle.page.url;
93
+ return buildIntakeMessage(dir, bundle, { quick: entry.info.quick });
94
+ }
95
+ record(entry, event) {
96
+ if (event.type === "state")
97
+ entry.info.state = event.state;
98
+ if (event.type === "task_written")
99
+ entry.info.taskId = event.id;
100
+ entry.events.push(event);
101
+ const seq = entry.events.length;
102
+ for (const fn of entry.subscribers)
103
+ fn(seq, event);
104
+ }
105
+ get(id) {
106
+ const e = this.entries.get(id);
107
+ return e ? { ...e.info } : null;
108
+ }
109
+ /** F-30: newest first. */
110
+ list() {
111
+ return [...this.entries.values()].map((e) => ({ ...e.info })).sort((a, b) => b.startedAt.localeCompare(a.startedAt));
112
+ }
113
+ /** Replay events with seq > `after`, then stream live ones. Returns an unsubscribe function. */
114
+ subscribe(id, after, fn) {
115
+ const e = this.entries.get(id);
116
+ if (!e)
117
+ return null;
118
+ for (let i = Math.max(0, after); i < e.events.length; i++)
119
+ fn(i + 1, e.events[i]);
120
+ e.subscribers.add(fn);
121
+ return () => e.subscribers.delete(fn);
122
+ }
123
+ send(id, text) {
124
+ const e = this.entries.get(id);
125
+ if (!e || isOver(e.info.state))
126
+ return false;
127
+ e.driver.send({ text });
128
+ return true;
129
+ }
130
+ async interrupt(id) {
131
+ const e = this.entries.get(id);
132
+ if (!e || isOver(e.info.state))
133
+ return false;
134
+ await e.driver.interrupt();
135
+ return true;
136
+ }
137
+ respondPermission(id, permissionId, behavior) {
138
+ const e = this.entries.get(id);
139
+ if (!e)
140
+ return "no_session";
141
+ return e.driver.respondPermission(permissionId, behavior) ? "ok" : "no_permission";
142
+ }
143
+ close(id) {
144
+ const e = this.entries.get(id);
145
+ if (!e)
146
+ return false;
147
+ e.driver.close();
148
+ return true;
149
+ }
150
+ closeAll() {
151
+ for (const e of this.entries.values())
152
+ e.driver.close();
153
+ }
154
+ }
155
+ function isOver(state) {
156
+ return state === "ended" || state === "error";
157
+ }
158
+ function isCaptureId(v) {
159
+ return typeof v === "string" && /^[A-Za-z0-9_-]+$/.test(v);
160
+ }
161
+ /** Route a request under /__crt/sessions. Returns false when the path is not a session route. */
162
+ export async function handleSessionRoute(path, query, req, res, registry) {
163
+ if (path !== SESSIONS_PATH && !path.startsWith(SESSIONS_PATH + "/"))
164
+ return false;
165
+ const method = req.method ?? "GET";
166
+ if (path === SESSIONS_PATH) {
167
+ if (method === "GET") {
168
+ json(res, 200, { ok: true, sessions: registry.list() });
169
+ return true;
170
+ }
171
+ if (method !== "POST") {
172
+ json(res, 405, { ok: false, error: "GET lists sessions; POST { captureId?, quick? } starts one" });
173
+ return true;
174
+ }
175
+ const body = await readJson(req, MAX_BODY);
176
+ if (!body.ok) {
177
+ json(res, body.status, { ok: false, error: body.error });
178
+ return true;
179
+ }
180
+ const { captureId, quick } = body.value;
181
+ if (captureId !== undefined && captureId !== null && !isCaptureId(captureId)) {
182
+ json(res, 400, { ok: false, error: "captureId must be a capture id string (or omitted for a warm start)" });
183
+ return true;
184
+ }
185
+ if (quick !== undefined && typeof quick !== "boolean") {
186
+ json(res, 400, { ok: false, error: "quick must be a boolean" });
187
+ return true;
188
+ }
189
+ try {
190
+ const info = registry.create(isCaptureId(captureId) ? captureId : null, { quick: quick === true });
191
+ json(res, 201, { ok: true, id: info.id, session: info });
192
+ }
193
+ catch (err) {
194
+ const message = err.message;
195
+ json(res, /not found/.test(message) ? 404 : 500, { ok: false, error: message });
196
+ }
197
+ return true;
198
+ }
199
+ const [id, action] = path.slice(SESSIONS_PATH.length + 1).split("/");
200
+ if (!id || !registry.get(id)) {
201
+ json(res, 404, { ok: false, error: `no session ${id ?? ""}` });
202
+ return true;
203
+ }
204
+ if (action === undefined) {
205
+ if (method === "GET")
206
+ json(res, 200, { ok: true, session: registry.get(id) });
207
+ else if (method === "DELETE")
208
+ json(res, 200, { ok: registry.close(id) });
209
+ else
210
+ json(res, 405, { ok: false, error: "GET or DELETE" });
211
+ return true;
212
+ }
213
+ if (action === "events" && method === "GET") {
214
+ streamEvents(id, query, req, res, registry);
215
+ return true;
216
+ }
217
+ if (method !== "POST") {
218
+ json(res, 405, { ok: false, error: `POST ${path}` });
219
+ return true;
220
+ }
221
+ const body = await readJson(req, MAX_BODY);
222
+ if (!body.ok) {
223
+ json(res, body.status, { ok: false, error: body.error });
224
+ return true;
225
+ }
226
+ const b = body.value;
227
+ switch (action) {
228
+ case "capture": {
229
+ if (!isCaptureId(b.captureId)) {
230
+ json(res, 400, { ok: false, error: "captureId (string) is required" });
231
+ return true;
232
+ }
233
+ try {
234
+ const r = registry.attachCapture(id, b.captureId);
235
+ json(res, r === "ok" ? 200 : 409, { ok: r === "ok", error: r === "ok" ? undefined : r });
236
+ }
237
+ catch (err) {
238
+ const message = err.message;
239
+ json(res, /not found/.test(message) ? 404 : 500, { ok: false, error: message });
240
+ }
241
+ return true;
242
+ }
243
+ case "messages": {
244
+ const text = typeof b.text === "string" ? b.text.trim() : "";
245
+ if (!text) {
246
+ json(res, 400, { ok: false, error: "text (string) is required" });
247
+ return true;
248
+ }
249
+ json(res, registry.send(id, text) ? 202 : 409, { ok: true });
250
+ return true;
251
+ }
252
+ case "interrupt":
253
+ json(res, (await registry.interrupt(id)) ? 202 : 409, { ok: true });
254
+ return true;
255
+ case "permission": {
256
+ const permissionId = typeof b.id === "string" ? b.id : "";
257
+ const behavior = b.behavior === "allow" || b.behavior === "deny" ? b.behavior : null;
258
+ if (!permissionId || !behavior) {
259
+ json(res, 400, { ok: false, error: "id (string) and behavior (allow|deny) are required" });
260
+ return true;
261
+ }
262
+ const r = registry.respondPermission(id, permissionId, behavior);
263
+ json(res, r === "ok" ? 200 : r === "no_session" ? 404 : 409, { ok: r === "ok", error: r === "ok" ? undefined : `${r}: already answered or unknown` });
264
+ return true;
265
+ }
266
+ default:
267
+ json(res, 404, { ok: false, error: `no session action ${action}` });
268
+ return true;
269
+ }
270
+ }
271
+ /** SSE: `id:` is the event sequence number, so EventSource reconnects resume via Last-Event-ID. */
272
+ function streamEvents(id, query, req, res, registry) {
273
+ const lastHeader = req.headers["last-event-id"];
274
+ const after = Number((Array.isArray(lastHeader) ? lastHeader[0] : lastHeader) ?? query.get("after") ?? 0) || 0;
275
+ res.writeHead(200, {
276
+ "content-type": "text/event-stream; charset=utf-8",
277
+ "cache-control": "no-store",
278
+ connection: "keep-alive",
279
+ "x-accel-buffering": "no",
280
+ });
281
+ res.write(":ok\n\n");
282
+ const write = (seq, event) => {
283
+ // Unnamed events so a plain EventSource.onmessage receives everything.
284
+ res.write(`id: ${seq}\ndata: ${JSON.stringify(event)}\n\n`);
285
+ };
286
+ const unsubscribe = registry.subscribe(id, after, write);
287
+ const keepalive = setInterval(() => res.write(":ka\n\n"), KEEPALIVE_MS);
288
+ req.on("close", () => {
289
+ clearInterval(keepalive);
290
+ unsubscribe?.();
291
+ });
292
+ }
293
+ //# sourceMappingURL=sessions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessions.js","sourceRoot":"","sources":["../src/sessions.ts"],"names":[],"mappings":"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"}
package/dist/target.js ADDED
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Target dev-server detection (PRD F-1).
3
+ * Resolution order: `--target` flag → `.crt/config.json` `target` → probe the
4
+ * well-known ports in order and take the first that answers HTTP at all.
5
+ * Any HTTP status counts as "up"; only a connection failure or timeout counts as down.
6
+ */
7
+ import { request as httpRequest } from "node:http";
8
+ import { request as httpsRequest } from "node:https";
9
+ import { CrtError } from "./errors.js";
10
+ export const PROBE_PORTS = [3000, 5173, 8080, 4200, 8000, 3001];
11
+ const PROBE_TIMEOUT_MS = 1500;
12
+ /** Accepts `3000`, `localhost:3000`, `http://localhost:3000/` and returns a normalised origin. */
13
+ export function normalizeTarget(input) {
14
+ let s = input.trim();
15
+ if (/^\d+$/.test(s))
16
+ s = `http://localhost:${s}`;
17
+ else if (!/^[a-z][a-z0-9+.-]*:\/\//i.test(s))
18
+ s = `http://${s}`;
19
+ let url;
20
+ try {
21
+ url = new URL(s);
22
+ }
23
+ catch {
24
+ throw new CrtError(`target "${input}" is not a valid URL — use e.g. --target http://localhost:3000`);
25
+ }
26
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
27
+ throw new CrtError(`target "${input}" must be http:// or https://`);
28
+ }
29
+ return url.origin;
30
+ }
31
+ /** True when something answers HTTP at `origin` within the timeout, regardless of status. */
32
+ export function isReachable(origin, timeoutMs = PROBE_TIMEOUT_MS) {
33
+ const url = new URL(origin);
34
+ const req = (url.protocol === "https:" ? httpsRequest : httpRequest)(url, {
35
+ method: "GET",
36
+ timeout: timeoutMs,
37
+ rejectUnauthorized: false,
38
+ headers: { accept: "*/*" },
39
+ });
40
+ return new Promise((resolve) => {
41
+ const done = (ok) => {
42
+ req.destroy();
43
+ resolve(ok);
44
+ };
45
+ req.on("response", (res) => {
46
+ res.resume();
47
+ done(true);
48
+ });
49
+ req.on("timeout", () => done(false));
50
+ req.on("error", () => done(false));
51
+ req.end();
52
+ });
53
+ }
54
+ export async function resolveTarget(opts = {}) {
55
+ const host = opts.host ?? "localhost";
56
+ const explicit = opts.flag ?? opts.configTarget ?? null;
57
+ if (explicit) {
58
+ const origin = normalizeTarget(explicit);
59
+ if (!(await isReachable(origin))) {
60
+ throw new CrtError(`target ${origin} is not responding — start your dev server there or pass --target <url>`);
61
+ }
62
+ return { origin, source: opts.flag ? "flag" : "config" };
63
+ }
64
+ const ports = opts.ports ?? PROBE_PORTS;
65
+ for (const port of ports) {
66
+ const origin = `http://${host}:${port}`;
67
+ if (await isReachable(origin))
68
+ return { origin, source: "probe" };
69
+ }
70
+ throw new CrtError(`no dev server found on ports ${ports.join(", ")} — start it, or pass --target <url>`);
71
+ }
72
+ //# sourceMappingURL=target.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"target.js","sourceRoot":"","sources":["../src/target.ts"],"names":[],"mappings":"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"}