crisp-tui 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/README.md +340 -2
- package/bin/crisp-tui.js +43 -0
- package/package.json +68 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 solcreek
|
|
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
|
@@ -1,3 +1,341 @@
|
|
|
1
|
-
#
|
|
1
|
+
# crisp-tui
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://github.com/solcreek/crisp-tui/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/crisp-tui)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
[](https://nodejs.org)
|
|
7
|
+
|
|
8
|
+
Crisp support inbox built with OpenTUI, SolidJS and Bun. People use the TUI;
|
|
9
|
+
agents use JSON commands and can prepare drafts in the same running screen.
|
|
10
|
+
[crispctl](https://github.com/solcreek/crisp-cli) v0.3.1 provides all REST and RTM
|
|
11
|
+
access. Both profile-based and 1Password sessions use its JSON interface;
|
|
12
|
+
this project has no separate HTTP or Socket.IO implementation.
|
|
13
|
+
|
|
14
|
+

|
|
15
|
+
|
|
16
|
+
Running on Omarchy with the Tokyo Night theme. The agent-prepared draft is ready
|
|
17
|
+
for human review; all contacts and messages shown are demo data.
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
Requires Node.js 20 or newer on macOS or Linux (glibc), on arm64 or x64.
|
|
22
|
+
**Bun is not required for npm/npx users.** npm installs the matching precompiled
|
|
23
|
+
executable, including the Bun runtime and OpenTUI renderer, automatically.
|
|
24
|
+
Windows and musl/Alpine are not currently supported.
|
|
25
|
+
|
|
26
|
+
This distribution targets v0.2.0. Until it is published, npm's v0.1.0 still
|
|
27
|
+
requires a separate Bun installation.
|
|
28
|
+
|
|
29
|
+
Try the demo without a global installation:
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
npx crisp-tui@0.2.0 --demo
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Or install the command:
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
npm install -g crisp-tui@0.2.0
|
|
39
|
+
crisp-tui --demo
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
For a Crisp workspace, use `crisp-tui --read-only --profile sandbox --poll 0`
|
|
43
|
+
with a crispctl profile configured, or `crisp-tui live --item 'Crisp development'` with
|
|
44
|
+
1Password. `crisp-tui check --item 'Crisp development'` runs a bounded read-only
|
|
45
|
+
connection check. Add `--rtm-timeout 60` to require RTM authentication and an
|
|
46
|
+
actual event within 60 seconds. The npm package includes crispctl as a dependency.
|
|
47
|
+
The following `bun run` examples are for a source checkout.
|
|
48
|
+
Keep npm optional dependencies enabled; they carry the platform executable.
|
|
49
|
+
Installation requires no lifecycle scripts or first-run download.
|
|
50
|
+
|
|
51
|
+
## Run from source
|
|
52
|
+
|
|
53
|
+
Requires Bun 1.4.2 or newer on macOS or Linux. Demo mode needs no credentials.
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
git clone https://github.com/solcreek/crisp-tui.git
|
|
57
|
+
cd crisp-tui
|
|
58
|
+
bun install
|
|
59
|
+
bun run demo
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Demo mode is explicit, in-memory, and never contacts Crisp. In another terminal:
|
|
63
|
+
|
|
64
|
+
```sh
|
|
65
|
+
bun run src/index.ts ctl state
|
|
66
|
+
bun run src/index.ts ctl goto session_demo_2
|
|
67
|
+
bun run src/index.ts ctl draft session_demo_2 'Let me help you check your settings.'
|
|
68
|
+
bun run src/index.ts ctl screen
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
The draft appears in the composer. Review it and press Enter to send. Demo
|
|
72
|
+
messages and drafts disappear on exit. Live mode never falls back to demo data.
|
|
73
|
+
|
|
74
|
+
## Read real data with 1Password
|
|
75
|
+
|
|
76
|
+
With `op` connected to the unlocked 1Password desktop app, create an item with
|
|
77
|
+
`API Identifier`, `API Key` and `website_id` fields. Choose its name explicitly:
|
|
78
|
+
|
|
79
|
+
```sh
|
|
80
|
+
bun run live:check --item 'Crisp development' # connection + rendering check
|
|
81
|
+
bun run live:readonly --item 'Crisp development' # interactive read-only TUI
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
`--website UUID` optionally overrides the item's website ID.
|
|
85
|
+
The credential fields are passed to crispctl through the child environment; no
|
|
86
|
+
config file, token file or customer-data capture is written. Errors omit raw
|
|
87
|
+
API response bodies and headers. The check prints website ID, counts,
|
|
88
|
+
message types and command names, without customer names or message text.
|
|
89
|
+
|
|
90
|
+
The session passes both `--read-only` and `CRISPCTL_READ_ONLY=1` to crispctl.
|
|
91
|
+
Its REST layer rejects non-GET/HEAD requests, and its listener only subscribes to
|
|
92
|
+
events. The TUI adapter also rejects
|
|
93
|
+
reply/note, resolve/reopen and mark-read before any HTTP request. The TUI displays
|
|
94
|
+
`READ ONLY` and hides its composer; agent drafts are disabled too. Automatic
|
|
95
|
+
polling is off in this mode: RTM events trigger refreshes, and Ctrl+R refreshes
|
|
96
|
+
manually. Opening a conversation does not mark it read.
|
|
97
|
+
|
|
98
|
+
`live:check` normally uses three REST commands: the first conversation page,
|
|
99
|
+
details of the first conversation, and its messages (one if the inbox is empty).
|
|
100
|
+
With `--rtm-timeout N`, it additionally listens until an event is received or the
|
|
101
|
+
deadline expires. It never sends a test message to generate that event.
|
|
102
|
+
|
|
103
|
+
For a crispctl-backed TUI, the same client/UI protection is available as:
|
|
104
|
+
|
|
105
|
+
```sh
|
|
106
|
+
bun run dev --read-only --profile sandbox --poll 0
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The flag applies to that TUI instance. The independent `cli` bridge retains
|
|
110
|
+
crispctl's own capabilities. To control the 1Password TUI, use `ctl` with
|
|
111
|
+
`--profile onepassword-readonly --website UUID` (or the same
|
|
112
|
+
`CRISP_TUI_SOCKET` override).
|
|
113
|
+
|
|
114
|
+
## Website token setup
|
|
115
|
+
|
|
116
|
+
This TUI uses **website tokens**. As specified in the
|
|
117
|
+
[Crisp website token documentation](https://docs.crisp.chat/guides/rest-api/authentication/website-token/),
|
|
118
|
+
requests use Basic auth with `identifier:key` and `X-Crisp-Tier: website`.
|
|
119
|
+
The token belongs to one workspace. `crispctl` supplies these headers; this
|
|
120
|
+
project never includes the secret in UI state or stores a second copy.
|
|
121
|
+
|
|
122
|
+
This source checkout uses crispctl v0.3.1. To configure it separately on PATH:
|
|
123
|
+
|
|
124
|
+
```sh
|
|
125
|
+
npm install -g crispctl@0.3.1
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Alternatively, build [crisp-cli from source](https://github.com/solcreek/crisp-cli#install)
|
|
129
|
+
in an adjacent checkout. For the read/write workflow below, configure a sandbox
|
|
130
|
+
profile using environment variables in your shell. Use a development workspace
|
|
131
|
+
for write testing, or the GET-only workflow above when inspecting real data.
|
|
132
|
+
|
|
133
|
+
```sh
|
|
134
|
+
export CRISP_IDENTIFIER='your-website-token-identifier'
|
|
135
|
+
export CRISP_KEY='your-website-token-key'
|
|
136
|
+
export CRISP_WEBSITE_ID='your-sandbox-website-id'
|
|
137
|
+
export CRISP_TIER=website
|
|
138
|
+
|
|
139
|
+
bun run src/index.ts cli auth set --profile sandbox
|
|
140
|
+
bun run dev --profile sandbox
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
The TUI defaults to `sandbox` (or `CRISPCTL_PROFILE`) and checks `auth show`
|
|
144
|
+
before starting. This is a local configuration check, not an API authentication
|
|
145
|
+
probe. It requires `tier=website`, identifier, key and website ID. An API error
|
|
146
|
+
appears in the status bar. The active website ID is visible in the header.
|
|
147
|
+
|
|
148
|
+
All crispctl config and environment precedence still applies, including
|
|
149
|
+
`CRISPCTL_CONFIG` and `CRISPCTL_*` credential overrides. `--website ID` is forwarded
|
|
150
|
+
to crispctl. Select the same `--profile` / `--website` when issuing `ctl` commands.
|
|
151
|
+
|
|
152
|
+
Executable lookup: `CRISPCTL_BIN` (one executable path, not a shell command),
|
|
153
|
+
then the npm launcher's bundled crispctl dependency, then the dependency resolved
|
|
154
|
+
from a source checkout, then `crispctl` on PATH, then
|
|
155
|
+
`../crisp-cli/dist/index.js` relative to this source
|
|
156
|
+
checkout. The last option requires Node. A compiled TUI should use PATH or
|
|
157
|
+
`CRISPCTL_BIN`. Credentials stay in the subprocess environment/config; commands
|
|
158
|
+
are spawned as argument arrays, never shell strings.
|
|
159
|
+
|
|
160
|
+
## Human workflow
|
|
161
|
+
|
|
162
|
+
The inbox supports paged conversations, server-side search, messages, text and
|
|
163
|
+
file-link display, replies, internal notes, resolve/reopen and explicit mark read.
|
|
164
|
+
Opening or polling a conversation does not mark it read. Drafts and reply/note
|
|
165
|
+
mode are kept separately for each conversation during this process.
|
|
166
|
+
|
|
167
|
+
| Key | Action |
|
|
168
|
+
| --- | --- |
|
|
169
|
+
| Tab / Shift+Tab | Cycle inbox, messages, composer |
|
|
170
|
+
| ↑↓ / j k | Select inbox row or scroll messages |
|
|
171
|
+
| Enter in inbox | Open conversation |
|
|
172
|
+
| Click inbox row | Open conversation |
|
|
173
|
+
| / in inbox/messages | Search; Enter submits; empty search returns to all |
|
|
174
|
+
| [ / ] in inbox/messages | Previous / next inbox page |
|
|
175
|
+
| Enter in composer | Send reply or internal note |
|
|
176
|
+
| Shift+Enter / Alt+Enter / Ctrl+J | Newline |
|
|
177
|
+
| Ctrl+N | Toggle reply / internal note |
|
|
178
|
+
| Ctrl+E | Resolve / reopen active conversation |
|
|
179
|
+
| Ctrl+U | Mark active conversation read |
|
|
180
|
+
| Ctrl+R | Refresh inbox and active conversation |
|
|
181
|
+
| Esc | Focus inbox |
|
|
182
|
+
| Ctrl+C | Quit |
|
|
183
|
+
|
|
184
|
+
A failed send keeps the draft; writes are never retried automatically. A timeout
|
|
185
|
+
can leave the send outcome unknown, so refresh before resending. Once a send is
|
|
186
|
+
acknowledged, a failed follow-up refresh does not restore the draft.
|
|
187
|
+
One-shot crispctl calls have a 30-second deadline; 1Password reads have a
|
|
188
|
+
60-second deadline. Partial output from a timed-out process is discarded.
|
|
189
|
+
|
|
190
|
+
## Agent workflow
|
|
191
|
+
|
|
192
|
+
Direct API operations work without a TUI. This is a verbatim bridge to crispctl;
|
|
193
|
+
pass its profile and `--json` flags explicitly:
|
|
194
|
+
|
|
195
|
+
```sh
|
|
196
|
+
bun run src/index.ts cli conversations list --profile sandbox --json
|
|
197
|
+
bun run src/index.ts cli messages list SESSION --profile sandbox --json
|
|
198
|
+
bun run src/index.ts cli reply SESSION --text 'Hello!' --profile sandbox --json
|
|
199
|
+
bun run src/index.ts cli assign SESSION --user OPERATOR_ID --profile sandbox --json
|
|
200
|
+
bun run src/index.ts cli segments SESSION --set billing,followup --profile sandbox --json
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
All other crispctl commands are available through `cli`, including people,
|
|
204
|
+
operators, resolve and reopen. Direct write commands act immediately.
|
|
205
|
+
|
|
206
|
+
The control commands work against the running TUI:
|
|
207
|
+
|
|
208
|
+
```sh
|
|
209
|
+
bun run src/index.ts ctl state
|
|
210
|
+
bun run src/index.ts ctl conversations
|
|
211
|
+
bun run src/index.ts ctl messages
|
|
212
|
+
bun run src/index.ts ctl goto SESSION
|
|
213
|
+
bun run src/index.ts ctl draft SESSION 'Proposed reply'
|
|
214
|
+
bun run src/index.ts ctl draft SESSION 'Internal context' --note
|
|
215
|
+
bun run src/index.ts ctl draft SESSION 'Revised draft' --replace
|
|
216
|
+
bun run src/index.ts ctl refresh
|
|
217
|
+
bun run src/index.ts ctl screen
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
`state` includes protocol version, source, current page/query, selected session,
|
|
221
|
+
conversation-loading state, active conversation,
|
|
222
|
+
loaded messages, per-session drafts and status. `messages` and `conversations`
|
|
223
|
+
return the currently loaded page, without an API call. `screen` is a semantic
|
|
224
|
+
text view of the loaded content, not an exact terminal screenshot. All other
|
|
225
|
+
successful control results are JSON; errors are JSON on stderr. Exit codes are
|
|
226
|
+
0 success, 1 operation error, 2 usage error, 3 no running TUI. `cli` preserves
|
|
227
|
+
crispctl's own output and exit code.
|
|
228
|
+
|
|
229
|
+
`draft` never sends or replaces an existing nonempty draft without `--replace`.
|
|
230
|
+
It switches to the target conversation and focuses the composer. There is no
|
|
231
|
+
control-socket send method; direct automated writes belong to crispctl.
|
|
232
|
+
|
|
233
|
+
### Control protocol
|
|
234
|
+
|
|
235
|
+
Unix socket in `/tmp/crisp-tui-<uid>/<profile-and-website-hash>.sock`.
|
|
236
|
+
Directory mode 0700, socket mode 0600. One TUI per socket; stale sockets are
|
|
237
|
+
recovered. Override with `CRISP_TUI_SOCKET` in both processes, using a
|
|
238
|
+
private parent directory. Demo and live share the selected profile socket, so
|
|
239
|
+
inspect `state.source` before acting. Processes using different config files
|
|
240
|
+
under the same profile name should use different socket overrides.
|
|
241
|
+
|
|
242
|
+
One newline-delimited JSON request per connection:
|
|
243
|
+
|
|
244
|
+
```json
|
|
245
|
+
{"id":1,"method":"draft","params":{"session":"session_demo_1","text":"Hello","note":false}}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Response: `{"id":1,"ok":true,"result":…}` or
|
|
249
|
+
`{"id":1,"ok":false,"error":"…"}`. Methods match `ctl` verbs. Unknown parameters
|
|
250
|
+
and invalid types are rejected. Screen-changing agent requests are serialized;
|
|
251
|
+
local snapshots (`state`, `screen`, `conversations`, `messages`) remain available
|
|
252
|
+
while a refresh or navigation waits on the API. CLI syntax, parameter validation
|
|
253
|
+
and command permissions are defined together in `src/commands.ts`.
|
|
254
|
+
No TCP server, daemon or MCP server is started.
|
|
255
|
+
|
|
256
|
+
## Refresh and current boundaries
|
|
257
|
+
|
|
258
|
+
The TUI starts `crispctl listen --json --read-only` and subscribes to message
|
|
259
|
+
send/receive/update/removal and conversation-state events. The header shows
|
|
260
|
+
`RTM live`, connecting, reconnecting or error. Crispctl handles endpoint discovery,
|
|
261
|
+
Socket.IO authentication and reconnects. The TUI coalesces event bursts into REST
|
|
262
|
+
refreshes, at most once every five seconds, and refreshes after authentication to
|
|
263
|
+
reconcile changes missed during a disconnected interval. This is event-triggered
|
|
264
|
+
REST reconciliation, not a local cache of every event.
|
|
265
|
+
|
|
266
|
+
Profile-based sessions also poll every 60 seconds by default. `--poll 0` disables
|
|
267
|
+
that periodic polling; it does not disable RTM. `--poll N` accepts at least 30
|
|
268
|
+
seconds. Polling failures back off exponentially to 15 minutes. A normal refresh
|
|
269
|
+
makes three REST requests. A quiet TUI polling every 60 seconds uses approximately
|
|
270
|
+
4,320 requests/day, with additional calls for RTM-triggered refreshes, searches
|
|
271
|
+
and writes. Consider this alongside the website token's documented daily quota.
|
|
272
|
+
|
|
273
|
+
Conversation history is the latest page exposed by crispctl; there is no older
|
|
274
|
+
message pagination, background daemon, push notifications, attachment upload or
|
|
275
|
+
preview, persisted drafts, or MCP in this first version. Assignment and segments
|
|
276
|
+
are available via the CLI bridge. The default tests use demo data, isolated
|
|
277
|
+
subprocesses and local sockets; they never read 1Password or contact Crisp.
|
|
278
|
+
Contract tests run the installed crispctl against an in-memory HTTP interceptor
|
|
279
|
+
with external network access disabled.
|
|
280
|
+
Real read-only checks are separate, explicitly invoked commands.
|
|
281
|
+
|
|
282
|
+
## Verification and binary
|
|
283
|
+
|
|
284
|
+
```sh
|
|
285
|
+
bun run typecheck
|
|
286
|
+
bun run build
|
|
287
|
+
bun run test:coverage
|
|
288
|
+
bun run test:package
|
|
289
|
+
./dist/crisp-tui-darwin-arm64 --demo # filename follows OS / architecture
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
The standalone binary embeds Bun and the TUI renderer and needs crispctl on PATH
|
|
293
|
+
or `CRISPCTL_BIN`. The npm package includes crispctl and its platform executable;
|
|
294
|
+
only Node.js is needed on PATH. Bun 1.4.2 is a development/build requirement.
|
|
295
|
+
Tests exercise the UI with OpenTUI's
|
|
296
|
+
headless renderer, send failures, concurrent navigation, draft isolation,
|
|
297
|
+
polling/RTM cleanup, subprocess argument handling and the Unix control protocol.
|
|
298
|
+
CI checks source and compiled PTY workflows, then packs and installs the npm
|
|
299
|
+
artifacts outside the checkout and runs their PTY workflows with Bun absent from
|
|
300
|
+
PATH. A local test registry lets real `npm exec`/`npx` install the root package
|
|
301
|
+
and choose the correct platform dependency automatically. Both installed and
|
|
302
|
+
npx workflows exercise TUI startup, agent drafts, human send, shutdown and the
|
|
303
|
+
crispctl bridge. The package check downloads dependencies from npm; Crisp API
|
|
304
|
+
access is not required. CI runs on macOS/Linux arm64/x64 with Node.js 20 or 24.
|
|
305
|
+
|
|
306
|
+
Coverage excludes test fixtures/helpers, checks for missing source files, and
|
|
307
|
+
enforces overall 90% line and function thresholds from LCOV counts. CI uploads
|
|
308
|
+
`coverage/lcov.info` for each platform. The report measures code executed within
|
|
309
|
+
the test process; PTY subprocess coverage
|
|
310
|
+
(including the thin `src/index.ts` entrypoint) is not merged into that percentage.
|
|
311
|
+
The subprocess tests independently verify the executable behavior.
|
|
312
|
+
|
|
313
|
+
### Publishing platform packages
|
|
314
|
+
|
|
315
|
+
All five package versions must match. `bun run build:package` compiles and stages
|
|
316
|
+
the host platform under `packages/<os>-<arch>/bin/`. `bun run test:package` produces
|
|
317
|
+
verified tarballs in `dist/npm/`. CI uploads them as `npm-<os>-<arch>` artifacts.
|
|
318
|
+
|
|
319
|
+
Use artifacts from one successful CI run for the release commit. Publish all four
|
|
320
|
+
platform packages first, then the main package, so new npx installs can always
|
|
321
|
+
find their binary. This requires npm publisher credentials; CI does not publish.
|
|
322
|
+
|
|
323
|
+
```sh
|
|
324
|
+
gh run download RUN_ID --pattern 'npm-*' --dir release-artifacts
|
|
325
|
+
for platform in darwin-arm64 darwin-x64 linux-arm64 linux-x64; do
|
|
326
|
+
npm publish "release-artifacts/npm-$platform/crisp-tui-$platform-0.2.0.tgz" --access public
|
|
327
|
+
done
|
|
328
|
+
npm publish release-artifacts/npm-darwin-arm64/crisp-tui-0.2.0.tgz --access public
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
Do not publish platform packages directly from an unbuilt workspace. The root
|
|
332
|
+
package's optional dependencies are pinned to the exact release version.
|
|
333
|
+
|
|
334
|
+
## Development data and license
|
|
335
|
+
|
|
336
|
+
Demo contacts, email addresses and test credentials are synthetic. Tests do not
|
|
337
|
+
load 1Password, use a real Crisp profile or contact the Crisp API. Build outputs,
|
|
338
|
+
local environment files, logs and captures are excluded from version control.
|
|
339
|
+
Use synthetic data when sharing screenshots, test fixtures and bug reports.
|
|
340
|
+
|
|
341
|
+
MIT — see [LICENSE](LICENSE). This is an independent community project.
|
package/bin/crisp-tui.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from "node:child_process"
|
|
3
|
+
import { createRequire } from "node:module"
|
|
4
|
+
import { constants } from "node:os"
|
|
5
|
+
|
|
6
|
+
const require = createRequire(import.meta.url)
|
|
7
|
+
const pkg = require("../package.json")
|
|
8
|
+
const platformPackage = `crisp-tui-${process.platform}-${process.arch}`
|
|
9
|
+
try {
|
|
10
|
+
if (!Object.hasOwn(pkg.optionalDependencies, platformPackage)) {
|
|
11
|
+
throw new Error(`Unsupported platform: ${process.platform}/${process.arch}. crisp-tui supports macOS and Linux on x64 and arm64.`)
|
|
12
|
+
}
|
|
13
|
+
if (process.platform === "linux" && !process.report.getReport().header.glibcVersionRuntime) {
|
|
14
|
+
throw new Error("This crisp-tui package requires glibc on Linux; musl/Alpine is not supported yet.")
|
|
15
|
+
}
|
|
16
|
+
let executable
|
|
17
|
+
try {
|
|
18
|
+
const installed = require(`${platformPackage}/package.json`)
|
|
19
|
+
if (installed.version !== pkg.version) throw new Error("Version mismatch")
|
|
20
|
+
executable = require.resolve(`${platformPackage}/bin/crisp-tui`)
|
|
21
|
+
} catch {
|
|
22
|
+
throw new Error(`Missing ${platformPackage}@${pkg.version}. Reinstall crisp-tui with optional dependencies enabled (npm install --include=optional crisp-tui@${pkg.version}).`)
|
|
23
|
+
}
|
|
24
|
+
const child = spawn(executable, process.argv.slice(2), {
|
|
25
|
+
stdio: "inherit",
|
|
26
|
+
env: { ...process.env, CRISP_TUI_NODE: process.execPath, CRISP_TUI_CRISPCTL: require.resolve("crispctl/dist/index.js") },
|
|
27
|
+
})
|
|
28
|
+
const signals = ["SIGINT", "SIGTERM", "SIGHUP"]
|
|
29
|
+
const handlers = signals.map(signal => { const handler = () => child.kill(signal); process.on(signal, handler); return handler })
|
|
30
|
+
const cleanup = () => signals.forEach((signal, i) => process.off(signal, handlers[i]))
|
|
31
|
+
child.once("error", () => {
|
|
32
|
+
cleanup()
|
|
33
|
+
console.error(JSON.stringify({ ok: false, error: "Could not start the crisp-tui executable. Reinstall the package and check executable permissions." }))
|
|
34
|
+
process.exitCode = 1
|
|
35
|
+
})
|
|
36
|
+
child.once("exit", (code, signal) => {
|
|
37
|
+
cleanup()
|
|
38
|
+
process.exitCode = code ?? (128 + (constants.signals[signal] || 1))
|
|
39
|
+
})
|
|
40
|
+
} catch (error) {
|
|
41
|
+
console.error(JSON.stringify({ ok: false, error: error instanceof Error ? error.message : "Could not start crisp-tui" }))
|
|
42
|
+
process.exitCode = 1
|
|
43
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,70 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "crisp-tui",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "A terminal inbox for Crisp, with JSON control commands for agents",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/solcreek/crisp-tui.git"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/solcreek/crisp-tui#readme",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/solcreek/crisp-tui/issues"
|
|
13
|
+
},
|
|
14
|
+
"type": "module",
|
|
15
|
+
"bin": {
|
|
16
|
+
"crisp-tui": "bin/crisp-tui.js"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"bin/crisp-tui.js",
|
|
20
|
+
"README.md",
|
|
21
|
+
"LICENSE"
|
|
22
|
+
],
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public",
|
|
25
|
+
"registry": "https://registry.npmjs.org/"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"dev": "bun run src/index.ts",
|
|
29
|
+
"demo": "bun run src/index.ts --demo",
|
|
30
|
+
"live:readonly": "bun run scripts/live-readonly.ts",
|
|
31
|
+
"live:check": "bun run scripts/live-readonly.ts --check",
|
|
32
|
+
"typecheck": "tsc --noEmit",
|
|
33
|
+
"test": "bun test",
|
|
34
|
+
"test:coverage": "bun test --coverage && bun run scripts/check-coverage.ts",
|
|
35
|
+
"test:package": "bun run scripts/test-package.ts",
|
|
36
|
+
"build": "bun run scripts/build.ts",
|
|
37
|
+
"build:package": "bun run scripts/build-package.ts",
|
|
38
|
+
"prepack": "bun run scripts/check-package.ts"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"crispctl": "0.3.1"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/bun": "1.3.14",
|
|
45
|
+
"typescript": "5.9.3",
|
|
46
|
+
"@opentui/core": "0.5.12",
|
|
47
|
+
"@opentui/solid": "0.5.12",
|
|
48
|
+
"solid-js": "1.9.12"
|
|
49
|
+
},
|
|
50
|
+
"engines": {
|
|
51
|
+
"node": ">=20"
|
|
52
|
+
},
|
|
53
|
+
"workspaces": [
|
|
54
|
+
"packages/*"
|
|
55
|
+
],
|
|
56
|
+
"os": [
|
|
57
|
+
"darwin",
|
|
58
|
+
"linux"
|
|
59
|
+
],
|
|
60
|
+
"cpu": [
|
|
61
|
+
"arm64",
|
|
62
|
+
"x64"
|
|
63
|
+
],
|
|
64
|
+
"optionalDependencies": {
|
|
65
|
+
"crisp-tui-darwin-arm64": "0.2.0",
|
|
66
|
+
"crisp-tui-darwin-x64": "0.2.0",
|
|
67
|
+
"crisp-tui-linux-arm64": "0.2.0",
|
|
68
|
+
"crisp-tui-linux-x64": "0.2.0"
|
|
69
|
+
}
|
|
70
|
+
}
|