@hozu/cli 0.4.2 → 0.6.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.
Files changed (57) hide show
  1. package/dist/cdp.d.ts +10 -0
  2. package/dist/cdp.d.ts.map +1 -0
  3. package/dist/cdp.js +108 -0
  4. package/dist/cdp.js.map +1 -0
  5. package/dist/commands/add-widget.d.ts +5 -0
  6. package/dist/commands/add-widget.d.ts.map +1 -0
  7. package/dist/commands/add-widget.js +90 -0
  8. package/dist/commands/add-widget.js.map +1 -0
  9. package/dist/commands/add.d.ts +1 -0
  10. package/dist/commands/add.d.ts.map +1 -1
  11. package/dist/commands/add.js +1 -1
  12. package/dist/commands/add.js.map +1 -1
  13. package/dist/commands/browse.d.ts +15 -0
  14. package/dist/commands/browse.d.ts.map +1 -0
  15. package/dist/commands/browse.js +466 -0
  16. package/dist/commands/browse.js.map +1 -0
  17. package/dist/commands/check.d.ts +2 -0
  18. package/dist/commands/check.d.ts.map +1 -1
  19. package/dist/commands/check.js +38 -2
  20. package/dist/commands/check.js.map +1 -1
  21. package/dist/commands/docs.d.ts +3 -0
  22. package/dist/commands/docs.d.ts.map +1 -0
  23. package/dist/commands/docs.js +36 -0
  24. package/dist/commands/docs.js.map +1 -0
  25. package/dist/commands/map.d.ts.map +1 -1
  26. package/dist/commands/map.js +8 -0
  27. package/dist/commands/map.js.map +1 -1
  28. package/dist/commands/request.d.ts +5 -0
  29. package/dist/commands/request.d.ts.map +1 -1
  30. package/dist/commands/request.js +31 -9
  31. package/dist/commands/request.js.map +1 -1
  32. package/dist/commands/scaffold.d.ts.map +1 -1
  33. package/dist/commands/scaffold.js +26 -150
  34. package/dist/commands/scaffold.js.map +1 -1
  35. package/dist/commands/validate.d.ts.map +1 -1
  36. package/dist/commands/validate.js +15 -12
  37. package/dist/commands/validate.js.map +1 -1
  38. package/dist/contract.d.ts +49 -0
  39. package/dist/contract.d.ts.map +1 -1
  40. package/dist/load.d.ts +1 -0
  41. package/dist/load.d.ts.map +1 -1
  42. package/dist/load.js +9 -0
  43. package/dist/load.js.map +1 -1
  44. package/dist/main.d.ts.map +1 -1
  45. package/dist/main.js +47 -6
  46. package/dist/main.js.map +1 -1
  47. package/dist/output.d.ts.map +1 -1
  48. package/dist/output.js +41 -0
  49. package/dist/output.js.map +1 -1
  50. package/package.json +7 -6
  51. package/schema/browse.schema.json +205 -0
  52. package/schema/check.schema.json +10 -2
  53. package/schema/docs.schema.json +45 -0
  54. package/schema/inspect.schema.json +38 -0
  55. package/schema/map.schema.json +31 -0
  56. package/schema/request.schema.json +7 -0
  57. package/schema/validate.schema.json +10 -2
