autopilot-ai 1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Sina Meraji
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/PLAN.md ADDED
@@ -0,0 +1,59 @@
1
+ # Implementation Plan: Web Search, GitHub Read-Only, Headless Browser
2
+
3
+ ## Overview
4
+ Add three new native tool categories to KimiFlare:
5
+ 1. **Web Search** (`search_web`) — query-based web search without requiring a known URL
6
+ 2. **GitHub Read-Only** (`github_read_pr`, `github_read_issue`, `github_read_code`) — structured GitHub API access, whitelisted in plan mode
7
+ 3. **Headless Browser** (`browser_fetch`) — JS-rendered page extraction via Playwright
8
+
9
+ ## Design Decisions
10
+
11
+ ### Web Search
12
+ - **Provider**: DuckDuckGo HTML scraping (no API key required)
13
+ - **Fallback**: If DuckDuckGo blocks us, degrade gracefully with a clear error
14
+ - **Output**: List of results with title, URL, and snippet
15
+ - **Permission**: `needsPermission: false` (read-only, no side effects)
16
+ - **Plan mode**: Whitelisted (read-only)
17
+
18
+ ### GitHub Read-Only
19
+ - **Auth**: Reuse existing `githubOAuthToken` from config
20
+ - **Tools**:
21
+ - `github_read_pr` — read a PR by owner/repo/number
22
+ - `github_read_issue` — read an issue by owner/repo/number
23
+ - `github_read_code` — read file contents from a repo at a specific ref
24
+ - **Permission**: `needsPermission: false` (read-only, no side effects)
25
+ - **Plan mode**: Whitelisted (explicitly read-only)
26
+ - **Why native tools vs gh CLI**: Native tools are always safe (no write ops), so they bypass permission prompts and work in plan mode
27
+
28
+ ### Headless Browser
29
+ - **Engine**: Playwright (Chromium in headless mode)
30
+ - **Behavior**: Launch invisible browser, navigate, wait for load, extract text + screenshot option
31
+ - **Output**: Extracted page text (via readability-style extraction) + optional screenshot path
32
+ - **Permission**: `needsPermission: false` for text extraction, `needsPermission: true` for screenshots (files on disk)
33
+ - **Plan mode**: Text extraction whitelisted; screenshots blocked
34
+ - **Dependency**: `playwright` as optional peer dependency — tool gracefully errors if not installed
35
+
36
+ ## Files to Create/Modify
37
+
38
+ ### New files
39
+ - `src/tools/web-search.ts` — DuckDuckGo search implementation
40
+ - `src/tools/github.ts` — GitHub API read-only tools
41
+ - `src/tools/browser.ts` — Playwright headless browser tool
42
+ - `src/tools/web-search.test.ts` — tests for search
43
+ - `src/tools/github.test.ts` — tests for GitHub tools
44
+ - `src/tools/browser.test.ts` — tests for browser tool
45
+
46
+ ### Modified files
47
+ - `src/tools/executor.ts` — register new tools in `ALL_TOOLS`
48
+ - `src/tools/reducer.ts` — add reduction rules for `search_web`, `github_read_*`, `browser_fetch`
49
+ - `src/mode.ts` — update `isBlockedInPlanMode` and `isReadOnlyBash` if needed
50
+ - `src/agent/system-prompt.ts` — mention new tools in static prefix (optional)
51
+ - `package.json` — add `playwright` to optional dependencies or devDependencies
52
+
53
+ ## Implementation Order
54
+ 1. Web search (simplest, no external deps)
55
+ 2. GitHub read-only (reuses existing auth)
56
+ 3. Headless browser (most complex, optional dep)
57
+ 4. Reducer updates + mode updates
58
+ 5. Tests
59
+ 6. Typecheck + commit
package/README.md ADDED
@@ -0,0 +1,457 @@
1
+ <h1 align="center">autopilot <sub>(formerly kimiflare)</sub></h1>
2
+
3
+ <p align="center">
4
+ <a href="https://www.npmjs.com/package/autopilot-ai"><img src="https://img.shields.io/npm/v/autopilot-ai?style=flat-square&color=cb3837" alt="npm version"></a>
5
+ <a href="https://www.npmjs.com/package/autopilot-ai"><img src="https://img.shields.io/npm/dm/autopilot-ai?style=flat-square&color=cb3837" alt="npm downloads"></a>
6
+ <a href="https://github.com/sinameraji/autopilot/blob/main/LICENSE"><img src="https://img.shields.io/github/license/sinameraji/autopilot?style=flat-square&color=2ea44f" alt="license"></a>
7
+ <img src="https://img.shields.io/badge/node-%3E%3D20-339933?style=flat-square&logo=nodedotjs&logoColor=white" alt="Node.js >= 20">
8
+ <img src="https://img.shields.io/badge/typescript-5.7-3178c6?style=flat-square&logo=typescript&logoColor=white" alt="TypeScript">
9
+ <a href="https://openrouter.ai"><img src="https://img.shields.io/badge/runs%20on-OpenRouter-6566f1?style=flat-square" alt="Runs on OpenRouter"></a>
10
+ </p>
11
+
12
+ <p align="center">
13
+ <strong>A terminal coding agent that runs any model on <a href="https://openrouter.ai">OpenRouter</a> with your own key.</strong><br>
14
+ One key, 400+ models, per-turn billed cost.
15
+ </p>
16
+
17
+ ## How it works
18
+
19
+ KimiFlare sends every model call to **[OpenRouter](https://openrouter.ai)** using **your own OpenRouter API key** — bring-your-own-key, nothing proxied, nothing marked up. On first run you paste the key once (it's checked against OpenRouter before it's saved) and pick a model. That's the whole setup.
20
+
21
+ - **Any model, one key.** The model picker is OpenRouter's live catalog — Claude, GPT, Gemini, Grok, Qwen, GLM, Kimi, DeepSeek, free models and more — opening on the best & latest by benchmark score, with fuzzy search over everything. Switch any time with `/model`.
22
+ - **Real cost, per turn.** OpenRouter reports what each generation actually cost; the status bar shows it (a local estimate marked `≈$` only until the billed number arrives). `/cost` totals it by session, day, month and all time.
23
+ - **Reliable tool calling.** Requests only go to upstream providers that support every parameter autopilot sends (tools above all), and OpenRouter routes tool-calling traffic to the providers with the best tool-call success rates. The status bar shows which provider served the last turn.
24
+ - **Prompt caching that stays warm.** Each session pins to one upstream provider (OpenRouter sticky routing), so the long, stable prompt prefix keeps hitting the provider's cache across turns.
25
+
26
+ ## What to remember
27
+
28
+ - **Up to 1M+ context** (model-dependent) — Read entire modules, large configs, and full stack traces without the model losing track.
29
+ - **Image understanding** — Drop image paths (PNG, JPG, WebP, GIF, BMP up to 5 MB) into any prompt. Great for UI reviews, diagrams, and screenshots.
30
+ - **Plan / Edit / Auto modes** — `plan` is a whitelist-only research mode: only read-only tools (read, glob, grep, web search, GitHub read-only, browser fetch) are allowed. Writes, edits, mutating bash, MCP tools, and LSP renames are all blocked. `edit` (default) prompts per mutating call. `auto` approves everything for trusted tasks.
31
+ - **Windows support** — OS-aware shell auto-detects `cmd.exe` / PowerShell on Windows, `bash` on Unix. The `bash` tool works out of the box on all platforms.
32
+ - **Message queuing** — Submit multiple messages while the agent is busy; they queue and auto-drain. Escape interrupts the current turn but preserves the queue.
33
+ - **Smart permission modal** — Denying a tool opens inline feedback so you can tell the agent what to do instead. Keyboard-native navigation (`↑/↓`, `j/k`, `Alt+1/2/3`).
34
+ - **Loop guardrails** — Agent hard-stops when all tools in a turn are blocked, preventing infinite token-burning cycles.
35
+ - **Persistent all-time cost history** — Append-only `history.jsonl` tracks daily usage forever, so `/cost` shows true all-time and monthly totals that survive across sessions and version updates.
36
+ - **LSP + MCP** — Semantic code intelligence (hover, go-to-definition, references, diagnostics) via Language Server Protocol. Extend with external tools via Model Context Protocol.
37
+ - **Local structured memory** — SQLite + embeddings cross-session memory. The agent recalls facts, instructions, and preferences across sessions via `remember`, `recall`, and `forget` tools.
38
+ - **Web search, GitHub, and headless browser** — Research the web, read GitHub repos, and fetch JavaScript-rendered pages without leaving your terminal.
39
+
40
+ ## Recently shipped
41
+
42
+ - **OpenRouter as the model provider** — Every OpenRouter model, your own key, billed cost per turn. Replaces Cloudflare Workers AI / AI Gateway (see [Upgrading from Cloudflare](#upgrading-from-the-cloudflare-version)).
43
+ - **OS-aware shell with Windows support** — Auto-detects `cmd.exe`, PowerShell, or bash based on platform. Override with `KIMIFLARE_SHELL` or `/shell`.
44
+ - **Smart permission modal with inline feedback** — Deny a tool and immediately tell the agent what to do instead. Keyboard-native navigation with `↑/↓`, `j/k`, `Alt+1/2/3`.
45
+ - **True message queuing** — Enter queues messages while the agent is busy; Escape interrupts and auto-drains the queue.
46
+ - **Hard-stop loop guardrail** — Stops token-burning cycles when all tools in a turn are blocked.
47
+ - **Headless SDK** — Programmatic `createAgentSession` API and JSONL-over-stdio RPC mode for building on top of KimiFlare.
48
+
49
+ See the full changelog at [github.com/sinameraji/autopilot/releases](https://github.com/sinameraji/autopilot/releases).
50
+
51
+ ## Quick start
52
+
53
+ ```sh
54
+ npm install -g autopilot-ai
55
+ autopilot
56
+ ```
57
+
58
+ On first run autopilot asks for your OpenRouter API key (create one at <https://openrouter.ai/keys>) and a model. That's it.
59
+
60
+ Or run without installing:
61
+
62
+ ```sh
63
+ npx autopilot-ai
64
+ ```
65
+
66
+ > **Coming from `kimiflare`?** The package was renamed. Run `npm uninstall -g kimiflare && npm install -g autopilot-ai` and use `autopilot` instead of `kimiflare`. Your settings, sessions, memory and cost history are kept (they stay in `~/.config/kimiflare` and `~/.local/share/kimiflare`), and `KIMIFLARE_*` environment variables still work.
67
+
68
+ Requires Node.js ≥ 20.
69
+
70
+ ### Your OpenRouter key
71
+
72
+ Three ways to provide it — the first one found wins:
73
+
74
+ 1. **Environment:** `OPENROUTER_API_KEY` (or `KIMIFLARE_OPENROUTER_KEY`). With this set, the setup screen never appears — the way to run kimiflare headless (CI, a VM, a container).
75
+ 2. **Setup screen / CLI:** paste it on first run, or run `autopilot auth openrouter` (prompts without echo, validates, saves). Inside the TUI, `/key set <key>` replaces it.
76
+ 3. **Config file:** `"openrouterApiKey": "sk-or-…"` in `~/.config/kimiflare/config.json` (created with mode 600).
77
+
78
+ `/key` shows which key is in use, what it has spent and how much credit is left. Model calls — including memory embeddings and small internal side-calls (summaries, memory extraction) — are all billed to this key.
79
+
80
+ A key with no credits can still use OpenRouter's **free models** (the "Free" section of `/model`, ids ending in `:free`), subject to OpenRouter's daily request cap.
81
+
82
+ ### Upgrading from the Cloudflare version
83
+
84
+ Earlier kimiflare versions ran on Cloudflare Workers AI / AI Gateway. On the first launch after upgrading you'll be asked for an OpenRouter key once; after that:
85
+
86
+ - Your settings (theme, MCP/LSP servers, hooks, memory, sessions, cost history) carry over.
87
+ - Model ids are migrated (`@cf/moonshotai/kimi-k2.6` → `moonshotai/kimi-k2.6`, and so on), and the retired Cloudflare fields (OAuth login, gateway, Unified Billing, provider keys) are removed from `config.json`.
88
+ - Memory keeps working unchanged: embeddings use the same `bge-base-en-v1.5` model, now via OpenRouter.
89
+ - `/gateway`, `autopilot auth cloudflare`, `--cloud` and the Cloud-only commands are gone. `/multi-agent` (Commute) still deploys to your Cloudflare account and keeps using `CLOUDFLARE_ACCOUNT_ID` / `CLOUDFLARE_API_TOKEN` for that.
90
+
91
+ ### Model
92
+
93
+ You pick the model on first run, and can switch any time with `/model`. The picker opens on the **best & latest** models — recent, tool-capable models ranked by the agentic and coding benchmark scores OpenRouter publishes (Artificial Analysis), at most two per lab — so it stays current as new models ship, with no list maintained in code. Start typing to fuzzy-search all of them (`sonet` finds Claude Sonnet, `gpt 6` the GPT-6 family). Or set one directly:
94
+
95
+ ```sh
96
+ /model moonshotai/kimi-k3 # 1M context
97
+ /model anthropic/claude-sonnet-5
98
+ /model deepseek/deepseek-v4-flash
99
+ autopilot -m moonshotai/kimi-k2.7-code -p "..."
100
+ ```
101
+
102
+ Any OpenRouter model id works, including variants like `:free` and `:nitro`. Models OpenRouter lists without tool calling are hidden from the picker — a coding agent needs tools.
103
+
104
+ **Provider routing (optional).** OpenRouter serves most models through several upstream providers. autopilot always requires providers that support every parameter it sends, and otherwise leaves routing to OpenRouter (price-weighted, uptime-aware, tool-calling quality first, sticky per session for caching). To steer it, add an `openrouterProvider` object to the config file — any of OpenRouter's [provider preferences](https://openrouter.ai/docs/guides/routing/provider-selection):
105
+
106
+ ```json
107
+ { "openrouterProvider": { "ignore": ["SomeProvider"], "data_collection": "deny" } }
108
+ ```
109
+
110
+ Avoid `order` / `sort` unless you need them: they turn off sticky routing, which is what keeps the prompt cache warm.
111
+
112
+ ### Custom gateway endpoint
113
+
114
+ Point every model call at your own OpenAI-compatible endpoint instead of OpenRouter — useful when a
115
+ host application (CI, an agents platform, a container) fronts model access with its own broker and
116
+ doesn't want to hand autopilot a raw provider key:
117
+
118
+ ```sh
119
+ export KIMIFLARE_BASE_URL="https://your-broker.example.com/v1" # /chat/completions is appended
120
+ export KIMIFLARE_API_KEY="<bearer for that endpoint>" # optional; header omitted if unset
121
+ autopilot -p "..." # or --mode rpc — no OpenRouter key needed
122
+ ```
123
+
124
+ The same pair can be persisted in `~/.config/kimiflare/config.json` as `baseUrl` / `apiKey`
125
+ (env vars win over the file, field by field). When a base URL is configured:
126
+
127
+ - Chat requests go to `<baseUrl>/chat/completions` and memory embeddings to `<baseUrl>/embeddings`,
128
+ with `Authorization: Bearer $KIMIFLARE_API_KEY` (no `Authorization` header at all when the key is
129
+ unset — e.g. a local llama.cpp/Ollama server).
130
+ - Model ids pass through in the request body unchanged; your endpoint owns provider dispatch.
131
+ - Cost is the local estimate only — your endpoint does its own metering.
132
+
133
+ ### One-shot mode
134
+
135
+ ```sh
136
+ autopilot -p "summarize PLAN.md" # stream answer to stdout
137
+ autopilot -p "..." --dangerously-allow-all # auto-approve mutating tools (for scripts)
138
+ autopilot -p "..." --reasoning # include chain-of-thought in stderr
139
+ ```
140
+
141
+ ### Headless SDK
142
+
143
+ Use KimiFlare programmatically from your own application — no TUI required.
144
+
145
+ ```ts
146
+ import { createAgentSession } from "autopilot-ai/sdk";
147
+
148
+ const { session } = await createAgentSession({
149
+ cwd: "/path/to/project",
150
+ config: {
151
+ openrouterApiKey: process.env.OPENROUTER_API_KEY,
152
+ model: "moonshotai/kimi-k2.7-code",
153
+ },
154
+ });
155
+
156
+ // Stream every event: text deltas, tool calls, tasks, usage
157
+ session.subscribe((event) => {
158
+ console.log(event.type, event);
159
+ });
160
+
161
+ // Send a prompt
162
+ await session.prompt("Refactor auth to JWT + Redis");
163
+
164
+ // Mid-flight correction while the agent is still running
165
+ await session.steer("Use Redis instead of in-memory store");
166
+
167
+ // After the turn finishes
168
+ await session.followUp("Also add unit tests");
169
+
170
+ // Clean up
171
+ session.dispose();
172
+ ```
173
+
174
+ **Key features:**
175
+ - `subscribe()` — receive typed events (`text_delta`, `tool_call`, `tool_result`, `task_update`, `usage`, `warning`, `error`, `done`, etc.)
176
+ - `prompt()` / `steer()` / `followUp()` — full conversation lifecycle
177
+ - `pause()` / `resume()` — graceful preemption
178
+ - `getStatus()` / `getUsage()` — inspect session state
179
+ - Custom `permissionHandler` — decide programmatically whether to allow mutating tools
180
+ - Optional `memoryEnabled`, `lspEnabled`, `costAttribution` flags
181
+
182
+ #### SDK Authentication
183
+
184
+ The SDK needs an OpenRouter API key — or a [custom gateway endpoint](#custom-gateway-endpoint)
185
+ (`baseUrl` / `apiKey` in `config`, or `KIMIFLARE_BASE_URL` / `KIMIFLARE_API_KEY`), in which case no
186
+ OpenRouter key is required. Resolved in this priority order:
187
+
188
+ 1. **Explicit `config` object** (`openrouterApiKey`) — recommended for apps
189
+ 2. **Environment variables**: `OPENROUTER_API_KEY` / `KIMIFLARE_OPENROUTER_KEY`
190
+ 3. **Config file**: `~/.config/kimiflare/config.json`
191
+
192
+ Pass `provider` in `createAgentSession` options to set OpenRouter provider-routing preferences for that session.
193
+
194
+ **For Electron / desktop apps**, we recommend storing the key in the OS keychain (e.g. Electron `safeStorage` or `keytar`) and passing it explicitly:
195
+
196
+ ```ts
197
+ import { createAgentSession } from "autopilot-ai/sdk";
198
+
199
+ const openrouterApiKey = await keytar.getPassword("autopilot", "openrouter");
200
+
201
+ const { session } = await createAgentSession({
202
+ cwd: projectPath,
203
+ config: { openrouterApiKey },
204
+ });
205
+ ```
206
+
207
+ #### RPC mode (subprocess)
208
+
209
+ If you need process isolation or a non-Node consumer, run KimiFlare in JSONL-over-stdio RPC mode:
210
+
211
+ ```sh
212
+ node bin/autopilot.mjs --mode rpc
213
+ ```
214
+
215
+ Give the subprocess `OPENROUTER_API_KEY` — or a [custom gateway endpoint](#custom-gateway-endpoint)
216
+ (`KIMIFLARE_BASE_URL` + `KIMIFLARE_API_KEY`), ideal for host apps that broker model access themselves.
217
+
218
+ ```ts
219
+ import { spawn } from "node:child_process";
220
+
221
+ const proc = spawn("npx", ["autopilot-ai", "--mode", "rpc"], {
222
+ cwd: projectPath,
223
+ stdio: ["pipe", "pipe", "pipe"],
224
+ });
225
+
226
+ // Read events
227
+ proc.stdout.on("data", (chunk) => {
228
+ for (const line of chunk.toString().split("\n")) {
229
+ if (!line.trim()) continue;
230
+ const event = JSON.parse(line);
231
+ console.log(event.type, event);
232
+ }
233
+ });
234
+
235
+ // Send commands
236
+ proc.stdin.write(JSON.stringify({ type: "new_session" }) + "\n");
237
+ proc.stdin.write(JSON.stringify({ type: "prompt", message: "Hello" }) + "\n");
238
+
239
+ // Resolve a permission request
240
+ proc.stdin.write(
241
+ JSON.stringify({ type: "resolve_permission", requestId: "req_0", decision: "allow" }) + "\n"
242
+ );
243
+
244
+ // Resume a previous session after a process restart (the `new_session`
245
+ // response echoes back the sessionId to store for later)
246
+ proc.stdin.write(JSON.stringify({ type: "new_session", sessionId: "sdk-session-…" }) + "\n");
247
+ ```
248
+
249
+ ### Image understanding
250
+
251
+ ```sh
252
+ autopilot
253
+ › fix the layout bug in this screenshot docs/bug.png
254
+ › convert this mockup design.png to Tailwind HTML
255
+ ```
256
+
257
+ ## Slash commands
258
+
259
+ | Command | Effect |
260
+ |---------|--------|
261
+ | `/mode edit\|plan\|auto` | Switch permission mode |
262
+ | `/shell auto\|bash\|cmd\|powershell` | Show or set the shell for the bash tool |
263
+ | `/thinking low\|medium\|high` | Reasoning effort (persists) |
264
+ | `/theme` | Interactive theme picker (`Ctrl+T`) |
265
+ | `/resume` | Pick a past conversation to restore |
266
+ | `/compact` | Summarize older turns to free context |
267
+ | `/init` | Scan repo and write `KIMI.md` project context |
268
+ | `/memory` | Show memory stats and search |
269
+ | `/mcp list` / `/mcp reload` | Manage MCP servers |
270
+ | `/reasoning` | Toggle chain-of-thought display |
271
+ | `/model` | Pick a model from OpenRouter's catalog (or `/model <id>`, `/model list [filter]`) |
272
+ | `/key` | Show your OpenRouter key's spend and credit (`/key set <key>`, `/key clear`) |
273
+ | `/cost` | Show OpenRouter-confirmed cost by session, day, month and all time |
274
+ | `/update` | Check for updates |
275
+ | `/help` | List all commands |
276
+
277
+ ## Keyboard shortcuts
278
+
279
+ | Shortcut | Action |
280
+ |----------|--------|
281
+ | `Ctrl+C` / `Esc` | Interrupt current turn when busy; exit when idle |
282
+ | `Ctrl+R` | Toggle reasoning display |
283
+ | `Ctrl+O` | Toggle verbose tool output |
284
+ | `Ctrl+T` | Open theme picker |
285
+ | `Shift+Tab` | Cycle mode (edit → plan → auto) |
286
+ | `↑` / `↓` | Walk prompt history |
287
+
288
+ ## Logs
289
+
290
+ KimiFlare writes structured JSON logs of agent-side activity (tool calls,
291
+ permission decisions, MCP/LSP lifecycle, session events, errors) to
292
+ `~/.config/kimiflare/logs/<date>.jsonl`, one file per day, with 7-day
293
+ retention pruned automatically at startup.
294
+
295
+ The logs deliberately exclude prompts and completions. To capture full
296
+ request/response payloads locally for debugging, run with
297
+ `KIMIFLARE_DUMP_LLM=1`; each generation is also visible in your
298
+ [OpenRouter activity log](https://openrouter.ai/activity).
299
+
300
+ ```sh
301
+ autopilot logs path # today's file
302
+ autopilot logs dir # log directory
303
+ autopilot logs prune # delete files older than 7 days
304
+
305
+ # Tail this session's activity, formatted:
306
+ tail -f $(autopilot logs path) | jq
307
+
308
+ # Find the slowest tool calls in the last day:
309
+ jq -r 'select(.event == "tool:end") | "\(.data.duration_ms)\t\(.data.tool)"' \
310
+ $(autopilot logs path) | sort -rn | head
311
+ ```
312
+
313
+ Disable the file sink entirely with `KIMIFLARE_LOG_SINK=off`. The
314
+ separate `KIMIFLARE_LOG_LEVEL` env var (default `off`) controls stderr
315
+ output — independent of the file sink.
316
+
317
+ ### Shipping to an OpenTelemetry collector
318
+
319
+ If you set `KIMIFLARE_OTEL_ENDPOINT`, KimiFlare also ships each log
320
+ entry to that endpoint over [OTLP/HTTP](https://opentelemetry.io/docs/specs/otlp/)
321
+ so it lands in Datadog, Honeycomb, Grafana Loki, an internal collector,
322
+ or any other backend that speaks OTel. Batched every 5 s (or every
323
+ 100 entries, whichever first) and best-effort — never blocks the agent
324
+ loop.
325
+
326
+ ```sh
327
+ # Full path:
328
+ export KIMIFLARE_OTEL_ENDPOINT="https://otel.example.com/v1/logs"
329
+ # Or just the base URL (we auto-append /v1/logs):
330
+ export KIMIFLARE_OTEL_ENDPOINT="https://otel.example.com"
331
+
332
+ # Optional headers (comma-separated key=value pairs) — e.g. for auth:
333
+ export KIMIFLARE_OTEL_HEADERS="Authorization=Bearer xyz,X-Tenant=acme"
334
+ ```
335
+
336
+ Each log entry maps to one OTel `LogRecord`. Correlation IDs
337
+ (`session_id`, `turn_id`, `request_id`) become record attributes,
338
+ `data.*` fields are flattened to attributes with type-preserving
339
+ encoding, and a `service.name=kimiflare` + `service.version` pair sits
340
+ on the resource.
341
+
342
+ ## Hooks
343
+
344
+ KimiFlare can fire shell commands at five points in an agent turn,
345
+ configured per-project (`.kimiflare/settings.json`) or globally
346
+ (`~/.config/kimiflare/settings.json`):
347
+
348
+ | Event | Fires when | Veto? |
349
+ |--------------------|-------------------------------------------------|-------|
350
+ | `PreToolUse` | A tool call is about to run | Yes |
351
+ | `PostToolUse` | A tool call just finished | No |
352
+ | `UserPromptSubmit` | You hit Enter on a prompt | Yes |
353
+ | `Stop` | A turn ended cleanly | No |
354
+ | `PreCompact` | Auto-compaction is about to run | No |
355
+
356
+ Hooks receive the event payload as JSON on stdin **and** as
357
+ `KIMIFLARE_HOOK_*` env vars (for shell-one-liner ergonomics).
358
+ Non-zero exit on a veto event cancels the underlying action and
359
+ surfaces the hook's stdout as the rejection reason.
360
+
361
+ ### Browse + enable from the TUI
362
+
363
+ ```text
364
+ /hooks # list configured hooks
365
+ /hooks recommended # list starter hooks shipped with autopilot
366
+ /hooks enable stop-bell # enable one (writes to .kimiflare/settings.json)
367
+ /hooks enable stop-bell global # ...or the global file
368
+ /hooks disable stop-bell
369
+ /hooks path # print settings.json paths
370
+ /hooks reload # re-read settings.json after a manual edit
371
+ ```
372
+
373
+ The recommended catalog includes terminal bells / macOS notifications
374
+ on `Stop`, secret-file guards on `PreToolUse` (e.g. block edits to
375
+ `*.env`), auto-format-with-prettier on `PostToolUse`, and a tool-call
376
+ audit log. All ship disabled — `/hooks recommended` lists them.
377
+
378
+ ### Schema example
379
+
380
+ ```json
381
+ {
382
+ "hooks": {
383
+ "PreToolUse": [
384
+ {
385
+ "id": "no-secrets",
386
+ "matcher": "^(edit|write)$",
387
+ "command": "case \"$KIMIFLARE_HOOK_PATH\" in *.env|*.pem) echo 'blocked'; exit 1;; esac"
388
+ }
389
+ ],
390
+ "PostToolUse": [
391
+ {
392
+ "id": "format-ts",
393
+ "matcher": "^(edit|write)$",
394
+ "command": "npx --no-install prettier --write \"$KIMIFLARE_HOOK_PATH\" >/dev/null 2>&1 || true"
395
+ }
396
+ ],
397
+ "Stop": [
398
+ { "id": "bell", "command": "printf '\\a'" }
399
+ ]
400
+ }
401
+ }
402
+ ```
403
+
404
+ Per-hook fields:
405
+ - `command` (required) — the shell command.
406
+ - `matcher` (optional) — anchored regex matched against the tool name
407
+ for `PreToolUse` / `PostToolUse`. Ignored for other events.
408
+ - `id` (optional) — stable handle for `/hooks enable|disable`.
409
+ Auto-derived from `event + command` when omitted.
410
+ - `enabled` (default `true`) — set `false` to keep a hook in config
411
+ but skip it.
412
+ - `timeoutMs` (default `30000`) — hard kill if the hook hangs.
413
+ - `description` (optional) — shown by `/hooks list`.
414
+
415
+ Hooks are always-on infrastructure: they fire whether the TUI is open
416
+ or autopilot is running in `--print` mode. They also fire for tool
417
+ calls generated from inside the Code Mode sandbox (heavy-tier turns),
418
+ because hook firing lives on the `ToolExecutor` itself — every call
419
+ path uses the same plumbing.
420
+
421
+ When intent classification has assigned a tier, hook payloads include
422
+ it as `tier: "light" | "medium" | "heavy"` (on `UserPromptSubmit`,
423
+ `PreToolUse`, `PostToolUse`) and as `$KIMIFLARE_HOOK_TIER`. Useful for
424
+ "skip auto-format on light turns" or "audit every heavy-turn write."
425
+
426
+ SDK consumers opt in to hooks with `enableHooks: true` on
427
+ `createAgentSession`. Default is off because the SDK is a primitive,
428
+ not the TUI.
429
+
430
+ ## Development
431
+
432
+ ```sh
433
+ git clone https://github.com/sinameraji/autopilot
434
+ cd autopilot
435
+ npm install
436
+ npm run build
437
+ npm link
438
+ ```
439
+
440
+ Scripts:
441
+ - `npm run build` — bundle with tsup
442
+ - `npm run dev` — run via tsx
443
+ - `npm run typecheck` — `tsc --noEmit`
444
+ - `npm test` — run tests
445
+
446
+ ## Contributing
447
+
448
+ 1. Fork the repository
449
+ 2. Create a branch: `git checkout -b feat/your-feature`
450
+ 3. Make your changes
451
+ 4. Run `npm run typecheck` and `npm run build`
452
+ 5. Commit with [Conventional Commits](https://www.conventionalcommits.org/)
453
+ 6. Open a Pull Request
454
+
455
+ ---
456
+
457
+ Built by [Sina Meraji](https://github.com/sinameraji) and [contributors](https://github.com/sinameraji/autopilot/graphs/contributors) · MIT License
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { startRpcServer } from "../dist/sdk/index.js";
3
+ await startRpcServer();
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import "../dist/index.js";
@@ -0,0 +1,2 @@
1
+
2
+ export { }