@particle-academy/fancy-term 0.5.1 → 0.6.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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,199 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@particle-academy/fancy-term` are documented here.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
+
7
+ > **Pre-1.0:** breaking changes land in MINOR releases. Until 1.0 the minor
8
+ > number is not a compatibility promise — read the entry, not the version.
9
+
10
+ > This file starts here. Earlier releases predate it and were never written up;
11
+ > `git log` is the record for those. It is not backfilled rather than
12
+ > guessed-at, because a changelog that invents its own history is worse than one
13
+ > that admits where it begins.
14
+
15
+ ## [Unreleased]
16
+
17
+ ## 0.6.1 — 2026-10-10
18
+
19
+ ### Added
20
+
21
+ - **`@particle-academy/fancy-term/styles.css`** — the same stylesheet under the
22
+ name the rest of the kit uses.
23
+
24
+ 0.6.0 shipped the re-export as `/xterm.css` only, which was descriptive but
25
+ wrong by convention: `fancy-code`, `fancy-whiteboard`, `fancy-artboard`,
26
+ `fancy-sheets` and `fancy-slides` **all** export `./styles.css`, unanimously.
27
+ A consumer who knows the kit types that name, and in 0.6.0 they got a resolve
28
+ error. Both names now serve the one file, and a test asserts they cannot drift
29
+ apart.
30
+
31
+ Use whichever reads better — `/styles.css` for consistency with the rest of
32
+ your Fancy imports, `/xterm.css` if you would rather the import said what it
33
+ actually is. Nothing to change if you are already on `/xterm.css`.
34
+
35
+ ## 0.6.0 — 2026-10-10
36
+
37
+ ### Added
38
+
39
+ - **`@particle-academy/fancy-term/xterm.css` — load the stylesheet without naming xterm.**
40
+
41
+ ```ts
42
+ import "@particle-academy/fancy-term/xterm.css";
43
+ ```
44
+
45
+ The terminal has never rendered without xterm's stylesheet, so every consumer
46
+ had to write `import "@xterm/xterm/css/xterm.css"` in their own source — which
47
+ made xterm the one third-party package a Fancy-only app still had to name.
48
+
49
+ **Nothing to do.** The old import is identical in effect and still works; this
50
+ is an additional way in, not a replacement. The new subpath is an `@import` of
51
+ xterm's own stylesheet rather than a copy of it, so it resolves to the single
52
+ copy already in your tree and there is no vendored third-party file to drift.
53
+
54
+ ### Changed
55
+
56
+ - **The `@xterm/*` peer ranges are now bounded above** — `@xterm/xterm` moves
57
+ from `>=5.0.0` to `>=5.0.0 <6`, and `@xterm/addon-fit` from `>=0.10.0` to
58
+ `>=0.10.0 <0.11`.
59
+
60
+ **This was live, not theoretical.** `@xterm/xterm@6.0.0` and
61
+ `@xterm/addon-fit@0.11.0` are both `latest` on npm as of today, so the old
62
+ ranges admitted a MAJOR this package has never been built against — and
63
+ nothing reported it, because a resolver quietly picking an untested version
64
+ looks exactly like success. The pairing made it worse rather than safer:
65
+ `addon-fit@0.10.0` declares `peerDependencies: {"@xterm/xterm": "^5.0.0"}` and
66
+ accidentally held the line, while **`0.11.0` declares no peer at all** — so
67
+ `>=0.10.0` plus `>=5.0.0` allowed xterm 6 with addon-fit 0.11, an untested
68
+ combination, silently.
69
+
70
+ **What you must do: almost certainly nothing.** If you are on xterm 5.x and
71
+ addon-fit 0.10.x — what `npm install` has been resolving all along, and what
72
+ this package is built and tested against — the range still admits your
73
+ version and the upgrade is invisible. **If you have explicitly moved to xterm
74
+ 6 or addon-fit 0.11, this release will now fail at install with a peer
75
+ conflict instead of running untested code.** That is the intended behaviour:
76
+ it turns a silent runtime risk into a loud install-time error. Tell us and we
77
+ will qualify 6 properly — widening a range later is safe by construction,
78
+ since it only ever adds candidates.
79
+
80
+ `>=X <2.0` remains correct for a *first-party* sibling, where we cut the
81
+ releases and the upper bound is a promise we keep. On third-party it is a
82
+ promise someone else makes.
83
+
84
+ - **xterm stays a PEER deliberately, and this is the release that writes down
85
+ why.** `<Terminal>` hands the live `XTerm` instance to the consumer through
86
+ `handle.xterm`, `handle.ready` and `onReady(xterm)` — the same reason a React
87
+ component cannot own its copy of React. If this package owned xterm, a
88
+ consumer on a different version would get two copies and addons and
89
+ `instanceof` would operate on the wrong class with no warning. The peer's
90
+ value is not "one copy", it is that a conflict fails loudly at install. The
91
+ reasoning now sits in the README, in `src/index.ts`, in `xterm.css` and in
92
+ `src/packaging.test.ts`, so the next person who proposes tidying it into
93
+ `dependencies` meets the argument first.
94
+
95
+ ### Fixed
96
+
97
+ - **`CHANGELOG.md` is now in the published tarball.** `files` did not whitelist it, so npm never shipped it — and this package puts breaking changes in MINOR releases and tells you in the README to read the entry before taking one. The instruction existed for the author, who has the file, and not for the consumer, who is the only one being instructed. Nothing for you to do; the file simply arrives from this release on.
98
+
99
+ ### Security
100
+
101
+ - `source-map-js` is pinned forward to `^1.2.2` via `overrides`. Versions up to
102
+ 1.2.1 allow an event-loop denial of service through indexed source-map section
103
+ offsets, and it arrives here transitively through the build toolchain.
104
+ **Nothing for a consumer to do, and no runtime change**: an npm package does
105
+ not ship a lockfile, so this governs builds OF this repo, not anything
106
+ installed FROM it. Recorded rather than left silent because the override it
107
+ sits beside — `shell-quote` `^1.9.0`, added for an earlier advisory — was
108
+ carried with no note of why, and had drifted back inside the vulnerable range
109
+ before anyone looked.
110
+
111
+ ## 0.5.1 — 2026-09-29
112
+
113
+ ### Fixed
114
+
115
+ - **`docs/` is real now.** `files` already listed `docs`, and the directory did
116
+ not exist — so every published tarball carried a `files` entry pointing at
117
+ nothing and shipped no reference at all. That is the worse half of this
118
+ defect: a `files` array that names `docs` reads as compliant to anyone
119
+ checking the manifest, so nothing ever looked in the tarball.
120
+
121
+ Adds `docs/Terminal.md` and `docs/ShellSwitcher.md` — the full prop and
122
+ `TerminalOptions` tables, the imperative handle (including `getBuffer()`, the
123
+ Human+ affordance an agent reads instead of scraping the DOM), why the
124
+ clipboard is injectable and what silently breaks in a sandboxed Electron
125
+ renderer without a provider, why OSC 52 defaults to write-only, and how
126
+ pasted images reach the host.
127
+
128
+ No code changed.
129
+
130
+ ## 0.5.0 — 2026-08-07
131
+
132
+ ### Changed
133
+
134
+ - **BREAKING — Node 22 is now declared as the floor.** `engines.node` is `>=22`, where this package previously declared **nothing at all**.
135
+
136
+ Declaring nothing was not the same as supporting old Node: a consumer on 18 installed cleanly and found out at runtime.
137
+
138
+ **What you must do:** on Node 22 or newer, nothing. Note npm only *warns* on an `engines` mismatch while **pnpm fails the install**, so this surfaces differently depending on your package manager. Node 18 is end-of-life and 20 is maintenance-only.
139
+
140
+ - **BREAKING — React 18 is no longer supported.** `peerDependencies.react` / `react-dom` are now `^19.0.0`.
141
+
142
+ **What you must do:** on React 19, nothing. On React 18, stay on the previous release, or upgrade your app to 19 first.
143
+
144
+ React 18 support was a claim nothing tested — every build and test in this package ran against 19, so the 18 half of the old range was never executed. An untested compatibility claim is worse than an absent one, because it reads as support.
145
+
146
+ ### Why
147
+
148
+ These are the kit 0.5 platform floors, applied across every package at once so a consumer never has to resolve a mix. **No API changed, nothing was removed, nothing was renamed** — only what the package requires.
149
+
150
+
151
+ ## 0.4.1 — 2026-07-06
152
+
153
+ ### Fixed
154
+
155
+ - context-menu Copy writes the menu-open selection snapshot, not a click-time re-read
156
+
157
+ ## 0.4.0 — 2026-07-02
158
+
159
+ ### Added
160
+
161
+ - Electron-safe clipboard — injectable provider, OSC 52, copy/paste modes, ready signal (#1)
162
+
163
+ ## 0.3.0 — 2026-06-14
164
+
165
+ ### Added
166
+
167
+ - clipboard (copy/paste + images) + customizable selection context menu
168
+
169
+ ## 0.2.2 — 2026-06-11
170
+
171
+ ### Fixed
172
+
173
+ - omit undefined rows/cols from xterm constructor (was console-erroring)
174
+
175
+ ## 0.2.1 — 2026-06-11
176
+
177
+ ### Fixed
178
+
179
+ - guard fit() via proposeDimensions — no xterm resize(undefined) on unlaid-out container
180
+
181
+ ## 0.2.0 — 2026-06-11
182
+
183
+ ### Changed
184
+
185
+ - **BREAKING** — shell / profile switching (UI + API + session)
186
+
187
+ ## 0.1.0 — 2026-06-10
188
+
189
+ ### Added
190
+
191
+ - fancy-term 0.1.0 — Human+ Terminal (xterm.js wrapper)
192
+
193
+ ### Changed
194
+
195
+ - Replaced an `eslint-disable jsx-a11y/no-autofocus` in `ShellSwitcher` with a
196
+ plain comment explaining why the autofocus is deliberate. `jsx-a11y` has never
197
+ been a dependency of this package, so the directive silenced a rule that did
198
+ not exist — and broke linting the moment ESLint was actually turned on.
199
+ **No action needed**, no behaviour change.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Particle Academy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -34,12 +34,29 @@ npm install @particle-academy/fancy-term @xterm/xterm @xterm/addon-fit
34
34
 
35
35
  `react`, `xterm`, and the fit addon are **peer dependencies** — the wrapper itself
36
36
  is zero-runtime-dep (the same posture as `fancy-echarts` over ECharts). Import the
37
- xterm stylesheet once in your app:
37
+ stylesheet once in your app, from here rather than from xterm:
38
38
 
39
39
  ```ts
40
- import "@xterm/xterm/css/xterm.css";
40
+ import "@particle-academy/fancy-term/xterm.css";
41
41
  ```
42
42
 
43
+ Without it the terminal does not render: xterm's character-measurement helper
44
+ has to stay out of layout, and without these rules it does not, so the cell size
45
+ comes out wrong.
46
+
47
+ That subpath re-exports xterm's own stylesheet with `@import`, so it resolves to
48
+ the single copy already in your tree. `import "@xterm/xterm/css/xterm.css"` is
49
+ identical in effect and still works — the subpath exists so a Fancy-only app has
50
+ no reason to name a third-party package in its own source.
51
+
52
+ **Why xterm is a peer and not a dependency**, since it is the obvious thing to
53
+ "tidy": `<Terminal>` hands you the live `XTerm` instance — `handle.xterm`,
54
+ `handle.ready`, `onReady(xterm)` — exactly as a React component hands out React
55
+ elements and therefore cannot own React. If this package owned its own xterm
56
+ copy, a consumer on a different version would get two, and addons and
57
+ `instanceof` would operate on the wrong class with no warning anywhere. The peer
58
+ turns that silent runtime break into a loud install-time error.
59
+
43
60
  ## `<Terminal>`
44
61
 
45
62
  The parent needs a height — the terminal fits its container (like any xterm
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@particle-academy/fancy-term",
3
- "version": "0.5.1",
3
+ "version": "0.6.1",
4
4
  "description": "Human+ Terminal for React — a controlled, themeable <Terminal> wrapping xterm.js, with hooks and an MCP-bridgeable surface so embedded agents read the buffer, write input, and run commands without DOM-scraping.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -22,12 +22,17 @@
22
22
  "types": "./dist/index.d.cts",
23
23
  "default": "./dist/index.cjs"
24
24
  }
25
- }
25
+ },
26
+ "./styles.css": "./xterm.css",
27
+ "./xterm.css": "./xterm.css",
28
+ "./package.json": "./package.json"
26
29
  },
27
30
  "files": [
28
31
  "dist",
32
+ "xterm.css",
29
33
  "docs",
30
- "README.md"
34
+ "README.md",
35
+ "CHANGELOG.md"
31
36
  ],
32
37
  "scripts": {
33
38
  "build": "tsup",
@@ -47,8 +52,8 @@
47
52
  "fancy"
48
53
  ],
49
54
  "peerDependencies": {
50
- "@xterm/addon-fit": ">=0.10.0",
51
- "@xterm/xterm": ">=5.0.0",
55
+ "@xterm/addon-fit": ">=0.10.0 <0.11",
56
+ "@xterm/xterm": ">=5.0.0 <6",
52
57
  "react": "^19.0.0",
53
58
  "react-dom": "^19.0.0"
54
59
  },
@@ -71,7 +76,8 @@
71
76
  },
72
77
  "license": "MIT",
73
78
  "overrides": {
74
- "esbuild": "^0.28.1"
79
+ "esbuild": "^0.28.1",
80
+ "source-map-js": "^1.2.2"
75
81
  },
76
82
  "engines": {
77
83
  "node": ">=22"
package/xterm.css ADDED
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @particle-academy/fancy-term/xterm.css
3
+ *
4
+ * The stylesheet <Terminal> needs, loadable without naming xterm.
5
+ *
6
+ * import "@particle-academy/fancy-term/xterm.css";
7
+ *
8
+ * xterm.js does not render without its own stylesheet — its character-measurement
9
+ * helper is absolutely positioned, so without these rules it participates in
10
+ * layout and the terminal computes a wrong cell size. Every consumer therefore
11
+ * had to write `import "@xterm/xterm/css/xterm.css"` in their own source, which
12
+ * made xterm the one third-party package a Fancy-only app still had to name.
13
+ *
14
+ * This is an @import, deliberately, NOT a copy of xterm's stylesheet:
15
+ *
16
+ * • It resolves from the CONSUMER's tree, where the peer is installed — so
17
+ * there is still exactly one xterm, which is the whole reason xterm is a
18
+ * peer rather than a dependency (<Terminal> hands the live XTerm instance
19
+ * out through `handle.xterm` / `handle.ready` / `onReady`, so a second copy
20
+ * would silently break addons and `instanceof`).
21
+ * • A vendored copy would drift from the xterm version actually installed,
22
+ * and would make us a redistributor of a third-party file.
23
+ *
24
+ * `src/packaging.test.ts` pins it: with comments stripped, this file must be
25
+ * EXACTLY the one @import below and nothing else. So do not add a rule here —
26
+ * app-level overrides belong in the app, where they can be seen.
27
+ */
28
+ @import "@xterm/xterm/css/xterm.css";