@@ -0,0 +1,466 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
3
+ import { tmpdir } from 'node:os';
4
+ import { dirname, extname, join, relative, resolve } from 'node:path';
5
+ import { findBrowser, launch } from '../cdp.js';
6
+ import { HozuCliError } from '../errors.js';
7
+ import { appParts } from './request.js';
8
+ const ORIGIN = 'http://localhost';
9
+ const LIMIT = 1500;
10
+ const QUIET_MS = 300;
11
+ const SETTLE_MS = 500;
12
+ const CAP_MS = 8000;
13
+ const MIME = {
14
+ '.png': 'image/png',
15
+ '.jpg': 'image/jpeg',
16
+ '.jpeg': 'image/jpeg',
17
+ '.svg': 'image/svg+xml',
18
+ '.ico': 'image/x-icon',
19
+ '.webp': 'image/webp',
20
+ '.json': 'application/json',
21
+ '.txt': 'text/plain',
22
+ '.css': 'text/css',
23
+ '.js': 'text/javascript',
24
+ '.woff2': 'font/woff2',
25
+ };
26
+ const KEYS = {
27
+ Enter: { code: 'Enter', keyCode: 13, text: '\r' },
28
+ Escape: { code: 'Escape', keyCode: 27 },
29
+ Tab: { code: 'Tab', keyCode: 9 },
30
+ Backspace: { code: 'Backspace', keyCode: 8 },
31
+ Space: { code: 'Space', keyCode: 32, text: ' ' },
32
+ ArrowUp: { code: 'ArrowUp', keyCode: 38 },
33
+ ArrowDown: { code: 'ArrowDown', keyCode: 40 },
34
+ ArrowLeft: { code: 'ArrowLeft', keyCode: 37 },
35
+ ArrowRight: { code: 'ArrowRight', keyCode: 39 },
36
+ };
37
+ const PAGE = String.raw `(() => {
38
+ const norm = (s) => (s ?? '').replace(/\s+/g, ' ').trim().toLowerCase()
39
+ const shown = (el) => { const r = el.getBoundingClientRect(); return r.width > 0 || r.height > 0 }
40
+ const nameOf = (el) => {
41
+ const aria = el.getAttribute('aria-label')
42
+ if (aria) return aria
43
+ const by = el.getAttribute('aria-labelledby')
44
+ if (by) return by.split(/\s+/).map((id) => document.getElementById(id)?.textContent ?? '').join(' ')
45
+ if (el.labels && el.labels.length) return [...el.labels].map((l) => l.textContent).join(' ')
46
+ if (el.tagName === 'INPUT' && ['submit', 'button'].includes(el.type)) return el.value
47
+ if (el.placeholder) return el.placeholder
48
+ if (el.getAttribute('title') && !el.textContent.trim()) return el.getAttribute('title')
49
+ return el.textContent
50
+ }
51
+ const KINDS = {
52
+ fill: 'input:not([type=hidden]):not([type=checkbox]):not([type=radio]):not([type=submit]):not([type=button]), textarea, [contenteditable=true]',
53
+ select: 'select',
54
+ check: 'input[type=checkbox], input[type=radio]',
55
+ click: 'button, a[href], [role=button], [role=link], [role=tab], [role=option], [role=menuitem], [role=checkbox], [role=switch], input[type=submit], input[type=button], summary, [title], label',
56
+ }
57
+ const find = (kind, name) => {
58
+ const all = [...document.querySelectorAll(KINDS[kind])].filter(shown)
59
+ const want = norm(name)
60
+ let hits = all.filter((el) => norm(nameOf(el)) === want || norm(el.getAttribute('title')) === want)
61
+ if (!hits.length && kind === 'click')
62
+ hits = [...document.body.querySelectorAll('*')].filter(
63
+ (el) => shown(el) && norm(el.textContent) === want && ![...el.children].some((c) => norm(c.textContent) === want),
64
+ )
65
+ if (!hits.length) {
66
+ const names = [...new Set(all.map((el) => (nameOf(el) ?? '').replace(/\s+/g, ' ').trim()).filter(Boolean))]
67
+ return { error: 'No ' + kind + ' target named "' + name + '"' + (names.length ? '. On the page: ' + names.slice(0, 20).map((n) => JSON.stringify(n.slice(0, 40))).join(', ') : '') }
68
+ }
69
+ return { el: hits[0], count: hits.length }
70
+ }
71
+ const setValue = (el, value) => {
72
+ const proto = el instanceof HTMLTextAreaElement ? HTMLTextAreaElement.prototype : el instanceof HTMLSelectElement ? HTMLSelectElement.prototype : HTMLInputElement.prototype
73
+ el.focus()
74
+ if (el.isContentEditable) el.textContent = value
75
+ else Object.getOwnPropertyDescriptor(proto, 'value').set.call(el, value)
76
+ el.dispatchEvent(new Event('input', { bubbles: true }))
77
+ el.dispatchEvent(new Event('change', { bubbles: true }))
78
+ }
79
+ const note = (count) => (count > 1 ? count + ' matched; used the first' : null)
80
+ return {
81
+ point(kind, name) {
82
+ const f = find(kind, name)
83
+ if (f.error) return f
84
+ f.el.scrollIntoView({ block: 'center', inline: 'center' })
85
+ const r = f.el.getBoundingClientRect()
86
+ return { x: r.left + r.width / 2, y: r.top + r.height / 2, note: note(f.count) }
87
+ },
88
+ fill(name, value) {
89
+ const f = find('fill', name)
90
+ if (f.error) return f
91
+ setValue(f.el, value)
92
+ return { note: note(f.count) }
93
+ },
94
+ select(name, option) {
95
+ const f = find('select', name)
96
+ if (f.error) return f
97
+ const o = [...f.el.options].find((o) => norm(o.textContent) === norm(option) || o.value === option)
98
+ if (!o) return { error: 'Select "' + name + '" has no option "' + option + '". Options: ' + [...f.el.options].map((o) => JSON.stringify(o.textContent.trim())).join(', ') }
99
+ setValue(f.el, o.value)
100
+ return { note: note(f.count) }
101
+ },
102
+ report(selectors, expected) {
103
+ const widgets = []
104
+ const hydrated = document.documentElement.hasAttribute('data-hozu-ready')
105
+ for (const el of document.querySelectorAll('[data-hozu-widget]')) {
106
+ const name = el.getAttribute('data-hozu-widget')
107
+ const state = el.getAttribute('data-hozu-widget-state')
108
+ const load = expected.find(([n]) => n === name)?.[1]
109
+ const r = el.getBoundingClientRect()
110
+ const empty = !el.children.length && !el.textContent.trim()
111
+ widgets.push({
112
+ name,
113
+ state: state === 'loading' ? 'not mounted' : state,
114
+ width: Math.round(r.width),
115
+ height: Math.round(r.height),
116
+ canvases: el.querySelectorAll('canvas').length,
117
+ elements: el.querySelectorAll('*').length,
118
+ hint:
119
+ state === 'failed'
120
+ ? 'its setup threw; see errors'
121
+ : state === 'loading'
122
+ ? load === 'visible' && (r.bottom < 0 || r.top > innerHeight)
123
+ ? "load: 'visible' mounts it when it scrolls into view"
124
+ : load === 'idle'
125
+ ? "load: 'idle' mounts it when the browser is idle"
126
+ : 'its module has not loaded; see errors'
127
+ : r.height === 0
128
+ ? 'it has no height, so a map or canvas inside shows nothing: give it a height class such as h-64'
129
+ : empty
130
+ ? 'it mounted but rendered nothing'
131
+ : null,
132
+ })
133
+ }
134
+ if (!hydrated)
135
+ for (const [name] of expected)
136
+ widgets.push({
137
+ name, state: 'not mounted', width: null, height: null, canvases: 0, elements: 0,
138
+ hint: 'the page did not hydrate; see errors',
139
+ })
140
+ const elements = []
141
+ for (const sel of selectors)
142
+ for (const el of document.querySelectorAll(sel)) {
143
+ const attrs = {}
144
+ for (const a of el.attributes) attrs[a.name] = a.value
145
+ const text = (el.innerText ?? el.textContent ?? '').replace(/\s+/g, ' ').trim()
146
+ elements.push({ selector: sel, tag: el.tagName.toLowerCase(), attrs, text: text.length > 120 ? text.slice(0, 120) + '…' : text })
147
+ }
148
+ return {
149
+ title: document.title,
150
+ url: location.pathname + location.search,
151
+ hydrated,
152
+ text: (document.body?.innerText ?? '').replace(/[ \t]+/g, ' ').replace(/\n\s*\n+/g, '\n').trim(),
153
+ widgets,
154
+ elements,
155
+ }
156
+ },
157
+ }
158
+ })()`;
159
+ async function bodyOf(request) {
160
+ if (request.postDataEntries?.length)
161
+ return Buffer.concat(request.postDataEntries.map((e) => Buffer.from(e.bytes ?? '', 'base64')));
162
+ return request.postData === undefined ? undefined : Buffer.from(request.postData);
163
+ }
164
+ export async function runBrowse(loaded, options) {
165
+ const path = options.path ?? '/';
166
+ if (!path.startsWith('/'))
167
+ throw new HozuCliError('usage', 'hozu browse needs a path', ['hozu browse /']);
168
+ const browser = findBrowser();
169
+ if (!browser)
170
+ throw new HozuCliError('config', 'hozu browse needs Chrome, Chromium or Edge, and none was found', [
171
+ 'Install Google Chrome, or set HOZU_CHROME=/path/to/chrome',
172
+ ]);
173
+ const parts = await appParts(loaded, 'browse', options.session);
174
+ const root = dirname(loaded.path);
175
+ const build = loaded.build(false);
176
+ const server = await parts.importFrom('@hozu/runtime-server', ['npm install @hozu/runtime-server']);
177
+ const styles = await (await parts.importFrom('@hozu/css', ['npm install @hozu/css'])).compileStyles(build, { base: root });
178
+ const used = server.usedWidgets(build.ir);
179
+ const widgets = used.length
180
+ ? await (await parts.importFrom('@hozu/bundle', ['npm install @hozu/bundle'])).bundleWidgets(build)
181
+ : null;
182
+ const handler = server.createHandler({
183
+ build,
184
+ styles,
185
+ widgets,
186
+ resolvers: parts.resolvers,
187
+ session: parts.session,
188
+ env: process.env,
189
+ });
190
+ const publicDir = join(root, 'public');
191
+ const respond = async (request) => {
192
+ const response = await handler.fetch(request);
193
+ const file = join(publicDir, decodeURIComponent(new URL(request.url).pathname));
194
+ if (response.status !== 404 || !file.startsWith(publicDir) || !existsSync(file))
195
+ return response;
196
+ return new Response(await readFile(file).catch(() => null), {
197
+ headers: { 'content-type': MIME[extname(file)] ?? 'application/octet-stream' },
198
+ });
199
+ };
200
+ const profile = await mkdtemp(join(tmpdir(), 'hozu-browse-'));
201
+ const cdp = launch(browser, profile);
202
+ const errors = [];
203
+ const steps = [];
204
+ let status = 0;
205
+ let inflight = 0;
206
+ let lastActivity = Date.now();
207
+ let loaded_ = false;
208
+ try {
209
+ const { targetId } = await cdp.send('Target.createTarget', { url: 'about:blank' });
210
+ const { sessionId } = await cdp.send('Target.attachToTarget', { targetId, flatten: true });
211
+ const send = (method, params = {}) => cdp.send(method, params, sessionId);
212
+ const documentUrls = new Set();
213
+ cdp.on((method, params, from) => {
214
+ if (from !== sessionId)
215
+ return;
216
+ if (method === 'Fetch.requestPaused') {
217
+ const r = params.request;
218
+ void (async () => {
219
+ try {
220
+ const response = await respond(new Request(r.url, {
221
+ method: r.method,
222
+ headers: r.headers,
223
+ ...(r.method === 'GET' || r.method === 'HEAD' ? {} : { body: (await bodyOf(r)) ?? null }),
224
+ }));
225
+ const headers = [...response.headers]
226
+ .filter(([k]) => k !== 'set-cookie')
227
+ .map(([name, value]) => ({ name, value }));
228
+ for (const c of response.headers.getSetCookie())
229
+ headers.push({ name: 'set-cookie', value: c });
230
+ const body = Buffer.from(await response.arrayBuffer()).toString('base64');
231
+ await send('Fetch.fulfillRequest', {
232
+ requestId: params.requestId,
233
+ responseCode: response.status,
234
+ responseHeaders: headers,
235
+ body,
236
+ });
237
+ }
238
+ catch (error) {
239
+ errors.push({ kind: 'request', text: `the app threw: ${String(error)}`, at: r.url });
240
+ await send('Fetch.failRequest', { requestId: params.requestId, errorReason: 'Failed' }).catch(() => { });
241
+ }
242
+ })();
243
+ }
244
+ if (method.startsWith('Network.'))
245
+ lastActivity = Date.now();
246
+ if (method === 'Network.requestWillBeSent') {
247
+ inflight++;
248
+ if (params.type === 'Document')
249
+ documentUrls.add(params.requestId);
250
+ }
251
+ if (method === 'Network.loadingFinished')
252
+ inflight--;
253
+ if (method === 'Network.loadingFailed') {
254
+ inflight--;
255
+ if (!params.canceled && params.blockedReason !== 'inspector')
256
+ errors.push({ kind: 'request', text: params.errorText, at: null });
257
+ }
258
+ if (method === 'Network.responseReceived') {
259
+ const url = params.response.url.startsWith(ORIGIN)
260
+ ? params.response.url.slice(ORIGIN.length)
261
+ : params.response.url;
262
+ if (documentUrls.has(params.requestId))
263
+ status = params.response.status;
264
+ if (params.response.status >= 400)
265
+ errors.push({ kind: 'request', text: `${params.response.status} ${url}`, at: url });
266
+ }
267
+ if (method === 'Runtime.exceptionThrown') {
268
+ const d = params.exceptionDetails;
269
+ const frame = d.stackTrace?.callFrames?.[0];
270
+ errors.push({
271
+ kind: 'exception',
272
+ text: d.exception?.description?.split('\n')[0] ?? d.text,
273
+ at: frame ? `${frame.url.replace(ORIGIN, '')}:${frame.lineNumber + 1}` : (d.url ?? null),
274
+ });
275
+ }
276
+ if (method === 'Runtime.consoleAPICalled' && params.type === 'error') {
277
+ const frame = params.stackTrace?.callFrames?.[0];
278
+ errors.push({
279
+ kind: 'console',
280
+ text: params.args
281
+ .map((a) => a.value !== undefined ? String(a.value) : String(a.description ?? a.type).split('\n')[0])
282
+ .join(' '),
283
+ at: frame ? `${frame.url.replace(ORIGIN, '')}:${frame.lineNumber + 1}` : null,
284
+ });
285
+ }
286
+ if (method === 'Page.frameStartedLoading' && params.frameId === targetId)
287
+ loaded_ = false;
288
+ if (method === 'Page.loadEventFired')
289
+ loaded_ = true;
290
+ });
291
+ await send('Fetch.enable', { patterns: [{ urlPattern: `${ORIGIN}/*` }] });
292
+ await send('Network.enable');
293
+ await send('Runtime.enable');
294
+ await send('Page.enable');
295
+ await send('Emulation.setDeviceMetricsOverride', {
296
+ width: 1280,
297
+ height: 800,
298
+ deviceScaleFactor: 1,
299
+ mobile: false,
300
+ });
301
+ if (options.reducedMotion)
302
+ await send('Emulation.setEmulatedMedia', {
303
+ features: [{ name: 'prefers-reduced-motion', value: 'reduce' }],
304
+ });
305
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
306
+ const evaluate = async (expression) => {
307
+ const r = await send('Runtime.evaluate', { expression, returnByValue: true, awaitPromise: true });
308
+ if (r.exceptionDetails)
309
+ throw new Error(r.exceptionDetails.exception?.description ?? r.exceptionDetails.text);
310
+ return r.result.value;
311
+ };
312
+ const settle = async () => {
313
+ const start = Date.now();
314
+ await sleep(SETTLE_MS);
315
+ while (Date.now() - start < CAP_MS) {
316
+ if (inflight <= 0 && Date.now() - lastActivity >= QUIET_MS) {
317
+ const ready = await evaluate("!document.getElementById('hozu-payload') || document.documentElement.hasAttribute('data-hozu-ready')").catch(() => false);
318
+ if (ready && loaded_)
319
+ return;
320
+ }
321
+ await sleep(50);
322
+ }
323
+ };
324
+ const open = async (to) => {
325
+ loaded_ = false;
326
+ lastActivity = Date.now();
327
+ await send('Page.navigate', { url: ORIGIN + to });
328
+ await settle();
329
+ };
330
+ const mouse = async (x, y) => {
331
+ for (const type of ['mouseMoved', 'mousePressed', 'mouseReleased'])
332
+ await send('Input.dispatchMouseEvent', { type, x, y, button: 'left', clickCount: 1 });
333
+ };
334
+ await open(path);
335
+ const firstStatus = status;
336
+ for (const raw of options.steps) {
337
+ const text = raw.trim();
338
+ const space = text.indexOf(' ');
339
+ const verb = space < 0 ? text : text.slice(0, space);
340
+ const rest = space < 0 ? '' : text.slice(space + 1).trim();
341
+ const pair = () => {
342
+ const eq = rest.indexOf('=');
343
+ if (eq <= 0)
344
+ throw new Error(`"${text}" needs <label>=<value>`);
345
+ return [rest.slice(0, eq).trim(), rest.slice(eq + 1)];
346
+ };
347
+ let result = {};
348
+ try {
349
+ if (verb === 'fill') {
350
+ const [label, value] = pair();
351
+ result = await evaluate(`${PAGE}.fill(${JSON.stringify(label)}, ${JSON.stringify(value)})`);
352
+ }
353
+ else if (verb === 'select') {
354
+ const [label, value] = pair();
355
+ result = await evaluate(`${PAGE}.select(${JSON.stringify(label)}, ${JSON.stringify(value)})`);
356
+ }
357
+ else if (verb === 'click' || verb === 'check') {
358
+ const at = await evaluate(`${PAGE}.point(${JSON.stringify(verb === 'click' ? 'click' : 'check')}, ${JSON.stringify(rest)})`);
359
+ if (at.error)
360
+ result = at;
361
+ else {
362
+ await mouse(at.x, at.y);
363
+ result = { note: at.note };
364
+ }
365
+ }
366
+ else if (verb === 'press') {
367
+ const key = KEYS[rest] ?? {
368
+ code: `Key${rest.toUpperCase()}`,
369
+ keyCode: rest.toUpperCase().charCodeAt(0),
370
+ text: rest,
371
+ };
372
+ await send('Input.dispatchKeyEvent', {
373
+ type: 'keyDown',
374
+ key: rest,
375
+ code: key.code,
376
+ windowsVirtualKeyCode: key.keyCode,
377
+ ...(key.text ? { text: key.text } : {}),
378
+ });
379
+ await send('Input.dispatchKeyEvent', {
380
+ type: 'keyUp',
381
+ key: rest,
382
+ code: key.code,
383
+ windowsVirtualKeyCode: key.keyCode,
384
+ });
385
+ }
386
+ else if (verb === 'wait') {
387
+ const ms = Number(rest);
388
+ if (!Number.isFinite(ms) || ms < 0 || ms > 30000)
389
+ throw new Error('wait takes milliseconds (0–30000)');
390
+ await sleep(ms);
391
+ }
392
+ else if (verb === 'goto') {
393
+ if (!rest.startsWith('/'))
394
+ throw new Error('goto takes a path such as /items/1');
395
+ await open(rest);
396
+ }
397
+ else
398
+ throw new Error(`Unknown step "${verb}": use fill <label>=<value>, select <label>=<option>, check <label>, click <name>, press <key>, wait <ms>, goto <path>`);
399
+ }
400
+ catch (error) {
401
+ result = { error: error instanceof Error ? error.message : String(error) };
402
+ }
403
+ steps.push({ step: text, ok: !result.error, note: result.error ?? result.note ?? null });
404
+ if (result.error)
405
+ break;
406
+ if (verb !== 'wait' && verb !== 'goto')
407
+ await settle();
408
+ }
409
+ for (const skipped of options.steps.slice(steps.length))
410
+ steps.push({ step: skipped.trim(), ok: false, note: 'skipped after a failed step' });
411
+ const expected = Object.entries((await evaluate("(() => { try { return JSON.parse(document.getElementById('hozu-payload')?.textContent ?? '{}').widgets ?? {} } catch { return {} } })()"))).map(([name, w]) => [name, w.load]);
412
+ const report = await evaluate(`${PAGE}.report(${JSON.stringify(options.select)}, ${JSON.stringify(expected)})`);
413
+ let screenshot = null;
414
+ if (options.screenshot) {
415
+ const shot = await send('Page.captureScreenshot', { format: 'png' });
416
+ const file = resolve(options.screenshot);
417
+ await writeFile(file, Buffer.from(shot.data, 'base64'));
418
+ const near = relative(process.cwd(), file);
419
+ screenshot = near && !near.startsWith('..') ? near : file;
420
+ }
421
+ const full = report.text;
422
+ return {
423
+ path,
424
+ url: report.url,
425
+ status: firstStatus,
426
+ title: report.title,
427
+ hydrated: report.hydrated,
428
+ steps,
429
+ errors,
430
+ widgets: report.widgets,
431
+ text: full.length > LIMIT && !options.full ? `${full.slice(0, LIMIT)}…` : full,
432
+ truncated: full.length > LIMIT && !options.full,
433
+ elements: report.elements,
434
+ screenshot,
435
+ };
436
+ }
437
+ finally {
438
+ await cdp.close().catch(() => { });
439
+ await rm(profile, { recursive: true, force: true }).catch(() => { });
440
+ }
441
+ }
442
+ export const browseFailed = (out) => out.errors.length > 0 || out.steps.some((s) => !s.ok) || out.widgets.some((w) => w.state === 'failed');
443
+ export function describeBrowse(out) {
444
+ const lines = [
445
+ `BROWSE ${out.path} → ${out.status}${out.url !== out.path ? ` (now ${out.url})` : ''} · ${out.hydrated ? 'hydrated' : 'not hydrated'}`,
446
+ ` title: ${out.title}`,
447
+ ];
448
+ for (const s of out.steps)
449
+ lines.push(` ${s.ok ? 'step' : 'FAILED'}: ${s.step}${s.note ? ` — ${s.note}` : ''}`);
450
+ if (!out.errors.length)
451
+ lines.push(' errors: none');
452
+ for (const e of out.errors)
453
+ lines.push(` error (${e.kind}): ${e.text}${e.at ? ` at ${e.at}` : ''}`);
454
+ for (const w of out.widgets)
455
+ lines.push(` widget ${w.name}: ${w.state}${w.width === null ? '' : ` ${w.width}×${w.height}`}${w.state === 'mounted' ? `, ${w.canvases} canvas, ${w.elements} elements` : ''}${w.hint ? ` — ${w.hint}` : ''}`);
456
+ lines.push(` text: ${out.text.replace(/\n/g, ' · ')}${out.truncated ? ' (truncated; --full shows all)' : ''}`);
457
+ for (const e of out.elements)
458
+ lines.push(` ${e.selector}: <${e.tag}${Object.entries(e.attrs)
459
+ .filter(([k]) => k !== 'class' && k !== 'style')
460
+ .map(([k, v]) => (v === '' ? ` ${k}` : ` ${k}="${v}"`))
461
+ .join('')}>${e.text ? ` ${e.text}` : ''}`);
462
+ if (out.screenshot)
463
+ lines.push(` screenshot: ${out.screenshot}`);
464
+ return `${lines.join('\n')}\n`;
465
+ }
466
+ //# sourceMappingURL=browse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browse.js","sourceRoot":"","sources":["../../src/commands/browse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACnE,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAChC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACrE,OAAO,EAAY,WAAW,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AAEzD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAE3C,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAEvC,MAAM,MAAM,GAAG,kBAAkB,CAAA;AACjC,MAAM,KAAK,GAAG,IAAI,CAAA;AAClB,MAAM,QAAQ,GAAG,GAAG,CAAA;AACpB,MAAM,SAAS,GAAG,GAAG,CAAA;AACrB,MAAM,MAAM,GAAG,IAAI,CAAA;AAcnB,MAAM,IAAI,GAA2B;IACnC,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,YAAY;IACpB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,eAAe;IACvB,MAAM,EAAE,cAAc;IACtB,OAAO,EAAE,YAAY;IACrB,OAAO,EAAE,kBAAkB;IAC3B,MAAM,EAAE,YAAY;IACpB,MAAM,EAAE,UAAU;IAClB,KAAK,EAAE,iBAAiB;IACxB,QAAQ,EAAE,YAAY;CACvB,CAAA;AAED,MAAM,IAAI,GAAqE;IAC7E,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;IACjD,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE;IACvC,GAAG,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE;IAChC,SAAS,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,EAAE;IAC5C,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE;IAChD,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,EAAE;IACzC,SAAS,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,EAAE;IAC7C,SAAS,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,EAAE;IAC7C,UAAU,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,EAAE,EAAE;CAChD,CAAA;AAED,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAyHlB,CAAA;AAEL,KAAK,UAAU,MAAM,CAAC,OAAsE;IAC1F,IAAI,OAAO,CAAC,eAAe,EAAE,MAAM;QACjC,OAAO,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAA;IAChG,OAAO,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;AACnF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,MAAc,EAAE,OAAsB;IACpE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,GAAG,CAAA;IAChC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,MAAM,IAAI,YAAY,CAAC,OAAO,EAAE,0BAA0B,EAAE,CAAC,eAAe,CAAC,CAAC,CAAA;IACzG,MAAM,OAAO,GAAG,WAAW,EAAE,CAAA;IAC7B,IAAI,CAAC,OAAO;QACV,MAAM,IAAI,YAAY,CAAC,QAAQ,EAAE,gEAAgE,EAAE;YACjG,2DAA2D;SAC5D,CAAC,CAAA;IACJ,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;IAC/D,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IACjC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAQ,CAAA;IACxC,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,UAAU,CAAM,sBAAsB,EAAE,CAAC,kCAAkC,CAAC,CAAC,CAAA;IACxG,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,KAAK,CAAC,UAAU,CAAM,WAAW,EAAE,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,aAAa,CACtG,KAAK,EACL,EAAE,IAAI,EAAE,IAAI,EAAE,CACf,CAAA;IACD,MAAM,IAAI,GAAa,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;IACnD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM;QACzB,CAAC,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,UAAU,CAAM,cAAc,EAAE,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;QACxG,CAAC,CAAC,IAAI,CAAA;IACR,MAAM,OAAO,GAAY,MAAM,CAAC,aAAa,CAAC;QAC5C,KAAK;QACL,MAAM;QACN,OAAO;QACP,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,GAAG,EAAE,OAAO,CAAC,GAAG;KACjB,CAAC,CAAA;IACF,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;IACtC,MAAM,OAAO,GAAG,KAAK,EAAE,OAAgB,EAAqB,EAAE;QAC5D,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,kBAAkB,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;QAC/E,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,QAAQ,CAAA;QAChG,OAAO,IAAI,QAAQ,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE;YAC1D,OAAO,EAAE,EAAE,cAAc,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,0BAA0B,EAAE;SAC/E,CAAC,CAAA;IACJ,CAAC,CAAA;IAED,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,cAAc,CAAC,CAAC,CAAA;IAC7D,MAAM,GAAG,GAAQ,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;IACzC,MAAM,MAAM,GAAkB,EAAE,CAAA;IAChC,MAAM,KAAK,GAAiB,EAAE,CAAA;IAC9B,IAAI,MAAM,GAAG,CAAC,CAAA;IACd,IAAI,QAAQ,GAAG,CAAC,CAAA;IAChB,IAAI,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;IAC7B,IAAI,OAAO,GAAG,KAAK,CAAA;IACnB,IAAI,CAAC;QACH,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,qBAAqB,EAAE,EAAE,GAAG,EAAE,aAAa,EAAE,CAAC,CAAA;QAClF,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,uBAAuB,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;QAC1F,MAAM,IAAI,GAAG,CAAC,MAAc,EAAE,MAAM,GAA4B,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,CAAA;QAC1G,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAA;QACtC,GAAG,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;YAC9B,IAAI,IAAI,KAAK,SAAS;gBAAE,OAAM;YAC9B,IAAI,MAAM,KAAK,qBAAqB,EAAE,CAAC;gBACrC,MAAM,CAAC,GAAG,MAAM,CAAC,OAAO,CAAA;gBACxB,KAAK,CAAC,KAAK,IAAI,EAAE;oBACf,IAAI,CAAC;wBACH,MAAM,QAAQ,GAAG,MAAM,OAAO,CAC5B,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE;4BACjB,MAAM,EAAE,CAAC,CAAC,MAAM;4BAChB,OAAO,EAAE,CAAC,CAAC,OAAO;4BAClB,GAAG,CAAC,CAAC,CAAC,MAAM,KAAK,KAAK,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,MAAM,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;yBAC1F,CAAC,CACH,CAAA;wBACD,MAAM,OAAO,GAAG,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC;6BAClC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,YAAY,CAAC;6BACnC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAA;wBAC5C,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,OAAO,CAAC,YAAY,EAAE;4BAAE,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAA;wBAC/F,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;wBACzE,MAAM,IAAI,CAAC,sBAAsB,EAAE;4BACjC,SAAS,EAAE,MAAM,CAAC,SAAS;4BAC3B,YAAY,EAAE,QAAQ,CAAC,MAAM;4BAC7B,eAAe,EAAE,OAAO;4BACxB,IAAI;yBACL,CAAC,CAAA;oBACJ,CAAC;oBAAC,OAAO,KAAK,EAAE,CAAC;wBACf,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,kBAAkB,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAA;wBACpF,MAAM,IAAI,CAAC,mBAAmB,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,CAC3F,GAAG,EAAE,GAAE,CAAC,CACT,CAAA;oBACH,CAAC;gBACH,CAAC,CAAC,EAAE,CAAA;YACN,CAAC;YACD,IAAI,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC;gBAAE,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;YAC5D,IAAI,MAAM,KAAK,2BAA2B,EAAE,CAAC;gBAC3C,QAAQ,EAAE,CAAA;gBACV,IAAI,MAAM,CAAC,IAAI,KAAK,UAAU;oBAAE,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;YACpE,CAAC;YACD,IAAI,MAAM,KAAK,yBAAyB;gBAAE,QAAQ,EAAE,CAAA;YACpD,IAAI,MAAM,KAAK,uBAAuB,EAAE,CAAC;gBACvC,QAAQ,EAAE,CAAA;gBACV,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,aAAa,KAAK,WAAW;oBAC1D,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,CAAC,SAAS,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;YACtE,CAAC;YACD,IAAI,MAAM,KAAK,0BAA0B,EAAE,CAAC;gBAC1C,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC;oBAChD,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC;oBAC1C,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAA;gBACvB,IAAI,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC;oBAAE,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAA;gBACvE,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,IAAI,GAAG;oBAC/B,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,IAAI,GAAG,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAA;YACvF,CAAC;YACD,IAAI,MAAM,KAAK,yBAAyB,EAAE,CAAC;gBACzC,MAAM,CAAC,GAAG,MAAM,CAAC,gBAAgB,CAAA;gBACjC,MAAM,KAAK,GAAG,CAAC,CAAC,UAAU,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,CAAA;gBAC3C,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,WAAW;oBACjB,IAAI,EAAE,CAAC,CAAC,SAAS,EAAE,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI;oBACxD,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC;iBACzF,CAAC,CAAA;YACJ,CAAC;YACD,IAAI,MAAM,KAAK,0BAA0B,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBACrE,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,CAAA;gBAChD,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,SAAS;oBACf,IAAI,EAAE,MAAM,CAAC,IAAI;yBACd,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CACd,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CACzF;yBACA,IAAI,CAAC,GAAG,CAAC;oBACZ,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI;iBAC9E,CAAC,CAAA;YACJ,CAAC;YACD,IAAI,MAAM,KAAK,0BAA0B,IAAI,MAAM,CAAC,OAAO,KAAK,QAAQ;gBAAE,OAAO,GAAG,KAAK,CAAA;YACzF,IAAI,MAAM,KAAK,qBAAqB;gBAAE,OAAO,GAAG,IAAI,CAAA;QACtD,CAAC,CAAC,CAAA;QACF,MAAM,IAAI,CAAC,cAAc,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,UAAU,EAAE,GAAG,MAAM,IAAI,EAAE,CAAC,EAAE,CAAC,CAAA;QACzE,MAAM,IAAI,CAAC,gBAAgB,CAAC,CAAA;QAC5B,MAAM,IAAI,CAAC,gBAAgB,CAAC,CAAA;QAC5B,MAAM,IAAI,CAAC,aAAa,CAAC,CAAA;QACzB,MAAM,IAAI,CAAC,oCAAoC,EAAE;YAC/C,KAAK,EAAE,IAAI;YACX,MAAM,EAAE,GAAG;YACX,iBAAiB,EAAE,CAAC;YACpB,MAAM,EAAE,KAAK;SACd,CAAC,CAAA;QACF,IAAI,OAAO,CAAC,aAAa;YACvB,MAAM,IAAI,CAAC,4BAA4B,EAAE;gBACvC,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,wBAAwB,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;aAChE,CAAC,CAAA;QAEJ,MAAM,KAAK,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;QACnE,MAAM,QAAQ,GAAG,KAAK,EAAE,UAAkB,EAAE,EAAE;YAC5C,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,kBAAkB,EAAE,EAAE,UAAU,EAAE,aAAa,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAA;YACjG,IAAI,CAAC,CAAC,gBAAgB;gBACpB,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,gBAAgB,CAAC,SAAS,EAAE,WAAW,IAAI,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAA;YACvF,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAA;QACvB,CAAC,CAAA;QACD,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE;YACxB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;YACxB,MAAM,KAAK,CAAC,SAAS,CAAC,CAAA;YACtB,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,MAAM,EAAE,CAAC;gBACnC,IAAI,QAAQ,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,YAAY,IAAI,QAAQ,EAAE,CAAC;oBAC3D,MAAM,KAAK,GAAG,MAAM,QAAQ,CAC1B,sGAAsG,CACvG,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAA;oBACpB,IAAI,KAAK,IAAI,OAAO;wBAAE,OAAM;gBAC9B,CAAC;gBACD,MAAM,KAAK,CAAC,EAAE,CAAC,CAAA;YACjB,CAAC;QACH,CAAC,CAAA;QACD,MAAM,IAAI,GAAG,KAAK,EAAE,EAAU,EAAE,EAAE;YAChC,OAAO,GAAG,KAAK,CAAA;YACf,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;YACzB,MAAM,IAAI,CAAC,eAAe,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,EAAE,EAAE,CAAC,CAAA;YACjD,MAAM,MAAM,EAAE,CAAA;QAChB,CAAC,CAAA;QACD,MAAM,KAAK,GAAG,KAAK,EAAE,CAAS,EAAE,CAAS,EAAE,EAAE;YAC3C,KAAK,MAAM,IAAI,IAAI,CAAC,YAAY,EAAE,cAAc,EAAE,eAAe,CAAC;gBAChE,MAAM,IAAI,CAAC,0BAA0B,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,CAAA;QACzF,CAAC,CAAA;QAED,MAAM,IAAI,CAAC,IAAI,CAAC,CAAA;QAChB,MAAM,WAAW,GAAG,MAAM,CAAA;QAC1B,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YAChC,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAA;YACvB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;YAC/B,MAAM,IAAI,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAA;YACpD,MAAM,IAAI,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;YAC1D,MAAM,IAAI,GAAG,GAAG,EAAE;gBAChB,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;gBAC5B,IAAI,EAAE,IAAI,CAAC;oBAAE,MAAM,IAAI,KAAK,CAAC,IAAI,IAAI,yBAAyB,CAAC,CAAA;gBAC/D,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAU,CAAA;YAChE,CAAC,CAAA;YACD,IAAI,MAAM,GAA6C,EAAE,CAAA;YACzD,IAAI,CAAC;gBACH,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;oBACpB,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,IAAI,EAAE,CAAA;oBAC7B,MAAM,GAAG,MAAM,QAAQ,CAAC,GAAG,IAAI,SAAS,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;gBAC7F,CAAC;qBAAM,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAC7B,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,IAAI,EAAE,CAAA;oBAC7B,MAAM,GAAG,MAAM,QAAQ,CAAC,GAAG,IAAI,WAAW,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;gBAC/F,CAAC;qBAAM,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;oBAChD,MAAM,EAAE,GAAG,MAAM,QAAQ,CACvB,GAAG,IAAI,UAAU,IAAI,CAAC,SAAS,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAClG,CAAA;oBACD,IAAI,EAAE,CAAC,KAAK;wBAAE,MAAM,GAAG,EAAE,CAAA;yBACpB,CAAC;wBACJ,MAAM,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAA;wBACvB,MAAM,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAA;oBAC5B,CAAC;gBACH,CAAC;qBAAM,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;oBAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI;wBACxB,IAAI,EAAE,MAAM,IAAI,CAAC,WAAW,EAAE,EAAE;wBAChC,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;wBACzC,IAAI,EAAE,IAAI;qBACX,CAAA;oBACD,MAAM,IAAI,CAAC,wBAAwB,EAAE;wBACnC,IAAI,EAAE,SAAS;wBACf,GAAG,EAAE,IAAI;wBACT,IAAI,EAAE,GAAG,CAAC,IAAI;wBACd,qBAAqB,EAAE,GAAG,CAAC,OAAO;wBAClC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;qBACxC,CAAC,CAAA;oBACF,MAAM,IAAI,CAAC,wBAAwB,EAAE;wBACnC,IAAI,EAAE,OAAO;wBACb,GAAG,EAAE,IAAI;wBACT,IAAI,EAAE,GAAG,CAAC,IAAI;wBACd,qBAAqB,EAAE,GAAG,CAAC,OAAO;qBACnC,CAAC,CAAA;gBACJ,CAAC;qBAAM,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;oBAC3B,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,CAAA;oBACvB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,KAAK;wBAC9C,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAA;oBACtD,MAAM,KAAK,CAAC,EAAE,CAAC,CAAA;gBACjB,CAAC;qBAAM,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;oBAC3B,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;wBAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAA;oBAChF,MAAM,IAAI,CAAC,IAAI,CAAC,CAAA;gBAClB,CAAC;;oBACC,MAAM,IAAI,KAAK,CACb,iBAAiB,IAAI,wHAAwH,CAC9I,CAAA;YACL,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,GAAG,EAAE,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAA;YAC5E,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC,CAAA;YACxF,IAAI,MAAM,CAAC,KAAK;gBAAE,MAAK;YACvB,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,MAAM;gBAAE,MAAM,MAAM,EAAE,CAAA;QACxD,CAAC;QACD,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC;YACrD,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,6BAA6B,EAAE,CAAC,CAAA;QAEtF,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAC7B,CAAC,MAAM,QAAQ,CACb,yIAAyI,CAC1I,CAAqC,CACvC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;QACpC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAC3B,GAAG,IAAI,WAAW,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CACjF,CAAA;QACD,IAAI,UAAU,GAAkB,IAAI,CAAA;QACpC,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YACvB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,wBAAwB,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAA;YACpE,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;YACxC,MAAM,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAA;YACvD,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,CAAA;YAC1C,UAAU,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA;QAC3D,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAc,CAAA;QAClC,OAAO;YACL,IAAI;YACJ,GAAG,EAAE,MAAM,CAAC,GAAG;YACf,MAAM,EAAE,WAAW;YACnB,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,KAAK;YACL,MAAM;YACN,OAAO,EAAE,MAAM,CAAC,OAAyB;YACzC,IAAI,EAAE,IAAI,CAAC,MAAM,GAAG,KAAK,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI;YAC9E,SAAS,EAAE,IAAI,CAAC,MAAM,GAAG,KAAK,IAAI,CAAC,OAAO,CAAC,IAAI;YAC/C,QAAQ,EAAE,MAAM,CAAC,QAA4B;YAC7C,UAAU;SACX,CAAA;IACH,CAAC;YAAS,CAAC;QACT,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QACjC,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;IACrE,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAAiB,EAAE,EAAE,CAChD,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAA;AAExG,MAAM,UAAU,cAAc,CAAC,GAAiB;IAC9C,MAAM,KAAK,GAAG;QACZ,UAAU,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,cAAc,EAAE;QACtI,YAAY,GAAG,CAAC,KAAK,EAAE;KACxB,CAAA;IACD,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,KAAK;QACvB,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IACvF,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;IACpD,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IACpG,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,OAAO;QACzB,KAAK,CAAC,IAAI,CACR,YAAY,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,MAAM,EAAE,GAChF,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,YAAY,CAAC,CAAC,QAAQ,WAAW,CAAC,CAAC,CAAC,EAC7E,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAClC,CAAA;IACH,KAAK,CAAC,IAAI,CACR,WAAW,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,gCAAgC,CAAC,CAAC,CAAC,EAAE,EAAE,CACpG,CAAA;IACD,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ;QAC1B,KAAK,CAAC,IAAI,CACR,KAAK,CAAC,CAAC,QAAQ,MAAM,CAAC,CAAC,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;aACjD,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,OAAO,IAAI,CAAC,KAAK,OAAO,CAAC;aAC/C,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;aACtD,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAC5C,CAAA;IACH,IAAI,GAAG,CAAC,UAAU;QAAE,KAAK,CAAC,IAAI,CAAC,iBAAiB,GAAG,CAAC,UAAU,EAAE,CAAC,CAAA;IACjE,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAA;AAChC,CAAC"}
@@ -1,5 +1,7 @@
1
+ import { type Diagnostic, type ProjectIR } from '@hozu/core/ir';
1
2
  import type { CheckOutput, TypeIssue } from '../contract.ts';
