create-opentray 0.24.0 → 0.26.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 (52) hide show
  1. package/README.md +21 -13
  2. package/dist/{bin-BQb2Bjcu.mjs → bin-Bz16rwKs.mjs} +249 -313
  3. package/dist/bin-Bz16rwKs.mjs.map +1 -0
  4. package/dist/bin-CrMTyTux.d.mts +751 -0
  5. package/dist/bin-CrMTyTux.d.mts.map +1 -0
  6. package/dist/bin.d.mts +2 -15
  7. package/dist/bin.mjs +2 -2
  8. package/dist/{decode-ico-BHd2POHf.mjs → decode-ico-DDEIV7iZ.mjs} +2 -2
  9. package/dist/{decode-ico-BHd2POHf.mjs.map → decode-ico-DDEIV7iZ.mjs.map} +1 -1
  10. package/dist/encode-CTEluLqt.mjs +167 -0
  11. package/dist/encode-CTEluLqt.mjs.map +1 -0
  12. package/dist/icon-codec-Bs3XehqZ.mjs +20 -0
  13. package/dist/icon-codec-Bs3XehqZ.mjs.map +1 -0
  14. package/dist/index.d.mts +1 -724
  15. package/dist/index.d.mts.map +1 -1
  16. package/dist/index.mjs +1 -1
  17. package/dist/rolldown-runtime-DJK8HYOj.mjs +34 -0
  18. package/dist/shell/assets/ghostty-web.js +1 -1
  19. package/dist/shell/assets/index.css +1 -1
  20. package/dist/shell/assets/index.js +2 -9
  21. package/dist/shell/assets/index2.js +9 -2
  22. package/dist/shell/assets/input.js +1 -1
  23. package/dist/shell/assets/main.js +8 -8
  24. package/dist/shell/assets/terminal-pane.js +2 -2
  25. package/dist/shell/assets/terminal.js +1 -1
  26. package/dist/shell/assets/toolbar.js +1 -0
  27. package/dist/shell/index.html +1 -1
  28. package/dist/shell/terminal.html +1 -1
  29. package/dist/shell/{browse.html → toolbar.html} +3 -3
  30. package/dist/skill/SKILL.md +14 -11
  31. package/dist/skill/references/cli-reference.md +1 -1
  32. package/dist/skill/references/how-it-works.md +15 -9
  33. package/dist/webui/assets/ghostty-web.js +1 -1
  34. package/dist/webui/assets/index.css +1 -1
  35. package/dist/webui/assets/index.js +2 -9
  36. package/dist/webui/assets/index2.js +9 -2
  37. package/dist/webui/assets/input.js +1 -1
  38. package/dist/webui/assets/main.js +8 -8
  39. package/dist/webui/assets/terminal-pane.js +2 -2
  40. package/dist/webui/assets/terminal.js +1 -1
  41. package/dist/webui/assets/toolbar.js +1 -0
  42. package/dist/webui/index.html +1 -1
  43. package/dist/webui/terminal.html +1 -1
  44. package/dist/webui/{browse.html → toolbar.html} +3 -3
  45. package/package.json +6 -6
  46. package/skill/SKILL.md +14 -11
  47. package/skill/references/cli-reference.md +1 -1
  48. package/skill/references/how-it-works.md +15 -9
  49. package/dist/bin-BQb2Bjcu.mjs.map +0 -1
  50. package/dist/bin.d.mts.map +0 -1
  51. package/dist/shell/assets/browse.js +0 -1
  52. package/dist/webui/assets/browse.js +0 -1
