create-opentray 0.0.0 → 0.19.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.
Files changed (44) hide show
  1. package/README.md +163 -0
  2. package/dist/assets/create-openspec-template-iOS-Dark-1024@1x.png +0 -0
  3. package/dist/assets/create-openspec-template-iOS-Default-1024@1x.png +0 -0
  4. package/dist/bin-B9VeXatR.mjs +3830 -0
  5. package/dist/bin-B9VeXatR.mjs.map +1 -0
  6. package/dist/bin-CeFW1wxR.d.mts +15 -0
  7. package/dist/bin-CeFW1wxR.d.mts.map +1 -0
  8. package/dist/bin.d.mts +2 -0
  9. package/dist/bin.mjs +3 -0
  10. package/dist/icon-codec-BQ3cGV1n.mjs +13 -0
  11. package/dist/icon-codec-BQ3cGV1n.mjs.map +1 -0
  12. package/dist/index.d.mts +557 -0
  13. package/dist/index.d.mts.map +1 -0
  14. package/dist/index.mjs +2 -0
  15. package/dist/shell/assets/__vite-browser-external-2447137e.js +1 -0
  16. package/dist/shell/assets/browse.js +1 -0
  17. package/dist/shell/assets/ghostty-web.js +13 -0
  18. package/dist/shell/assets/index.css +1 -0
  19. package/dist/shell/assets/index.js +9 -0
  20. package/dist/shell/assets/input.js +1 -0
  21. package/dist/shell/assets/main.js +43 -0
  22. package/dist/shell/assets/terminal-pane.js +2 -0
  23. package/dist/shell/assets/terminal.js +1 -0
  24. package/dist/shell/browse.html +15 -0
  25. package/dist/shell/ghostty-vt.wasm +0 -0
  26. package/dist/shell/index.html +15 -0
  27. package/dist/shell/terminal.html +15 -0
  28. package/dist/webui/assets/__vite-browser-external-2447137e.js +1 -0
  29. package/dist/webui/assets/browse.js +1 -0
  30. package/dist/webui/assets/ghostty-web.js +13 -0
  31. package/dist/webui/assets/index.css +1 -0
  32. package/dist/webui/assets/index.js +9 -0
  33. package/dist/webui/assets/input.js +1 -0
  34. package/dist/webui/assets/main.js +43 -0
  35. package/dist/webui/assets/terminal-pane.js +2 -0
  36. package/dist/webui/assets/terminal.js +1 -0
  37. package/dist/webui/browse.html +15 -0
  38. package/dist/webui/ghostty-vt.wasm +0 -0
  39. package/dist/webui/index.html +16 -0
  40. package/dist/webui/terminal.html +15 -0
  41. package/dist/webui/vendor/ghostty-vt.wasm +0 -0
  42. package/dist/webui/vendor/ghostty-web.js +2963 -0
  43. package/package.json +45 -5
  44. package/index.js +0 -1
