create-opentray 0.19.1 → 0.20.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 (49) hide show
  1. package/README.md +136 -133
  2. package/assets/create-opentray-logo.png +0 -0
  3. package/dist/bin-sZB5nWq0.mjs +2142 -0
  4. package/dist/bin-sZB5nWq0.mjs.map +1 -0
  5. package/dist/bin.d.mts +15 -2
  6. package/dist/bin.d.mts.map +1 -0
  7. package/dist/bin.mjs +1 -1
  8. package/dist/index.d.mts +62 -351
  9. package/dist/index.d.mts.map +1 -1
  10. package/dist/index.mjs +2 -1
  11. package/dist/shell/assets/browse.js +1 -1
  12. package/dist/shell/assets/index.css +1 -1
  13. package/dist/shell/assets/index.js +7 -7
  14. package/dist/shell/assets/input.js +1 -1
  15. package/dist/shell/assets/main.js +21 -43
  16. package/dist/shell/assets/terminal-pane.js +1 -1
  17. package/dist/shell/browse.html +3 -0
  18. package/dist/shell/favicon-16.png +0 -0
  19. package/dist/shell/favicon-32.png +0 -0
  20. package/dist/shell/favicon-64.png +0 -0
  21. package/dist/shell/index.html +3 -0
  22. package/dist/shell/logo.png +0 -0
  23. package/dist/shell/terminal.html +3 -0
  24. package/dist/skill/SKILL.md +156 -0
  25. package/dist/skill/references/cli-reference.md +77 -0
  26. package/dist/skill/references/how-it-works.md +49 -0
  27. package/dist/webui/assets/browse.js +1 -1
  28. package/dist/webui/assets/index.css +1 -1
  29. package/dist/webui/assets/index.js +7 -7
  30. package/dist/webui/assets/input.js +1 -1
  31. package/dist/webui/assets/main.js +21 -43
  32. package/dist/webui/assets/terminal-pane.js +1 -1
  33. package/dist/webui/browse.html +3 -0
  34. package/dist/webui/favicon-16.png +0 -0
  35. package/dist/webui/favicon-32.png +0 -0
  36. package/dist/webui/favicon-64.png +0 -0
  37. package/dist/webui/index.html +3 -0
  38. package/dist/webui/logo.png +0 -0
  39. package/dist/webui/terminal.html +3 -0
  40. package/package.json +12 -6
  41. package/skill/SKILL.md +156 -0
  42. package/skill/references/cli-reference.md +77 -0
  43. package/skill/references/how-it-works.md +49 -0
  44. package/dist/bin-B9VeXatR.mjs +0 -3830
  45. package/dist/bin-B9VeXatR.mjs.map +0 -1
  46. package/dist/bin-CeFW1wxR.d.mts +0 -15
  47. package/dist/bin-CeFW1wxR.d.mts.map +0 -1
  48. package/dist/icon-codec-BQ3cGV1n.mjs +0 -13
  49. package/dist/icon-codec-BQ3cGV1n.mjs.map +0 -1
package/README.md CHANGED
@@ -1,7 +1,10 @@
1
+ <p align="center"><img src="./assets/create-opentray-logo.png" alt="create-opentray logo" width="180"></p>
2
+
1
3
  # create-opentray
2
4
 
3
5
  Turn any start command that serves HTTP locally into an OpenTray-hosted
4
- desktop app — through a browser wizard, without writing OpenTray code.
6
+ desktop app — through a browser wizard or fully non-interactively, without
7
+ writing OpenTray code.
5
8
 
6
9
  ```bash
7
10
  npx create-opentray
@@ -9,149 +12,148 @@ npx create-opentray
9
12
 
10
13
  Requires Node >= 20 (native `sharp` icon pipeline).
11
14
 
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
15
+ ## Command tree
52
16
 
53
- ```
54
- create-opentray [targetDir] [--no-open] [--port <n>] [--pm npm|pnpm|bun]
55
- [--skip-install] [--force]
17
+ ```text
18
+ create-opentray # WebUI wizard (compatibility default)
19
+ create-opentray web [--port <n>] [--no-open]
20
+ create-opentray create [options] # non-interactive creation
21
+ create-opentray app list|edit|copy|export|uninstall
22
+ create-opentray skill [list|read] # packaged English AI skill
56
23
  ```
57
24
 
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.
25
+ Every command accepts `--json` for a machine-readable typed result on stdout
26
+ (progress and diagnostics then use stderr only).
62
27
 
63
- ## Generated project
28
+ ## Non-interactive create
64
29
 
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).
30
+ ```bash
31
+ npx create-opentray create \
32
+ --app-id app.local.mytool \
33
+ --app-name "My Tool" \
34
+ --exec npm --arg run --arg dev \
35
+ --cwd /path/to/project \
36
+ --app-icon https://example.com/logo.png \
37
+ --tray-icon ./tray.png \
38
+ --pm npm
39
+ ```
72
40
 
