skalpel 3.4.19 → 4.0.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 +29 -37
- package/auth.mjs +179 -0
- package/{prosumer-hooks/bootstrap.mjs → bootstrap.mjs} +14 -8
- package/{prosumer-hooks/incremental-ingest.mjs → incremental-ingest.mjs} +5 -10
- package/{prosumer-hooks/install.mjs → install.mjs} +6 -9
- package/login.mjs +164 -0
- package/package.json +17 -57
- package/postinstall.mjs +68 -0
- package/skalpel-setup.mjs +896 -0
- package/{prosumer-hooks/skalpel-statusline.mjs → skalpel-statusline.mjs} +1 -2
- package/INSTALL.md +0 -250
- package/LICENSE +0 -201
- package/design-tokens.json +0 -52
- package/npm-bin/colors.js +0 -125
- package/npm-bin/skalpel.bug-0039.test.js +0 -232
- package/npm-bin/skalpel.js +0 -517
- package/npm-bin/skalpeld.js +0 -20
- package/postinstall/index.js +0 -277
- package/postinstall/index.test.js +0 -147
- package/postinstall/launchd/com.skalpel.skalpeld.plist.tmpl +0 -46
- package/postinstall/lib/ca-install.js +0 -268
- package/postinstall/lib/ca-install.test.js +0 -327
- package/postinstall/lib/detect-prior.js +0 -62
- package/postinstall/lib/env-inject.js +0 -105
- package/postinstall/lib/integrations.js +0 -207
- package/postinstall/lib/launch.js +0 -38
- package/postinstall/lib/log.js +0 -31
- package/postinstall/lib/paths.js +0 -236
- package/postinstall/lib/prosumer-hooks.js +0 -146
- package/postinstall/lib/prosumer-hooks.test.js +0 -278
- package/postinstall/lib/rc-edit.js +0 -168
- package/postinstall/lib/rc-edit.test.js +0 -243
- package/postinstall/lib/run-tests.js +0 -59
- package/postinstall/lib/service-register.js +0 -248
- package/postinstall/lib/sign-in.js +0 -80
- package/postinstall/lib/template.js +0 -36
- package/postinstall/preinstall.js +0 -111
- package/postinstall/preinstall.test.js +0 -47
- package/postinstall/snippets/bash.sh.tmpl +0 -12
- package/postinstall/snippets/fish.fish.tmpl +0 -11
- package/postinstall/snippets/powershell.ps1.tmpl +0 -12
- package/postinstall/snippets/zsh.sh.tmpl +0 -13
- package/postinstall/systemd/skalpeld.service.tmpl +0 -34
- package/postinstall/uninstall.js +0 -98
- package/postinstall/windows/Task.xml.tmpl +0 -42
- package/postinstall/windows/register-task.ps1.tmpl +0 -45
- package/prosumer-hooks/auth.mjs +0 -93
- package/prosumer-hooks/bootstrap.test.mjs +0 -93
- package/prosumer-hooks/incremental-ingest.test.mjs +0 -320
- /package/{prosumer-hooks/insights.mjs → insights.mjs} +0 -0
- /package/{prosumer-hooks/metrics.mjs → metrics.mjs} +0 -0
- /package/{prosumer-hooks/skalpel-hook-session-end.mjs → skalpel-hook-session-end.mjs} +0 -0
- /package/{prosumer-hooks/skalpel-hook-session.mjs → skalpel-hook-session.mjs} +0 -0
- /package/{prosumer-hooks/skalpel-hook.mjs → skalpel-hook.mjs} +0 -0
- /package/{prosumer-hooks/stats.mjs → stats.mjs} +0 -0
|
@@ -26,8 +26,7 @@ function main() {
|
|
|
26
26
|
} catch {
|
|
27
27
|
// Missing/corrupt first-run state is an honest zero, not a reason to hide the status line.
|
|
28
28
|
}
|
|
29
|
-
const finiteOrZero = (value) =>
|
|
30
|
-
typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
29
|
+
const finiteOrZero = (value) => (typeof value === "number" && Number.isFinite(value) ? value : 0);
|
|
31
30
|
const sess = finiteOrZero(s.session_hours).toFixed(1);
|
|
32
31
|
const total = finiteOrZero(s.total_hours).toFixed(1);
|
|
33
32
|
const steers = finiteOrZero(s.total_events);
|
package/INSTALL.md
DELETED
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
# Install and bundling — `skalpel` and `skalpeld`
|
|
2
|
-
|
|
3
|
-
The `skalpel` npm package is the canonical distribution surface for the Skalpel client on a developer's machine. The package contains two executables: `skalpel`, the Bubble Tea terminal UI specified in `SPEC.md` (in this repo) and `docs/RUN_CLIENT_LOCALLY.md` (also in this repo), and `skalpeld`, the local proxy and daemon. Installing one always installs the other; the two are released, signed, and versioned as a single bundle. A user who runs `npx skalpel`, `npm install -g skalpel`, or pulls a GitHub Releases tarball receives both binaries in a single transaction. There is no separate `skalpeld` package, no separate version cadence, and no "TUI without daemon" install path.
|
|
4
|
-
|
|
5
|
-
This document is the canonical specification for what gets installed where, how the first-run flow lands the user on the Engines tab, and how updates and uninstalls are handled. See `SPEC.md` for the TUI specification, `docs/RUN_CLIENT_LOCALLY.md` for the dev workflow, and the upstream infrastructure / cross-surface-contract documents (when available) for bundle composition and auth-handoff details.
|
|
6
|
-
|
|
7
|
-
The bundling commitment is a product decision before it is an implementation decision. A user who installs the TUI receives the daemon in the same transaction because the configurator (TUI) and the proxy (`skalpeld`) are two halves of the same product surface. Splitting them into independently versioned packages would introduce a class of "TUI-newer-than-daemon" or "daemon-newer-than-TUI" failures that no recovery clause in `SPEC.md` §8 is designed to handle. The bundle is the unit of release; the version is the unit of identity; the install path is the unit of choice.
|
|
8
|
-
|
|
9
|
-
## What gets installed
|
|
10
|
-
|
|
11
|
-
The npm package places two executables on the user's machine. Both arrive together; neither is shipped without the other.
|
|
12
|
-
|
|
13
|
-
| Binary | Role | On-disk location |
|
|
14
|
-
|---|---|---|
|
|
15
|
-
| `skalpel` | Bubble Tea terminal UI; the configurator the user invokes by typing `skalpel` in a shell. | A directory on the user's `PATH`. For `npx`, this is npm's transient cache. For `npm install -g`, this is the npm global prefix's `bin/` directory (typically `/usr/local/bin/skalpel` on macOS and Linux, `%AppData%\npm\skalpel.cmd` on Windows). |
|
|
16
|
-
| `skalpeld` | Local proxy/daemon; intercepts traffic from coding agents (Cursor, Claude Code, Codex), applies engines, and forwards to upstream providers. | Co-located with `skalpel` in the same `bin/` directory. Per-OS service registration (launchd agent on macOS, systemd user unit on Linux, Task Scheduler entry on Windows) is performed by the `postinstall` script so the daemon survives reboot; see "Daemon lifecycle on subsequent launches" below and `../../Skalpel_Infrastructure/INFRASTRUCTURE.md` for the platform constraints. |
|
|
17
|
-
|
|
18
|
-
Both binaries are produced from the same release workflow named in `INFRASTRUCTURE.md`'s CLI Distribution section. Both are signed keylessly via Sigstore / cosign. Both carry the same version string. Mismatch by version is impossible by construction on a machine that received either binary via a supported install path.
|
|
19
|
-
|
|
20
|
-
### Platform support
|
|
21
|
-
|
|
22
|
-
The release workflow targets three platforms in v1: macOS (arm64 and amd64), Linux (amd64; arm64 as a follow-on), and Windows (amd64). Each platform receives its own pair of binaries built from the same source revision. The npm package selects the right pair at install time based on the user's `os` and `cpu`; the GitHub Releases tarballs are named per-platform and the user picks. The configuration directory paths and service-registration entry points named elsewhere in this document differ per platform; the bundling and version-coupling commitments do not.
|
|
23
|
-
|
|
24
|
-
### Configuration directory
|
|
25
|
-
|
|
26
|
-
The configuration directory is per-OS, per `SPEC.md` §7. Both binaries read it: the TUI for `auth.json` and `config.toml`, the daemon for the same files plus its socket and logfile path. The directory is created by the wizard on first run and is owned by the user. It is not part of the npm package; it is created by the binaries on first invocation and survives uninstalls so that reinstalls can resume.
|
|
27
|
-
|
|
28
|
-
## Install paths
|
|
29
|
-
|
|
30
|
-
Three first-class install paths are supported. Each delivers both binaries; none can deliver one without the other.
|
|
31
|
-
|
|
32
|
-
- **`npx skalpel`** — the zero-install path. npm fetches the package on demand and runs the `skalpel` binary. `skalpeld` is materialized in the same npx cache and is reachable on the same `PATH`-like resolution that npx uses for the lifetime of the invocation. This is the recommended path for users running Skalpel for the first time.
|
|
33
|
-
- **`npm install -g skalpel`** — the persistent-install path. The package is installed into npm's global prefix; both binaries are placed in the global `bin/` directory and become available system-wide. Subsequent invocations resolve `skalpel` and `skalpeld` from `PATH` without the npm overhead. Recommended for users who want the binaries co-located with their other CLI tools.
|
|
34
|
-
- **GitHub Releases tarballs** — the air-gapped path. Each release attaches per-platform tarballs containing both binaries plus their cosign signatures and checksums (per `INFRASTRUCTURE.md`'s CLI Distribution section, which mandates keyless Sigstore signing for every release artifact). Recommended for users on a machine that cannot reach the public npm registry, or for environments where supply-chain verification is performed manually before placing binaries on `PATH`.
|
|
35
|
-
|
|
36
|
-
All three paths produce identical binaries — same SHAs, same cosign signatures, same version metadata. The choice between them is operational, not functional.
|
|
37
|
-
|
|
38
|
-
## First-run flow
|
|
39
|
-
|
|
40
|
-
Post-W4 (OAuth port): first run is a guided TUI walkthrough plus browser-loopback Cognito sign-in. The historical `sk-skalpel-*` API-key paste path is gone — the daemon no longer persists or sends api_keys on any code path. The flow is:
|
|
41
|
-
|
|
42
|
-
1. The user installs (`npm install -g skalpel`) and runs `skalpel`.
|
|
43
|
-
2. If `auth.json` is missing, `skalpel` renders a branded walkthrough in-terminal: daemon status, sign-in requirement, CA trust behavior, wrapper scope (new sessions only), and quick toggles (`skalpel off` / `skalpel on`).
|
|
44
|
-
3. On Enter, `skalpel` opens a browser to the Skalpel hosted-UI sign-in page (Cognito), waits on a loopback HTTP callback, and validates the signed envelope returned by the callback.
|
|
45
|
-
4. On a verified envelope, the CLI writes `auth.json` to the per-OS configuration directory (per `SPEC.md` §7). The file is owned by the user with `0600` permissions and carries the Cognito JWT bundle (access_token, refresh_token, expires_at).
|
|
46
|
-
5. Login idempotently enables the `behavior_graph` actuator and installs or refreshes the managed Claude Code and Codex prompt/session hooks. This does not depend on `skalpel setup` or on a live daemon.
|
|
47
|
-
6. Browser/paste login auto-launches the TUI and starts or resumes exactly one intent-graph worker, with progress on the Dashboard. Activation login stays TUI-free and launches the same worker in the background.
|
|
48
|
-
|
|
49
|
-
This flow corresponds to Journey 1 — First launch, fresh authentication — in `SPEC.md`. That narrative describes what the user feels at each step; this document describes what the install machinery actually does.
|
|
50
|
-
|
|
51
|
-
If the user runs `skalpel` without first running `skalpel login`, the walkthrough prompts them to sign in inline (Enter), skip for now (`s`), turn interception off (`o`), or quit (`q`). The walkthrough also surfaces the website onboarding URL (`https://skalpel.ai/signup`) and notes that a wizard activation command can be pasted directly — npm frequently hides `postinstall` output, so this CLI-side hint is where self-serve `npm install -g` users reliably learn how to activate. To sign out of an existing account on this machine, run `skalpel logout` from a shell — the CLI revokes the backend session (best-effort) and removes `auth.json` via `internal/auth.Delete`.
|
|
52
|
-
|
|
53
|
-
### Guided activation vs. self-serve global install
|
|
54
|
-
|
|
55
|
-
The primary, guided path is the website signup wizard, which mints a one-time, version-pinned-to-`latest` command:
|
|
56
|
-
|
|
57
|
-
```bash
|
|
58
|
-
npm install -g skalpel@<latest> && skalpel login --activation <token>
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
The `&& npm install -g` step puts `skalpel` on your PATH so shell wrappers from setup work in new terminals; it only runs if activation succeeds.
|
|
62
|
-
|
|
63
|
-
The shell wrappers — and the `skalpel active` / `skalpel inactive` indicator each new `claude` / `codex` session prints — **require a persistent global install** (`npm install -g skalpel`). The wrapper block is gated on `command -v skalpel`, so a block written while only an ephemeral `npx` binary is on PATH never activates. If you run only the `npx … login --activation` step (without the global install), harness setup detects that no persistent `skalpel` is on PATH and **tells you to run `npm install -g skalpel@latest`** instead of silently writing an inert block. Run the global install, then `skalpel setup` (or restart your shell), and the indicator appears.
|
|
64
|
-
|
|
65
|
-
`login --activation` is **auth-only with respect to the TUI**: it claims the token, writes `auth.json`, heals behavior hooks, starts or resumes graph learning in the background, and never launches the TUI (the magic flow is a deliberate terminal handoff). External-shell wrapping remains a separate consent boundary: in an interactive terminal activation offers the same detection + checkbox prompt as `skalpel setup`; in a non-interactive shell (CI, piped) it only prints what it detected and points at `skalpel setup`, never editing shell startup files unattended. Browser-loopback `skalpel login` still lands the user on the dashboard and shows graph progress there.
|
|
66
|
-
|
|
67
|
-
A user who independently runs `npm install -g skalpel` is still supported: `postinstall` prints a best-effort pointer to `https://skalpel.ai/signup`, and the first `skalpel` run repeats that pointer where output is guaranteed.
|
|
68
|
-
|
|
69
|
-
When Claude Code is already present, the persistent install also registers Skalpel's local,
|
|
70
|
-
read-only `statusLine` command. It is visible immediately as `~0.0h saved` and grows only from
|
|
71
|
-
confirmed savings. Install alone does **not** opt the user into prompt/session hooks; the first
|
|
72
|
-
successful `skalpel login` activates them. An existing custom Claude status line is preserved.
|
|
73
|
-
|
|
74
|
-
### `skalpel setup` — repair wrappers and behavior hooks
|
|
75
|
-
|
|
76
|
-
Normal authentication, hook activation, and graph learning require no setup command. `skalpel setup` remains as an explicit recovery/advanced command for re-running optional external-shell wrapping and repairing managed hooks. Harness wrapping is also offered interactively at the tail of `login --activation` (see above). `skalpel setup` detects which coding-agent harnesses are installed (cross-platform on Linux, Windows, and macOS) via PATH and per-user config probes:
|
|
77
|
-
|
|
78
|
-
- **Claude Code** and **Codex CLI** — detected and wrappable.
|
|
79
|
-
- **Cursor** — detected for display only (no Skalpel wrapper today).
|
|
80
|
-
|
|
81
|
-
In an **interactive** terminal, `setup` shows a checkbox list (nothing pre-selected), matching Claude Code’s multi-select pattern: **↑/↓** to move, **enter** (or **space**) on an agent row toggles a green **[✓]**, then move to **Confirm and wrap selected** and press **enter** to apply. **esc** skips without changes. It does not use a free-text `>` prompt and does not wrap all detected agents unless you pass `--yes` / `-y` or run in a non-interactive shell (which wraps all detected agents for explicit `skalpel setup` only — the chained `login --activation` path never writes shell files unattended).
|
|
82
|
-
|
|
83
|
-
Harness detection uses the same `internal/harness` probes as the published npm binary (`claude` / `codex` on PATH, or `~/.claude` / `~/.codex` config dirs). If nothing is found, the CLI prints what it looked for — that is not a dev-only stub.
|
|
84
|
-
|
|
85
|
-
After wrapping, `setup` prints per-agent success lines and reminds you that new `claude` / `codex` sessions show **`skalpel active`** or **`skalpel inactive`** on stderr before the agent loads (via the shell wrapper calling `skalpel status`). Toggle interception without editing shell files: **`skalpel off`** / **`skalpel on`**.
|
|
86
|
-
|
|
87
|
-
The wrapper block only fires when `skalpel` is **permanently on your PATH** (a global `npm install -g skalpel`, not an ephemeral `npx` run). If you invoke `setup` from a non-persistent `skalpel` (e.g. via `npx`), it will not write the rc block — it instead prints the exact `npm install -g skalpel@latest` command to run first, because the wrappers cannot activate without it.
|
|
88
|
-
|
|
89
|
-
`setup` resolves the correct shell startup file for the current OS + shell (zsh/bash/fish rc files, or the PowerShell `$PROFILE` on Windows), writes a managed fenced block (identical fences to the install-time block, so `skalpel uninstall` removes either), and prints exactly which file changed plus undo instructions (`skalpel uninstall`, or `SKALPEL_NO_AGENT_WRAP=1` to disable wrapping). It never launches the TUI. On an unknown OS/shell it prints manual instructions instead of writing.
|
|
90
|
-
|
|
91
|
-
Historical note: prior versions of skalpel supported pasting a `sk-skalpel-*` API key copied from the web dashboard as an alternative to `skalpel login`. The W4 OAuth-port grep-delete removed both the api_key-paste wizard and the daemon-side api_key sending path. Users on stale auth.json files (api_key-only, no Cognito bundle) need to run `skalpel login` once to refresh.
|
|
92
|
-
|
|
93
|
-
## Daemon lifecycle on subsequent launches
|
|
94
|
-
|
|
95
|
-
On every launch after the first, the TUI checks whether `skalpeld` is reachable. If it is, the TUI proceeds to Dashboard without further interaction. If it is not, the TUI attempts to start it (per spec §8.5) and shows the `Starting skalpeld…` splash for up to three seconds. If the daemon does not come up in that window, the TUI proceeds with the daemon-unreachable banner and the user is offered a `[r]` retry affordance.
|
|
96
|
-
|
|
97
|
-
The TUI is not a process supervisor. Per `SPEC.md` §01: the TUI tries to start the daemon at launch and surfaces the daemon's state via the banner, but there is no "stop daemon," "restart daemon," or "view daemon logs" control in the TUI; those are shell-level concerns. The install machinery makes both binaries available; the runtime relationship between them is the TUI's start-on-launch attempt and nothing more.
|
|
98
|
-
|
|
99
|
-
Per-OS service registration is performed by the npm `postinstall` script (`postinstall/lib/service-register.js`). On macOS the script renders and loads a launchd agent (`com.skalpel.skalpeld.plist`) and kickstarts it via `launchctl`; on Linux the script writes a systemd user unit (`skalpeld.service`) and starts it via `systemctl --user`; on Windows the script registers a Task Scheduler entry (`Task.xml`) and runs it via `schtasks /Run`. The `postinstall` script also starts the daemon immediately on first install so the user does not have to wait for the next TUI launch to bring `skalpeld` online; subsequent boots rely on the registered service entry, with the TUI's start-on-launch attempt as a defence-in-depth fallback. Both the bundling commitment (atomic install of TUI + daemon) and the TUI's runtime behaviour on launch are independent of the service registration mechanism.
|
|
100
|
-
|
|
101
|
-
## Updates
|
|
102
|
-
|
|
103
|
-
After install or upgrade, `skalpel --version` should report the same semver as `npm view skalpel version` (for example `skalpel v3.2.10` when the registry shows `3.2.10`). The release pipeline enforces that match before publish; if they diverge, reinstall with `npx --yes skalpel@latest`.
|
|
104
|
-
|
|
105
|
-
`npx skalpel@latest` and `npm update -g skalpel` are the two update paths. Both update both binaries atomically: the new `skalpel` and the new `skalpeld` arrive together, and the old `skalpel` and old `skalpeld` are replaced together. There is no window during which the binaries are at different versions on disk.
|
|
106
|
-
|
|
107
|
-
The CLI auto-update polling described in `INFRASTRUCTURE.md` (CLI Distribution, the `cli/latest` endpoint) surfaces a non-blocking notice when a newer version is available. The user runs the update command themselves; the TUI does not perform an in-place upgrade. After an update, the next `skalpel` invocation launches the new TUI, which in turn starts the new `skalpeld` if needed.
|
|
108
|
-
|
|
109
|
-
GitHub Releases tarball users update by downloading the new tarball, verifying signatures and checksums, and replacing the binaries on `PATH`. Both replacements happen as a single user-initiated operation; partial updates are not a supported state.
|
|
110
|
-
|
|
111
|
-
A user who has rolled back to a previous version (by running `npm install -g skalpel@<older>` or by replacing tarball binaries with archived ones) lands at a coherent older bundle: the older `skalpel` and the older `skalpeld` arrive together. There is no roll-back-the-TUI-only or roll-back-the-daemon-only operation. The same atomicity that protects forward updates protects rollbacks.
|
|
112
|
-
|
|
113
|
-
## Uninstall
|
|
114
|
-
|
|
115
|
-
```
|
|
116
|
-
npx skalpel uninstall
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
is the canonical one-liner for a clean, full removal on every supported OS. The Go binary owns the state cleanup; the Node shim owns `npm uninstall -g`. The watchdog catches `npm uninstall -g skalpel` alone within ~60s. It works whether or not skalpel was previously installed globally:
|
|
120
|
-
|
|
121
|
-
1. Unregisters the per-OS service entry (launchd on macOS, systemd user unit on Linux, Task Scheduler entry on Windows).
|
|
122
|
-
2. Removes the managed shell-rc block injected on install.
|
|
123
|
-
3. Deletes user state under the per-OS configuration directory: `auth.json`, `config.toml`, `skalpeld.lock`, `logs/`, and `cache/`.
|
|
124
|
-
4. Auto-detects a global npm install (via `npm prefix -g`) and removes it via `npm uninstall -g skalpel`, so the `skalpel` binary leaves your `PATH` in the same command.
|
|
125
|
-
|
|
126
|
-
Flags: `--keep-data` preserves user-data files (engine toggles, cached auth) for a future reinstall; `--keep-package` preserves the global npm package (only the state cleanup runs); `--dry-run` previews every action without writing anything.
|
|
127
|
-
|
|
128
|
-
`skalpel uninstall` from a global install behaves identically — same flags, same auto-removal of the npm package. Pick whichever is convenient: `npx skalpel uninstall` requires no prior install; `skalpel uninstall` is faster on a machine that already has the binary on `PATH`.
|
|
129
|
-
|
|
130
|
-
### Why `npm uninstall -g skalpel` is not the documented path
|
|
131
|
-
|
|
132
|
-
npm 7+ removed the `preuninstall`/`uninstall`/`postuninstall` lifecycle scripts; the `npm uninstall` command runs Arborist's `reify` which simply deletes files from the global `node_modules` and returns. There is no hook left for skalpel to clean up the rc-file managed block, the service entry, or user data on `npm uninstall -g skalpel` alone. Running `npm uninstall -g skalpel` without first running `skalpel uninstall` (or `npx skalpel uninstall`) leaves orphaned shell-rc env vars pointing at a dead proxy port and an orphaned launchd/systemd/Task Scheduler entry trying to start a binary that no longer exists. The `npx skalpel uninstall` one-liner above does both the state cleanup and the package removal in a single command — that's why it's the documented path.
|
|
133
|
-
|
|
134
|
-
The configuration directory itself (auth.json + config.toml + cache + logs) is deliberately wiped by the default uninstall so a reinstalled skalpel starts from a known state. Users who want to reinstall and keep their auth + engine toggles should pass `--keep-data`.
|
|
135
|
-
|
|
136
|
-
### Watchdog and cleanup.lock
|
|
137
|
-
|
|
138
|
-
`skalpel uninstall` is one path to a clean machine; `npm uninstall -g skalpel` followed by no further action is another. The daemon's **watchdog** subsystem closes the loop on the second path. Every ~30s, `skalpeld` polls its own executable path; when the binary disappears (because npm just nuked the global `node_modules`), it self-runs the same cleanup the Go CLI does, then exits.
|
|
139
|
-
|
|
140
|
-
To opt out (e.g. on shared hosts where the daemon is centrally managed), set `[daemon] watchdog_enabled = false` in `~/.config/skalpel/config.toml`:
|
|
141
|
-
|
|
142
|
-
```toml
|
|
143
|
-
[daemon]
|
|
144
|
-
watchdog_enabled = false
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
`cleanup.lock` is a small marker file `<configDir>/cleanup.lock` that `skalpel uninstall` writes before any destructive step. It contains `<pid>\n<unix_ms>\n`. The watchdog reads it every tick:
|
|
148
|
-
|
|
149
|
-
- If the lock's PID is alive AND its timestamp is fresher than 10 minutes → stand down (a user-initiated uninstall owns this window).
|
|
150
|
-
- Else (dead PID or stale timestamp) → ignore the lock and proceed as if it weren't there.
|
|
151
|
-
|
|
152
|
-
`cleanup.lock` is safe to delete manually if you see one outside an active uninstall — the next watchdog tick will recover.
|
|
153
|
-
|
|
154
|
-
## Version coupling
|
|
155
|
-
|
|
156
|
-
`skalpel` and `skalpeld` carry the same version string at all times. The release workflow produces both from the same git tag; the npm package's `version` field, the binaries' embedded version metadata, and the cosign signatures all reference the same value. There is no path by which the two could diverge on a machine that received either via a supported install path.
|
|
157
|
-
|
|
158
|
-
When the TUI connects to the daemon at launch, the handshake includes a version exchange. If the version reported by `skalpeld` does not match the version embedded in `skalpel` — a state that should be unreachable through the supported install paths — the TUI enters a degraded state per `SPEC.md` §8 and surfaces a banner instructing the user to reinstall the bundle. The handshake is a defence in depth; the install paths are designed so that the handshake should never fire on a mismatch.
|
|
159
|
-
|
|
160
|
-
The handshake is also where the TUI reads the daemon's engine list and the daemon's per-agent detection results (per `SPEC.md` §6 and §9). A version-coupled handshake is also a guarantee that the TUI is reading those results from a daemon whose schema it understands. When the bundle promises versions match, the TUI does not need a defensive parse-and-recover path for the daemon's responses; the schema is whatever the bundle's joint version says it is.
|
|
161
|
-
|
|
162
|
-
## Advanced: chaining `skalpeld` through a local interception proxy
|
|
163
|
-
|
|
164
|
-
By default `skalpeld` is the host's HTTP proxy for coding agents. If you
|
|
165
|
-
also run a separate local interception proxy (e.g. an mitmproxy that
|
|
166
|
-
records traffic for research), you can have the daemon **chain** its
|
|
167
|
-
outbound provider traffic through it without either rig fighting over the
|
|
168
|
-
proxy role. This is opt-in and controlled by two environment variables on
|
|
169
|
-
the **daemon** process:
|
|
170
|
-
|
|
171
|
-
| Variable | Values | Default | Effect |
|
|
172
|
-
|---|---|---|---|
|
|
173
|
-
| `SKALPEL_VIA_MITM` | `true` \| `false` \| `bypass` | `true` | `true`: the daemon routes its **provider** calls (Anthropic / OpenAI / …) through the proxy at `MITM_PROXY_URL`, while its own **control-plane** calls to `api.skalpel.ai` and the **Cognito** auth hop bypass the proxy (so your recordings never contain Skalpel control-plane chatter). `false` / `bypass`: the daemon talks direct to providers, no chaining; `bypass` is the explicit "turn everything off" debugging value. An unset or unrecognised value behaves as `true`. |
|
|
174
|
-
| `MITM_PROXY_URL` | a proxy URL | `http://127.0.0.1:8888` | The interception-proxy address to chain through when `SKALPEL_VIA_MITM=true`. The daemon's own live proxy address-file and `SKALPEL_PROXY_URL` take precedence over this if set. |
|
|
175
|
-
|
|
176
|
-
The bypass list is fixed and suffix-based — it covers the Skalpel control
|
|
177
|
-
plane (`api.skalpel.ai`, `.skalpel.ai`), Cognito and AWS
|
|
178
|
-
(`amazoncognito.com`, `amazonaws.com`), object stores
|
|
179
|
-
(`r2.cloudflarestorage.com`), the package registries the install path
|
|
180
|
-
reaches (`pypi.org`, `crates.io`, `*.github.com`), and loopback. Provider
|
|
181
|
-
hosts are NOT on the list, so they route through the proxy.
|
|
182
|
-
|
|
183
|
-
Because the daemon is service-managed, set these via a systemd drop-in
|
|
184
|
-
rather than an interactive shell:
|
|
185
|
-
|
|
186
|
-
```ini
|
|
187
|
-
# ~/.config/systemd/user/skalpeld.service.d/proxy-chain.conf
|
|
188
|
-
[Service]
|
|
189
|
-
Environment=SKALPEL_VIA_MITM=true
|
|
190
|
-
Environment=MITM_PROXY_URL=http://127.0.0.1:8888
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
```bash
|
|
194
|
-
systemctl --user daemon-reload
|
|
195
|
-
systemctl --user restart skalpeld
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
To disable chaining, set `SKALPEL_VIA_MITM=bypass` (or `false`) and
|
|
199
|
-
restart the daemon. The interception proxy must trust nothing extra for
|
|
200
|
-
this to work; the chain is purely a network-layer redirect of the
|
|
201
|
-
daemon's outbound sockets.
|
|
202
|
-
|
|
203
|
-
## Open questions
|
|
204
|
-
|
|
205
|
-
A small set of bundling questions are recorded here for the build phase. Each will be resolved before v1 ships; none affect the design commitments above.
|
|
206
|
-
|
|
207
|
-
- **`npx` cache eviction and version-pinning UX.** `npx skalpel` caches per-version; a user who runs `npx skalpel@1.2.3` after `1.2.4` has shipped continues to execute `1.2.3` until npm's cache resolves. The auto-update notice surfaces in the TUI, but the underlying npx semantics are an open ergonomic question.
|
|
208
|
-
- ~~**Signed-link pre-population of the API key.**~~ Obsolete post-W4 (OAuth-port grep-delete): the api_key-paste wizard the question referred to is gone. The first-run flow is browser-loopback Cognito sign-in via `skalpel login`. Left here as a historical breadcrumb for anyone tracing the pre-W4 design dockets.
|
|
209
|
-
- **Bundle size budget.** The two binaries together set a download-size budget for first-time `npx` users; whether to ship a slim TUI front-end and a separately-downloaded `skalpeld` payload via a `postinstall` fetch (still in the same npm transaction) or to ship both in the package tarball directly is a build-phase decision. Either approach preserves the bundling commitment because both binaries are still resolved and authenticated within the same install operation.
|
|
210
|
-
- **Install-time telemetry.** Whether the install path emits any telemetry event (e.g., "first install completed") is open. The TUI itself does not phone home in v1 (per the privacy stance in `SPEC.md` §05); whether the install wizard shares that posture or whether anonymous install counts are acceptable for release-quality measurement is a build-phase decision.
|
|
211
|
-
- **Windows install ergonomics.** Whether `npx skalpel` on Windows requires Windows Terminal or a recent PowerShell to render the Bubble Tea TUI's adaptive colours and key bindings cleanly, and whether a fallback message should explain the requirement, is open. The bundling commitment is platform-agnostic; the first-run experience may not be.
|
|
212
|
-
|
|
213
|
-
## References
|
|
214
|
-
|
|
215
|
-
- `SPEC.md` — TUI specification: §1 (goals and non-goals; Install/uninstall flow is named as a non-goal there with a pointer here), §7 (configuration directory and file layout), §8 (degraded states and banners, including the version-mismatch banner), §16 (Install and distribution; cross-links here as the canonical source).
|
|
216
|
-
- `SPEC.md` — Skalpel TUI design dockets: §01 (the daemon non-supervisor stance), §03 Journey 1 (first-launch fresh-authentication flow that this document's first-run flow corresponds to), §05 (privacy stance referenced in the install-time telemetry open question).
|
|
217
|
-
- `../../design-dockets/cross-surface-contract.md` — Cross-surface contract: the Auth handoff section (machine-client identity, the `npx skalpel` install wizard arriving in the same transaction as the daemon), the ownership matrix's Post-signup install row.
|
|
218
|
-
- `../../Skalpel_Infrastructure/INFRASTRUCTURE.md` — CLI Distribution section (npm, GitHub Releases, Sigstore signing, the `cli/latest` auto-update endpoint, emergency-release fallback path).
|
|
219
|
-
|
|
220
|
-
## Codex setup (macOS)
|
|
221
|
-
|
|
222
|
-
During `npm install -g skalpel` on macOS you will see a **one-time Touch ID / password prompt** from the system. This prompt is the macOS keychain asking you to trust the daemon's local intercept CA in your **login keychain**. The trust is needed because Codex CLI is Rust and validates TLS against the OS keychain — without the trust, `codex` would reject the daemon's MITM leaf certs and skalpel would never see Codex traffic.
|
|
223
|
-
|
|
224
|
-
**Scope of trust:**
|
|
225
|
-
|
|
226
|
-
- Per-user (your `login.keychain-db`), not system-wide.
|
|
227
|
-
- Trusts only the daemon-minted local CA labelled `Skalpel Local Intercept CA`.
|
|
228
|
-
- Used exclusively for `chatgpt.com` / `api.openai.com` traffic the daemon intercepts; every other host is blind-tunnelled untouched.
|
|
229
|
-
|
|
230
|
-
**If you missed the prompt** or declined it, run `skalpel login` or invoke `codex` once — the postinstall step writes a deferred-install sentinel and the next entry point retries the trust-store install.
|
|
231
|
-
|
|
232
|
-
**macOS — revoke trust:**
|
|
233
|
-
|
|
234
|
-
1. Open **Keychain Access**.
|
|
235
|
-
2. Select the `login` keychain.
|
|
236
|
-
3. Search for `Skalpel Local Intercept CA`.
|
|
237
|
-
4. Right-click → Delete.
|
|
238
|
-
|
|
239
|
-
**Linux — revoke trust:**
|
|
240
|
-
|
|
241
|
-
```bash
|
|
242
|
-
sudo rm /usr/local/share/ca-certificates/skalpel-local-intercept-ca.crt
|
|
243
|
-
sudo update-ca-certificates --fresh
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
**Linux install requirements:** postinstall (and the deferred retry on first `skalpel login` / `codex` invocation) copies the daemon CA to `/usr/local/share/ca-certificates/skalpel-local-intercept-ca.crt` and runs `update-ca-certificates`. This needs **root** or **passwordless `sudo`**. If `sudo` is unavailable, postinstall prints the manual commands and does not fail the install.
|
|
247
|
-
|
|
248
|
-
After deletion, Codex traffic falls back to bare TLS (daemon won't see it). Re-install the CA via `skalpel login` if you change your mind.
|
|
249
|
-
|
|
250
|
-
**Windows status:** the trust-store install path is **not yet shipped** on Windows. Codex MITM on Windows still requires manual cert trust until a `certutil` path lands.
|
package/LICENSE
DELETED
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
Apache License
|
|
2
|
-
Version 2.0, January 2004
|
|
3
|
-
http://www.apache.org/licenses/
|
|
4
|
-
|
|
5
|
-
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
-
|
|
7
|
-
1. Definitions.
|
|
8
|
-
|
|
9
|
-
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
-
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
-
|
|
12
|
-
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
-
the copyright owner that is granting the License.
|
|
14
|
-
|
|
15
|
-
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
-
other entities that control, are controlled by, or are under common
|
|
17
|
-
control with that entity. For the purposes of this definition,
|
|
18
|
-
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
-
direction or management of such entity, whether by contract or
|
|
20
|
-
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
-
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
-
|
|
23
|
-
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
-
exercising permissions granted by this License.
|
|
25
|
-
|
|
26
|
-
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
-
including but not limited to software source code, documentation
|
|
28
|
-
source, and configuration files.
|
|
29
|
-
|
|
30
|
-
"Object" form shall mean any form resulting from mechanical
|
|
31
|
-
transformation or translation of a Source form, including but
|
|
32
|
-
not limited to compiled object code, generated documentation,
|
|
33
|
-
and conversions to other media types.
|
|
34
|
-
|
|
35
|
-
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
-
Object form, made available under the License, as indicated by a
|
|
37
|
-
copyright notice that is included in or attached to the work
|
|
38
|
-
(an example is provided in the Appendix below).
|
|
39
|
-
|
|
40
|
-
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
-
form, that is based on (or derived from) the Work and for which the
|
|
42
|
-
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
-
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
-
of this License, Derivative Works shall not include works that remain
|
|
45
|
-
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
-
the Work and Derivative Works thereof.
|
|
47
|
-
|
|
48
|
-
"Contribution" shall mean any work of authorship, including
|
|
49
|
-
the original version of the Work and any modifications or additions
|
|
50
|
-
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
-
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
-
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
-
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
-
means any form of electronic, verbal, or written communication sent
|
|
55
|
-
to the Licensor or its representatives, including but not limited to
|
|
56
|
-
communication on electronic mailing lists, source code control systems,
|
|
57
|
-
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
-
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
-
excluding communication that is conspicuously marked or otherwise
|
|
60
|
-
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
-
|
|
62
|
-
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
-
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
-
subsequently incorporated within the Work.
|
|
65
|
-
|
|
66
|
-
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
-
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
-
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
-
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
-
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
-
Work and such Derivative Works in Source or Object form.
|
|
72
|
-
|
|
73
|
-
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
-
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
-
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
-
(except as stated in this section) patent license to make, have made,
|
|
77
|
-
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
-
where such license applies only to those patent claims licensable
|
|
79
|
-
by such Contributor that are necessarily infringed by their
|
|
80
|
-
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
-
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
-
institute patent litigation against any entity (including a
|
|
83
|
-
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
-
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
-
or contributory patent infringement, then any patent licenses
|
|
86
|
-
granted to You under this License for that Work shall terminate
|
|
87
|
-
as of the date such litigation is filed.
|
|
88
|
-
|
|
89
|
-
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
-
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
-
modifications, and in Source or Object form, provided that You
|
|
92
|
-
meet the following conditions:
|
|
93
|
-
|
|
94
|
-
(a) You must give any other recipients of the Work or
|
|
95
|
-
Derivative Works a copy of this License; and
|
|
96
|
-
|
|
97
|
-
(b) You must cause any modified files to carry prominent notices
|
|
98
|
-
stating that You changed the files; and
|
|
99
|
-
|
|
100
|
-
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
-
that You distribute, all copyright, patent, trademark, and
|
|
102
|
-
attribution notices from the Source form of the Work,
|
|
103
|
-
excluding those notices that do not pertain to any part of
|
|
104
|
-
the Derivative Works; and
|
|
105
|
-
|
|
106
|
-
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
-
distribution, then any Derivative Works that You distribute must
|
|
108
|
-
include a readable copy of the attribution notices contained
|
|
109
|
-
within such NOTICE file, excluding those notices that do not
|
|
110
|
-
pertain to any part of the Derivative Works, in at least one
|
|
111
|
-
of the following places: within a NOTICE text file distributed
|
|
112
|
-
as part of the Derivative Works; within the Source form or
|
|
113
|
-
documentation, if provided along with the Derivative Works; or,
|
|
114
|
-
within a display generated by the Derivative Works, if and
|
|
115
|
-
wherever such third-party notices normally appear. The contents
|
|
116
|
-
of the NOTICE file are for informational purposes only and
|
|
117
|
-
do not modify the License. You may add Your own attribution
|
|
118
|
-
notices within Derivative Works that You distribute, alongside
|
|
119
|
-
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
-
that such additional attribution notices cannot be construed
|
|
121
|
-
as modifying the License.
|
|
122
|
-
|
|
123
|
-
You may add Your own copyright statement to Your modifications and
|
|
124
|
-
may provide additional or different license terms and conditions
|
|
125
|
-
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
-
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
-
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
-
the conditions stated in this License.
|
|
129
|
-
|
|
130
|
-
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
-
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
-
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
-
this License, without any additional terms or conditions.
|
|
134
|
-
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
-
the terms of any separate license agreement you may have executed
|
|
136
|
-
with Licensor regarding such Contributions.
|
|
137
|
-
|
|
138
|
-
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
-
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
-
except as required for describing the origin of the Work and
|
|
141
|
-
reproducing the content of the NOTICE file.
|
|
142
|
-
|
|
143
|
-
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
-
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
-
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
-
implied, including, without limitation, any warranties or conditions
|
|
148
|
-
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
-
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
-
appropriateness of using or redistributing the Work and assume any
|
|
151
|
-
risks associated with Your exercise of permissions under this License.
|
|
152
|
-
|
|
153
|
-
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
-
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
-
unless required by applicable law (such as deliberate and grossly
|
|
156
|
-
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
-
liable to You for damages, including any direct, indirect, special,
|
|
158
|
-
incidental, or consequential damages of any character arising as a
|
|
159
|
-
result of this License or out of the use or inability to use the
|
|
160
|
-
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
-
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
-
other commercial damages or losses), even if such Contributor
|
|
163
|
-
has been advised of the possibility of such damages.
|
|
164
|
-
|
|
165
|
-
9. Accepting Warranty or Support. While redistributing the Work or
|
|
166
|
-
Derivative Works thereof, You may choose to offer, and charge a
|
|
167
|
-
fee for, acceptance of support, warranty, indemnity, or other
|
|
168
|
-
liability obligations and/or rights consistent with this License.
|
|
169
|
-
However, in accepting such obligations, You may act only on Your
|
|
170
|
-
own behalf and on Your sole responsibility, not on behalf of any
|
|
171
|
-
other Contributor, and only if You agree to indemnify, defend,
|
|
172
|
-
and hold each Contributor harmless for any liability incurred by,
|
|
173
|
-
or claims asserted against, such Contributor by reason of your
|
|
174
|
-
accepting any such warranty or support.
|
|
175
|
-
|
|
176
|
-
END OF TERMS AND CONDITIONS
|
|
177
|
-
|
|
178
|
-
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
-
|
|
180
|
-
To apply the Apache License to your work, attach the following
|
|
181
|
-
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
-
replaced with your own identifying information. (Don't include
|
|
183
|
-
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
-
comment syntax for the file format. We also recommend that a
|
|
185
|
-
file or class name and description of purpose be included on the
|
|
186
|
-
same "printed page" as the copyright notice for easier
|
|
187
|
-
identification within third-party archives.
|
|
188
|
-
|
|
189
|
-
Copyright 2026 SkalpelAI Inc.
|
|
190
|
-
|
|
191
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
-
you may not use this file except in compliance with the License.
|
|
193
|
-
You may obtain a copy of the License at
|
|
194
|
-
|
|
195
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
-
|
|
197
|
-
Unless required by applicable law or agreed to in writing, software
|
|
198
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
-
See the License for the specific language governing permissions and
|
|
201
|
-
limitations under the License.
|
package/design-tokens.json
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "design-tokens.schema.json",
|
|
3
|
-
"version": 1,
|
|
4
|
-
"themes": {
|
|
5
|
-
"tokyo-night-storm": {
|
|
6
|
-
"base": "#1a1b26",
|
|
7
|
-
"mantle": "#16161e",
|
|
8
|
-
"crust": "#16161e",
|
|
9
|
-
"surface0": "#16161e",
|
|
10
|
-
"surface1": "#1f2335",
|
|
11
|
-
"surface2": "#24283b",
|
|
12
|
-
"overlay0": "#3b4261",
|
|
13
|
-
"overlay1": "#565f89",
|
|
14
|
-
"overlay2": "#737aa2",
|
|
15
|
-
"text": "#c0caf5",
|
|
16
|
-
"subtext0": "#a9b1d6",
|
|
17
|
-
"subtext1": "#a9b1d6",
|
|
18
|
-
"lilac": "#bb9af7",
|
|
19
|
-
"pink": "#f7768e",
|
|
20
|
-
"red": "#f7768e",
|
|
21
|
-
"maroon": "#f7768e",
|
|
22
|
-
"peach": "#ff9e64",
|
|
23
|
-
"lemon": "#e0af68",
|
|
24
|
-
"mint": "#9ece6a",
|
|
25
|
-
"teal": "#73daca",
|
|
26
|
-
"sky": "#7aa2f7",
|
|
27
|
-
"sapphire": "#7aa2f7",
|
|
28
|
-
"blue": "#7aa2f7",
|
|
29
|
-
"lavender": "#bb9af7"
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
|
-
"semantic": {
|
|
33
|
-
"tab.dashboard": "tokyo-night-storm.lilac",
|
|
34
|
-
"tab.engines": "tokyo-night-storm.sky",
|
|
35
|
-
"tab.sessions": "tokyo-night-storm.pink",
|
|
36
|
-
"tab.account": "tokyo-night-storm.mint",
|
|
37
|
-
"tab.graph": "tokyo-night-storm.teal",
|
|
38
|
-
"tab.logs": "tokyo-night-storm.lemon",
|
|
39
|
-
"selection.bg": "tokyo-night-storm.lilac",
|
|
40
|
-
"selection.fg": "tokyo-night-storm.crust",
|
|
41
|
-
"border.dim": "tokyo-night-storm.overlay0",
|
|
42
|
-
"footer.text": "tokyo-night-storm.overlay1",
|
|
43
|
-
"section.cost": "tokyo-night-storm.pink",
|
|
44
|
-
"section.engine": "tokyo-night-storm.lilac",
|
|
45
|
-
"section.quality": "tokyo-night-storm.mint",
|
|
46
|
-
"level.error": "tokyo-night-storm.red",
|
|
47
|
-
"level.warn": "tokyo-night-storm.lemon",
|
|
48
|
-
"level.info": "tokyo-night-storm.sky",
|
|
49
|
-
"level.success": "tokyo-night-storm.mint",
|
|
50
|
-
"level.debug": "tokyo-night-storm.overlay0"
|
|
51
|
-
}
|
|
52
|
-
}
|