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/proxy.js
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reverse proxy (PRD F-2, F-3, F-4, F-6).
|
|
3
|
+
* • Everything not under /__crt/ is forwarded to the target with Host rewritten and
|
|
4
|
+
* X-Forwarded-* added; bodies stream both ways.
|
|
5
|
+
* • text/html responses are buffered, decompressed, injected with the overlay tag,
|
|
6
|
+
* and re-served uncompressed with a correct Content-Length (F-2).
|
|
7
|
+
* • WebSocket upgrades are replayed over a raw TCP/TLS socket and piped untouched,
|
|
8
|
+
* so Next.js / Vite HMR keep working (F-3).
|
|
9
|
+
* • /__crt/overlay.js, /__crt/early.js, /__crt/health, POST /__crt/captures (F-13, F-23) and
|
|
10
|
+
* the /__crt/sessions routes (sessions.ts, F-24…F-30) are served here; anything else under
|
|
11
|
+
* /__crt/ is a 404 and never reaches the target (F-4).
|
|
12
|
+
* • Every /__crt/ response carries CORS headers when the request's Origin is a localhost
|
|
13
|
+
* origin, so an app can load the overlay with a script tag instead of the proxy (F-6).
|
|
14
|
+
* The caller binds the returned server to 127.0.0.1 (see serve.ts).
|
|
15
|
+
*/
|
|
16
|
+
import { readFile } from "node:fs/promises";
|
|
17
|
+
import { Agent as HttpAgent, createServer, request as httpRequest, } from "node:http";
|
|
18
|
+
import { Agent as HttpsAgent, request as httpsRequest } from "node:https";
|
|
19
|
+
import { connect as netConnect } from "node:net";
|
|
20
|
+
import { dirname, join } from "node:path";
|
|
21
|
+
import { connect as tlsConnect } from "node:tls";
|
|
22
|
+
import { CaptureValidationError, writeCapture } from "./captures.js";
|
|
23
|
+
import { applyCors, json, readJson } from "./http.js";
|
|
24
|
+
import { decodeBody, EARLY_PATH, filterAcceptEncoding, injectOverlayTag, isHtml, OVERLAY_PATH, relaxCsp } from "./inject.js";
|
|
25
|
+
import { handleSessionRoute, SESSIONS_PATH } from "./sessions.js";
|
|
26
|
+
export const CRT_PREFIX = "/__crt";
|
|
27
|
+
export const CAPTURES_PATH = `${CRT_PREFIX}/captures`;
|
|
28
|
+
/** A capture is a JSON document with a few base64 PNGs; 64 MB is far beyond any real page. */
|
|
29
|
+
const MAX_CAPTURE_BODY = 64 * 1024 * 1024;
|
|
30
|
+
/** Headers that describe the current hop, not the message; never forwarded (RFC 7230 §6.1). */
|
|
31
|
+
const HOP_BY_HOP = new Set([
|
|
32
|
+
"connection",
|
|
33
|
+
"keep-alive",
|
|
34
|
+
"proxy-authenticate",
|
|
35
|
+
"proxy-authorization",
|
|
36
|
+
"proxy-connection",
|
|
37
|
+
"te",
|
|
38
|
+
"trailer",
|
|
39
|
+
"transfer-encoding",
|
|
40
|
+
"upgrade",
|
|
41
|
+
]);
|
|
42
|
+
export function createProxyServer(opts) {
|
|
43
|
+
const target = new URL(opts.target);
|
|
44
|
+
const secure = target.protocol === "https:";
|
|
45
|
+
const targetPort = Number(target.port) || (secure ? 443 : 80);
|
|
46
|
+
const agent = secure
|
|
47
|
+
? new HttpsAgent({ keepAlive: true, rejectUnauthorized: false })
|
|
48
|
+
: new HttpAgent({ keepAlive: true });
|
|
49
|
+
const request = secure ? httpsRequest : httpRequest;
|
|
50
|
+
/** Every way a dev server might spell its own origin in a Location header. */
|
|
51
|
+
const targetOrigins = new Set(["localhost", "127.0.0.1", "[::1]", "0.0.0.0", target.hostname].map((h) => `${target.protocol}//${h}:${targetPort}`));
|
|
52
|
+
const server = createServer((req, res) => {
|
|
53
|
+
const url = req.url ?? "/";
|
|
54
|
+
if (url === CRT_PREFIX || url.startsWith(CRT_PREFIX + "/")) {
|
|
55
|
+
void handleCrtRoute(url, req, res, opts);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const crtOrigin = `http://${req.headers.host ?? "localhost"}`;
|
|
59
|
+
const headers = {};
|
|
60
|
+
for (const [k, v] of Object.entries(req.headers)) {
|
|
61
|
+
if (v === undefined || HOP_BY_HOP.has(k))
|
|
62
|
+
continue;
|
|
63
|
+
headers[k] = v;
|
|
64
|
+
}
|
|
65
|
+
headers.host = target.host;
|
|
66
|
+
const ae = filterAcceptEncoding(req.headers["accept-encoding"]);
|
|
67
|
+
if (ae !== undefined)
|
|
68
|
+
headers["accept-encoding"] = ae;
|
|
69
|
+
headers["x-forwarded-host"] = req.headers.host ?? "";
|
|
70
|
+
headers["x-forwarded-proto"] = "http";
|
|
71
|
+
const prior = req.headers["x-forwarded-for"];
|
|
72
|
+
const remote = req.socket.remoteAddress ?? "";
|
|
73
|
+
headers["x-forwarded-for"] = prior ? `${prior}, ${remote}` : remote;
|
|
74
|
+
let upstreamDone = false;
|
|
75
|
+
const upstream = request({ host: target.hostname, port: targetPort, method: req.method, path: url, headers, agent }, (up) => {
|
|
76
|
+
const status = up.statusCode ?? 502;
|
|
77
|
+
const outHeaders = responseHeaders(up.headers, targetOrigins, crtOrigin);
|
|
78
|
+
const inject = isHtml(up.headers["content-type"]) && req.method !== "HEAD" && status !== 204 && status !== 304;
|
|
79
|
+
up.on("end", () => {
|
|
80
|
+
upstreamDone = true;
|
|
81
|
+
});
|
|
82
|
+
up.on("error", () => res.destroy());
|
|
83
|
+
if (!inject) {
|
|
84
|
+
res.writeHead(status, outHeaders);
|
|
85
|
+
up.pipe(res);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const chunks = [];
|
|
89
|
+
up.on("data", (c) => chunks.push(c));
|
|
90
|
+
up.on("end", () => {
|
|
91
|
+
const raw = Buffer.concat(chunks);
|
|
92
|
+
const decoded = decodeBody(raw, up.headers["content-encoding"]);
|
|
93
|
+
if (decoded === null) {
|
|
94
|
+
// Unknown encoding: serve it untouched rather than corrupt it.
|
|
95
|
+
res.writeHead(status, outHeaders);
|
|
96
|
+
res.end(raw);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
// latin1 round-trips every byte, so injection is safe for any charset.
|
|
100
|
+
const body = Buffer.from(injectOverlayTag(decoded.toString("latin1")), "latin1");
|
|
101
|
+
delete outHeaders["content-encoding"];
|
|
102
|
+
outHeaders["content-length"] = String(body.length);
|
|
103
|
+
const csp = outHeaders["content-security-policy"];
|
|
104
|
+
if (typeof csp === "string")
|
|
105
|
+
outHeaders["content-security-policy"] = relaxCsp(csp);
|
|
106
|
+
res.writeHead(status, outHeaders);
|
|
107
|
+
res.end(body);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
upstream.on("error", (err) => {
|
|
111
|
+
if (!res.headersSent)
|
|
112
|
+
res.writeHead(502, { "content-type": "text/plain; charset=utf-8" });
|
|
113
|
+
res.end(`CRT: target ${opts.target} unreachable (${err.code ?? err.message})`);
|
|
114
|
+
});
|
|
115
|
+
res.on("close", () => {
|
|
116
|
+
if (!upstreamDone)
|
|
117
|
+
upstream.destroy();
|
|
118
|
+
});
|
|
119
|
+
req.pipe(upstream);
|
|
120
|
+
});
|
|
121
|
+
server.on("upgrade", (req, socket, head) => {
|
|
122
|
+
const up = secure
|
|
123
|
+
? tlsConnect({ host: target.hostname, port: targetPort, servername: target.hostname, rejectUnauthorized: false })
|
|
124
|
+
: netConnect({ host: target.hostname, port: targetPort });
|
|
125
|
+
up.once(secure ? "secureConnect" : "connect", () => {
|
|
126
|
+
up.write(rawUpgradeRequest(req, target.host));
|
|
127
|
+
if (head.length)
|
|
128
|
+
up.write(head);
|
|
129
|
+
up.pipe(socket);
|
|
130
|
+
socket.pipe(up);
|
|
131
|
+
});
|
|
132
|
+
wireClose(up, socket);
|
|
133
|
+
});
|
|
134
|
+
return server;
|
|
135
|
+
}
|
|
136
|
+
/** Replay the client's upgrade request verbatim, with Host rewritten and X-Forwarded-* added. */
|
|
137
|
+
function rawUpgradeRequest(req, targetHost) {
|
|
138
|
+
const lines = [`${req.method} ${req.url} HTTP/${req.httpVersion}`];
|
|
139
|
+
const raw = req.rawHeaders;
|
|
140
|
+
for (let i = 0; i < raw.length; i += 2) {
|
|
141
|
+
const name = raw[i];
|
|
142
|
+
const value = name.toLowerCase() === "host" ? targetHost : raw[i + 1];
|
|
143
|
+
lines.push(`${name}: ${value}`);
|
|
144
|
+
}
|
|
145
|
+
lines.push(`X-Forwarded-Host: ${req.headers.host ?? ""}`, "X-Forwarded-Proto: http", "", "");
|
|
146
|
+
return lines.join("\r\n");
|
|
147
|
+
}
|
|
148
|
+
function wireClose(a, b) {
|
|
149
|
+
a.on("error", () => b.destroy());
|
|
150
|
+
b.on("error", () => a.destroy());
|
|
151
|
+
a.on("close", () => b.destroy());
|
|
152
|
+
b.on("close", () => a.destroy());
|
|
153
|
+
}
|
|
154
|
+
/** Copy upstream response headers minus hop-by-hop ones, rewriting Location to the CRT origin. */
|
|
155
|
+
function responseHeaders(headers, targetOrigins, crtOrigin) {
|
|
156
|
+
const out = {};
|
|
157
|
+
for (const [k, v] of Object.entries(headers)) {
|
|
158
|
+
if (v === undefined || HOP_BY_HOP.has(k))
|
|
159
|
+
continue;
|
|
160
|
+
out[k] = v;
|
|
161
|
+
}
|
|
162
|
+
const location = out.location;
|
|
163
|
+
if (typeof location === "string") {
|
|
164
|
+
for (const origin of targetOrigins) {
|
|
165
|
+
if (location === origin || location.startsWith(origin + "/") || location.startsWith(origin + "?")) {
|
|
166
|
+
out.location = crtOrigin + location.slice(origin.length);
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return out;
|
|
172
|
+
}
|
|
173
|
+
async function handleCrtRoute(url, req, res, opts) {
|
|
174
|
+
const qs = url.indexOf("?");
|
|
175
|
+
const path = qs === -1 ? url : url.slice(0, qs);
|
|
176
|
+
const query = new URLSearchParams(qs === -1 ? "" : url.slice(qs + 1));
|
|
177
|
+
const cors = applyCors(req, res);
|
|
178
|
+
if (req.method === "OPTIONS") {
|
|
179
|
+
// F-6 preflight for the JSON POSTs from script-tag mode; non-local origins get nothing.
|
|
180
|
+
res.writeHead(cors ? 204 : 403);
|
|
181
|
+
res.end();
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (path === OVERLAY_PATH || path === EARLY_PATH) {
|
|
185
|
+
try {
|
|
186
|
+
const js = await readFile(path === OVERLAY_PATH ? opts.overlayPath : earlyPath(opts.overlayPath));
|
|
187
|
+
res.writeHead(200, {
|
|
188
|
+
"content-type": "text/javascript; charset=utf-8",
|
|
189
|
+
"content-length": String(js.length),
|
|
190
|
+
"cache-control": "no-store, max-age=0",
|
|
191
|
+
});
|
|
192
|
+
res.end(req.method === "HEAD" ? undefined : js);
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
res.writeHead(500, { "content-type": "text/plain; charset=utf-8" });
|
|
196
|
+
res.end(`CRT: overlay bundle missing at ${opts.overlayPath} — run \`npm run build\``);
|
|
197
|
+
}
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (path === `${CRT_PREFIX}/health`) {
|
|
201
|
+
json(res, 200, { ok: true, target: opts.target, projectRoot: opts.projectRoot });
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
if (path === CAPTURES_PATH) {
|
|
205
|
+
if (req.method !== "POST") {
|
|
206
|
+
json(res, 405, { ok: false, error: "POST a capture bundle here" });
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
const body = await readJson(req, MAX_CAPTURE_BODY);
|
|
210
|
+
if (!body.ok) {
|
|
211
|
+
json(res, body.status, { ok: false, error: `capture ${body.error}` });
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
try {
|
|
215
|
+
const written = writeCapture(opts.projectRoot, body.value);
|
|
216
|
+
json(res, 201, { ok: true, id: written.id, dir: written.dir, files: written.files });
|
|
217
|
+
}
|
|
218
|
+
catch (err) {
|
|
219
|
+
if (err instanceof CaptureValidationError) {
|
|
220
|
+
json(res, 400, { ok: false, error: err.message, errors: err.errors });
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
json(res, 500, { ok: false, error: `could not write capture: ${err.message}` });
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
if (path === SESSIONS_PATH || path.startsWith(SESSIONS_PATH + "/")) {
|
|
229
|
+
if (!opts.sessions) {
|
|
230
|
+
json(res, 503, { ok: false, error: "intake sessions are not enabled on this server" });
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
await handleSessionRoute(path, query, req, res, opts.sessions);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
json(res, 404, { ok: false, error: `no CRT route ${path}` });
|
|
237
|
+
}
|
|
238
|
+
/** early.js sits next to overlay.js in dist/. */
|
|
239
|
+
function earlyPath(overlayPath) {
|
|
240
|
+
return join(dirname(overlayPath), "early.js");
|
|
241
|
+
}
|
|
242
|
+
//# sourceMappingURL=proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"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"}
|
package/dist/serve.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `crt serve` (PRD F-1, F-4, F-5, F-23, F-24, N-6): run `init`, prune stale captures, resolve the
|
|
3
|
+
* target, wire the session registry, bind the proxy to 127.0.0.1, print the one-line status, and
|
|
4
|
+
* optionally open the browser. Every failure surfaces as a CrtError with a single actionable line.
|
|
5
|
+
*
|
|
6
|
+
* `CRT_SESSION_STUB=1` swaps the Agent SDK driver for the scripted stub (tests only).
|
|
7
|
+
*/
|
|
8
|
+
import { spawn } from "node:child_process";
|
|
9
|
+
import { readdirSync, readFileSync } from "node:fs";
|
|
10
|
+
import { resolve } from "node:path";
|
|
11
|
+
import { pruneCaptures } from "./captures.js";
|
|
12
|
+
import { CrtError } from "./errors.js";
|
|
13
|
+
import { initProject, readConfig } from "./init.js";
|
|
14
|
+
import { findProjectRoot } from "./project.js";
|
|
15
|
+
import { createProxyServer } from "./proxy.js";
|
|
16
|
+
import { startSession } from "./session.js";
|
|
17
|
+
import { startStubSession } from "./session-stub.js";
|
|
18
|
+
import { SessionRegistry } from "./sessions.js";
|
|
19
|
+
import { parseFrontmatter } from "./tasks.js";
|
|
20
|
+
import { resolveTarget } from "./target.js";
|
|
21
|
+
export async function serve(opts) {
|
|
22
|
+
const log = opts.log ?? ((line) => console.log(line));
|
|
23
|
+
const projectRoot = findProjectRoot(opts.cwd ?? process.cwd());
|
|
24
|
+
const init = initProject(projectRoot);
|
|
25
|
+
if (init.created.length)
|
|
26
|
+
log(`crt init: created ${init.created.join(", ")}`);
|
|
27
|
+
const pruned = pruneCaptures(projectRoot);
|
|
28
|
+
if (pruned.length)
|
|
29
|
+
log(`crt: pruned ${pruned.length} capture${pruned.length === 1 ? "" : "s"} older than 7 days`);
|
|
30
|
+
const config = readConfig(projectRoot);
|
|
31
|
+
const port = opts.port ?? config.port;
|
|
32
|
+
const target = await resolveTarget({ flag: opts.target, configTarget: config.target });
|
|
33
|
+
const tasksDir = resolve(projectRoot, config.tasksDir);
|
|
34
|
+
const sessions = new SessionRegistry({
|
|
35
|
+
projectRoot,
|
|
36
|
+
tasksDir,
|
|
37
|
+
intakePrompt: loadIntakePrompt(opts.intakePromptPath),
|
|
38
|
+
start: opts.sessionStarter ?? (process.env.CRT_SESSION_STUB ? startStubSession : startSession),
|
|
39
|
+
log,
|
|
40
|
+
});
|
|
41
|
+
const server = createProxyServer({ target: target.origin, projectRoot, overlayPath: opts.overlayPath, sessions });
|
|
42
|
+
await listen(server, port);
|
|
43
|
+
const url = `http://localhost:${port}`;
|
|
44
|
+
const tasks = countTasks(init.tasksDir);
|
|
45
|
+
log(`CRT ready at ${url} → ${target.origin} (project: ${projectRoot}, ${tasks} task${tasks === 1 ? "" : "s"})`);
|
|
46
|
+
if (opts.open)
|
|
47
|
+
openBrowser(url, log);
|
|
48
|
+
return {
|
|
49
|
+
server,
|
|
50
|
+
url,
|
|
51
|
+
target: target.origin,
|
|
52
|
+
projectRoot,
|
|
53
|
+
close: () => new Promise((done) => {
|
|
54
|
+
sessions.closeAll();
|
|
55
|
+
server.closeAllConnections();
|
|
56
|
+
server.close(() => done());
|
|
57
|
+
}),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* F-24/F-39: the intake instructions are the body of `plugin/skills/intake/SKILL.md` (below its
|
|
62
|
+
* frontmatter), copied into dist/ at build time so the published package carries them.
|
|
63
|
+
*/
|
|
64
|
+
export function loadIntakePrompt(path) {
|
|
65
|
+
let text;
|
|
66
|
+
try {
|
|
67
|
+
text = readFileSync(path, "utf8");
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
throw new CrtError(`intake instructions missing at ${path} — run npm run build`);
|
|
71
|
+
}
|
|
72
|
+
const fm = parseFrontmatter(text);
|
|
73
|
+
return (fm ? fm.body : text).trim();
|
|
74
|
+
}
|
|
75
|
+
function listen(server, port) {
|
|
76
|
+
return new Promise((resolve, reject) => {
|
|
77
|
+
const onError = (err) => {
|
|
78
|
+
server.removeListener("listening", onListening);
|
|
79
|
+
if (err.code === "EADDRINUSE") {
|
|
80
|
+
reject(new CrtError(`port ${port} is already in use — stop the other process or pass --port <n>`));
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
reject(new CrtError(`cannot listen on 127.0.0.1:${port} (${err.code ?? err.message})`));
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
const onListening = () => {
|
|
87
|
+
server.removeListener("error", onError);
|
|
88
|
+
resolve();
|
|
89
|
+
};
|
|
90
|
+
server.once("error", onError);
|
|
91
|
+
server.once("listening", onListening);
|
|
92
|
+
server.listen(port, "127.0.0.1");
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
function countTasks(tasksDir) {
|
|
96
|
+
try {
|
|
97
|
+
return readdirSync(tasksDir).filter((f) => /^CRT-\d{4}-.*\.md$/.test(f)).length;
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return 0;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/** Open `url` in the default browser via the platform opener, spawned without a shell. */
|
|
104
|
+
export function openBrowser(url, log) {
|
|
105
|
+
const [cmd, args] = process.platform === "win32"
|
|
106
|
+
? ["cmd.exe", ["/c", "start", "", url]]
|
|
107
|
+
: process.platform === "darwin"
|
|
108
|
+
? ["open", [url]]
|
|
109
|
+
: ["xdg-open", [url]];
|
|
110
|
+
const child = spawn(cmd, args, { shell: false, stdio: "ignore", detached: true, windowsHide: true });
|
|
111
|
+
child.on("error", (err) => log(`crt: could not open browser (${err.message}); open ${url} yourself`));
|
|
112
|
+
child.unref();
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=serve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serve.js","sourceRoot":"","sources":["../src/serve.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEpD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AA6B5C,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,IAAkB;IAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9D,MAAM,WAAW,GAAG,eAAe,CAAC,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAE/D,MAAM,IAAI,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;IACtC,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM;QAAE,GAAG,CAAC,qBAAqB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC7E,MAAM,MAAM,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;IAC1C,IAAI,MAAM,CAAC,MAAM;QAAE,GAAG,CAAC,eAAe,MAAM,CAAC,MAAM,WAAW,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,oBAAoB,CAAC,CAAC;IAElH,MAAM,MAAM,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;IACvC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC;IACtC,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IAEvF,MAAM,QAAQ,GAAG,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IACvD,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC;QACnC,WAAW;QACX,QAAQ;QACR,YAAY,EAAE,gBAAgB,CAAC,IAAI,CAAC,gBAAgB,CAAC;QACrD,KAAK,EAAE,IAAI,CAAC,cAAc,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,YAAY,CAAC;QAC9F,GAAG;KACJ,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,iBAAiB,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,CAAC,CAAC;IAClH,MAAM,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAE3B,MAAM,GAAG,GAAG,oBAAoB,IAAI,EAAE,CAAC;IACvC,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACxC,GAAG,CAAC,gBAAgB,GAAG,MAAM,MAAM,CAAC,MAAM,cAAc,WAAW,KAAK,KAAK,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;IAChH,IAAI,IAAI,CAAC,IAAI;QAAE,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAErC,OAAO;QACL,MAAM;QACN,GAAG;QACH,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,WAAW;QACX,KAAK,EAAE,GAAG,EAAE,CACV,IAAI,OAAO,CAAO,CAAC,IAAI,EAAE,EAAE;YACzB,QAAQ,CAAC,QAAQ,EAAE,CAAC;YACpB,MAAM,CAAC,mBAAmB,EAAE,CAAC;YAC7B,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;QAC7B,CAAC,CAAC;KACL,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,QAAQ,CAAC,kCAAkC,IAAI,sBAAsB,CAAC,CAAC;IACnF,CAAC;IACD,MAAM,EAAE,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAClC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;AACtC,CAAC;AAED,SAAS,MAAM,CAAC,MAAc,EAAE,IAAY;IAC1C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,OAAO,GAAG,CAAC,GAA0B,EAAE,EAAE;YAC7C,MAAM,CAAC,cAAc,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;YAChD,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;gBAC9B,MAAM,CAAC,IAAI,QAAQ,CAAC,QAAQ,IAAI,gEAAgE,CAAC,CAAC,CAAC;YACrG,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,IAAI,QAAQ,CAAC,8BAA8B,IAAI,KAAK,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;YAC1F,CAAC;QACH,CAAC,CAAC;QACF,MAAM,WAAW,GAAG,GAAG,EAAE;YACvB,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YACxC,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC;QACF,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC9B,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;QACtC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,UAAU,CAAC,QAAgB;IAClC,IAAI,CAAC;QACH,OAAO,WAAW,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAClF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,WAAW,CAAC,GAAW,EAAE,GAA2B;IAClE,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,GACf,OAAO,CAAC,QAAQ,KAAK,OAAO;QAC1B,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;QACvC,CAAC,CAAC,OAAO,CAAC,QAAQ,KAAK,QAAQ;YAC7B,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC;YACjB,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5B,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;IACrG,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,gCAAgC,GAAG,CAAC,OAAO,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC;IACtG,KAAK,CAAC,KAAK,EAAE,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The contract between an intake session and the chat panel (PRD F-25, F-26, F-28, F-29).
|
|
3
|
+
* `session.ts` (real, on the Agent SDK) and `session-stub.ts` (scripted, for e2e) both produce
|
|
4
|
+
* these events; `sessions.ts` numbers them and streams them over SSE; the overlay imports only
|
|
5
|
+
* the types. Nothing here depends on the SDK, so this file is safe for the overlay bundle.
|
|
6
|
+
*/
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=session-events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-events.js","sourceRoot":"","sources":["../src/session-events.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scripted intake session for tests (task CRT-0003 Ask 7). Enabled by `CRT_SESSION_STUB=1` on
|
|
3
|
+
* `crt serve`; produces the same `SessionEvent`s the real driver would, without the SDK:
|
|
4
|
+
*
|
|
5
|
+
* init → streamed text → a pre-allowed tool (Read) → a tool that needs permission (Bash npm test,
|
|
6
|
+
* through the real F-26 policy) → text depending on Allow/Deny → result.
|
|
7
|
+
* Next developer message containing "write" → `writeTask` → task_written → result.
|
|
8
|
+
* Any other message → echoed back → result. `interrupt()` cuts the current turn short.
|
|
9
|
+
* A first message carrying the F-14 quick-note instructions skips the permission prompt and the
|
|
10
|
+
* DoD wait: Read, then `writeTask` straight away (unless the note says "ask me", which makes
|
|
11
|
+
* the stub ask a question instead, so the panel-opens-itself path can be tested too).
|
|
12
|
+
*/
|
|
13
|
+
import { randomUUID } from "node:crypto";
|
|
14
|
+
const TICK_MS = 15;
|
|
15
|
+
export function startStubSession(opts) {
|
|
16
|
+
const listeners = new Set();
|
|
17
|
+
const pending = new Map();
|
|
18
|
+
let state = "starting";
|
|
19
|
+
let closed = false;
|
|
20
|
+
let turn = 0; // increments on interrupt/close so a running script notices and stops
|
|
21
|
+
let busy = false;
|
|
22
|
+
const queue = [];
|
|
23
|
+
let n = 0;
|
|
24
|
+
const emit = (e) => {
|
|
25
|
+
for (const fn of listeners)
|
|
26
|
+
fn(e);
|
|
27
|
+
};
|
|
28
|
+
const setState = (next, detail) => {
|
|
29
|
+
if (closed)
|
|
30
|
+
return;
|
|
31
|
+
state = next;
|
|
32
|
+
emit(detail === undefined ? { type: "state", state: next } : { type: "state", state: next, detail });
|
|
33
|
+
};
|
|
34
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
35
|
+
const cancelled = (t) => closed || t !== turn;
|
|
36
|
+
const say = async (t, text) => {
|
|
37
|
+
const messageId = `stub-msg-${++n}`;
|
|
38
|
+
emit({ type: "assistant_start", messageId });
|
|
39
|
+
for (const piece of text.split(/(?<=\s)/)) {
|
|
40
|
+
if (cancelled(t))
|
|
41
|
+
return;
|
|
42
|
+
emit({ type: "text", messageId, text: piece });
|
|
43
|
+
await sleep(TICK_MS);
|
|
44
|
+
}
|
|
45
|
+
emit({ type: "assistant_end", messageId });
|
|
46
|
+
};
|
|
47
|
+
const useTool = async (t, name, input, label, result) => {
|
|
48
|
+
const id = `stub-tool-${++n}`;
|
|
49
|
+
const decision = opts.decide(name, input);
|
|
50
|
+
let allowed = decision.kind === "allow";
|
|
51
|
+
if (decision.kind === "ask") {
|
|
52
|
+
allowed = await askPermission(t, name, label, input);
|
|
53
|
+
if (cancelled(t))
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
if (!allowed)
|
|
57
|
+
return false;
|
|
58
|
+
emit({ type: "tool_use", id, name, label });
|
|
59
|
+
await sleep(TICK_MS);
|
|
60
|
+
emit({ type: "tool_result", id, isError: false, summary: result });
|
|
61
|
+
return true;
|
|
62
|
+
};
|
|
63
|
+
const askPermission = (t, toolName, title, input) => new Promise((resolve) => {
|
|
64
|
+
const id = randomUUID();
|
|
65
|
+
const timeoutMs = opts.permissionTimeoutMs ?? 5 * 60 * 1000;
|
|
66
|
+
const timer = setTimeout(() => settle("deny", "timeout"), timeoutMs);
|
|
67
|
+
const settle = (behavior, by) => {
|
|
68
|
+
if (!pending.delete(id))
|
|
69
|
+
return;
|
|
70
|
+
clearTimeout(timer);
|
|
71
|
+
emit({ type: "permission_resolved", id, behavior, by });
|
|
72
|
+
if (!cancelled(t) && pending.size === 0)
|
|
73
|
+
setState("running");
|
|
74
|
+
resolve(behavior === "allow");
|
|
75
|
+
};
|
|
76
|
+
pending.set(id, { settle });
|
|
77
|
+
emit({ type: "permission", id, toolName, title, detail: String(input.command ?? input.file_path ?? JSON.stringify(input)), expiresAt: Date.now() + timeoutMs });
|
|
78
|
+
setState("waiting");
|
|
79
|
+
});
|
|
80
|
+
const finish = (t, ok, errors = []) => {
|
|
81
|
+
if (cancelled(t))
|
|
82
|
+
return; // an interrupt already produced this turn's result
|
|
83
|
+
emit({ type: "result", ok, durationMs: 100, costUsd: 0.001, errors });
|
|
84
|
+
setState("idle");
|
|
85
|
+
};
|
|
86
|
+
const firstTurn = async (first) => {
|
|
87
|
+
const t = turn;
|
|
88
|
+
emit({ type: "user", text: first.text, images: (first.images ?? []).map((i) => i.label) });
|
|
89
|
+
await sleep(TICK_MS);
|
|
90
|
+
if (cancelled(t))
|
|
91
|
+
return;
|
|
92
|
+
emit({ type: "init", sessionId: opts.id, model: "stub-model", cwd: opts.cwd, claudeCodeVersion: "stub" });
|
|
93
|
+
setState("running");
|
|
94
|
+
await say(t, "I read the capture. The annotated element is rendered by **CartSummary**; let me look at the source.\n");
|
|
95
|
+
if (cancelled(t))
|
|
96
|
+
return;
|
|
97
|
+
if (!(await useTool(t, "Read", { file_path: "src/components/Cart.tsx" }, "Read src/components/Cart.tsx", "88 lines")))
|
|
98
|
+
return;
|
|
99
|
+
const ran = await useTool(t, "Bash", { command: "npm test" }, "Bash npm test", "12 passing");
|
|
100
|
+
if (cancelled(t))
|
|
101
|
+
return;
|
|
102
|
+
await say(t, ran
|
|
103
|
+
? "Tests pass today, so the fix needs a new one.\n\nProposed definition of done:\n- [ ] Cart total applies the promo discount\n- [ ] Unit test covers the discounted total\n\nReply **write** to save the task, or tell me what to change."
|
|
104
|
+
: "Understood, I won't run tests.\n\nProposed definition of done:\n- [ ] Cart total applies the promo discount\n\nReply **write** to save the task, or tell me what to change.");
|
|
105
|
+
finish(t, true);
|
|
106
|
+
};
|
|
107
|
+
/** F-14: the quick-note script. Note text decides whether the stub writes or asks. */
|
|
108
|
+
const quickTurn = async (t, first) => {
|
|
109
|
+
emit({ type: "user", text: first.text, images: (first.images ?? []).map((i) => i.label) });
|
|
110
|
+
await sleep(TICK_MS);
|
|
111
|
+
if (cancelled(t))
|
|
112
|
+
return;
|
|
113
|
+
emit({ type: "init", sessionId: opts.id, model: "stub-model", cwd: opts.cwd, claudeCodeVersion: "stub" });
|
|
114
|
+
setState("running");
|
|
115
|
+
if (!(await useTool(t, "Read", { file_path: "src/components/Cart.tsx" }, "Read src/components/Cart.tsx", "88 lines")))
|
|
116
|
+
return;
|
|
117
|
+
if (/ask me/i.test(first.text)) {
|
|
118
|
+
await say(t, "Quick question before I write this: should the discount apply before or after tax?");
|
|
119
|
+
finish(t, true);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
await writeStubTask(t);
|
|
123
|
+
finish(t, true);
|
|
124
|
+
};
|
|
125
|
+
const writeStubTask = async (t) => {
|
|
126
|
+
const id = `stub-tool-${++n}`;
|
|
127
|
+
emit({ type: "tool_use", id, name: "mcp__crt__write_task", label: "Write task: Cart total excludes applied discount" });
|
|
128
|
+
try {
|
|
129
|
+
const written = await opts.writeTask({
|
|
130
|
+
title: "Cart total excludes applied discount",
|
|
131
|
+
summary: "The cart total ignores the SAVE10 promo that the page shows as applied.",
|
|
132
|
+
context: "Reproduce: open /cart?promo=SAVE10. `CartSummary` (src/components/Cart.tsx:88) renders `subtotal` instead of `total`.",
|
|
133
|
+
ask: "Render the discounted total and cover it with a unit test.",
|
|
134
|
+
definitionOfDone: ["Cart total applies the promo discount", "Unit test covers the discounted total"],
|
|
135
|
+
notes: "Stub intake; nothing was read from disk.",
|
|
136
|
+
tags: ["cart", "pricing"],
|
|
137
|
+
files: ["src/components/Cart.tsx"],
|
|
138
|
+
});
|
|
139
|
+
emit({ type: "tool_result", id, isError: false, summary: `Task ${written.id} written to ${written.path}` });
|
|
140
|
+
emit({ type: "task_written", id: written.id, path: written.path });
|
|
141
|
+
await say(t, `Written **${written.id}** at \`${written.path}\`.`);
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
emit({ type: "tool_result", id, isError: true, summary: err.message });
|
|
145
|
+
await say(t, `Could not write the task: ${err.message}`);
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
const laterTurn = async (text) => {
|
|
149
|
+
const t = turn;
|
|
150
|
+
setState("running");
|
|
151
|
+
await sleep(TICK_MS);
|
|
152
|
+
if (cancelled(t))
|
|
153
|
+
return;
|
|
154
|
+
if (/\bwrite\b/i.test(text)) {
|
|
155
|
+
await writeStubTask(t);
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
await say(t, `You said: ${text}`);
|
|
159
|
+
}
|
|
160
|
+
finish(t, true);
|
|
161
|
+
};
|
|
162
|
+
const pump = async () => {
|
|
163
|
+
if (busy)
|
|
164
|
+
return;
|
|
165
|
+
busy = true;
|
|
166
|
+
try {
|
|
167
|
+
while (queue.length && !closed)
|
|
168
|
+
await laterTurn(queue.shift());
|
|
169
|
+
}
|
|
170
|
+
finally {
|
|
171
|
+
busy = false;
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
let started = false;
|
|
175
|
+
const begin = (first) => {
|
|
176
|
+
started = true;
|
|
177
|
+
busy = true;
|
|
178
|
+
const script = /Quick note \(F-14\)/.test(first.text) ? quickTurn(turn, first) : firstTurn(first);
|
|
179
|
+
void script.finally(() => {
|
|
180
|
+
busy = false;
|
|
181
|
+
void pump();
|
|
182
|
+
});
|
|
183
|
+
};
|
|
184
|
+
if (opts.first) {
|
|
185
|
+
const first = opts.first;
|
|
186
|
+
queueMicrotask(() => begin(first));
|
|
187
|
+
}
|
|
188
|
+
return {
|
|
189
|
+
id: opts.id,
|
|
190
|
+
send(u) {
|
|
191
|
+
if (closed)
|
|
192
|
+
return;
|
|
193
|
+
if (!started) {
|
|
194
|
+
begin(u); // warm start: this is the capture message
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
emit({ type: "user", text: u.text, images: (u.images ?? []).map((i) => i.label) });
|
|
198
|
+
queue.push(u.text);
|
|
199
|
+
void pump();
|
|
200
|
+
},
|
|
201
|
+
async interrupt() {
|
|
202
|
+
if (closed || state === "idle")
|
|
203
|
+
return;
|
|
204
|
+
turn++;
|
|
205
|
+
for (const p of [...pending.values()])
|
|
206
|
+
p.settle("deny", "session");
|
|
207
|
+
emit({ type: "result", ok: false, durationMs: 0, costUsd: 0, errors: ["interrupted"] });
|
|
208
|
+
setState("idle");
|
|
209
|
+
},
|
|
210
|
+
respondPermission(id, behavior) {
|
|
211
|
+
const p = pending.get(id);
|
|
212
|
+
if (!p)
|
|
213
|
+
return false;
|
|
214
|
+
p.settle(behavior, "user");
|
|
215
|
+
return true;
|
|
216
|
+
},
|
|
217
|
+
close() {
|
|
218
|
+
if (closed)
|
|
219
|
+
return;
|
|
220
|
+
turn++;
|
|
221
|
+
for (const p of [...pending.values()])
|
|
222
|
+
p.settle("deny", "session");
|
|
223
|
+
setState("ended");
|
|
224
|
+
closed = true;
|
|
225
|
+
},
|
|
226
|
+
onEvent(fn) {
|
|
227
|
+
listeners.add(fn);
|
|
228
|
+
return () => listeners.delete(fn);
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
//# sourceMappingURL=session-stub.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-stub.js","sourceRoot":"","sources":["../src/session-stub.ts"],"names":[],"mappings":"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"}
|