crisp-tui 0.1.0 → 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/README.md CHANGED
@@ -1,18 +1,41 @@
1
1
  # crisp-tui
2
2
 
3
+ [![CI](https://github.com/solcreek/crisp-tui/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/solcreek/crisp-tui/actions/workflows/ci.yml)
4
+ [![npm version](https://img.shields.io/npm/v/crisp-tui?logo=npm)](https://www.npmjs.com/package/crisp-tui)
5
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
6
+ [![Node.js: >=20](https://img.shields.io/badge/Node.js-%3E%3D20-5fa04e?logo=nodedotjs)](https://nodejs.org)
7
+
3
8
  Crisp support inbox built with OpenTUI, SolidJS and Bun. People use the TUI;
4
9
  agents use JSON commands and can prepare drafts in the same running screen.
5
- [crispctl](https://github.com/solcreek/crisp-cli) v0.2.0 provides all REST and RTM
10
+ [crispctl](https://github.com/solcreek/crisp-cli) v0.3.1 provides all REST and RTM
6
11
  access. Both profile-based and 1Password sessions use its JSON interface;
7
12
  this project has no separate HTTP or Socket.IO implementation.
8
13
 
14
+ ![crisp-tui running in Ghostty on Omarchy, with an English demo conversation and an agent-prepared reply draft](docs/images/crisp-tui-omarchy.png)
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
+
9
19
  ## Install
10
20
 
11
- Requires [Bun](https://bun.sh) 1.4.2 or newer and Node.js 20 or newer on macOS or Linux.
12
- The npm package installs the `crisp-tui` command; Bun must also be on PATH.
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:
13
30
 
14
31
  ```sh
15
- npm install -g crisp-tui
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
16
39
  crisp-tui --demo
17
40
  ```
18
41
 
@@ -22,6 +45,8 @@ with a crispctl profile configured, or `crisp-tui live --item 'Crisp development
22
45
  connection check. Add `--rtm-timeout 60` to require RTM authentication and an
23
46
  actual event within 60 seconds. The npm package includes crispctl as a dependency.
24
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.
25
50
 
26
51
  ## Run from source
27
52
 
@@ -39,7 +64,7 @@ Demo mode is explicit, in-memory, and never contacts Crisp. In another terminal:
39
64
  ```sh
40
65
  bun run src/index.ts ctl state
41
66
  bun run src/index.ts ctl goto session_demo_2
42
- bun run src/index.ts ctl draft session_demo_2 '我來協助你確認設定。'
67
+ bun run src/index.ts ctl draft session_demo_2 'Let me help you check your settings.'
43
68
  bun run src/index.ts ctl screen
44
69
  ```
45
70
 
@@ -94,10 +119,10 @@ requests use Basic auth with `identifier:key` and `X-Crisp-Tier: website`.
94
119
  The token belongs to one workspace. `crispctl` supplies these headers; this
95
120
  project never includes the secret in UI state or stores a second copy.
96
121
 
97
- The npm installation includes crispctl v0.2.0. To configure it separately on PATH:
122
+ This source checkout uses crispctl v0.3.1. To configure it separately on PATH:
98
123
 
99
124
  ```sh
100
- npm install -g crispctl@0.2.0
125
+ npm install -g crispctl@0.3.1
101
126
  ```
102
127
 
103
128
  Alternatively, build [crisp-cli from source](https://github.com/solcreek/crisp-cli#install)
@@ -125,7 +150,8 @@ All crispctl config and environment precedence still applies, including
125
150
  to crispctl. Select the same `--profile` / `--website` when issuing `ctl` commands.
126
151
 
127
152
  Executable lookup: `CRISPCTL_BIN` (one executable path, not a shell command),
128
- then the installed crispctl dependency, then `crispctl` on PATH, then
153
+ then the npm launcher's bundled crispctl dependency, then the dependency resolved
154
+ from a source checkout, then `crispctl` on PATH, then
129
155
  `../crisp-cli/dist/index.js` relative to this source
130
156
  checkout. The last option requires Node. A compiled TUI should use PATH or
131
157
  `CRISPCTL_BIN`. Credentials stay in the subprocess environment/config; commands
@@ -158,6 +184,8 @@ mode are kept separately for each conversation during this process.
158
184
  A failed send keeps the draft; writes are never retried automatically. A timeout
159
185
  can leave the send outcome unknown, so refresh before resending. Once a send is
160
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.
161
189
 
162
190
  ## Agent workflow
163
191
 
@@ -189,7 +217,8 @@ bun run src/index.ts ctl refresh
189
217
  bun run src/index.ts ctl screen
190
218
  ```
191
219
 
192
- `state` includes protocol version, source, current page/query, active conversation,
220
+ `state` includes protocol version, source, current page/query, selected session,
221
+ conversation-loading state, active conversation,
193
222
  loaded messages, per-session drafts and status. `messages` and `conversations`
194
223
  return the currently loaded page, without an API call. `screen` is a semantic
195
224
  text view of the loaded content, not an exact terminal screenshot. All other
@@ -217,8 +246,12 @@ One newline-delimited JSON request per connection:
217
246
  ```
218
247
 
219
248
  Response: `{"id":1,"ok":true,"result":…}` or
220
- `{"id":1,"ok":false,"error":"…"}`. Methods match `ctl` verbs. Screen-changing
221
- agent requests are serialized. No TCP server, daemon or MCP server is started.
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.
222
255
 
223
256
  ## Refresh and current boundaries
224
257
 
@@ -240,24 +273,63 @@ and writes. Consider this alongside the website token's documented daily quota.
240
273
  Conversation history is the latest page exposed by crispctl; there is no older
241
274
  message pagination, background daemon, push notifications, attachment upload or
242
275
  preview, persisted drafts, or MCP in this first version. Assignment and segments
243
- are available via the CLI bridge. The default tests use demo data, fake
276
+ are available via the CLI bridge. The default tests use demo data, isolated
244
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.
245
280
  Real read-only checks are separate, explicitly invoked commands.
246
281
 
247
282
  ## Verification and binary
248
283
 
249
284
  ```sh
250
285
  bun run typecheck
251
- bun test
252
286
  bun run build
287
+ bun run test:coverage
288
+ bun run test:package
253
289
  ./dist/crisp-tui-darwin-arm64 --demo # filename follows OS / architecture
254
290
  ```
255
291
 
256
292
  The standalone binary embeds Bun and the TUI renderer and needs crispctl on PATH
257
- or `CRISPCTL_BIN`. The npm package includes crispctl and needs Bun and Node 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.
258
295
  Tests exercise the UI with OpenTUI's
259
296
  headless renderer, send failures, concurrent navigation, draft isolation,
260
- subprocess argument handling and the Unix control protocol.
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.
261
333
 
262
334
  ## Development data and license
263
335
 
package/bin/crisp-tui.js CHANGED
@@ -1,4 +1,43 @@
1
- #!/usr/bin/env bun
2
- // Register Solid's client runtime before loading the precompiled application.
3
- import "@opentui/solid/preload"
4
- await import("../dist/cli.js")
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,15 +1,29 @@
1
1
  {
2
2
  "name": "crisp-tui",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "A terminal inbox for Crisp, with JSON control commands for agents",
5
5
  "license": "MIT",
6
- "repository": { "type": "git", "url": "git+https://github.com/solcreek/crisp-tui.git" },
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/solcreek/crisp-tui.git"
9
+ },
7
10
  "homepage": "https://github.com/solcreek/crisp-tui#readme",
8
- "bugs": { "url": "https://github.com/solcreek/crisp-tui/issues" },
11
+ "bugs": {
12
+ "url": "https://github.com/solcreek/crisp-tui/issues"
13
+ },
9
14
  "type": "module",
10
- "bin": { "crisp-tui": "bin/crisp-tui.js" },
11
- "files": ["bin/crisp-tui.js", "dist/cli.js", "README.md", "LICENSE"],
12
- "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org/" },
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
+ },
13
27
  "scripts": {
14
28
  "dev": "bun run src/index.ts",
15
29
  "demo": "bun run src/index.ts --demo",
@@ -17,16 +31,40 @@
17
31
  "live:check": "bun run scripts/live-readonly.ts --check",
18
32
  "typecheck": "tsc --noEmit",
19
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",
20
36
  "build": "bun run scripts/build.ts",
21
37
  "build:package": "bun run scripts/build-package.ts",
22
- "prepack": "bun run build:package"
38
+ "prepack": "bun run scripts/check-package.ts"
23
39
  },
24
40
  "dependencies": {
41
+ "crispctl": "0.3.1"
42
+ },
43
+ "devDependencies": {
44
+ "@types/bun": "1.3.14",
45
+ "typescript": "5.9.3",
25
46
  "@opentui/core": "0.5.12",
26
47
  "@opentui/solid": "0.5.12",
27
- "crispctl": "0.2.0",
28
48
  "solid-js": "1.9.12"
29
49
  },
30
- "devDependencies": { "@types/bun": "1.3.14", "typescript": "5.9.3" },
31
- "engines": { "bun": ">=1.4.2" }
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
+ }
32
70
  }