@@ -0,0 +1,751 @@
1
+ import { AppIcon } from "@opentray/spec";
2
+
3
+ //#region packages/core/src/command-family.d.ts
4
+ type Family = "npm" | "go" | "rust" | "python" | "dotnet" | "custom";
5
+ interface FamilyFormState {
6
+ readonly family: Family;
7
+ /** npm/python 系列的 runner(如 `npx`、`yarn dlx`、`uvx`、`pipx run`)。 */
8
+ readonly runner: string;
9
+ /** runner 与包名之间的选项 token(如 `deno run -A` 的 `-A`)。 */
10
+ readonly runnerFlags: string;
11
+ /** 包名 / module 路径 / crate / 工具 ID(保持用户输入原样)。 */
12
+ readonly pkg: string;
13
+ /** 空串 = latest/省略。 */
14
+ readonly version: string;
15
+ /** 包名之后的参数(原样字符串)。 */
16
+ readonly args: string;
17
+ /** 仅 Rust:运行二进制名;空串 = 与 crate 同名。 */
18
+ readonly binary: string;
19
+ /** 仅自定义:完整自由命令。 */
20
+ readonly raw: string;
21
+ }
22
+ //#endregion
23
+ //#region packages/core/src/launch-vector.d.ts
24
+ interface LaunchVector {
25
+ readonly command: string;
26
+ readonly args: readonly string[];
27
+ readonly cwd: string;
28
+ /** Optional explicit env overlay merged over the runtime environment. */
29
+ readonly env?: Readonly<Record<string, string>>;
30
+ }
31
+ interface ResolveLaunchVectorOptions {
32
+ readonly tokens: readonly string[];
33
+ readonly cwd: string;
34
+ readonly platform?: NodeJS.Platform;
35
+ readonly pathEnv?: string;
36
+ readonly accessFile?: (path: string) => Promise<void>;
37
+ readonly firstLine?: (path: string) => Promise<string | undefined>;
38
+ }
39
+ /** Resolve a bare command name against PATH; returns undefined when absent. */
40
+ declare const resolveOnPath: (command: string, options: Pick<ResolveLaunchVectorOptions, "platform" | "pathEnv" | "accessFile">) => Promise<string | undefined>;
41
+ /** Read a `#!/usr/bin/env <interpreter>` shebang; undefined for other files. */
42
+ declare const parseShebangInterpreter: (firstLine: string | undefined) => {
43
+ interpreter: string;
44
+ args: readonly string[];
45
+ } | undefined;
46
+ /**
47
+ * Resolve the user's command tokens to a PATH-independent vector:
48
+ * - absolute-ize bare executables through PATH lookup;
49
+ * - resolve relative script paths against cwd;
50
+ * - when the executable is an `env <interpreter>` shebang script, run the
51
+ * interpreter directly with the script as its first argument.
52
+ * The persisted descriptor never includes an environment map.
53
+ */
54
+ declare const resolveLaunchVector: (options: ResolveLaunchVectorOptions) => Promise<LaunchVector>;
55
+ //#endregion
56
+ //#region packages/core/src/port-scan.d.ts
57
+ interface DiscoveredService {
58
+ readonly port: number;
59
+ readonly url: string;
60
+ readonly firstSeenAt: number;
61
+ title?: string;
62
+ }
63
+ type ListenersRunner = (platform: NodeJS.Platform) => Promise<ReadonlySet<number>>;
64
+ /** Listener snapshot with process ownership: port -> owning PIDs. */
65
+ type ListenerOwners = ReadonlyMap<number, ReadonlySet<number>>;
66
+ /** Loopback service URL for a discovered port. */
67
+ declare const serviceUrl: (port: number) => string;
68
+ declare const parseLsofPorts: (stdout: string) => ReadonlySet<number>;
69
+ /** Parses `netstat -ano -p tcp` output; keeps LISTENING rows. */
70
+ declare const parseNetstatPorts: (stdout: string) => ReadonlySet<number>;
71
+ declare const parsePowerShellPorts: (stdout: string) => ReadonlySet<number>;
72
+ /** TCP-connect probe used by the generated app and discovery verification. */
73
+ declare const waitForTcpPort: (port: number, timeoutMs: number, intervalMs?: number, host?: string) => Promise<boolean>;
74
+ /** Verify a port answers with an HTTP response (any status counts). */
75
+ declare const verifyHttpService: (port: number, timeoutMs?: number) => Promise<boolean>;
76
+ interface PortDiscoveryOptions {
77
+ readonly platform?: NodeJS.Platform;
78
+ readonly baseline: ReadonlySet<number>;
79
+ readonly listListeners?: ListenersRunner;
80
+ readonly verifyHttp?: (port: number) => Promise<boolean>;
81
+ /** Resolves the PIDs whose listeners count as services (preview process tree). */
82
+ readonly resolveOwnerPids?: () => Promise<ReadonlySet<number>>;
83
+ readonly listOwners?: () => Promise<ListenerOwners>;
84
+ readonly intervalMs?: number;
85
+ }
86
+ interface PortDiscoverySession {
87
+ /** Known new services, first-seen order. */
88
+ services(): readonly DiscoveredService[];
89
+ /** One polling pass; resolves to services discovered during this pass. */
90
+ poll(): Promise<readonly DiscoveredService[]>;
91
+ stop(): void;
92
+ }
93
+ /**
94
+ * Diff-based port discovery. Each poll re-enumerates listeners, keeps ports
95
+ * absent from the baseline, and adds HTTP-verified ones in first-seen order.
96
+ */
97
+ declare const createPortDiscovery: (options: PortDiscoveryOptions) => PortDiscoverySession;
98
+ //#endregion
99
+ //#region packages/core/src/scrape.d.ts
100
+ /** Variant tag: the original art, a solid-color silhouette derived from it,
101
+ * or an AI subject-extraction derived by the wizard's browser client. */
102
+ type IconVariant = "original" | "solid-black" | "solid-white" | "subject";
103
+ /** One scraped icon candidate, ranked and deduplicated. */
104
+ interface ScrapedIcon {
105
+ /** Index within the candidate list (stable for /api/icon-data/:port/:index). */
106
+ readonly index: number;
107
+ /** Absolute URL the bytes came from (variants inherit their source URL). */
108
+ readonly url: string;
109
+ /** Absolute temp file holding the icon bytes. */
110
+ readonly path: string;
111
+ /** True pixel clarity (largest dimension; SVG uses intrinsic or 512). */
112
+ readonly width: number;
113
+ readonly height: number;
114
+ /** png | svg | jpeg | webp | gif | ico (ico payloads are extracted to png). */
115
+ readonly format: string;
116
+ /** Which art this entry carries (originals feed the app-icon picker; the
117
+ * advanced tray picker also shows solid variants). */
118
+ readonly variant: IconVariant;
119
+ /** Index of the original candidate a variant was derived from. */
120
+ readonly variantOf?: number;
121
+ }
122
+ interface ScrapeResult {
123
+ readonly ok: boolean;
124
+ readonly title: string | undefined;
125
+ /** Absolute temp file holding the chosen (clearest) favicon bytes, when found. */
126
+ readonly iconPath: string | undefined;
127
+ readonly iconUrl?: string;
128
+ /** All viable candidates ranked by clarity, near-duplicates removed. */
129
+ readonly icons: readonly ScrapedIcon[];
130
+ }
131
+ interface FaviconCandidate {
132
+ readonly href: string;
133
+ readonly rel: string;
134
+ readonly sizes?: string;
135
+ }
136
+ /** Extract `<title>` text from HTML. */
137
+ declare const extractTitle: (html: string) => string | undefined;
138
+ /** Extract `<link rel=... href=...>` favicon candidates from HTML head. */
139
+ declare const extractFaviconCandidates: (html: string) => readonly FaviconCandidate[];
140
+ /** Largest dimension of a `sizes` attribute value such as `32x32` or `any`. */
141
+ declare const faviconCandidateSize: (candidate: FaviconCandidate) => number;
142
+ /** Resolve a favicon href against the service origin. */
143
+ declare const resolveFaviconUrl: (href: string, origin: string) => string | undefined;
144
+ /** Order candidates: declared-size icons descending, then apple-touch-icon, then others. */
145
+ declare const rankFaviconCandidates: (candidates: readonly FaviconCandidate[]) => readonly FaviconCandidate[];
146
+ interface ScrapePage {
147
+ readonly ok: boolean;
148
+ readonly status: number;
149
+ readonly body: string;
150
+ }
151
+ interface ScrapeBytes {
152
+ readonly ok: boolean;
153
+ readonly status: number;
154
+ readonly bytes: Buffer;
155
+ readonly contentType: string;
156
+ }
157
+ interface ScrapeFetch {
158
+ page(url: string, timeoutMs?: number): Promise<ScrapePage>;
159
+ bytes(url: string, timeoutMs?: number): Promise<ScrapeBytes>;
160
+ }
161
+ /**
162
+ * Scrape title and ALL icon candidates from an arbitrary http(s) URL.
163
+ * Never throws: failures return `ok: false` with whatever partial identity
164
+ * was found. (`scrapeService` is the loopback-port wrapper over this.)
165
+ */
166
+ declare const scrapeUrl: (url: string, options?: {
167
+ fetch?: ScrapeFetch;
168
+ tempDir?: string;
169
+ }) => Promise<ScrapeResult>;
170
+ /**
171
+ * Scrape title and ALL icon candidates from a service port. Never throws:
172
+ * failures return `ok: false` with whatever partial identity was found.
173
+ */
174
+ declare const scrapeService: (port: number, options?: {
175
+ fetch?: ScrapeFetch;
176
+ tempDir?: string;
177
+ }) => Promise<ScrapeResult>;
178
+ //#endregion
179
+ //#region ../icon/src/generate.d.ts
180
+ interface OpenTrayAppIconOptions {
181
+ readonly sourcePath: string;
182
+ readonly outputPath?: string;
183
+ readonly icnsOutputPath?: string;
184
+ readonly icoOutputPath?: string;
185
+ readonly linuxOutputDirectory?: string;
186
+ readonly manifestOutputPath?: string;
187
+ readonly cachePath?: string;
188
+ /** Advanced: override the module whose bytes identify the generator implementation. */
189
+ readonly implementationPath?: string;
190
+ /** Advanced: override the source file whose bytes identify the generator implementation. */
191
+ readonly implementationSourcePath?: string;
192
+ /**
193
+ * Pre-composed source: skip glyph re-tiling; pass pixels through verbatim.
194
+ */
195
+ readonly composed?: boolean;
196
+ /**
197
+ * Separate macOS content source; ICNS encodes from this while ICO/Linux
198
+ * use sourcePath.
199
+ */
200
+ readonly macosSourcePath?: string;
201
+ }
202
+ interface OpenTrayAppIconCacheMetadata {
203
+ readonly schemaVersion: number;
204
+ readonly sourceSha256: string;
205
+ readonly macosSourceSha256?: string;
206
+ readonly composed?: boolean;
207
+ readonly sourceImplementationSha256: string | null;
208
+ readonly implementationSha256: string;
209
+ readonly recipeVersion: string;
210
+ readonly jsquashPngVersion: string;
211
+ readonly jsquashResizeVersion: string;
212
+ readonly resvgVersion: string;
213
+ readonly iconEncoderVersion: string;
214
+ readonly figmaSquircleVersion: string;
215
+ readonly exifrVersion: string;
216
+ readonly outputPath: string;
217
+ readonly icnsOutputPath: string;
218
+ readonly icoOutputPath: string;
219
+ readonly linuxPngOutputPaths: readonly {
220
+ readonly size: number;
221
+ readonly path: string;
222
+ }[];
223
+ readonly manifestOutputPath: string;
224
+ /** Absolute file sources ready to pass to OpenTray at runtime. */
225
+ readonly appIcon: AppIcon;
226
+ }
227
+ /** Generate one strict cross-platform AppIcon asset set. */
228
+ declare function generateOpenTrayAppIcon(options: OpenTrayAppIconOptions): Promise<OpenTrayAppIconCacheMetadata>;
229
+ //#endregion
230
+ //#region ../icon/src/default-icon.d.ts
231
+ interface DefaultAppIconOptions {
232
+ readonly appName: string;
233
+ readonly accent?: string;
234
+ readonly outputDir: string;
235
+ /**
236
+ * Output file stem. The runtime uses the default (`default-app-icon`); the
237
+ * create pipeline passes `app-icon` so the glyph fallback lands in the
238
+ * scaffold's standard catalog layout — one generator, one visual standard.
239
+ */
240
+ readonly fileStem?: string;
241
+ /** Cache metadata path; defaults to `<outputDir>/../.cache/default-app-icon.json`. */
242
+ readonly cachePath?: string;
243
+ }
244
+ interface DefaultAppIconResult {
245
+ readonly fullPngPath: string;
246
+ readonly macOSPngPath: string;
247
+ readonly icnsPath: string;
248
+ readonly icoPath: string;
249
+ readonly linuxPngPaths: readonly {
250
+ size: number;
251
+ path: string;
252
+ }[];
253
+ readonly manifestPath: string;
254
+ /** Absolute file sources ready to pass to the runtime as `appIcon`. */
255
+ readonly appIcon: AppIcon;
256
+ readonly cacheIdentity: string;
257
+ /**
258
+ * True when the name's own first glyph could not be covered by the font
259
+ * ladder on this host and the neutral terminal mark was used instead
260
+ * (e.g. CJK names on CJK-less CI runners and containers).
261
+ */
262
+ readonly degraded: boolean;
263
+ }
264
+ /** Generate (or reuse, by full identity) the default glyph App icon catalog. */
265
+ declare function generateDefaultAppIcon(options: DefaultAppIconOptions): Promise<DefaultAppIconResult>;
266
+ //#endregion
267
+ //#region ../icon/src/compose.d.ts
268
+ type IconBackground = "black" | "white" | "transparent";
269
+ //#endregion
270
+ //#region packages/core/src/command-run.d.ts
271
+ interface CommandRunEvent {
272
+ readonly type: "stdout" | "stderr" | "exit" | "spawn-error" | "pty-ready" | "pty-unavailable";
273
+ /** The PTY binding's output chunk, verbatim; rendering is the frontend's job. */
274
+ readonly chunk?: string;
275
+ readonly code?: number | null;
276
+ readonly message?: string;
277
+ /**
278
+ * Stable machine code for pty-unavailable events so consumers can localize
279
+ * (and detect) the reason without parsing the human-readable message.
280
+ */
281
+ readonly reason?: "pty_bun_terminal_missing" | "pty_node_pty_missing";
282
+ }
283
+ interface CommandRunTerminalSize {
284
+ readonly cols: number;
285
+ readonly rows: number;
286
+ }
287
+ interface CommandRunOptions {
288
+ readonly tokens: readonly string[];
289
+ readonly cwd?: string;
290
+ readonly env?: NodeJS.ProcessEnv;
291
+ readonly ringLimit?: number;
292
+ /** Attach through a PTY when available; defaults to true. */
293
+ readonly pty?: boolean;
294
+ readonly terminalSize?: CommandRunTerminalSize;
295
+ readonly onEvent: (event: CommandRunEvent) => void;
296
+ }
297
+ interface CommandRun {
298
+ readonly pid: number | undefined;
299
+ readonly pty: boolean;
300
+ readonly exited: Promise<{
301
+ code: number | null;
302
+ spawnError?: string;
303
+ }>;
304
+ readonly output: readonly string[];
305
+ /** Write terminal input bytes to the command's stdin (PTY mode only). */
306
+ write(data: string): void;
307
+ /** Resize the pseudo-terminal (PTY mode only). */
308
+ resize(size: CommandRunTerminalSize): void;
309
+ kill(): Promise<void>;
310
+ }
311
+ declare const startCommandRun: (options: CommandRunOptions) => Promise<CommandRun>;
312
+ //#endregion
313
+ //#region packages/core/src/user-messages.d.ts
314
+ declare const UI_LOCALES: readonly ["zh-CN", "ja", "ko", "en", "ar", "fr", "es", "de", "ru"];
315
+ type UiLocale = (typeof UI_LOCALES)[number];
316
+ //#endregion
317
+ //#region packages/core/src/scaffold.d.ts
318
+ interface ScaffoldAppConfig {
319
+ readonly schemaVersion: 1;
320
+ readonly appId: string;
321
+ readonly appName: string;
322
+ /** Command source; exactly one of command/url is present (v1 XOR). */
323
+ readonly command?: LaunchVector;
324
+ /** URL source: the address the generated window opens directly. */
325
+ readonly url?: string;
326
+ readonly service: {
327
+ readonly port: number;
328
+ };
329
+ readonly window: {
330
+ readonly width: number;
331
+ readonly height: number;
332
+ /**
333
+ * Host the native navigation-toolbar carrier (add-webview-orchestration
334
+ * D12/D13): one toolbar webview above one content webview per generated
335
+ * window, for BOTH URL and command applications. This is the one
336
+ * canonical toolbar field — the legacy shell `showAddressBar` input is
337
+ * retired (stale frozen occurrences are ignored by loose parsing).
338
+ */
339
+ readonly toolbar?: boolean;
340
+ readonly titleFollowsDocument: boolean;
341
+ readonly iconFollowsDocument: boolean;
342
+ };
343
+ /** Tray icon asset (written by materialize); omitted → text-only tray. */
344
+ readonly trayIcon?: {
345
+ readonly path: string;
346
+ readonly template: boolean;
347
+ };
348
+ /** Generated-app shell options (startup terminal visibility only). */
349
+ readonly shell?: {
350
+ readonly showTerminal: boolean;
351
+ };
352
+ /** v1 developerMode: only WebView DevTools admission; default false. */
353
+ readonly developerMode?: boolean;
354
+ }
355
+ interface ScaffoldOptions {
356
+ readonly config: ScaffoldAppConfig;
357
+ readonly targetDir: string;
358
+ /** opentray/@opentray/ext-webview version range written into package.json. */
359
+ readonly dependencyRange: string;
360
+ /** Whether install will be skipped; only affects README guidance text. */
361
+ readonly skipInstall?: boolean;
362
+ /** Directory holding the prebuilt shell UI (copied to app-shell/).
363
+ * Defaults to the adapter-staged assets resolved from the running package
364
+ * layout (published create-opentray/dist/shell, or the workspace build). */
365
+ readonly shellAssetsDir?: string;
366
+ }
367
+ interface ScaffoldResult {
368
+ readonly projectDir: string;
369
+ readonly entryPath: string;
370
+ readonly configPath: string;
371
+ readonly appIconDir: string;
372
+ readonly writtenFiles: readonly string[];
373
+ }
374
+ declare const writeScaffold: (options: ScaffoldOptions) => Promise<ScaffoldResult>;
375
+ //#endregion
376
+ //#region packages/core/src/materialize.d.ts
377
+ type MaterializeLogEvent = {
378
+ readonly type: "step";
379
+ readonly step: string;
380
+ readonly message: string;
381
+ } | {
382
+ readonly type: "log";
383
+ readonly message: string;
384
+ };
385
+ interface MaterializeInput {
386
+ readonly config: ScaffoldAppConfig;
387
+ readonly targetDir: string;
388
+ readonly dependencyRange: string;
389
+ readonly iconSourcePath: string | undefined;
390
+ /** True when the tray source is a solid silhouette (darwin template). */
391
+ readonly trayIconIsSolid?: boolean;
392
+ /** Icon composition (owner round-12): background + foreground scale. */
393
+ readonly iconBackground?: IconBackground;
394
+ readonly iconScale?: number;
395
+ /** Nearest-neighbor sampling for pixel-art sources (v1 imageSmoothingEnabled). */
396
+ readonly imageSmoothingEnabled?: boolean;
397
+ /** Tray icon source; defaults to the app icon source when omitted. */
398
+ readonly trayIconSourcePath?: string;
399
+ /** Generated-app shell options (startup terminal visibility only; the
400
+ * toolbar is a `window.toolbar` fact, add-webview-orchestration D13). */
401
+ readonly shell?: {
402
+ showTerminal: boolean;
403
+ };
404
+ /** Adapter-owned prebuilt shell UI directory (copied to app-shell/). */
405
+ readonly shellAssetsDir?: string;
406
+ readonly packageManager: "npm" | "pnpm" | "bun";
407
+ readonly skipInstall: boolean;
408
+ readonly force: boolean;
409
+ }
410
+ interface MaterializeResult {
411
+ readonly scaffold: ScaffoldResult;
412
+ readonly projectDir: string;
413
+ }
414
+ interface MaterializeContext {
415
+ readonly log: (event: MaterializeLogEvent) => void;
416
+ readonly generateIcon?: typeof generateOpenTrayAppIcon;
417
+ /** Same seam for the glyph default catalog (wizard tests stub both). */
418
+ readonly generateDefaultIcon?: typeof generateDefaultAppIcon;
419
+ readonly runInstall?: (options: RunInstallOptions) => Promise<void>;
420
+ }
421
+ interface RunInstallOptions {
422
+ readonly projectDir: string;
423
+ readonly packageManager: "npm" | "pnpm" | "bun";
424
+ readonly log: (message: string) => void;
425
+ }
426
+ /** True when the directory exists and contains anything beyond ignorable files. */
427
+ declare const isDirectoryOccupied: (dir: string) => Promise<boolean>;
428
+ /** Detect package manager from lockfiles then npm_config_user_agent. */
429
+ declare const detectPackageManager: (files: readonly string[], userAgent: string | undefined) => "npm" | "pnpm" | "bun";
430
+ /** Expected stable Darwin bundle path for the generated project's identity. */
431
+ declare const expectedDarwinBundlePath: (config: {
432
+ appName: string;
433
+ appId: string;
434
+ }) => string;
435
+ /**
436
+ * Backward-compatible composition used by the wizard adapter: generation is
437
+ * the payload phase. There is no first-launch validation — the wizard panel's
438
+ * command preview is the validator (decision D1).
439
+ */
440
+ declare const materialize: (input: MaterializeInput, context: MaterializeContext) => Promise<MaterializeResult>;
441
+ //#endregion
442
+ //#region src/wizard.d.ts
443
+ interface WizardEnvEntry {
444
+ readonly key: string;
445
+ readonly value: string;
446
+ }
447
+ /** App-icon composition (owner round-12): foreground over black/white/
448
+ * transparent background; the wizard derives the auto suggestion. */
449
+ type WizardIconBackground = "black" | "white" | "transparent";
450
+ interface WizardIconComposition {
451
+ readonly key: string;
452
+ readonly compositePath: string;
453
+ readonly macOSPath: string;
454
+ readonly background: WizardIconBackground;
455
+ }
456
+ interface WizardIconAnalysis {
457
+ readonly luminance: number | undefined;
458
+ readonly coverage: number;
459
+ readonly suggested: WizardIconBackground;
460
+ }
461
+ /** Command execution options (advanced): working directory, custom env, and
462
+ * the input mode — array mode takes argv elements verbatim (no string
463
+ * splitting), string mode tokenizes one command line. */
464
+ interface WizardCommandOptions {
465
+ /** Empty = the wizard's working directory. */
466
+ readonly cwd: string;
467
+ readonly env: readonly WizardEnvEntry[];
468
+ readonly argsMode: "string" | "array";
469
+ /**
470
+ * 系列作者状态(plan.md D11 / Codex B1):显式投影是系列/appId 推导的
471
+ * 服务端权威(Rust 的 crate/binary 无法从命令串恢复);null = 按命令串派生。
472
+ * 命令串始终是执行/持久化向量。env 预设(npm_config_yes 等)不再有隐形
473
+ * 注入开关——env 行是唯一可信源(R10 用户拍板)。
474
+ */
475
+ readonly family: FamilyFormState | null;
476
+ }
477
+ type WizardState = "idle" | "running" | "discovered" | "failed" | "frozen" | "materializing" | "success";
478
+ interface WizardFormValues {
479
+ readonly appId: string;
480
+ readonly appName: string;
481
+ readonly iconPath: string;
482
+ /** Icon composition (owner round-12). */
483
+ readonly iconBackground: WizardIconBackground;
484
+ readonly iconScale: number;
485
+ /** Empty = follow the app icon choice (default). */
486
+ readonly trayIconPath: string;
487
+ readonly pm: "npm" | "pnpm" | "bun";
488
+ /** Wipe an existing non-empty target directory before materializing. */
489
+ readonly force: boolean;
490
+ /** Advanced: render the command PTY in the generated app (default false). */
491
+ readonly showStartupTerminal: boolean;
492
+ /**
493
+ * 「导航工具栏」开关 (add-webview-orchestration D15): compose the native
494
+ * navigation-toolbar carrier over the target/service window — a
495
+ * desired-state fact compiling into the v1 `window.toolbar` field for BOTH
496
+ * application flows (default false). Replaces the retired showAddressBar
497
+ * input (D13); enabling it requires no embedding knowledge.
498
+ */
499
+ readonly toolbar: boolean;
500
+ /** Advanced v1 sampling intent: false keeps pixel-art edges (default true). */
501
+ readonly imageSmoothingEnabled: boolean;
502
+ /** Advanced v1 developer mode: only WebView DevTools admission (default false). */
503
+ readonly developerMode: boolean;
504
+ }
505
+ /** Placeholder suggestions shown in the form; empty fields resolve to these. */
506
+ interface WizardFormDefaults {
507
+ readonly appId: string;
508
+ readonly appName: string;
509
+ /** Resolved project directory the app will be generated into. */
510
+ readonly targetDir: string;
511
+ /**
512
+ * Effective default icon source (the clearest scraped candidate). The form
513
+ * value stays empty until the user picks/upload; composition must follow
514
+ * this default too, or the preview would never appear without a click.
515
+ */
516
+ readonly iconPath: string;
517
+ }
518
+ type WizardEvent = {
519
+ readonly type: "state";
520
+ readonly state: WizardState;
521
+ readonly reason?: string;
522
+ } | {
523
+ readonly type: "log";
524
+ readonly stream: "stdout" | "stderr";
525
+ readonly chunk: string;
526
+ } | {
527
+ readonly type: "term-mode";
528
+ readonly interactive: boolean;
529
+ readonly message?: string;
530
+ } | {
531
+ readonly type: "run-status";
532
+ readonly running: boolean;
533
+ readonly code?: number | null;
534
+ } | {
535
+ readonly type: "command-display";
536
+ readonly command: string;
537
+ } | {
538
+ readonly type: "command-options";
539
+ readonly options: WizardCommandOptions;
540
+ readonly defaultCwd: string;
541
+ } | {
542
+ readonly type: "services";
543
+ readonly services: readonly DiscoveredService[];
544
+ readonly selectedPort: number | undefined;
545
+ } | {
546
+ readonly type: "scrape";
547
+ readonly port: number;
548
+ readonly title?: string;
549
+ readonly hasIcon: boolean;
550
+ } | {
551
+ readonly type: "icons";
552
+ readonly port: number;
553
+ readonly icons: readonly ScrapedIcon[];
554
+ /** Bumps on every scrape-side REPLACEMENT of the list (not appends):
555
+ * indexes restart from zero per scrape, so clients keying per-candidate
556
+ * work (e.g. subject extraction) need this to tell generations apart. */
557
+ readonly generation: number;
558
+ } | {
559
+ readonly type: "form";
560
+ readonly values: WizardFormValues;
561
+ readonly defaults: WizardFormDefaults;
562
+ readonly targetDirExists: boolean;
563
+ } | {
564
+ readonly type: "materialize-log";
565
+ readonly message: string;
566
+ } | {
567
+ readonly type: "materialize-step";
568
+ readonly step: string;
569
+ readonly message: string;
570
+ } | {
571
+ readonly type: "success";
572
+ readonly projectDir: string;
573
+ readonly bundlePath?: string;
574
+ readonly pinHint: string;
575
+ } /** Authoritative whole-session state; sent to every NEW SSE client first. */ | {
576
+ readonly type: "snapshot";
577
+ readonly state: WizardState;
578
+ readonly runAlive: boolean;
579
+ readonly command: string; /** URL 模式激活时的源地址(命令模式为 undefined)。 */
580
+ readonly urlSource?: string;
581
+ readonly commandOptions: WizardCommandOptions;
582
+ readonly form: WizardFormValues;
583
+ readonly defaults: WizardFormDefaults;
584
+ readonly targetDirExists: boolean;
585
+ readonly services: readonly DiscoveredService[];
586
+ readonly selectedPort?: number | undefined;
587
+ readonly iconCandidates: readonly ScrapedIcon[];
588
+ readonly iconsPort?: number | undefined; /** Scrape-generation counter carried by icons events and snapshots. */
589
+ readonly iconsGeneration: number;
590
+ readonly interactive: boolean;
591
+ };
592
+ interface WizardOptions {
593
+ readonly cwd: string;
594
+ /**
595
+ * USER_HOME anchor: the command-execution default cwd AND the root of the
596
+ * default generated-project location (~/.opentray/create/<name>).
597
+ */
598
+ readonly homeDir?: string;
599
+ /** Explicit project directory (CLI positional); default: the create root. */
600
+ readonly targetDir?: string | undefined;
601
+ readonly skipInstall: boolean;
602
+ /** Seed the 强制覆盖 toggle (CLI --force); the form owns the live value. */
603
+ readonly force?: boolean | undefined;
604
+ readonly packageManager?: "npm" | "pnpm" | "bun";
605
+ readonly dependencyRange: string;
606
+ readonly emit: (event: WizardEvent) => void;
607
+ readonly spawnRun?: typeof startCommandRun;
608
+ readonly listListeners?: () => Promise<ReadonlySet<number>>;
609
+ readonly verifyHttp?: (port: number) => Promise<boolean>;
610
+ /** Test/embedding seam for listener ownership. */
611
+ readonly listPortOwners?: () => Promise<ListenerOwners>;
612
+ readonly scrape?: typeof scrapeService;
613
+ /** Test seam for the URL-mode preset scrape. */
614
+ readonly scrapeUrl?: typeof scrapeUrl;
615
+ readonly resolveVector?: typeof resolveLaunchVector;
616
+ /** Test/embedding seam for PATH resolution of the cargo-install guard. */
617
+ readonly resolveOnPath?: typeof resolveOnPath;
618
+ /** Test/embedding seam for the materialize pipeline. */
619
+ readonly materializeContext?: Partial<MaterializeContext>;
620
+ readonly platform?: NodeJS.Platform;
621
+ readonly pollIntervalMs?: number;
622
+ readonly scrapeIntervalMs?: number;
623
+ }
624
+ interface WizardSession {
625
+ readonly state: WizardState;
626
+ readonly services: readonly DiscoveredService[];
627
+ readonly selectedPort: number | undefined;
628
+ /** True while the preview process is alive (Run button shows Interrupt). */
629
+ readonly runAlive: boolean;
630
+ /** Latest scraped icon candidates for the selected service, ranked by clarity. */
631
+ readonly iconCandidates: readonly ScrapedIcon[];
632
+ /** Persist an uploaded image into the session temp dir; returns its path. */
633
+ saveIconUpload(bytes: Buffer): Promise<string>;
634
+ /** Candidate lookup scoped to the port it was scraped from. */
635
+ iconCandidate(port: number, index: number): ScrapedIcon | undefined;
636
+ /** Select a scraped candidate as the icon source (marks the field touched). */
637
+ selectIconCandidate(port: number, index: number): boolean;
638
+ /** Select a candidate (original or solid variant) as the TRAY icon. */
639
+ selectTrayIconCandidate(port: number, index: number): boolean;
640
+ /** Test/extension seam: replace the scraped candidate set for a port. */
641
+ replaceIconCandidates(port: number, icons: readonly ScrapedIcon[]): void;
642
+ /** Append a wizard-derived candidate (e.g. browser-side subject extraction)
643
+ * for the port the current candidates belong to; bytes land in the
644
+ * session-owned temp dir so icon routes keep serving them. Returns the
645
+ * appended candidate, or undefined when the port/state rejects it. */
646
+ addIconCandidate(port: number, candidate: {
647
+ readonly bytes: Buffer;
648
+ readonly variantOf: number;
649
+ readonly width: number;
650
+ readonly height: number;
651
+ readonly format: string;
652
+ }): Promise<ScrapedIcon | undefined>;
653
+ /** Compose the app icon preview/asset for the current foreground. */
654
+ composeIcon(options: {
655
+ foregroundPath: string;
656
+ background?: WizardIconBackground;
657
+ scale?: number;
658
+ }): Promise<WizardIconComposition>;
659
+ /** Register a composition for token-scoped byte serving (server seam). */
660
+ trackIconComposition(composition: WizardIconComposition): void;
661
+ /** Look up a registered composition by cache key. */
662
+ iconComposition(key: string): WizardIconComposition | undefined;
663
+ /** Wizard-owned icon source roots (containment for icon routes). */
664
+ iconSourceRoots(): readonly string[];
665
+ /** Auto-suggestion for the foreground (background + reason). */
666
+ analyzeIconForeground(foregroundPath: string): Promise<WizardIconAnalysis>;
667
+ readonly form: WizardFormValues;
668
+ readonly result: MaterializeResult | undefined;
669
+ /** Adopt the webui's locale for every user-facing string this session emits. */
670
+ setLocale(locale: UiLocale): void;
671
+ /** Whole-session state for reconnecting clients (page refresh recovery). */
672
+ snapshot(): WizardEvent;
673
+ /** String form is tokenized; array form is taken as argv verbatim (array
674
+ * input mode — no string splitting is ever applied to it). */
675
+ submitCommand(command: string | readonly string[]): Promise<void>;
676
+ /** URL 模式入口:地址即源(一次抓取预设,进入 discovered 可确认态);
677
+ * 空 url 退出 URL 模式回到 idle。 */
678
+ submitUrl(url: string): Promise<void>;
679
+ /** Active URL-mode source address; undefined in command mode. */
680
+ readonly urlSource: string | undefined;
681
+ /** Derive placeholder defaults from command text without spawning anything. */
682
+ prime(command: string | readonly string[]): void;
683
+ readonly commandOptions: WizardCommandOptions;
684
+ updateCommandOptions(patch: Partial<WizardCommandOptions>): void;
685
+ selectService(port: number): void;
686
+ updateForm(patch: Partial<WizardFormValues>): void;
687
+ terminalInput(data: string): void;
688
+ terminalResize(size: {
689
+ cols: number;
690
+ rows: number;
691
+ }): void;
692
+ confirm(): void;
693
+ /** Abort a frozen confirmation and return to the editable pre-freeze state. */
694
+ cancel(): void;
695
+ /**
696
+ * Share the FROZEN parameters (wizard-share-and-list-scan D3): build an
697
+ * export artifact from the confirmation state WITHOUT running the command
698
+ * or materializing anything. Works pre-create. Scraped web icons keep
699
+ * their http source URL plus the icon-generation flags by default;
700
+ * `inlineIcon` opts into embedding the bytes instead.
701
+ */
702
+ exportFrozen(options: {
703
+ readonly format: "command" | "sh" | "ps1";
704
+ readonly acknowledgeEnv?: boolean;
705
+ readonly forceCopy?: boolean; /** true=内嵌字节;false=按引用分享(URL/本地路径);缺省=按来源默认。 */
706
+ readonly inlineIcon?: boolean;
707
+ }): Promise<WizardExportResult>;
708
+ create(): Promise<void>;
709
+ stop(): Promise<void>;
710
+ }
711
+ type WizardExportResult = {
712
+ readonly ok: true;
713
+ readonly kind: "command";
714
+ readonly command: string;
715
+ } | {
716
+ readonly ok: true;
717
+ readonly kind: "script";
718
+ readonly filename: string;
719
+ readonly content: string; /** 核心调用行(不含注释/脚手架),复制命令用。 */
720
+ readonly commandLine: string;
721
+ readonly requiresEnvAcknowledgement: boolean; /** How the app icon actually traveled in this artifact. */
722
+ readonly iconSharedAs: "url" | "embedded" | "local" | "none"; /** What the icon source CAN be shared as: url / local path / none. */
723
+ readonly iconReference: "url" | "local" | "none";
724
+ } | {
725
+ readonly ok: false;
726
+ readonly code: "state_error" | "resolve_failed" | "env_ack_required" | "export_unsafe";
727
+ readonly message: string;
728
+ };
729
+ declare const createWizardSession: (options: WizardOptions) => WizardSession;
730
+ //#endregion
731
+ //#region src/bin.d.ts
732
+ interface WizardCliOptions {
733
+ readonly open: boolean;
734
+ readonly port: number | undefined;
735
+ readonly pm: "npm" | "pnpm" | "bun" | undefined;
736
+ readonly skipInstall: boolean;
737
+ readonly force: boolean;
738
+ readonly targetDir: string | undefined;
739
+ }
740
+ declare const parseWizardCli: (argv: readonly string[]) => WizardCliOptions;
741
+ declare const openBrowser: (url: string) => Promise<void>;
742
+ /** Draft form values carry fields across versions — forward only the
743
+ * known-safe, type-checked subset. Retired fields (the legacy
744
+ * showAddressBar, replaced by `toolbar` in add-webview-orchestration D13)
745
+ * are ignored here: a stale draft never resurrects a removed input.
746
+ * Exported for tests alongside parseWizardCli. */
747
+ declare const normalizeDraftForm: (raw: unknown) => Partial<WizardFormValues> | undefined;
748
+ declare const main: (argv: readonly string[]) => Promise<number>;
749
+ //#endregion
750
+ export { resolveFaviconUrl as A, LaunchVector as B, UiLocale as C, extractTitle as D, extractFaviconCandidates as E, parseNetstatPorts as F, resolveLaunchVector as H, parsePowerShellPorts as I, serviceUrl as L, DiscoveredService as M, createPortDiscovery as N, faviconCandidateSize as O, parseLsofPorts as P, verifyHttpService as R, writeScaffold as S, ScrapeResult as T, resolveOnPath as U, parseShebangInterpreter as V, isDirectoryOccupied as _, parseWizardCli as a, ScaffoldOptions as b, WizardSession as c, MaterializeContext as d, MaterializeInput as f, expectedDarwinBundlePath as g, detectPackageManager as h, openBrowser as i, scrapeService as j, rankFaviconCandidates as k, WizardState as l, MaterializeResult as m, main as n, WizardEvent as o, MaterializeLogEvent as p, normalizeDraftForm as r, WizardFormValues as s, WizardCliOptions as t, createWizardSession as u, materialize as v, FaviconCandidate as w, ScaffoldResult as x, ScaffoldAppConfig as y, waitForTcpPort as z };
751
+ //# sourceMappingURL=bin-CrMTyTux.d.mts.map