glimpse-cli 0.0.1 → 0.2.1

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,295 @@
1
+ #!/usr/bin/env node
2
+ import { a as socketPath, o as statePath, t as openWindow } from "./glimpse-adapter-COgj6E-W.mjs";
3
+ import { unlinkSync, watch, writeFileSync } from "node:fs";
4
+ import net from "node:net";
5
+ import { randomUUID } from "node:crypto";
6
+ import * as v from "valibot";
7
+ import { readFile } from "node:fs/promises";
8
+ //#region src/ipc/protocol.ts
9
+ const RequestSchema = v.object({
10
+ id: v.string(),
11
+ method: v.string(),
12
+ params: v.optional(v.any())
13
+ });
14
+ const ok = (id, result) => ({
15
+ id,
16
+ ok: true,
17
+ result
18
+ });
19
+ const fail = (id, code, message) => ({
20
+ id,
21
+ ok: false,
22
+ error: {
23
+ code,
24
+ message
25
+ }
26
+ });
27
+ //#endregion
28
+ //#region src/ipc/server.ts
29
+ function serve(dispatch) {
30
+ try {
31
+ unlinkSync(socketPath());
32
+ } catch {}
33
+ const server = net.createServer((sock) => {
34
+ let buf = "";
35
+ sock.on("data", async (chunk) => {
36
+ buf += chunk.toString();
37
+ for (;;) {
38
+ const i = buf.indexOf("\n");
39
+ if (i < 0) break;
40
+ const line = buf.slice(0, i);
41
+ buf = buf.slice(i + 1);
42
+ if (!line.trim()) continue;
43
+ let id = "unknown";
44
+ try {
45
+ const req = v.parse(RequestSchema, JSON.parse(line));
46
+ id = req.id;
47
+ sock.write(JSON.stringify(ok(id, await dispatch(req.method, req.params))) + "\n");
48
+ } catch (err) {
49
+ sock.write(JSON.stringify(fail(id, "command_failed", err.message)) + "\n");
50
+ }
51
+ }
52
+ });
53
+ });
54
+ server.listen(socketPath(), () => writeFileSync(statePath(), JSON.stringify({
55
+ pid: process.pid,
56
+ socketPath: socketPath(),
57
+ startedAt: (/* @__PURE__ */ new Date()).toISOString()
58
+ })));
59
+ return server;
60
+ }
61
+ //#endregion
62
+ //#region src/daemon/event-queue.ts
63
+ var EventQueue = class {
64
+ max;
65
+ events = [];
66
+ seq = 0;
67
+ constructor(max = 1e3) {
68
+ this.max = max;
69
+ this.max = Math.min(Math.max(max, 1), 2e4);
70
+ }
71
+ push(type, data) {
72
+ if (type.startsWith("window.") || type.startsWith("glimpse.") || type.startsWith("html.")) type = "glimpse.error";
73
+ this.events.push({
74
+ id: ++this.seq,
75
+ type,
76
+ data,
77
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
78
+ });
79
+ if (this.events.length > this.max) this.events.shift();
80
+ }
81
+ system(type, data) {
82
+ this.events.push({
83
+ id: ++this.seq,
84
+ type,
85
+ data,
86
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
87
+ });
88
+ if (this.events.length > this.max) this.events.shift();
89
+ }
90
+ peek(type) {
91
+ return type ? this.events.filter((e) => e.type === type) : [...this.events];
92
+ }
93
+ read(type) {
94
+ const i = type ? this.events.findIndex((e) => e.type === type) : 0;
95
+ return i < 0 ? null : this.events.splice(i, 1)[0];
96
+ }
97
+ get size() {
98
+ return this.events.length;
99
+ }
100
+ };
101
+ //#endregion
102
+ //#region src/daemon/watchers.ts
103
+ function watchHtmlFile(path, target) {
104
+ let timer;
105
+ let reloading = false;
106
+ let pending = false;
107
+ const reload = async () => {
108
+ if (reloading) {
109
+ pending = true;
110
+ return;
111
+ }
112
+ reloading = true;
113
+ try {
114
+ const html = await readFile(path, "utf8");
115
+ target.setHtml(html);
116
+ target.onReload?.();
117
+ } catch (error) {
118
+ target.onError?.(error);
119
+ } finally {
120
+ reloading = false;
121
+ if (pending) {
122
+ pending = false;
123
+ reload();
124
+ }
125
+ }
126
+ };
127
+ const watcher = watch(path, { persistent: false }, () => {
128
+ if (timer) clearTimeout(timer);
129
+ timer = setTimeout(() => void reload(), 75);
130
+ });
131
+ watcher.on("error", (error) => target.onError?.(error));
132
+ return watcher;
133
+ }
134
+ //#endregion
135
+ //#region src/daemon/window-registry.ts
136
+ var WindowRegistry = class {
137
+ windows = /* @__PURE__ */ new Map();
138
+ resolve(ref) {
139
+ return this.windows.get(ref) ?? [...this.windows.values()].find((w) => w.name === ref && w.state === "open");
140
+ }
141
+ list(includeClosed = false) {
142
+ const now = Date.now();
143
+ return [...this.windows.values()].filter((w) => w.state === "open" || includeClosed && (w.expiresAt ?? 0) > now).map((w) => ({
144
+ windowId: w.id,
145
+ name: w.name,
146
+ state: w.state,
147
+ eventQueueSize: w.queue.size,
148
+ source: w.source,
149
+ bridge: w.bridge,
150
+ security: w.security,
151
+ expiresAt: w.expiresAt ? new Date(w.expiresAt).toISOString() : void 0
152
+ }));
153
+ }
154
+ open(html, opts = {}) {
155
+ if (opts.name) {
156
+ const old = this.resolve(opts.name);
157
+ if (old && !opts.replace) throw new Error(`Window name is already in use: ${opts.name}`);
158
+ if (old) this.close(old.id, true);
159
+ }
160
+ const rec = {
161
+ id: `win_${randomUUID()}`,
162
+ name: opts.name,
163
+ state: "open",
164
+ source: opts.source,
165
+ bridge: opts.bridge ?? true,
166
+ security: opts.security,
167
+ queue: new EventQueue(),
168
+ win: openWindow(html, opts.options ?? {})
169
+ };
170
+ this.windows.set(rec.id, rec);
171
+ rec.win?.once("ready", () => rec.queue.system("window.ready"));
172
+ rec.win?.on("message", (data) => rec.queue.push(typeof data === "object" && data && "type" in data ? String(data.type) : "json", data));
173
+ rec.win?.once("closed", () => this.markClosed(rec));
174
+ rec.win?.on("error", (err) => rec.queue.system("glimpse.error", { message: String(err?.message ?? err) }));
175
+ if (opts.watchPath) rec.watcher = watchHtmlFile(opts.watchPath, {
176
+ setHtml: (html) => rec.win?.setHTML(html),
177
+ onReload: () => rec.queue.system("html.reloaded"),
178
+ onError: (error) => rec.queue.system("glimpse.error", { message: String(error?.message ?? error) })
179
+ });
180
+ return rec;
181
+ }
182
+ setHtml(ref, html) {
183
+ const w = this.must(ref);
184
+ w.win.setHTML(html);
185
+ w.source = { kind: "html" };
186
+ w.queue.system("html.reloaded");
187
+ return w;
188
+ }
189
+ eval(ref, js) {
190
+ this.must(ref).win.send(`Promise.resolve(${js}).then(r=>window.glimpse?.send({type:'eval.result',data:r})).catch(e=>window.glimpse?.send({type:'glimpse.error',data:{message:String(e)}}))`);
191
+ }
192
+ send(ref, type, data) {
193
+ const w = this.must(ref);
194
+ if (!w.bridge) throw new Error("Window has no bridge");
195
+ w.win.send(`window.dispatchEvent(new CustomEvent('glimpse-message',{detail:${JSON.stringify({
196
+ type,
197
+ data
198
+ })}}))`);
199
+ }
200
+ close(ref, force = false) {
201
+ const w = this.must(ref);
202
+ w.watcher?.close();
203
+ if (force) {
204
+ w.win?.close();
205
+ this.windows.delete(w.id);
206
+ return;
207
+ }
208
+ w.win?.close();
209
+ this.markClosed(w);
210
+ }
211
+ closeAll(force = false) {
212
+ for (const w of [...this.windows.values()].filter((w) => w.state === "open")) this.close(w.id, force);
213
+ }
214
+ requireOpen(ref) {
215
+ const w = this.resolve(ref);
216
+ if (!w || w.state !== "open") throw new Error(`Window ${ref} is not open.`);
217
+ return w;
218
+ }
219
+ must(ref) {
220
+ return this.requireOpen(ref);
221
+ }
222
+ markClosed(w) {
223
+ if (w.state === "closed") return;
224
+ w.watcher?.close();
225
+ w.state = "closed";
226
+ w.queue.system("window.closed");
227
+ w.closedAt = Date.now();
228
+ w.expiresAt = w.closedAt + 3e4;
229
+ w.name = void 0;
230
+ setTimeout(() => this.windows.delete(w.id), 3e4).unref?.();
231
+ }
232
+ };
233
+ //#endregion
234
+ //#region src/daemon/daemon.ts
235
+ const registry = new WindowRegistry();
236
+ async function dispatch(method, p = {}) {
237
+ switch (method) {
238
+ case "ping": return { pong: true };
239
+ case "open": {
240
+ const w = registry.open(p.html, p);
241
+ return {
242
+ windowId: w.id,
243
+ name: w.name
244
+ };
245
+ }
246
+ case "set-html":
247
+ registry.setHtml(p.window, p.html);
248
+ return { ok: true };
249
+ case "navigate":
250
+ registry.setHtml(p.window, `<script>location.href=${JSON.stringify(p.url)}<\/script>`);
251
+ return { ok: true };
252
+ case "send":
253
+ registry.send(p.window, p.type, p.data);
254
+ return { ok: true };
255
+ case "eval":
256
+ registry.eval(p.window, p.js);
257
+ return { ok: true };
258
+ case "read": return { event: registry.resolve(p.window)?.queue.read(p.type) ?? null };
259
+ case "peek":
260
+ case "events": return { events: registry.resolve(p.window)?.queue.peek(p.type) ?? [] };
261
+ case "wait": return wait(p.window, p.type, p.timeout);
262
+ case "close":
263
+ p.all ? registry.closeAll(p.force) : registry.close(p.window, p.force);
264
+ return { ok: true };
265
+ case "list": return {
266
+ daemon: { running: true },
267
+ windows: registry.list(p.includeClosed)
268
+ };
269
+ default: throw new Error(`Unknown IPC method: ${method}`);
270
+ }
271
+ }
272
+ function wait(window, type, timeout) {
273
+ registry.requireOpen(window);
274
+ return new Promise((resolve, reject) => {
275
+ const deadline = timeout ? setTimeout(() => {
276
+ clearInterval(iv);
277
+ reject(/* @__PURE__ */ new Error("timeout"));
278
+ }, timeout) : null;
279
+ const iv = setInterval(() => {
280
+ const ev = registry.requireOpen(window).queue.read(type);
281
+ if (ev) {
282
+ if (deadline) clearTimeout(deadline);
283
+ clearInterval(iv);
284
+ resolve({ event: ev });
285
+ }
286
+ }, 50);
287
+ });
288
+ }
289
+ //#endregion
290
+ //#region src/daemon-main.ts
291
+ serve(dispatch);
292
+ //#endregion
293
+ export {};
294
+
295
+ //# sourceMappingURL=daemon-main.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon-main.mjs","names":[],"sources":["../src/ipc/protocol.ts","../src/ipc/server.ts","../src/daemon/event-queue.ts","../src/daemon/watchers.ts","../src/daemon/window-registry.ts","../src/daemon/daemon.ts","../src/daemon-main.ts"],"sourcesContent":["import * as v from 'valibot';\n\nexport const RequestSchema = v.object({ id: v.string(), method: v.string(), params: v.optional(v.any()) });\nexport type IpcRequest = v.InferOutput<typeof RequestSchema>;\nexport type IpcResponse = { id: string; ok: true; result?: unknown } | { id: string; ok: false; error: { code: string; message: string } };\nexport const ok = (id: string, result?: unknown): IpcResponse => ({ id, ok: true, result });\nexport const fail = (id: string, code: string, message: string): IpcResponse => ({ id, ok: false, error: { code, message } });\n","import net from 'node:net';\nimport { unlinkSync, writeFileSync } from 'node:fs';\nimport * as v from 'valibot';\nimport { RequestSchema, ok, fail } from './protocol.ts';\nimport { socketPath, statePath } from '../platform/paths.ts';\n\nexport function serve(dispatch: (method: string, params: any) => Promise<unknown>|unknown) {\n try { unlinkSync(socketPath()); } catch {}\n const server = net.createServer(sock => {\n let buf = '';\n sock.on('data', async chunk => {\n buf += chunk.toString();\n for (;;) {\n const i = buf.indexOf('\\n'); if (i < 0) break;\n const line = buf.slice(0, i); buf = buf.slice(i + 1);\n if (!line.trim()) continue;\n let id = 'unknown';\n try {\n const req = v.parse(RequestSchema, JSON.parse(line)); id = req.id;\n sock.write(JSON.stringify(ok(id, await dispatch(req.method, req.params))) + '\\n');\n } catch (err) { sock.write(JSON.stringify(fail(id, 'command_failed', (err as Error).message)) + '\\n'); }\n }\n });\n });\n server.listen(socketPath(), () => writeFileSync(statePath(), JSON.stringify({ pid: process.pid, socketPath: socketPath(), startedAt: new Date().toISOString() })));\n return server;\n}\n","export type WindowEvent = { id: number; type: string; data?: unknown; timestamp: string };\n\nexport class EventQueue {\n private events: WindowEvent[] = [];\n private seq = 0;\n constructor(private max = 1000) { this.max = Math.min(Math.max(max, 1), 20_000); }\n push(type: string, data?: unknown) {\n if (type.startsWith('window.') || type.startsWith('glimpse.') || type.startsWith('html.')) type = 'glimpse.error';\n this.events.push({ id: ++this.seq, type, data, timestamp: new Date().toISOString() });\n if (this.events.length > this.max) this.events.shift();\n }\n system(type: string, data?: unknown) { this.events.push({ id: ++this.seq, type, data, timestamp: new Date().toISOString() }); if (this.events.length > this.max) this.events.shift(); }\n peek(type?: string) { return type ? this.events.filter(e => e.type === type) : [...this.events]; }\n read(type?: string): WindowEvent | null { const i = type ? this.events.findIndex(e => e.type === type) : 0; return i < 0 ? null : this.events.splice(i, 1)[0]; }\n get size() { return this.events.length; }\n}\n","import { watch, FSWatcher } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\n\nexport type HtmlWatchTarget = {\n setHtml(html: string): void;\n onReload?(): void;\n onError?(error: unknown): void;\n};\n\nexport function watchHtmlFile(path: string, target: HtmlWatchTarget): FSWatcher {\n let timer: ReturnType<typeof setTimeout> | undefined;\n let reloading = false;\n let pending = false;\n\n const reload = async () => {\n if (reloading) { pending = true; return; }\n reloading = true;\n try {\n const html = await readFile(path, 'utf8');\n target.setHtml(html);\n target.onReload?.();\n } catch (error) {\n target.onError?.(error);\n } finally {\n reloading = false;\n if (pending) { pending = false; void reload(); }\n }\n };\n\n const watcher = watch(path, { persistent: false }, () => {\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => void reload(), 75);\n });\n\n watcher.on('error', error => target.onError?.(error));\n return watcher;\n}\n","import { randomUUID } from 'node:crypto';\nimport type { FSWatcher } from 'node:fs';\nimport { EventQueue } from './event-queue.ts';\nimport { watchHtmlFile } from './watchers.ts';\nimport { openWindow, RuntimeWindow } from '../runtime/glimpse-adapter.ts';\n\nexport type WindowRecord = { id: string; name?: string; state: 'open'|'closed'; source: any; bridge: boolean; security: any; queue: EventQueue; win?: RuntimeWindow; watcher?: FSWatcher; closedAt?: number; expiresAt?: number };\n\nexport class WindowRegistry {\n private windows = new Map<string, WindowRecord>();\n resolve(ref: string) { return this.windows.get(ref) ?? [...this.windows.values()].find(w => w.name === ref && w.state === 'open'); }\n list(includeClosed = false) { const now = Date.now(); return [...this.windows.values()].filter(w => w.state === 'open' || (includeClosed && (w.expiresAt ?? 0) > now)).map(w => ({ windowId: w.id, name: w.name, state: w.state, eventQueueSize: w.queue.size, source: w.source, bridge: w.bridge, security: w.security, expiresAt: w.expiresAt ? new Date(w.expiresAt).toISOString() : undefined })); }\n open(html: string, opts: { name?: string; replace?: boolean; options?: any; source?: any; bridge?: boolean; security?: any; watchPath?: string } = {}) {\n if (opts.name) {\n const old = this.resolve(opts.name);\n if (old && !opts.replace) throw new Error(`Window name is already in use: ${opts.name}`);\n if (old) this.close(old.id, true);\n }\n const rec: WindowRecord = { id: `win_${randomUUID()}`, name: opts.name, state: 'open', source: opts.source, bridge: opts.bridge ?? true, security: opts.security, queue: new EventQueue(), win: openWindow(html, opts.options ?? {}) };\n this.windows.set(rec.id, rec);\n rec.win?.once('ready', () => rec.queue.system('window.ready'));\n rec.win?.on('message', data => rec.queue.push(typeof data === 'object' && data && 'type' in data ? String((data as any).type) : 'json', data));\n rec.win?.once('closed', () => this.markClosed(rec));\n rec.win?.on('error', err => rec.queue.system('glimpse.error', { message: String(err?.message ?? err) }));\n if (opts.watchPath) {\n rec.watcher = watchHtmlFile(opts.watchPath, {\n setHtml: html => rec.win?.setHTML(html),\n onReload: () => rec.queue.system('html.reloaded'),\n onError: error => rec.queue.system('glimpse.error', { message: String((error as Error)?.message ?? error) }),\n });\n }\n return rec;\n }\n setHtml(ref: string, html: string) { const w = this.must(ref); w.win!.setHTML(html); w.source = { kind: 'html' }; w.queue.system('html.reloaded'); return w; }\n eval(ref: string, js: string) { const w = this.must(ref); w.win!.send(`Promise.resolve(${js}).then(r=>window.glimpse?.send({type:'eval.result',data:r})).catch(e=>window.glimpse?.send({type:'glimpse.error',data:{message:String(e)}}))`); }\n send(ref: string, type: string, data: unknown) { const w = this.must(ref); if (!w.bridge) throw new Error('Window has no bridge'); w.win!.send(`window.dispatchEvent(new CustomEvent('glimpse-message',{detail:${JSON.stringify({ type, data })}}))`); }\n close(ref: string, force = false) { const w = this.must(ref); w.watcher?.close(); if (force) { w.win?.close(); this.windows.delete(w.id); return; } w.win?.close(); this.markClosed(w); }\n closeAll(force = false) { for (const w of [...this.windows.values()].filter(w => w.state === 'open')) this.close(w.id, force); }\n requireOpen(ref: string) { const w = this.resolve(ref); if (!w || w.state !== 'open') throw new Error(`Window ${ref} is not open.`); return w; }\n private must(ref: string) { return this.requireOpen(ref); }\n private markClosed(w: WindowRecord) { if (w.state === 'closed') return; w.watcher?.close(); w.state = 'closed'; w.queue.system('window.closed'); w.closedAt = Date.now(); w.expiresAt = w.closedAt + 30_000; w.name = undefined; setTimeout(() => this.windows.delete(w.id), 30_000).unref?.(); }\n}\n","import { WindowRegistry } from './window-registry.ts';\n\nconst registry = new WindowRegistry();\n\nexport async function dispatch(method: string, p: any = {}) {\n switch (method) {\n case 'ping': return { pong: true };\n case 'open': { const w = registry.open(p.html, p); return { windowId: w.id, name: w.name }; }\n case 'set-html': registry.setHtml(p.window, p.html); return { ok: true };\n case 'navigate': registry.setHtml(p.window, `<script>location.href=${JSON.stringify(p.url)}</script>`); return { ok: true };\n case 'send': registry.send(p.window, p.type, p.data); return { ok: true };\n case 'eval': registry.eval(p.window, p.js); return { ok: true };\n case 'read': return { event: registry.resolve(p.window)?.queue.read(p.type) ?? null };\n case 'peek':\n case 'events': return { events: registry.resolve(p.window)?.queue.peek(p.type) ?? [] };\n case 'wait': return wait(p.window, p.type, p.timeout);\n case 'close': p.all ? registry.closeAll(p.force) : registry.close(p.window, p.force); return { ok: true };\n case 'list': return { daemon: { running: true }, windows: registry.list(p.includeClosed) };\n default: throw new Error(`Unknown IPC method: ${method}`);\n }\n}\n\nfunction wait(window: string, type?: string, timeout?: number) {\n registry.requireOpen(window);\n return new Promise((resolve, reject) => {\n const deadline = timeout ? setTimeout(() => { clearInterval(iv); reject(new Error('timeout')); }, timeout) : null;\n const iv = setInterval(() => {\n const w = registry.requireOpen(window);\n const ev = w.queue.read(type);\n if (ev) { if (deadline) clearTimeout(deadline); clearInterval(iv); resolve({ event: ev }); }\n }, 50);\n });\n}\n","#!/usr/bin/env node\nimport { serve } from './ipc/server.ts';\nimport { dispatch } from './daemon/daemon.ts';\nserve(dispatch);\n"],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import { mkdirSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { tmpdir } from "node:os";
4
+ import * as glimpse from "glimpseui";
5
+ //#region src/platform/paths.ts
6
+ function runtimeDir() {
7
+ const uid = typeof process.getuid === "function" ? process.getuid() : process.env.USER ?? "user";
8
+ const dir = join(process.env.TMPDIR || tmpdir(), `glimpse-cli-${uid}`);
9
+ mkdirSync(dir, {
10
+ recursive: true,
11
+ mode: 448
12
+ });
13
+ return dir;
14
+ }
15
+ const socketPath = () => join(runtimeDir(), "daemon.sock");
16
+ const statePath = () => join(runtimeDir(), "daemon.json");
17
+ const lockPath = () => join(runtimeDir(), "daemon.lock");
18
+ //#endregion
19
+ //#region src/runtime/glimpse-adapter.ts
20
+ function withBridge(html, csp) {
21
+ const meta = csp ? `<meta http-equiv="Content-Security-Policy" content="${csp.replaceAll("\"", "&quot;")}">` : "";
22
+ const bridgeHint = "<script>window.dispatchEvent(new Event(\"glimpse:loaded\"));<\/script>";
23
+ return /<head[^>]*>/i.test(html) ? html.replace(/<head[^>]*>/i, (m) => `${m}${meta}${bridgeHint}`) : `${meta}${bridgeHint}${html}`;
24
+ }
25
+ function openWindow(html, options = {}) {
26
+ return glimpse.open(html, options);
27
+ }
28
+ async function promptWindow(html, options = {}) {
29
+ return glimpse.prompt(html, options);
30
+ }
31
+ //#endregion
32
+ export { socketPath as a, lockPath as i, promptWindow as n, statePath as o, withBridge as r, openWindow as t };
33
+
34
+ //# sourceMappingURL=glimpse-adapter-COgj6E-W.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glimpse-adapter-COgj6E-W.mjs","names":[],"sources":["../src/platform/paths.ts","../src/runtime/glimpse-adapter.ts"],"sourcesContent":["import { mkdirSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { tmpdir } from 'node:os';\n\nexport function runtimeDir(): string {\n const uid = typeof process.getuid === 'function' ? process.getuid() : process.env.USER ?? 'user';\n const dir = join(process.env.TMPDIR || tmpdir(), `glimpse-cli-${uid}`);\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n return dir;\n}\nexport const socketPath = () => join(runtimeDir(), 'daemon.sock');\nexport const statePath = () => join(runtimeDir(), 'daemon.json');\nexport const lockPath = () => join(runtimeDir(), 'daemon.lock');\n","import * as glimpse from 'glimpseui';\n\nexport type RuntimeWindow = {\n on(event: 'ready'|'message'|'closed'|'error', cb: (...args: any[]) => void): void;\n once(event: 'ready'|'message'|'closed'|'error', cb: (...args: any[]) => void): void;\n setHTML(html: string): void;\n send(js: string): void;\n close(): void;\n};\n\nexport function withBridge(html: string, csp?: string): string {\n // Glimpse injects window.glimpse at document start in the native host.\n // Do not polyfill/overwrite it here, or page-to-CLI messages stop working.\n const meta = csp ? `<meta http-equiv=\"Content-Security-Policy\" content=\"${csp.replaceAll('\"','&quot;')}\">` : '';\n const bridgeHint = '<script>window.dispatchEvent(new Event(\"glimpse:loaded\"));</script>';\n return /<head[^>]*>/i.test(html) ? html.replace(/<head[^>]*>/i, m => `${m}${meta}${bridgeHint}`) : `${meta}${bridgeHint}${html}`;\n}\n\nexport function openWindow(html: string, options: Record<string, unknown> = {}): RuntimeWindow {\n return glimpse.open(html, options) as RuntimeWindow;\n}\n\nexport async function promptWindow(html: string, options: Record<string, unknown> = {}) {\n return glimpse.prompt(html, options);\n}\n"],"mappings":";;;;;AAIA,SAAgB,aAAqB;CACnC,MAAM,MAAM,OAAO,QAAQ,WAAW,aAAa,QAAQ,OAAO,IAAI,QAAQ,IAAI,QAAQ;CAC1F,MAAM,MAAM,KAAK,QAAQ,IAAI,UAAU,OAAO,GAAG,eAAe,KAAK;CACrE,UAAU,KAAK;EAAE,WAAW;EAAM,MAAM;CAAM,CAAC;CAC/C,OAAO;AACT;AACA,MAAa,mBAAmB,KAAK,WAAW,GAAG,aAAa;AAChE,MAAa,kBAAkB,KAAK,WAAW,GAAG,aAAa;AAC/D,MAAa,iBAAiB,KAAK,WAAW,GAAG,aAAa;;;ACF9D,SAAgB,WAAW,MAAc,KAAsB;CAG7D,MAAM,OAAO,MAAM,uDAAuD,IAAI,WAAW,MAAI,QAAQ,EAAE,MAAM;CAC7G,MAAM,aAAa;CACnB,OAAO,eAAe,KAAK,IAAI,IAAI,KAAK,QAAQ,iBAAgB,MAAK,GAAG,IAAI,OAAO,YAAY,IAAI,GAAG,OAAO,aAAa;AAC5H;AAEA,SAAgB,WAAW,MAAc,UAAmC,CAAC,GAAkB;CAC7F,OAAO,QAAQ,KAAK,MAAM,OAAO;AACnC;AAEA,eAAsB,aAAa,MAAc,UAAmC,CAAC,GAAG;CACtF,OAAO,QAAQ,OAAO,MAAM,OAAO;AACrC"}