41
+ - `--arg` is repeatable; each value is ONE exact argv element — never a shell
42
+ string (`&&` stays a literal argument).
43
+ - Icon sources: local files, `http(s)` URLs, or `data:` URLs. The CLI never
44
+ scrapes names or favicons.
45
+ - `--config <file>` loads a complete v1 document; explicit flags override
46
+ only their named fields.
47
+ - `--dry-run` prints the plan without mutating anything.
48
+ - `--force` replaces only a VERIFIED create-opentray payload — it never
49
+ adopts or clears a user directory.
50
+ - `--no-image-smoothing` renders icons with nearest-neighbor sampling
51
+ (pixel-art safe: enlarged app/tray icons keep hard edges).
52
+ - `--developer-mode` admits WebView DevTools in the generated app (default
53
+ off; it means nothing else).
54
+ - `--window <WxH>` sets the window size (default 1200x800).
55
+
56
+ ## The v1 registry layout
57
+
58
+ ```text
59
+ ~/.opentray/create/<encoded-app-id>/
60
+ create-opentray.json # the SOLE editable authority (schemaVersion 1)
61
+ app/ # generated payload (managed dir, or a link)
62
+ app-icon.<ext> # committed icon snapshots (hash-verified)
63
+ tray-icon.<ext>
73
64
  ```
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
65
+
66
+ `create-opentray.json` is the only file you edit: identity/name, exact
67
+ command vector (executable/args/cwd/env), package manager, icon resource
68
+ references with content hashes and provenance, icon-rendering options
69
+ (including `imageSmoothingEnabled`), window options, and `developerMode`.
70
+ Generated files are derived output and are regenerated on every apply.
71
+
72
+ Key rules:
73
+
74
+ - **appId is immutable** — a new identity is `app copy`, never an edit.
75
+ - **The registry root is fixed** at `~/.opentray/create/`.
76
+ - **Snapshots are stable** — URL-fetched icons are committed locally; later
77
+ URL drift never changes an existing registration.
78
+ - **Breaking boundary**: projects identified only by the older
79
+ `opentray.app.json` marker are not discovered, listed, or migrated.
80
+
81
+ ## Managing applications
82
+
83
+ ```bash
84
+ npx create-opentray app list
85
+ npx create-opentray app edit app.local.mytool --app-name "Renamed" --force
86
+ npx create-opentray app copy app.local.mytool --new-app-id app.local.tool2
87
+ npx create-opentray app export app.local.mytool --format sh -o make.sh
88
+ npx create-opentray app uninstall app.local.mytool
98
89
  ```
99
90
 
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).
91
+ - `app list` reports health: `healthy`, `invalid-config`,
92
+ `incompatible-version`, `missing-payload`, `broken-link`, or `running`,
93
+ with registration and payload paths.
94
+ - A running instance blocks edits/uninstalls with a typed `app_running`
95
+ result until `--stop-running` is passed. Processes are terminated only
96
+ when the recorded PID, ownership token, and start fingerprint still match;
97
+ a reused PID is refused, never killed.
98
+ - `app uninstall` retains a linked external target unless `--purge-target`
99
+ explicitly authorizes deletion after revalidation. macOS Dock pins and
100
+ Windows taskbar pins are user-managed.
101
+
102
+ ## Export
103
+
104
+ `app export` produces a complete recreation artifact:
105
+
106
+ - `--format command` exact argv command line (uploads embed as data URLs
107
+ only with `--force-copy`).
108
+ - `--format sh` / `--format ps1` self-contained scripts (LF / CRLF);
109
+ uploaded icon bytes are embedded and reconstructed into a temp file before
110
+ invocation.
111
+ - Any environment entry makes complete export require `--acknowledge-env`.
112
+ create-opentray never guesses which values are sensitive — it always asks
113
+ once, and never echoes env values in ordinary output.
114
+
115
+ ## WebUI wizard
116
+
117
+ `create-opentray` (or `create-opentray web`) starts a token-guarded WebUI on
118
+ `127.0.0.1` and opens your browser: paste a start command, watch it run in a
119
+ real interactive terminal, confirmed HTTP services open as tabs, and
120
+ identity/icon defaults are suggested from the served page (every suggestion
121
+ is a placeholder you can override). The wizard speaks the same Core as the
122
+ CLI, so both produce identical plans.
123
+
124
+ ## Generated project
125
+
126
+ The entry (`main.mjs`) spawns the recorded command (output → `app.log`),
127
+ continuously discovers the command's OWNED HTTP listening ports (foreign
128
+ listeners such as browser DevTools sockets are never adopted), hosts each
129
+ verified port in an application-mode WebView window, and owns the tray
130
+ session (Quit lives in the tray menu). Optional startup-terminal and
131
+ address-bar shells are available through the wizard's advanced options.
122
132
 
123
133
  ## Platform notes
124
134
 
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
135
  - 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.
136
+ first launch; pin it to the Dock (removing a pin is manual).
137
+ - Windows: directory links use junctions (or symlinks when permitted);
138
+ failure is a typed error, never a silent copy. The appMode window joins
139
+ the taskbar/Alt-Tab. Native acceptance runs on Windows agents
140
+ non-Windows fixtures are preparatory evidence only.
141
+ - Linux: taskbar pinning depends on the desktop environment.
142
+
143
+ ## AI skill
144
+
145
+ The package ships an English AI skill (`skill/`) readable without any
146
+ network access:
147
+
148
+ ```bash
149
+ npx create-opentray skill # read SKILL.md
150
+ npx create-opentray skill list references # list one directory
151
+ npx create-opentray skill read SKILL.md # read any packaged file
152
+ ```
153
+
154
+ Skill access is read-only and contained: absolute paths, `..` traversal, NUL
155
+ bytes, and symlink escapes are rejected before any filesystem read, and the
156
+ output is always the canonical English tree regardless of host locale.
155
157
 
156
158
  ## Programmatic use
157
159
 
@@ -159,5 +161,6 @@ URL. Quit lives in the tray menu.
159
161
  import { createWizardSession, deriveDefaultAppId } from "create-opentray";
160
162
  ```
161
163
 
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).
164
+ See the package's TypeScript definitions (dist/index.d.mts) for the full
165
+ surface (wizard session, server, discovery, scraping, launch-vector
166
+ resolution, scaffold, materialize).
Binary file