flashlite 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +583 -2
- package/dist/adapters/anthropic.js +341 -0
- package/dist/adapters/openai.js +241 -0
- package/dist/approval.js +28 -0
- package/dist/boostworkflow.js +15 -0
- package/dist/boundedfs.js +214 -0
- package/dist/chatviewport.js +123 -0
- package/dist/checkpoint.js +100 -0
- package/dist/client.js +463 -0
- package/dist/clipboard.js +72 -0
- package/dist/commandpolicy.js +544 -0
- package/dist/commands.js +29 -0
- package/dist/compaction.js +66 -0
- package/dist/config.js +206 -0
- package/dist/contextbudget.js +201 -0
- package/dist/customcommands.js +105 -0
- package/dist/effort.js +79 -0
- package/dist/hooks.js +86 -0
- package/dist/images.js +84 -0
- package/dist/index.js +459 -0
- package/dist/lineinput.js +982 -0
- package/dist/loop.js +442 -0
- package/dist/markdown.js +426 -0
- package/dist/memory.js +55 -0
- package/dist/pathcomplete.js +92 -0
- package/dist/projectinstructions.js +77 -0
- package/dist/repl.js +1659 -0
- package/dist/researchweb.js +87 -0
- package/dist/sanitize.js +89 -0
- package/dist/sessions.js +209 -0
- package/dist/sse.js +80 -0
- package/dist/subagents.js +182 -0
- package/dist/systemprompt.js +35 -0
- package/dist/terminal.js +235 -0
- package/dist/todo.js +34 -0
- package/dist/token.js +17 -0
- package/dist/tokenprofiles.js +25 -0
- package/dist/toolcache.js +50 -0
- package/dist/toolpreview.js +253 -0
- package/dist/toolresultview.js +62 -0
- package/dist/tools.js +889 -0
- package/dist/types.js +3 -0
- package/dist/ui.js +1630 -0
- package/package.json +28 -4
package/README.md
CHANGED
|
@@ -1,3 +1,584 @@
|
|
|
1
|
-
#
|
|
1
|
+
# flashlite
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A personal agentic coding CLI — Claude Code / pi style — for any OpenAI- or
|
|
4
|
+
Anthropic-compatible chat endpoint. Streaming chat REPL plus an agent loop
|
|
5
|
+
with **filesystem tools** for creating and organizing projects, reading/editing code,
|
|
6
|
+
searching, copying assets, and removal, plus **terminal commands** for builds, tests,
|
|
7
|
+
and other requested work. Opt-in **guarded auto** runs arbitrary terminal commands
|
|
8
|
+
without prompts, but still asks before network access, installs, sudo, paths outside
|
|
9
|
+
the project, and destructive Git operations — and refuses obviously catastrophic
|
|
10
|
+
deletion/disk commands. A separate **unguarded auto** mode permits whole-drive file
|
|
11
|
+
access and every command; only recognizable catastrophic actions ask.
|
|
12
|
+
|
|
13
|
+
TypeScript on Node ≥ 24, run straight from source via Node's native type stripping:
|
|
14
|
+
**zero build step, zero runtime dependencies** (only `typescript` + `@types/node` as
|
|
15
|
+
devDependencies for typechecking). macOS only.
|
|
16
|
+
|
|
17
|
+
## Setup
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install # devDependencies only (typescript + @types/node)
|
|
21
|
+
npm run typecheck # tsc --noEmit
|
|
22
|
+
npm test # node --test — the full suite is offline
|
|
23
|
+
|
|
24
|
+
# put the CLI (command `flash`) on your PATH (no root needed):
|
|
25
|
+
mkdir -p ~/.local/bin
|
|
26
|
+
ln -s "$PWD/scripts/flashlite-wrapper.sh" ~/.local/bin/flash # or copy it; chmod +x
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
On first interactive launch, `flash` asks for your endpoint URL and then your API key
|
|
30
|
+
with masked input, saving both to `~/.config/flashlite/config.json` (chmod 600). Each
|
|
31
|
+
local user provides their own endpoint and key; nothing is bundled with the npm package
|
|
32
|
+
or baked into the binary. Keys are never printed, logged, or committed — not even
|
|
33
|
+
masked. Non-interactive runs require an existing config file (or `--base-url`).
|
|
34
|
+
Configuration is validated before
|
|
35
|
+
use: `auto_approve` must be a JSON boolean (the string `"false"` cannot enable it),
|
|
36
|
+
`max_output_tokens` must be an integer from 256–65536,
|
|
37
|
+
and `tool_result_budget_bytes` from 0–4,000,000 (0 disables tool-result elision).
|
|
38
|
+
Invalid fields produce value-free warnings and fall back to defaults; permission
|
|
39
|
+
fields fail closed. Base URLs must use HTTP(S) and cannot contain login credentials,
|
|
40
|
+
query strings or fragments.
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
flash --check # connectivity + model catalog diagnostic
|
|
44
|
+
flash # the REPL
|
|
45
|
+
flash -p "explain this code: …" # text-only one-shot; no tools or workspace access
|
|
46
|
+
flash --agent -p "inspect this repo" # headless tools, read-only by default
|
|
47
|
+
flash --agent --auto -p "fix the failing tests and verify" # trusted project; guarded commands
|
|
48
|
+
flash --agent --auto-approve -p "update the README" # file changes only
|
|
49
|
+
flash --absolute # unguarded auto: whole drive + every command; no gate
|
|
50
|
+
flash --auto # guarded auto; network/installs/sudo/outside/destructive still ask
|
|
51
|
+
flash --auto-approve # file-only auto; every terminal command still asks
|
|
52
|
+
flash --model <id> --debug
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Real-work workflows
|
|
56
|
+
|
|
57
|
+
The agent is instructed to inspect relevant files, make focused changes, run authorized
|
|
58
|
+
validation, diagnose failures, retry, and report what was actually verified. Tool
|
|
59
|
+
schemas explain scope, approval and supported follow-up options instead of treating
|
|
60
|
+
bounded output as a dead end. Applicable `CLAUDE.md` files are loaded from the nearest
|
|
61
|
+
repository root down to the launch directory, attributed to their source/scope. Outside
|
|
62
|
+
a repository, only the launch directory is considered. Sources are regular, non-symlink
|
|
63
|
+
files, bounded to 16 KiB each / 32 KiB total; nested guidance must be inspected when
|
|
64
|
+
working in a deeper subtree. Project instructions cannot override host permissions or
|
|
65
|
+
credential protection.
|
|
66
|
+
|
|
67
|
+
For automation, **`--agent -p` explicitly enables tools**. It defaults to read-only,
|
|
68
|
+
ignoring saved `auto_approve` permissions. Add `--auto-approve` for file changes or
|
|
69
|
+
`--auto` for file changes plus guarded commands. Actions without approval
|
|
70
|
+
are denied as tool results, never an unattended approval prompt; denied/failed tools
|
|
71
|
+
or unfinished turns produce a nonzero exit code. Headless runs save private transcripts
|
|
72
|
+
and retain completed-action evidence. They use bounded tool rounds but currently do
|
|
73
|
+
not fetch model context windows or auto-compact; keep automated tasks scoped. Unguarded
|
|
74
|
+
auto is interactive-only. Ordinary `-p` remains text-only, not a repo-inspection mode.
|
|
75
|
+
|
|
76
|
+
## The REPL
|
|
77
|
+
|
|
78
|
+
- **Terminal UI:** chat scrolls above a bottom-anchored panel, with the selected model
|
|
79
|
+
on its top divider, the orange `❯` input between dividers, and a labeled status row
|
|
80
|
+
below. Your input echoes with its orange `❯` chevron; streamed assistant replies
|
|
81
|
+
start with a subtle `●` marker. Tool calls are grouped by name only within a single
|
|
82
|
+
model-proposed batch, not across later calls. The layout uses a flat light yellow accent (#ffe066)
|
|
83
|
+
for branding, models, menus, and availability, with orange (#ff9f40) for keywords. The status row names every token (`mode`/`effort`); the effort value
|
|
84
|
+
warms from light yellow to red as the level rises, and the drive-wide mode badge reads
|
|
85
|
+
`unguarded auto`. A resting status word is omitted from the footer; success states stay
|
|
86
|
+
green and warnings amber/red, and **Shift+Tab** cycles the permission mode. Command menus
|
|
87
|
+
and views open immediately **below the input**, outside
|
|
88
|
+
the scrolling conversation. While a command is open, the normal status row is
|
|
89
|
+
hidden so only its controls remain. Reasoning text is hidden; answers and
|
|
90
|
+
in-flow tool activity cards stay in chat. The compact header shows only the
|
|
91
|
+
working directory. Pipes and very small terminals keep a simple layout; `--no-color`
|
|
92
|
+
disables styling and animation. Set `FLASHLITE_THEME=light` for white/light terminals: the
|
|
93
|
+
warm palette darkens and switches to explicit true-color (no bright `9x`, no `2` faint) so
|
|
94
|
+
every text role keeps ≥4.5:1 contrast; `dark` is the default and unchanged. Restart `flash`
|
|
95
|
+
after source changes — existing sessions do not hot-reload.
|
|
96
|
+
- **Context meter:** the bottom bar shows conversation context usage as a color-coded
|
|
97
|
+
percent with token counts (e.g. `ctx 42% 42k/100k`) — accent up to 70%, yellow 70–85%, red above 85%;
|
|
98
|
+
missing or disabled context shows nothing. The context amount is always kept visible,
|
|
99
|
+
even on narrow terminals — the status truncates around it.
|
|
100
|
+
- **Dynamic slash commands:** type `/` to open a live filtered palette below the input.
|
|
101
|
+
↑/↓ selects, Tab completes, Enter runs, and Esc dismisses. `/model` opens the model
|
|
102
|
+
picker; `/model <id>` still sets
|
|
103
|
+
directly and persists the default. `/compact` summarizes older complete
|
|
104
|
+
turns while retaining the latest user turn; the append-only session log stores a checkpoint
|
|
105
|
+
so resumed conversations use the compacted context. `/settings` offers token saver
|
|
106
|
+
(off/low/high/custom) and boost (on/off) instead of raw token-budget controls. Off
|
|
107
|
+
uses saved budgets; low/high reduce output, context and replay budgets and compact
|
|
108
|
+
earlier. Custom opens the advanced output/context/replay/compaction controls.
|
|
109
|
+
Boost keeps the same model, reasoning effort and token budgets. For substantial
|
|
110
|
+
requests it starts independent read-only code/UI investigation or research helpers
|
|
111
|
+
while the main agent works. Finished findings arrive at safe model-round boundaries
|
|
112
|
+
so the main agent can avoid duplicate investigation; remaining helpers are awaited
|
|
113
|
+
before concluding. Focused validation stays with the main agent.
|
|
114
|
+
Small tasks skip delegation. Boost tints the model name, `ϟ` glyph and composer rules
|
|
115
|
+
orange. While the model works, a highlight sweeps the full model bar and the lower
|
|
116
|
+
composer rule; at rest the bar holds its static orange. Set
|
|
117
|
+
`FLASHLITE_REDUCED_MOTION=1` (or `NO_COLOR`) to disable motion, and animations never
|
|
118
|
+
run in piped output.
|
|
119
|
+
Flashlite already uses fast context checks, bounded replay and parallel tool calls in
|
|
120
|
+
every mode; Boost cannot force faster provider inference. Presets do not overwrite
|
|
121
|
+
advanced config values. **Shift+Alt+Tab** toggles Boost in the interactive editor. Settings also include the local API key,
|
|
122
|
+
default model, reasoning effort, permission default, endpoint and **Memory** entry.
|
|
123
|
+
Pick Memory to append a global prompt for the next turn. Context checks use exact
|
|
124
|
+
counting near the limit where supported and estimates otherwise. Key entry is masked and never echoed; credentials come only from the local config. `/mode` picks `ask`, `files`, guarded `auto`,
|
|
125
|
+
or unguarded `auto`; `/mode auto` and `/mode unguarded` switch directly, and **Shift+Tab**
|
|
126
|
+
cycles the mode from the prompt. Modes are session-only. `/clear` resets the visible conversation and starts
|
|
127
|
+
a fresh transcript; `/exit` quits. Command notices and controls stay below the
|
|
128
|
+
input; agent answers and tool cards stay in chat. Pipes and tiny terminals use plain
|
|
129
|
+
command output.
|
|
130
|
+
- **Anchored scrolling and selection:** Page Up/Down scroll conversation history while
|
|
131
|
+
the input stays fixed, even during a streaming answer. New output does not pull you
|
|
132
|
+
away from the history you are reading. Page Down returns live; submitting a new
|
|
133
|
+
turn also returns live. Open command panels/pickers receive these keys instead.
|
|
134
|
+
Display history retains the latest 10,000 logical lines; full transcripts stay on disk.
|
|
135
|
+
Mouse reporting stays disabled so normal click-and-drag text selection and copy work
|
|
136
|
+
without a modifier key. The mouse wheel uses your terminal's native scrolling.
|
|
137
|
+
- **Effort:** `/effort` opens a picker for `auto`, `low`, `medium`, `high`, `xhigh`, `max`;
|
|
138
|
+
`/effort high` sets directly. The choice is shown in the bar and saved as
|
|
139
|
+
`reasoning_effort`. `flash --effort high` overrides it for this run, including `-p`.
|
|
140
|
+
`auto` omits an explicit API setting. Chat Completions uses `reasoning_effort`; Messages
|
|
141
|
+
uses thinking budgets (2,048 / 4,096 / 8,192 / 16,384 / 32,000 tokens), raising total
|
|
142
|
+
`max_tokens` when necessary to leave at least 4,096 tokens for the answer. Supported
|
|
143
|
+
levels depend on the model/router; a rejection is reported, not silently downgraded.
|
|
144
|
+
DeepSeek is the exception: its picker offers only the levels the model accepts
|
|
145
|
+
(`auto`, `low`, `high`, `max`; `auto`, `high`, `max` for `pro`) and the wire value is
|
|
146
|
+
coerced (`medium`/`xhigh` → `high`) so an unsupported level is never sent.
|
|
147
|
+
Signed thinking blocks are retained for tool continuations, never shown in chat.
|
|
148
|
+
- **Live agent cards:** the thinking indicator updates in place in the chat area, above
|
|
149
|
+
the composer, not in the bottom status strip. It is transient (not transcript/history
|
|
150
|
+
content), disappears when the answer starts, and stays hidden while viewing older
|
|
151
|
+
chat. Hidden model reasoning remains hidden. Tool activity updates a card **in the
|
|
152
|
+
conversation**, rather than pinning it to the composer; file writes/edits show pending
|
|
153
|
+
code as arguments stream, then update that same card to success/denied/error. An edit
|
|
154
|
+
over a readable file renders as a line-numbered unified diff — context rows, `+`/`−`
|
|
155
|
+
rows and a `+N −M` chip — with the code token-colored by the file's language; when the
|
|
156
|
+
target can't be read (a new file, a partial stream) it falls back to a plain `− old`/
|
|
157
|
+
`+ new` block. The finished card keeps the `+N −M` count. Completed
|
|
158
|
+
cards remain in chat history, and later replies follow them. Previews do not execute
|
|
159
|
+
changes: writes follow the selected permission mode. Completed cards name what a tool acted on
|
|
160
|
+
beside its timing — e.g. `✓ read_file 2x · src/a.ts · src/b.ts · 1.2s` and
|
|
161
|
+
`✗ run_command · npm test · 2m 05s` — and denied runs say what was denied; live queued cards show
|
|
162
|
+
the subject too (e.g. `● read_file src/a.ts`).
|
|
163
|
+
- **Image attachments:** **Ctrl+V** reads an image from the macOS clipboard and queues
|
|
164
|
+
it for your next prompt; your typed draft stays intact. Copy an image, or capture a
|
|
165
|
+
screenshot directly to the clipboard with **Ctrl+Cmd+Shift+4**, then Ctrl+V in `flash`.
|
|
166
|
+
**Cmd+V** still handles ordinary terminal text paste. An empty/text-only clipboard
|
|
167
|
+
produces a notice, not a message to the agent. Clipboard access occurs only on this
|
|
168
|
+
explicit shortcut, never in the background or via agent tools.
|
|
169
|
+
Pending filenames appear in the footer. Type your question and Enter, or Enter alone
|
|
170
|
+
to send an image-only turn. **Ctrl+X** removes pending attachments; `/clear` removes
|
|
171
|
+
both queued attachments and images already in conversation history. Images stay in
|
|
172
|
+
history across tool rounds and follow-up questions. Failed requests retain the original
|
|
173
|
+
user message and images in history once; send a continuation to retry without reattaching. Use an **image-capable model**: router/model support varies,
|
|
174
|
+
and unsupported images are reported rather than silently dropped.
|
|
175
|
+
- Up to 4 images per prompt, 10 MiB each, 20 MiB total. Clipboard PNG is preserved;
|
|
176
|
+
screenshot TIFF is converted to PNG using AppKit. No resizing or HEIC conversion.
|
|
177
|
+
TIFF input is bounded to 40 MiB / 40 million pixels before PNG conversion.
|
|
178
|
+
- `flash --image ./shot.png -p "Explain this screenshot"` works in one-shot mode;
|
|
179
|
+
repeat `--image` for multiple files. Without `-p`, images are queued in the REPL.
|
|
180
|
+
Local files support PNG, JPEG, WebP, GIF, quoted paths, `~/`, and absolute paths.
|
|
181
|
+
- No image slash commands. Type `/` for the palette or `/help` for shortcuts and recovery.
|
|
182
|
+
Clipboard images are local snapshots; nothing is uploaded until you submit a prompt.
|
|
183
|
+
Remote image URLs and Finder file-copy clipboard references are not supported.
|
|
184
|
+
- Clipboard access uses macOS's built-in `/usr/bin/osascript` with fixed AppKit/JXA
|
|
185
|
+
code via `execFile` (no shell, packages, native compilation, or temporary image files).
|
|
186
|
+
Reads time out after 10 seconds and Ctrl+C cancels; failed/cancelled reads keep the
|
|
187
|
+
queue intact. Shortcuts are disabled during turns, permission prompts, model pickers
|
|
188
|
+
and command panels.
|
|
189
|
+
- UI and Markdown transcripts show filenames/metadata only. Private JSONL transcripts
|
|
190
|
+
(mode 0600) retain the encoded image bytes, so they can be much larger and include
|
|
191
|
+
private image content. No clipboard payload is printed to the terminal.
|
|
192
|
+
- Context warnings use exact Messages token counting when available, otherwise a rough
|
|
193
|
+
2,048-token allowance per image; actual image tokens vary by model and resolution.
|
|
194
|
+
- **Live typing and steering:** the composer stays editable while the AI streams or
|
|
195
|
+
runs tools. **Enter** queues your text as steering; muted grey message rows above
|
|
196
|
+
the composer show what's pending, with the count in the existing footer. The latest
|
|
197
|
+
three messages are visible (earlier ones are summarized); long rows use an ellipsis.
|
|
198
|
+
Smaller terminals reduce this preview to preserve chat and the anchored composer.
|
|
199
|
+
Messages are delivered in order at the next safe model boundary,
|
|
200
|
+
after all results from an in-flight tool batch. A queued message received during
|
|
201
|
+
a final answer starts another response in the same turn. It does not interrupt a
|
|
202
|
+
running request or undo tools already executing — **Ctrl+C** stops the turn.
|
|
203
|
+
Pending previews update in place and disappear when sent. Applied messages use the
|
|
204
|
+
ordinary user-message styling, with no “steer:” prefix, and are included in the same
|
|
205
|
+
active workflow/transcript. Delivering them does not stop or restart the agent or a
|
|
206
|
+
running terminal command. A provider request already in flight cannot accept new
|
|
207
|
+
input retroactively; the next continuation receives the messages after tool results.
|
|
208
|
+
Pending text is display-only.
|
|
209
|
+
Unsubmitted drafts survive turn completion and temporarily yield to permission
|
|
210
|
+
questions, then return afterward. Permission answers are not steering. Ctrl+C
|
|
211
|
+
during approval cancels rather than approving the write. Unapplied steering on
|
|
212
|
+
cancellation, error or the tool-round cap returns to the editor for an explicit
|
|
213
|
+
retry; multiple restored messages are joined in order. Slash commands work during
|
|
214
|
+
a turn: `/model`, `/effort`, and `/mode` open their usual controls while
|
|
215
|
+
the AI continues. Model/effort changes apply to the **next turn**; current requests
|
|
216
|
+
and tool continuations retain their original settings, and usage/transcripts remain
|
|
217
|
+
attributed to the active turn's model.
|
|
218
|
+
Cancelling a command does not cancel the agent. Permission questions take priority
|
|
219
|
+
over open command controls. `/clear` cancels and awaits the active turn before
|
|
220
|
+
resetting history/queued steering; `/exit` stops both. Clipboard shortcuts remain
|
|
221
|
+
idle-only.
|
|
222
|
+
- **Agent loop:** no fixed tool-round cap — the turn runs until the model stops requesting
|
|
223
|
+
tools (bounded by the context budget, output limits and auto-compaction).
|
|
224
|
+
- **Tool-result budget:** to keep replay tokens bounded, older tool results are elided from
|
|
225
|
+
the request the model sees once their combined size exceeds `tool_result_budget_bytes`
|
|
226
|
+
(default 8,192; advanced value in config.json, 0 disables). The newest result is always
|
|
227
|
+
sent whole; older ones are replaced with a short `[earlier tool result elided …]` stub that
|
|
228
|
+
records the original size. This trims only the replayed request — canonical history, the
|
|
229
|
+
transcript and tool-call/result pairing stay intact, and the elision is idempotent across
|
|
230
|
+
rounds.
|
|
231
|
+
- **Multi-turn context:** each turn appends the user message and the assistant answer to
|
|
232
|
+
the conversation, so follow-ups continue the same context. The router only concatenates
|
|
233
|
+
a prior turn's chain of thought when the request carries `tools`; this CLI follows that
|
|
234
|
+
rule — OpenAI `reasoning_content` is retained on the assistant message but replayed only
|
|
235
|
+
while tools are present (so tool continuations keep continuity), and tool-less requests
|
|
236
|
+
omit it. Model reasoning is never shown in chat or written to the Markdown log; it stays
|
|
237
|
+
in the private JSONL transcript. "Steering" is separate: it queues a message delivered at
|
|
238
|
+
the next safe boundary *within* an active turn.
|
|
239
|
+
File and terminal approvals appear in a bordered panel above the composer with a
|
|
240
|
+
separate choice row, not as text in the normal input bar. File changes accept
|
|
241
|
+
`y` = once, `a` = all file changes (this session), `n` or Enter = deny.
|
|
242
|
+
`--auto-approve` or `"auto_approve": true` skips **file-write** prompts only.
|
|
243
|
+
`/mode auto` or `--auto` runs arbitrary terminal commands, still asking before the five
|
|
244
|
+
guarded-auto risk categories.
|
|
245
|
+
In `ask` and `files` modes, all terminal commands show the full
|
|
246
|
+
command/cwd/timeout and require their own explicit `y`/`yes`; blank, `a`/`all`, EOF
|
|
247
|
+
and cancellation do not authorize them. Unguarded auto skips file and command prompts
|
|
248
|
+
entirely, except recognizable catastrophic commands.
|
|
249
|
+
`/mode ask` revokes automatic grants;
|
|
250
|
+
queued auto/unguarded commands and unguarded file mutations cannot start after
|
|
251
|
+
revocation. Running commands need cancellation to stop; file operations also recheck
|
|
252
|
+
cancellation/authorization at bounded checkpoints.
|
|
253
|
+
Tool batches have four workers; approvals are asked just-in-time (one prompt at a time,
|
|
254
|
+
in call order) so an early tool can run while later calls still await approval, and
|
|
255
|
+
results keep their call order. After the last
|
|
256
|
+
permitted batch, one tools-disabled request lets the model evaluate its results.
|
|
257
|
+
Truncated/incomplete proposals never execute; unmatched/duplicate batch IDs stop with
|
|
258
|
+
an explicit interruption rather than corrupting the next request. Round exhaustion,
|
|
259
|
+
context exhaustion, invalid calls and model truncation have distinct recoverable
|
|
260
|
+
notices—not invented success. Completed tool evidence survives failures.
|
|
261
|
+
Interactive context checks reserve actual output/thinking capacity. Auto-compaction
|
|
262
|
+
can summarize older exchanges within a long active task, retaining current instructions
|
|
263
|
+
and the latest two complete exchanges (including required signed thinking). Attempts
|
|
264
|
+
are bounded and recounted; if retained context still cannot fit, the turn stops instead
|
|
265
|
+
of knowingly sending an overfull request. Fallback token counts remain estimates.
|
|
266
|
+
- **Keys:** Enter submits, arrows walk history, Ctrl+C interrupts (aborts a streaming
|
|
267
|
+
turn), Ctrl+D exits. **Ctrl+O** expands/collapses the latest completed tool batch's
|
|
268
|
+
output in place; the expanded view shares the chat viewport across calls, with
|
|
269
|
+
omitted lines indicated (full results remain in the private transcript).
|
|
270
|
+
Full output also remains in the private session transcript. `/agents` shows running
|
|
271
|
+
agents and role settings; select a role to launch or configure its model/effort.
|
|
272
|
+
Defaults inherit the current main model and effort at launch; changes affect future
|
|
273
|
+
launches, not running jobs. `/agents <role> <task>` starts one directly, while
|
|
274
|
+
`/agents list`, `/agents show <id>` and `/agents stop <id>` inspect or stop jobs.
|
|
275
|
+
Roles include ui-ux, code, minor, oracle, reviewer, coder and researcher. All agents
|
|
276
|
+
are read-only: they can inspect project files but never edit them or run shell
|
|
277
|
+
commands. Boost-spawned helpers remain read-only too. Researchers can read public
|
|
278
|
+
HTTPS text/HTML/JSON pages without a network prompt; local/private endpoints and
|
|
279
|
+
redirects are blocked. Running and finished agents remain listed above the input.
|
|
280
|
+
**Ctrl+R** opens a bash-style reverse history search: typing narrows,
|
|
281
|
+
Ctrl+R or ↑ walk older matches, ↓ newer, Enter accepts the match back into your draft (Enter
|
|
282
|
+
again submits), and Esc restores your exact pre-search draft. Multi-line bracketed pastes
|
|
283
|
+
submit as one turn. The model picker
|
|
284
|
+
navigates with ↑/↓ (or `j`/`k`), confirms with Enter, cancels with Esc or Ctrl+C.
|
|
285
|
+
- **Markdown:** answers render as markdown — `**bold**`, `` `code` ``, fenced code
|
|
286
|
+
blocks (light yellow), `#` headings, list markers, and `[links](url)` (URL dropped). Italic is
|
|
287
|
+
intentionally unsupported (`*`/`_` collide with identifiers). Fenced code with a recognized
|
|
288
|
+
language (`ts`, `js`, `jsx`, `json`, `bash`, `sh`, `zsh`, `python`, `go`, `rust`, `yaml`, `toml`)
|
|
289
|
+
is token-colored live and in one-shot — keywords orange, strings green, numbers yellow, comments
|
|
290
|
+
dim — while prose stays default. Unknown or absent languages keep the flat light-yellow accent,
|
|
291
|
+
and fence openers show their language tag in orange. Transcripts keep the raw
|
|
292
|
+
markdown; styling is display-only. Partial prose, bold/code spans, and code-block
|
|
293
|
+
content appear as chunks arrive, without waiting for a newline or Ctrl+C. Only
|
|
294
|
+
ambiguous Markdown prefixes/links use bounded lookahead. Streamed replies discard
|
|
295
|
+
oversized leading/trailing blank gaps and use one blank line between prose paragraphs;
|
|
296
|
+
code-block whitespace is preserved.
|
|
297
|
+
- **Sessions:** every turn appends to `~/.config/flashlite/sessions/` — a
|
|
298
|
+
markdown log plus a JSONL transcript. Resume the newest saved conversation with
|
|
299
|
+
`flash --resume latest`, a specific one with `flash --resume <session-id>`, or use
|
|
300
|
+
`/sessions` from the REPL to select one. New sessions record their canonical workspace;
|
|
301
|
+
resuming from a different folder is blocked rather than silently retargeting paths.
|
|
302
|
+
Legacy sessions require explicit workspace acknowledgement (CLI:
|
|
303
|
+
`--acknowledge-legacy-workspace`). Permissions are never restored from a transcript.
|
|
304
|
+
Validated context and recoverable checkpoints retain completed actions even after a
|
|
305
|
+
later provider failure. Transcript errors do not undo execution; a later successful
|
|
306
|
+
JSONL write checkpoints unsaved context. If logging keeps failing, evidence is retained
|
|
307
|
+
only in the running process, not guaranteed on disk. Future turns append to the same
|
|
308
|
+
private transcript; `/clear` starts fresh.
|
|
309
|
+
- Model IDs auto-route to the right wire dialect: `anthropic/*` speaks the Messages
|
|
310
|
+
API; everything else speaks Chat Completions. Bare `claude-*` and
|
|
311
|
+
`gpt-*`/`grok-*`/`deepseek-*` also work; other bare IDs ask for the full
|
|
312
|
+
provider-prefixed ID from `/model`.
|
|
313
|
+
|
|
314
|
+
## Custom commands, memory, hooks, todos, and undo
|
|
315
|
+
|
|
316
|
+
Five extension points build on the same tool/approval engine:
|
|
317
|
+
|
|
318
|
+
- **Custom slash commands.** Drop markdown files in `~/.config/flashlite/commands/`
|
|
319
|
+
(global) or `<project>/.flashlite/commands/` (project; shadows global by name). The filename
|
|
320
|
+
is the command (`review.md` → `/review`); the body is a prompt template. `$1`..`$9`
|
|
321
|
+
substitute positional arguments and `$ARGS` substitutes them all. Optional frontmatter
|
|
322
|
+
sets `description` (shown in the `/` palette) and `argument-hint`. No shell interpolation
|
|
323
|
+
runs — the body is prompt text, not a script.
|
|
324
|
+
- **Path completion.** Tab completes `@file` mentions and bare paths relative to the working
|
|
325
|
+
directory (directories get a trailing `/`); an unambiguous match resolves fully, an
|
|
326
|
+
ambiguous one extends to the longest common prefix.
|
|
327
|
+
- **Memory.** `~/.config/flashlite/memory.md` (global) and `<project>/.flashlite/memory.md`
|
|
328
|
+
(project) are loaded into the system prompt (bounded, treated as data). The `/settings`
|
|
329
|
+
**Memory** entry appends a global memory prompt; project memory can be edited directly.
|
|
330
|
+
- **Todos.** The agent can call `todo_write` to publish a task list
|
|
331
|
+
(`pending`/`in_progress`/`completed`/`cancelled`); it renders live in a dock strip with
|
|
332
|
+
`☐`/`◐`/`✓`/`✗` and clears on `/clear`.
|
|
333
|
+
- **Undo.** Before a mutating file tool runs, its target's original bytes are captured; a
|
|
334
|
+
turn's captures form a checkpoint. `/undo` reverts the most recent turn's file changes
|
|
335
|
+
(created files are removed, changed files restored). Shell side effects are never
|
|
336
|
+
captured — this only reverses the file tools.
|
|
337
|
+
- **Hooks + notifications.** Executable scripts named `PreToolUse`, `PostToolUse`,
|
|
338
|
+
`Notification`, or `Stop` in `~/.config/flashlite/hooks/` or `<project>/.flashlite/hooks/`
|
|
339
|
+
receive one JSON object on stdin. `PreToolUse` may veto a call with
|
|
340
|
+
`{"decision":"block","reason":"…"}`; hook errors fail open. A ~15s+ turn also fires a
|
|
341
|
+
macOS notification.
|
|
342
|
+
|
|
343
|
+
## Tool policy
|
|
344
|
+
|
|
345
|
+
Tools are available in the interactive agent REPL. Launch `flash` from the folder you
|
|
346
|
+
want it to work in. In `ask`, `files`, and guarded `auto`, **filesystem-tool paths**
|
|
347
|
+
are relative to that folder and confined there: absolute paths, `~`, parent-directory
|
|
348
|
+
escapes, and symlink escapes are refused. In unguarded `auto`, tools can use
|
|
349
|
+
absolute paths, `~/`, parent paths and external symlink parents across the drive,
|
|
350
|
+
wherever your current macOS account has permission. Terminal commands are separately
|
|
351
|
+
authorized (explicitly, by guarded auto, or by unguarded auto) and are
|
|
352
|
+
**not sandboxed**. Their starting directory is validated, but their effects can extend
|
|
353
|
+
to other files on your PC and the network. Ordinary `-p` is chat-only; explicit
|
|
354
|
+
`--agent -p` uses the same tools with the noninteractive approval policy above.
|
|
355
|
+
|
|
356
|
+
| Tool | What it does | Approval |
|
|
357
|
+
| --- | --- | --- |
|
|
358
|
+
| `read_file` | Read text, with UTF-8-safe byte pages up to 256 KiB and continuation metadata | No |
|
|
359
|
+
| `read_files` | Read 1–20 text files with per-file errors and a shared 256 KiB content budget | No |
|
|
360
|
+
| `file_info` | Inspect type, size, permissions and modification time; no file content | No |
|
|
361
|
+
| `list_dir` | Sorted directory pages using `offset` and `limit` (up to 500 per page) | No |
|
|
362
|
+
| `find_files` | Find paths by literal substring, optionally files/directories only | No |
|
|
363
|
+
| `grep` | Stream literal text search in a file or directory with bounded snippets and honest partial-result metadata | No |
|
|
364
|
+
| `write_file` | Create/overwrite text, including missing parents, up to 1 MiB | Yes |
|
|
365
|
+
| `edit_file` | Replace a nonempty, unique exact match; resulting file up to 1 MiB | Yes |
|
|
366
|
+
| `make_dir` | Create folders and missing parents | Yes |
|
|
367
|
+
| `copy_path` | Copy a file (including binary assets) or directory tree | Yes |
|
|
368
|
+
| `move_path` | Move/rename a file or directory | Yes |
|
|
369
|
+
| `remove_path` | Permanently delete a file/directory (no recovery store; use git or a copy) | Yes |
|
|
370
|
+
| `run_command` | Noninteractive terminal command with bounded output/time | Explicit yes; guarded auto for arbitrary commands except five risk categories; unguarded auto for everything |
|
|
371
|
+
|
|
372
|
+
File mutations marked Yes ask in `ask` mode and run automatically in `files`/`auto`/`unguarded`.
|
|
373
|
+
Neither file approve-all nor `--auto-approve` grants terminal authorization.
|
|
374
|
+
|
|
375
|
+
`copy_path` and `move_path` **never overwrite an existing destination**.
|
|
376
|
+
Copy/move/remove preflight trees with a 5,000-entry / 100 MiB limit. Tree
|
|
377
|
+
operations reject symlinks and special files rather than silently omitting entries.
|
|
378
|
+
Outside unguarded auto they also reject `.git` internals;
|
|
379
|
+
mutations reject symlink paths (even links staying inside the project), the working
|
|
380
|
+
directory itself, and `.git` internals. Unguarded auto lifts those project/protected-name
|
|
381
|
+
path guards, but write/edit still refuse final symlinks and non-regular files, and
|
|
382
|
+
tree operations still refuse symlink entries. Text tools reject NUL-containing binary
|
|
383
|
+
files. Write/edit may overwrite according to the selected permission mode; read before
|
|
384
|
+
changing an existing file. Aborted/revoked copies roll back their newly-created destination
|
|
385
|
+
contents; an individual OS copy syscall cannot be interrupted, and newly-created parent
|
|
386
|
+
folders may remain. File paging/search is not snapshot-isolated from concurrent rewrites.
|
|
387
|
+
|
|
388
|
+
`find_files` caps at 500 results / 5,000 inspected entries; `grep` caps at 200 results /
|
|
389
|
+
5,000 inspected entries (including directories). Both skip symlinks. Outside unguarded
|
|
390
|
+
auto they also skip `.git`, dependencies, common build directories and
|
|
391
|
+
`.DS_Store`; unguarded searches include those names, without dropping traversal/output
|
|
392
|
+
caps. Find patterns are literal, not globs or regular expressions.
|
|
393
|
+
|
|
394
|
+
Large text files can be inspected without increasing context arbitrarily:
|
|
395
|
+
`read_file(path, offset_bytes?, max_bytes?)` returns ordinary text for a complete small
|
|
396
|
+
file, or a JSON page with byte positions, total bytes and `next_offset_bytes` for a
|
|
397
|
+
large/ranged read. Page content is UTF-8-safe; continue using the returned offset.
|
|
398
|
+
`list_dir(path?, offset?, limit?)` sorts entries and reports the next offset when more
|
|
399
|
+
remain. Pages are not filesystem snapshots: restart after directory changes. A listing
|
|
400
|
+
that reaches its 100,000-entry scan bound is explicitly partial, without a misleading
|
|
401
|
+
continuation offset for an unscanned remainder.
|
|
402
|
+
|
|
403
|
+
`grep` can search a single regular file as well as a directory. Its default scan
|
|
404
|
+
budget is 16 MiB (configurable with `max_scan_bytes` up to 100 MiB), and results use
|
|
405
|
+
bounded snippets with byte positions. `max_output_bytes` controls the aggregate result
|
|
406
|
+
budget up to 64 KiB, including partial-result notices; `max_results` is capped at 200.
|
|
407
|
+
For a single file, pass the reported `next_start_byte` as `start_byte`; inspect matching ranges
|
|
408
|
+
with `read_file`. Directory traversal caps/skipped files are explicitly reported:
|
|
409
|
+
partial search is not an exhaustive “no matches.” Narrow the directory scope when
|
|
410
|
+
traversal is capped. Search may read up to 16.5 KiB of preceding context and 16 KiB of
|
|
411
|
+
unsearched suffix context for snippets/credential redaction; matches and continuation
|
|
412
|
+
stay within the forward scan budget. Read-page limits bound source bytes, not JSON
|
|
413
|
+
escaping/redaction overhead. Binary/special files remain unsupported by text tools.
|
|
414
|
+
|
|
415
|
+
Mutations from concurrent tool batches are serialized per project in this process.
|
|
416
|
+
Confinement is a path guard, not an OS sandbox against another process changing the
|
|
417
|
+
filesystem concurrently; avoid moving project folders or changing symlinks mid-operation.
|
|
418
|
+
|
|
419
|
+
**Removal is permanent.** `remove_path` deletes with `fs.rm`; there is no recovery
|
|
420
|
+
store, `list_removed`/`restore_file`, or automatic purge — git (or a copy made first) is
|
|
421
|
+
the only recovery. A shell `rm` is likewise a real deletion, and redirects/`tee` can
|
|
422
|
+
clobber a file. These file-tool protections are not an OS sandbox: an approved terminal
|
|
423
|
+
command can delete files the tools guard.
|
|
424
|
+
|
|
425
|
+
### Terminal commands
|
|
426
|
+
|
|
427
|
+
`run_command(command, cwd?, timeout_ms?)` uses macOS `/bin/zsh -f -c`, with ignored
|
|
428
|
+
stdin and piped stdout/stderr, not an interactive terminal. `cwd` must be an existing
|
|
429
|
+
project directory (default project root), except unguarded auto also permits existing
|
|
430
|
+
directories elsewhere on the drive. The default timeout is 60 seconds, maximum
|
|
431
|
+
5 minutes; commands are limited to 16 KiB and captured output to a combined 1 MiB.
|
|
432
|
+
Overflow terminates the command and reports truncation, not unlimited collection.
|
|
433
|
+
Results include status, exit code/signal, stdout/stderr and truncation; failure is
|
|
434
|
+
reported faithfully. The live card shows lifecycle only, not raw command output.
|
|
435
|
+
|
|
436
|
+
In ask/file-only mode, every command gets a separate approval. Guarded auto runs
|
|
437
|
+
arbitrary commands without a prompt except for five risk categories (below); unguarded
|
|
438
|
+
auto runs every command except recognizable catastrophic deletion/disk destruction.
|
|
439
|
+
When a command needs approval, its full text,
|
|
440
|
+
canonical cwd and effective timeout appear in chat before the anchored yes/no question;
|
|
441
|
+
control/invisible characters and backslashes are escaped visibly rather than executed
|
|
442
|
+
by the terminal. Known router-key-bearing commands are rejected before display.
|
|
443
|
+
Commands use a minimal environment allowlist (standard path/home/user/temp/locale
|
|
444
|
+
variables, `TERM=dumb`), not ambient credential variables. Known router credentials
|
|
445
|
+
are redacted from captured output before model/history/transcript use. This is not
|
|
446
|
+
comprehensive secret isolation: commands can still read local configuration or make
|
|
447
|
+
network requests. Review what you approve. `/bin/zsh -f` disables ordinary user rc
|
|
448
|
+
loading; it does not isolate system startup behavior.
|
|
449
|
+
|
|
450
|
+
### Guarded auto
|
|
451
|
+
|
|
452
|
+
Enable with `flash --auto`, `/mode auto`, or the `/mode` picker. It is opt-in for this
|
|
453
|
+
session, never saved as a default. `files` mode and legacy `auto_approve` remain file-only;
|
|
454
|
+
`--auto`, `--auto-approve`, and `--absolute` are mutually exclusive.
|
|
455
|
+
|
|
456
|
+
Guarded auto is **trust-by-default**: arbitrary commands and pipelines run without a
|
|
457
|
+
prompt, including unknown executables, interpreters, builds, tests and file mutations.
|
|
458
|
+
Exactly five categories still ask, and none can be hidden behind a wrapper, pipeline,
|
|
459
|
+
env assignment or literal `sh -c` body:
|
|
460
|
+
|
|
461
|
+
- **Network access** — `curl`, `wget`, `nc`, `ssh`, `scp`, `rsync`, `git fetch|pull|push|clone|remote`, and similar.
|
|
462
|
+
- **Installs / package managers** — `npm install|ci|add|…`, `pnpm`/`yarn add`, `brew`, `pip`, `apt`, `cargo install`, `go get`, `npx`, and similar.
|
|
463
|
+
- **Privilege escalation** — `sudo`, `doas`, `su`, `pkexec`.
|
|
464
|
+
- **Paths outside the project** — absolute paths, `~`, parent (`..`) traversal, and symlink escapes.
|
|
465
|
+
- **Destructive Git** — `git reset --hard`, `git clean -f…`, `git push --force`, `git branch -D`.
|
|
466
|
+
|
|
467
|
+
Obviously catastrophic deletion or disk commands (recursive deletion of a filesystem
|
|
468
|
+
root, home or volume; `diskutil` erase; `mkfs`; `dd`/redirection to a raw disk) are
|
|
469
|
+
**refused outright**, not offered. Syntax the classifier cannot reduce to inspectable
|
|
470
|
+
words — command substitution, backticks, globs, here-docs, `eval`/`source`, subshells
|
|
471
|
+
and background jobs — fails closed and asks. Paths must resolve inside the project,
|
|
472
|
+
plus the CLI's own `~/.config/flashlite` tree for reads. `cp`/`mv` never overwrite.
|
|
473
|
+
|
|
474
|
+
**Guarded auto trusts arbitrary commands and project code.** A classifier is not proof
|
|
475
|
+
of safety, this is not an OS sandbox, and buildings/tests can execute arbitrary code with
|
|
476
|
+
side effects. There is an external filesystem race between inspection and execution;
|
|
477
|
+
command text cannot provide isolation. Do not enable auto in an untrusted repository.
|
|
478
|
+
Turning auto off revokes queued grants, including after turning it on again, but does
|
|
479
|
+
not interrupt work already running.
|
|
480
|
+
|
|
481
|
+
### Unguarded auto
|
|
482
|
+
|
|
483
|
+
Enable with `flash --absolute`, `/mode unguarded`, or the `/mode` picker. It takes effect
|
|
484
|
+
immediately with a one-line notice — there is no typed acknowledgement or disclaimer
|
|
485
|
+
gate. A `/mode` switch applies to the session; the `/config` default-mode picker can save
|
|
486
|
+
it as the launch default (written to config as `unguarded`, never `absolute`). An
|
|
487
|
+
interactive terminal is required, and `--absolute` is rejected with `-p`, `--check`, or
|
|
488
|
+
piped input/output.
|
|
489
|
+
|
|
490
|
+
**Unguarded auto has no approval prompts and no guarded-auto ask list.** Ordinary `rm`,
|
|
491
|
+
builds, installs, Git changes, elevated, unknown and opaque commands all run. File tools
|
|
492
|
+
can read/change paths across the drive, including absolute paths and `~/`, and commands
|
|
493
|
+
may start outside the project. The mode badge reads `unguarded auto`. Use only when you
|
|
494
|
+
trust the task and the files/code the agent will encounter.
|
|
495
|
+
|
|
496
|
+
The only exceptional action-confirmation gate recognizes **very large irreversible
|
|
497
|
+
operations**: recursive deletion of a filesystem root, whole home/user tree, named
|
|
498
|
+
system root or whole mounted volume (including whole-tree glob variants); destructive
|
|
499
|
+
`diskutil` erase/partition/APFS-delete operations; formatting a raw disk with
|
|
500
|
+
`mkfs`/`newfs`; `dd` writing a raw disk; or shell output redirected to a raw disk.
|
|
501
|
+
Recognized literal `sudo`/`env` wrappers, compound commands and `sh`/`zsh`/`bash -c`
|
|
502
|
+
bodies are checked too. These show the exact command/canonical cwd/timeout and require
|
|
503
|
+
an explicit **yes for that command only**, without disabling unguarded auto. Denial,
|
|
504
|
+
cancellation or revocation prevents that command from starting.
|
|
505
|
+
|
|
506
|
+
This is a **best-effort recognizer, not a safety guarantee**: it does not inspect
|
|
507
|
+
script files, aliases, arbitrary expansions, remote code or general interpreter
|
|
508
|
+
programs, and it does not make opaque commands safe. Unrecognized actions still run
|
|
509
|
+
without a prompt in unguarded auto; do not rely on this gate to protect your machine.
|
|
510
|
+
|
|
511
|
+
This is current-account access, **not automatic root/sudo or a bypass of macOS privacy
|
|
512
|
+
permissions**. No interactive password entry is provided. Tool byte/tree limits,
|
|
513
|
+
regular-file and symlink-tree rules, no-overwrite copy/move and permanent-deletion
|
|
514
|
+
guards, bounded command output/time and cancellation remain. Commands can still
|
|
515
|
+
perform permanent deletion. Known router credentials are rejected in commands and
|
|
516
|
+
redacted from command output and unguarded file-tool results/errors before history;
|
|
517
|
+
this is not comprehensive secret isolation or a network sandbox.
|
|
518
|
+
|
|
519
|
+
Unguarded auto is session-only, never saved or enabled by `auto_approve`. `/mode ask`
|
|
520
|
+
disables it; queued unguarded commands/mutations recheck their mode generation before
|
|
521
|
+
executing. Turning it back on cannot revive old grants. Running commands are not
|
|
522
|
+
interrupted by a mode change; use Ctrl+C to stop the active turn. File tools recheck
|
|
523
|
+
live authorization at bounded checkpoints and before commits; revoked copies roll back
|
|
524
|
+
new destination data.
|
|
525
|
+
|
|
526
|
+
### Command cancellation
|
|
527
|
+
|
|
528
|
+
Ctrl+C, `/clear`, `/exit`, timeout and output overflow terminate the process group,
|
|
529
|
+
with TERM→KILL escalation. Normal shell completion also cleans up ordinary background
|
|
530
|
+
descendants. There is no persistent-background-job or interactive-input API; programs
|
|
531
|
+
requiring a TTY or password entry may fail. Descendants that detach into another
|
|
532
|
+
process group/session can escape cleanup; no sandbox guarantee is made. Commands
|
|
533
|
+
serialize with project mutations in this process and recheck cancellation before
|
|
534
|
+
queued execution starts. Tool results remain paired with calls after cancellation,
|
|
535
|
+
so continuing the conversation does not send broken tool history.
|
|
536
|
+
|
|
537
|
+
For example: “Create a small website in `site/`, copy my assets into it, and run its
|
|
538
|
+
tests.” In ask mode, the agent creates the structure with approval and asks before
|
|
539
|
+
running tests. In guarded auto, the project work runs without per-call prompts, but a
|
|
540
|
+
network install or `sudo` still asks. Package installs and downloads are performed
|
|
541
|
+
through authorized commands, not silently through filesystem tools.
|
|
542
|
+
|
|
543
|
+
## Development
|
|
544
|
+
|
|
545
|
+
```
|
|
546
|
+
src/index.ts entry, flags, bootstrap test/ node:test suites
|
|
547
|
+
src/client.ts RouterClient (HTTP, retry) scripts/ SSE harness (live)
|
|
548
|
+
src/adapters/ openai.ts, anthropic.ts
|
|
549
|
+
src/tools.ts file tools + confinement src/loop.ts agent round driver
|
|
550
|
+
src/repl.ts REPL shell src/lineinput.ts raw-mode editor
|
|
551
|
+
src/sessions.ts transcripts
|
|
552
|
+
src/markdown.ts terminal markdown renderer
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
Live wire-shape verification:
|
|
556
|
+
|
|
557
|
+
```bash
|
|
558
|
+
node scripts/sse-harness.ts --model <id> --dialect openai|anthropic|auto [--tools] [--save test/fixtures/x.sse]
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
## Manual E2E checklist
|
|
562
|
+
|
|
563
|
+
- [ ] `flash --check` green; `npm test` green; `npm run typecheck` clean
|
|
564
|
+
- [ ] `/model` → arrow-key picker → streamed chat answers (markdown-rendered)
|
|
565
|
+
- [ ] multi-tool task (create → edit → grep) exercising y / a / n approvals
|
|
566
|
+
- [ ] Page Up/Down scroll chat with input anchored, including mid-stream; mouse drag selects text
|
|
567
|
+
- [ ] Ctrl+V queues a clipboard screenshot without submitting; Ctrl+X clears pending images
|
|
568
|
+
- [ ] text Cmd+V still works; `/` palette has no image commands; `/help` opens shortcuts
|
|
569
|
+
- [ ] `/clear` starts a fresh transcript; session files exist
|
|
570
|
+
- [ ] type during streaming; Enter queues steering and leaves tool/result ordering valid
|
|
571
|
+
- [ ] an unfinished draft survives a permission question and turn completion
|
|
572
|
+
- [ ] Ctrl+C mid-stream prints `*[stopped]*` and restores any unapplied steering
|
|
573
|
+
- [ ] `flash -p "hi"` one-shot; `echo "…" | flash` piped mode works
|
|
574
|
+
- [ ] bad key exits with the 401 hint; `FLASHLITE_BASE_URL` pointing at a dead port
|
|
575
|
+
reports a network error, not a crash
|
|
576
|
+
- [ ] `flash --debug` shows frame sizes and retry metadata without message content or credentials
|
|
577
|
+
|
|
578
|
+
## Notes
|
|
579
|
+
|
|
580
|
+
- **Zero runtime deps** — `src/` and `scripts/` use Node built-ins only.
|
|
581
|
+
- **Never print an API key** — not even masked. Real keys live only in the local config.
|
|
582
|
+
- Diagnostic logging never includes message content. Private transcripts live under
|
|
583
|
+
`~/.config/…/sessions/`; normal UI/one-shot output shows the requested answer.
|
|
584
|
+
`--debug` reports metadata only, never raw SSE payloads.
|