package/README.md ADDED
@@ -0,0 +1,163 @@
1
+ # create-opentray
2
+
3
+ Turn any start command that serves HTTP locally into an OpenTray-hosted
4
+ desktop app — through a browser wizard, without writing OpenTray code.
5
+
6
+ ```bash
7
+ npx create-opentray
8
+ ```
9
+
10
+ Requires Node >= 20 (native `sharp` icon pipeline).
11
+
12
+ ## What it does
13
+
14
+ 1. Starts a token-guarded WebUI (React + shadcn/ui) on `127.0.0.1` and opens
15
+ your browser.
16
+ 2. You paste a start command (e.g. `npx somecommand start --xx`). It runs
17
+ immediately in a **real interactive terminal** inside a Chrome-style tabs
18
+ panel: prompts, TUI output, and keystrokes all work.
19
+ 3. Confirmed HTTP services (TCP listener owned by the command's process tree
20
+ **and** answering an HTTP probe) each open an iframe tab automatically —
21
+ newly sniffed tabs take focus — and stay alive across switches. The tab
22
+ strip sits above the context toolbar; on service tabs it shows an editable
23
+ URL with back/forward/reload backed by a per-tab history. The terminal tab's status bar shows cursor position,
24
+ selection range, and clickable service entries that jump to the matching
25
+ iframe tab by hostname.
26
+ 4. Auto-derived defaults (scraped title, derived appId) are shown as
27
+ **input placeholders** — an empty field means "use the default"; edits win
28
+ over later scrapes. The icon row is a square file picker plus scraped
29
+ candidates: every icon the page declares (SVG, apple-touch-icon, sized
30
+ PNG sets, /favicon.ico) is collected, measured by true pixel clarity,
31
+ deduplicated perceptually, and ranked; clicking a candidate (or uploading
32
+ a local image) selects it, and the clearest candidate is the default.
33
+ 5. 高级选项 — the settings button beside the command bar opens an accordion:
34
+ - 命令选项: 参数输入模式 (string vs 数组/argv — array mode commits ONE argv
35
+ element per tag, verbatim, never splitting strings), 工作目录 (cwd;
36
+ default is the USER_HOME directory, displayed in full — relative paths
37
+ resolve from there), and 环境变量 (env overlay; also persisted into the
38
+ generated app).
39
+ - 应用选项: the tray-icon picker (defaults to the app icon choice; solid
40
+ black/white silhouettes derived from every candidate) and the two
41
+ generated-app window options 显示启动终端 / 显示地址栏 (both default off).
42
+ Service ports are NEVER hard-bound: the form has no manual port input, and
43
+ the generated app resolves its address exclusively by sniffing the
44
+ command's owned listening ports (HTTP-verified) at runtime.
45
+ 6. 确定创建 freezes the resolved identity, shows a confirmation dialog, then
46
+ 确认生成 runs the pipeline with live logs: scaffold → icon generation →
47
+ dependency install → first launch → (macOS) stable bundle verification.
48
+ 7. Success offers 打开应用 plus a platform pinning hint (Windows taskbar /
49
+ macOS Dock).
50
+
51
+ ## CLI
52
+
53
+ ```
54
+ create-opentray [targetDir] [--no-open] [--port <n>] [--pm npm|pnpm|bun]
55
+ [--skip-install] [--force]
56
+ ```
57
+
58
+ - `--no-open` — print the wizard URL instead of opening a browser.
59
+ - `--pm` — force the package manager used for the generated project.
60
+ - `--skip-install` — scaffold without installing dependencies.
61
+ - `--force` — allow materializing into a non-empty directory.
62
+
63
+ ## Generated project
64
+
65
+ Projects default to `~/.opentray/create/<name>/` (stable per app — re-running
66
+ the wizard for the same command regenerates the same location and never
67
+ pollutes the invocation directory). Pass a positional argument to place the
68
+ project elsewhere. When the target directory already exists, the wizard
69
+ warns in 高级选项 and offers 强制覆盖, which CLEARS the directory and
70
+ regenerates it (equivalent to `--force`; the generated tree is fully
71
+ wizard-owned and regenerable).
72
+
73
+ ```
74
+ <project>/
75
+ package.json deps: opentray, @opentray/ext-webview (+ @lydell/node-pty
76
+ when the startup terminal is enabled)
77
+ opentray.app.json frozen identity, command vector, service port, window size,
78
+ tray icon, shell options
79
+ main.mjs entry: supervises the command, owns tray + windows
80
+ app-shell-server.mjs local shell host (only when a shell option is enabled):
81
+ serves app-shell/ + SSE state + terminal input
82
+ app-shell/ prebuilt shell UI pages (terminal.html, browse.html)
83
+ app-icon/ generated ICNS/ICO/Linux PNGs + app-icon.json manifest
84
+ + tray-icon.png (always, when any icon source exists)
85
+
86
+ Icon composition: the wizard analyzes the chosen foreground (alpha-weighted
87
+ luminance + opaque coverage, read at full size so no resampling padding
88
+ skews the reading) and composites it — ORIGINAL pixels preserved, never
89
+ recolored — over one of three backgrounds: light art → black, dark art →
90
+ white, fully-opaque art → transparent. Live preview, auto/manual selection,
91
+ and a 50–95% foreground scale control. Every composition is clipped to the
92
+ squircle alpha carried by the bundled backgrounds (including the transparent
93
+ one), which rounds the composite's corners on macOS. For macOS the ENTIRE tile
94
+ (background + art) is scaled to 824 and centered on the transparent 1024
95
+ canvas — Dock icons since Big Sur carry those margins — while Windows/Linux
96
+ use the full-bleed 1024. The tray icon stays on the raw source.
97
+ README.md
98
+ ```
99
+
100
+ The entry spawns the recorded command (output → `app.log`), waits for the
101
+ service port via TCP, then calls `createTray` with the frozen `appId`,
102
+ `appName`, generated `appIcon`, an optional tray icon, and an explicit absolute
103
+ `appLaunch` vector, and opens an `appMode: true` WebView window on the service
104
+ URL. Quit lives in the tray menu.
105
+
106
+ ### Shell options (dedicated windows)
107
+
108
+ - 显示启动终端 — the command runs through a PTY and a DEDICATED terminal
109
+ window opens: command bar on top, the same ghostty renderer the wizard uses,
110
+ status bar with cursor, size, and live listened ports (detached ports are
111
+ marked). Input flows back through the shell server.
112
+ - 显示地址栏 — every service window renders as an address-bar wrapper: the bar
113
+ sits above the service iframe and navigation is managed through the Web
114
+ Navigation API (same-origin `?url=` pseudo-routes are intercepted so only
115
+ the iframe moves; a history fallback covers engines without the API). With
116
+ the option off, service windows open the service URL directly.
117
+ - Every listened HTTP port owned by the command opens its own window
118
+ automatically; when a port stops listening, its window title becomes
119
+ `AppName (detached)` and reverts when the port returns.
120
+ - Generated entries always launch with Node even when the wizard ran under Bun
121
+ (the native PTY transport requires a Node host).
122
+
123
+ ## Platform notes
124
+
125
+ - **Objective terminal transport**: the preview runs through
126
+ [@lydell/node-pty](https://github.com/lydell/node-pty) (prebuilt per-platform
127
+ binaries; no compiler needed) and is rendered by
128
+ [ghostty-web](https://github.com/coder/ghostty-web). The backend forwards the
129
+ PTY binding's chunks verbatim — no re-decoding, no analysis; the renderer
130
+ owns every escape sequence. Invalid bytes are replaced with U+FFFD *inside
131
+ the PTY binding* (its documented text-channel contract, shared with every
132
+ node-pty consumer); the wizard adds no interpretation on top.
133
+ - The optional PTY dependency degrades to a read-only pipe mode with a visible
134
+ notice when it cannot load; the wizard itself keeps working.
135
+ - **Runtime-native PTY backends**: under Bun the terminal attaches through
136
+ the built-in `Bun.Terminal` + `Bun.spawn({ terminal })` (no native npm
137
+ dependency, fully interactive — verified output, stdin echo, resize, and
138
+ exit codes on Bun 1.3.14). Under Node it uses prebuilt `@lydell/node-pty`.
139
+ Both transport the PTY's chunks verbatim. Only when neither backend exists
140
+ (Node without the optional dependency, or a Bun older than 1.2.19) does the
141
+ preview degrade to read-only pipes with a visible notice.
142
+ - The Run button becomes an Interrupt button while the preview process is
143
+ alive and returns to Run when the process exits — including when it is
144
+ killed outside the wizard.
145
+ - The generated app runs the command supervised but headless (output goes to
146
+ `app.log`); commands that require an interactive TTY at runtime are not
147
+ supported inside the generated app.
148
+ - macOS: the stable `.app` bundle is materialized by the OpenTray runtime on
149
+ first launch; 打开应用 uses `open <bundle>.app` (cold launch via the launch
150
+ descriptor, warm reopen focuses the retained window). Pin it to the Dock.
151
+ - Windows: the appMode window participates in the taskbar/Alt-Tab; pin it from
152
+ the taskbar. Persistent shortcut generation is not provided yet.
153
+ - Linux: taskbar pinning depends on the desktop environment; `.desktop`
154
+ generation is not provided yet.
155
+
156
+ ## Programmatic use
157
+
158
+ ```ts
159
+ import { createWizardSession, deriveDefaultAppId } from "create-opentray";
160
+ ```
161
+
162
+ See the package's TypeScript definitions (dist/index.d.mts) for the full surface (wizard session, server,
163
+ discovery, scraping, launch-vector resolution, scaffold, materialize).