2
3
  import type { Loaded } from '../load.ts';
3
4
  export declare function typeErrors(output: string, root: string): TypeIssue[];
5
+ export declare function serverEntryIssues(root: string, ir: ProjectIR): Diagnostic[];
4
6
  export declare function runCheck(loaded: Loaded, cwd: string, updateLock: boolean): Promise<CheckOutput>;
5
7
  //# sourceMappingURL=check.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC5D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAcxC,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,CAcpE;AAED,wBAAsB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC,CAsBrG"}
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAIA,OAAO,EAAS,KAAK,UAAU,EAAE,KAAK,SAAS,EAAe,MAAM,eAAe,CAAA;AACnF,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC5D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAcxC,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,CAcpE;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,GAAG,UAAU,EAAE,CAoC3E;AAED,wBAAsB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC,CAiCrG"}
@@ -1,7 +1,8 @@
1
1
  import { spawnSync } from 'node:child_process';
2
- import { readFileSync } from 'node:fs';
2
+ import { existsSync, readFileSync } from 'node:fs';
3
3
  import { createRequire } from 'node:module';
4
4
  import { dirname, join, relative } from 'node:path';
5
+ import { codes, usedWidgets } from '@hozu/core/ir';
5
6
  import { runValidate } from './validate.js';
6
7
  function typescriptBin(from) {
7
8
  try {
@@ -29,6 +30,30 @@ export function typeErrors(output, root) {
29
30
  }
30
31
  return errors;
31
32
  }
33
+ export function serverEntryIssues(root, ir) {
34
+ const file = join(root, 'serve.ts');
35
+ if (!existsSync(file))
36
+ return [];
37
+ const text = readFileSync(file, 'utf8');
38
+ const lines = text.split('\n');
39
+ const at = lines.findIndex((l) => /create(Server|Handler)\(/.test(l));
40
+ const source = { file: 'serve.ts', line: at + 1, column: 1 };
41
+ const issue = (message, cause, summary, snippet) => ({
42
+ code: 'HZ045',
43
+ severity: codes.HZ045.severity,
44
+ message,
45
+ location: { feature: null, pointer: '', source },
46
+ cause,
47
+ fix: { summary, snippet, patch: null },
48
+ });
49
+ const out = [];
50
+ const widgets = usedWidgets(ir);
51
+ if (widgets.length && !/bundleWidgets\s*\(|manifest/.test(text))
52
+ out.push(issue(`serve.ts starts the server without a widget bundle, but views use ${widgets.join(', ')}`, 'Widget client code is bundled separately; without it the server refuses to start.', "npm install @hozu/bundle, then pass widgets: await bundleWidgets(build) to createServer (import { bundleWidgets } from '@hozu/bundle')", 'widgets: await bundleWidgets(build),'));
53
+ if (ir.session && !/\bsession\s*[:,}]/.test(text))
54
+ out.push(issue('The project declares a session, but serve.ts passes none to createServer', 'Without a session store every request is signed out, so user-scoped queries fail.', "Pass session: sessionCookie({ name: 'sid', secret: process.env.SESSION_SECRET }) from @hozu/runtime-server", "session: sessionCookie({ name: 'sid', secret: process.env.SESSION_SECRET ?? '' }),"));
55
+ return out;
56
+ }
32
57
  export async function runCheck(loaded, cwd, updateLock) {
33
58
  const root = dirname(loaded.path);
34
59
  const tsc = typescriptBin(loaded.path);
@@ -46,10 +71,21 @@ export async function runCheck(loaded, cwd, updateLock) {
46
71
  skipped: false,
47
72
  errors: run.status === 0 || errors.length
48
73
  ? errors
49
- : [{ file: '', line: 0, column: 0, code: 'tsc', message: (run.stderr || run.stdout).trim() }],
74
+ : [
75
+ {
76
+ file: '',
77
+ line: 0,
78
+ column: 0,
79
+ code: 'tsc',
80
+ message: (run.stderr || run.stdout).trim(),
81
+ },
82
+ ],
50
83
  };
51
84
  }
52
85
  const validate = await runValidate(loaded, undefined, cwd, updateLock);
86
+ const entry = serverEntryIssues(root, loaded.build(false).ir);
87
+ validate.diagnostics.push(...entry);
88
+ validate.summary.warnings += entry.length;
53
89
  return { ok: types.ok && validate.ok, types, validate };
54
90
  }
55
91
  //# sourceMappingURL=check.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"check.js","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAGnD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAE3C,SAAS,aAAa,CAAC,IAAY;IACjC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC,CAAA;QACnC,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAA;QAC3D,MAAM,GAAG,GAAI,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAsC,CAAC,GAAG,EAAE,GAAG,CAAA;QACrG,OAAO,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAc,EAAE,IAAY;IACrD,MAAM,MAAM,GAAgB,EAAE,CAAA;IAC9B,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACtC,MAAM,CAAC,GAAG,6CAA6C,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;QACzE,IAAI,CAAC;YACH,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC;gBACvC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAClB,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBACpB,IAAI,EAAE,CAAC,CAAC,CAAC,CAAE;gBACX,OAAO,EAAE,CAAC,CAAC,CAAC,CAAE;aACf,CAAC,CAAA;IACN,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,MAAc,EAAE,GAAW,EAAE,UAAmB;IAC7E,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IACjC,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IACtC,IAAI,KAA2B,CAAA;IAC/B,IAAI,CAAC,GAAG;QAAE,KAAK,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAA;SACrD,CAAC;QACJ,MAAM,GAAG,GAAG,SAAS,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE;YAC1F,GAAG,EAAE,IAAI;YACT,QAAQ,EAAE,MAAM;SACjB,CAAC,CAAA;QACF,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,CAAA;QAC/D,KAAK,GAAG;YACN,EAAE,EAAE,GAAG,CAAC,MAAM,KAAK,CAAC;YACpB,OAAO,EAAE,KAAK;YACd,MAAM,EACJ,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM;gBAC/B,CAAC,CAAC,MAAM;gBACR,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;SAClG,CAAA;IACH,CAAC;IACD,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,CAAC,CAAA;IACtE,OAAO,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,IAAI,QAAQ,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAA;AACzD,CAAC"}
1
+ {"version":3,"file":"check.js","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { DocsOutput } from '../contract.ts';
2
+ export declare function runDocs(cwd: string, topic: string | undefined): Promise<DocsOutput>;
3
+ //# sourceMappingURL=docs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docs.d.ts","sourceRoot":"","sources":["../../src/commands/docs.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAGhD,wBAAsB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAgCzF"}
@@ -0,0 +1,36 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { readdir, readFile } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { closest } from '@hozu/validator';
5
+ import { defaultSkill } from 'create-hozu';
6
+ import { HozuCliError } from '../errors.js';
7
+ export async function runDocs(cwd, topic) {
8
+ const dir = [
9
+ join(cwd, '.claude/skills/hozu/topics'),
10
+ join(cwd, '.agents/skills/hozu/topics'),
11
+ join(defaultSkill, 'topics'),
12
+ ].find((d) => existsSync(d));
13
+ if (!dir)
14
+ throw new HozuCliError('config', 'No Hozu topics found; run hozu skill to write the skill', []);
15
+ const topics = await Promise.all((await readdir(dir))
16
+ .filter((f) => f.endsWith('.md'))
17
+ .sort()
18
+ .map(async (f) => ({
19
+ name: f.slice(0, -3),
20
+ title: (await readFile(join(dir, f), 'utf8')).split('\n')[0].replace(/^#\s*/, ''),
21
+ })));
22
+ if (!topic) {
23
+ const text = `${topics.map((t) => `${t.name.padEnd(12)} ${t.title}`).join('\n')}\n`;
24
+ return { topic: null, text, topics };
25
+ }
26
+ const name = topic.toLowerCase();
27
+ if (!topics.some((t) => t.name === name)) {
28
+ const guess = closest(name, topics.map((t) => t.name));
29
+ throw new HozuCliError('usage', `No topic "${topic}"`, [
30
+ ...(guess ? [`hozu docs ${guess}`] : []),
31
+ `topics: ${topics.map((t) => t.name).join(', ')}`,
32
+ ]);
33
+ }
34
+ return { topic: name, text: await readFile(join(dir, `${name}.md`), 'utf8'), topics };
35
+ }
36
+ //# sourceMappingURL=docs.js.map