@particle-academy/fancy-term 0.5.1 → 0.6.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.
- package/CHANGELOG.md +181 -0
- package/LICENSE +21 -0
- package/README.md +19 -2
- package/package.json +11 -6
- package/xterm.css +28 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
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.0 — 2026-10-10
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- **`@particle-academy/fancy-term/xterm.css` — load the stylesheet without naming xterm.**
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import "@particle-academy/fancy-term/xterm.css";
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The terminal has never rendered without xterm's stylesheet, so every consumer
|
|
28
|
+
had to write `import "@xterm/xterm/css/xterm.css"` in their own source — which
|
|
29
|
+
made xterm the one third-party package a Fancy-only app still had to name.
|
|
30
|
+
|
|
31
|
+
**Nothing to do.** The old import is identical in effect and still works; this
|
|
32
|
+
is an additional way in, not a replacement. The new subpath is an `@import` of
|
|
33
|
+
xterm's own stylesheet rather than a copy of it, so it resolves to the single
|
|
34
|
+
copy already in your tree and there is no vendored third-party file to drift.
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
|
|
38
|
+
- **The `@xterm/*` peer ranges are now bounded above** — `@xterm/xterm` moves
|
|
39
|
+
from `>=5.0.0` to `>=5.0.0 <6`, and `@xterm/addon-fit` from `>=0.10.0` to
|
|
40
|
+
`>=0.10.0 <0.11`.
|
|
41
|
+
|
|
42
|
+
**This was live, not theoretical.** `@xterm/xterm@6.0.0` and
|
|
43
|
+
`@xterm/addon-fit@0.11.0` are both `latest` on npm as of today, so the old
|
|
44
|
+
ranges admitted a MAJOR this package has never been built against — and
|
|
45
|
+
nothing reported it, because a resolver quietly picking an untested version
|
|
46
|
+
looks exactly like success. The pairing made it worse rather than safer:
|
|
47
|
+
`addon-fit@0.10.0` declares `peerDependencies: {"@xterm/xterm": "^5.0.0"}` and
|
|
48
|
+
accidentally held the line, while **`0.11.0` declares no peer at all** — so
|
|
49
|
+
`>=0.10.0` plus `>=5.0.0` allowed xterm 6 with addon-fit 0.11, an untested
|
|
50
|
+
combination, silently.
|
|
51
|
+
|
|
52
|
+
**What you must do: almost certainly nothing.** If you are on xterm 5.x and
|
|
53
|
+
addon-fit 0.10.x — what `npm install` has been resolving all along, and what
|
|
54
|
+
this package is built and tested against — the range still admits your
|
|
55
|
+
version and the upgrade is invisible. **If you have explicitly moved to xterm
|
|
56
|
+
6 or addon-fit 0.11, this release will now fail at install with a peer
|
|
57
|
+
conflict instead of running untested code.** That is the intended behaviour:
|
|
58
|
+
it turns a silent runtime risk into a loud install-time error. Tell us and we
|
|
59
|
+
will qualify 6 properly — widening a range later is safe by construction,
|
|
60
|
+
since it only ever adds candidates.
|
|
61
|
+
|
|
62
|
+
`>=X <2.0` remains correct for a *first-party* sibling, where we cut the
|
|
63
|
+
releases and the upper bound is a promise we keep. On third-party it is a
|
|
64
|
+
promise someone else makes.
|
|
65
|
+
|
|
66
|
+
- **xterm stays a PEER deliberately, and this is the release that writes down
|
|
67
|
+
why.** `<Terminal>` hands the live `XTerm` instance to the consumer through
|
|
68
|
+
`handle.xterm`, `handle.ready` and `onReady(xterm)` — the same reason a React
|
|
69
|
+
component cannot own its copy of React. If this package owned xterm, a
|
|
70
|
+
consumer on a different version would get two copies and addons and
|
|
71
|
+
`instanceof` would operate on the wrong class with no warning. The peer's
|
|
72
|
+
value is not "one copy", it is that a conflict fails loudly at install. The
|
|
73
|
+
reasoning now sits in the README, in `src/index.ts`, in `xterm.css` and in
|
|
74
|
+
`src/packaging.test.ts`, so the next person who proposes tidying it into
|
|
75
|
+
`dependencies` meets the argument first.
|
|
76
|
+
|
|
77
|
+
### Fixed
|
|
78
|
+
|
|
79
|
+
- **`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.
|
|
80
|
+
|
|
81
|
+
### Security
|
|
82
|
+
|
|
83
|
+
- `source-map-js` is pinned forward to `^1.2.2` via `overrides`. Versions up to
|
|
84
|
+
1.2.1 allow an event-loop denial of service through indexed source-map section
|
|
85
|
+
offsets, and it arrives here transitively through the build toolchain.
|
|
86
|
+
**Nothing for a consumer to do, and no runtime change**: an npm package does
|
|
87
|
+
not ship a lockfile, so this governs builds OF this repo, not anything
|
|
88
|
+
installed FROM it. Recorded rather than left silent because the override it
|
|
89
|
+
sits beside — `shell-quote` `^1.9.0`, added for an earlier advisory — was
|
|
90
|
+
carried with no note of why, and had drifted back inside the vulnerable range
|
|
91
|
+
before anyone looked.
|
|
92
|
+
|
|
93
|
+
## 0.5.1 — 2026-09-29
|
|
94
|
+
|
|
95
|
+
### Fixed
|
|
96
|
+
|
|
97
|
+
- **`docs/` is real now.** `files` already listed `docs`, and the directory did
|
|
98
|
+
not exist — so every published tarball carried a `files` entry pointing at
|
|
99
|
+
nothing and shipped no reference at all. That is the worse half of this
|
|
100
|
+
defect: a `files` array that names `docs` reads as compliant to anyone
|
|
101
|
+
checking the manifest, so nothing ever looked in the tarball.
|
|
102
|
+
|
|
103
|
+
Adds `docs/Terminal.md` and `docs/ShellSwitcher.md` — the full prop and
|
|
104
|
+
`TerminalOptions` tables, the imperative handle (including `getBuffer()`, the
|
|
105
|
+
Human+ affordance an agent reads instead of scraping the DOM), why the
|
|
106
|
+
clipboard is injectable and what silently breaks in a sandboxed Electron
|
|
107
|
+
renderer without a provider, why OSC 52 defaults to write-only, and how
|
|
108
|
+
pasted images reach the host.
|
|
109
|
+
|
|
110
|
+
No code changed.
|
|
111
|
+
|
|
112
|
+
## 0.5.0 — 2026-08-07
|
|
113
|
+
|
|
114
|
+
### Changed
|
|
115
|
+
|
|
116
|
+
- **BREAKING — Node 22 is now declared as the floor.** `engines.node` is `>=22`, where this package previously declared **nothing at all**.
|
|
117
|
+
|
|
118
|
+
Declaring nothing was not the same as supporting old Node: a consumer on 18 installed cleanly and found out at runtime.
|
|
119
|
+
|
|
120
|
+
**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.
|
|
121
|
+
|
|
122
|
+
- **BREAKING — React 18 is no longer supported.** `peerDependencies.react` / `react-dom` are now `^19.0.0`.
|
|
123
|
+
|
|
124
|
+
**What you must do:** on React 19, nothing. On React 18, stay on the previous release, or upgrade your app to 19 first.
|
|
125
|
+
|
|
126
|
+
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.
|
|
127
|
+
|
|
128
|
+
### Why
|
|
129
|
+
|
|
130
|
+
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.
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
## 0.4.1 — 2026-07-06
|
|
134
|
+
|
|
135
|
+
### Fixed
|
|
136
|
+
|
|
137
|
+
- context-menu Copy writes the menu-open selection snapshot, not a click-time re-read
|
|
138
|
+
|
|
139
|
+
## 0.4.0 — 2026-07-02
|
|
140
|
+
|
|
141
|
+
### Added
|
|
142
|
+
|
|
143
|
+
- Electron-safe clipboard — injectable provider, OSC 52, copy/paste modes, ready signal (#1)
|
|
144
|
+
|
|
145
|
+
## 0.3.0 — 2026-06-14
|
|
146
|
+
|
|
147
|
+
### Added
|
|
148
|
+
|
|
149
|
+
- clipboard (copy/paste + images) + customizable selection context menu
|
|
150
|
+
|
|
151
|
+
## 0.2.2 — 2026-06-11
|
|
152
|
+
|
|
153
|
+
### Fixed
|
|
154
|
+
|
|
155
|
+
- omit undefined rows/cols from xterm constructor (was console-erroring)
|
|
156
|
+
|
|
157
|
+
## 0.2.1 — 2026-06-11
|
|
158
|
+
|
|
159
|
+
### Fixed
|
|
160
|
+
|
|
161
|
+
- guard fit() via proposeDimensions — no xterm resize(undefined) on unlaid-out container
|
|
162
|
+
|
|
163
|
+
## 0.2.0 — 2026-06-11
|
|
164
|
+
|
|
165
|
+
### Changed
|
|
166
|
+
|
|
167
|
+
- **BREAKING** — shell / profile switching (UI + API + session)
|
|
168
|
+
|
|
169
|
+
## 0.1.0 — 2026-06-10
|
|
170
|
+
|
|
171
|
+
### Added
|
|
172
|
+
|
|
173
|
+
- fancy-term 0.1.0 — Human+ Terminal (xterm.js wrapper)
|
|
174
|
+
|
|
175
|
+
### Changed
|
|
176
|
+
|
|
177
|
+
- Replaced an `eslint-disable jsx-a11y/no-autofocus` in `ShellSwitcher` with a
|
|
178
|
+
plain comment explaining why the autofocus is deliberate. `jsx-a11y` has never
|
|
179
|
+
been a dependency of this package, so the directive silenced a rule that did
|
|
180
|
+
not exist — and broke linting the moment ESLint was actually turned on.
|
|
181
|
+
**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
|
-
|
|
37
|
+
stylesheet once in your app, from here rather than from xterm:
|
|
38
38
|
|
|
39
39
|
```ts
|
|
40
|
-
import "@
|
|
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.
|
|
3
|
+
"version": "0.6.0",
|
|
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,16 @@
|
|
|
22
22
|
"types": "./dist/index.d.cts",
|
|
23
23
|
"default": "./dist/index.cjs"
|
|
24
24
|
}
|
|
25
|
-
}
|
|
25
|
+
},
|
|
26
|
+
"./xterm.css": "./xterm.css",
|
|
27
|
+
"./package.json": "./package.json"
|
|
26
28
|
},
|
|
27
29
|
"files": [
|
|
28
30
|
"dist",
|
|
31
|
+
"xterm.css",
|
|
29
32
|
"docs",
|
|
30
|
-
"README.md"
|
|
33
|
+
"README.md",
|
|
34
|
+
"CHANGELOG.md"
|
|
31
35
|
],
|
|
32
36
|
"scripts": {
|
|
33
37
|
"build": "tsup",
|
|
@@ -47,8 +51,8 @@
|
|
|
47
51
|
"fancy"
|
|
48
52
|
],
|
|
49
53
|
"peerDependencies": {
|
|
50
|
-
"@xterm/addon-fit": ">=0.10.0",
|
|
51
|
-
"@xterm/xterm": ">=5.0.0",
|
|
54
|
+
"@xterm/addon-fit": ">=0.10.0 <0.11",
|
|
55
|
+
"@xterm/xterm": ">=5.0.0 <6",
|
|
52
56
|
"react": "^19.0.0",
|
|
53
57
|
"react-dom": "^19.0.0"
|
|
54
58
|
},
|
|
@@ -71,7 +75,8 @@
|
|
|
71
75
|
},
|
|
72
76
|
"license": "MIT",
|
|
73
77
|
"overrides": {
|
|
74
|
-
"esbuild": "^0.28.1"
|
|
78
|
+
"esbuild": "^0.28.1",
|
|
79
|
+
"source-map-js": "^1.2.2"
|
|
75
80
|
},
|
|
76
81
|
"engines": {
|
|
77
82
|
"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";
|